Compare commits
41 Commits
inf-663
...
open-relea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c6d3e01869 | ||
|
|
6ee2d4b07e | ||
|
|
2dd093b803 | ||
|
|
2563209ae3 | ||
|
|
0f7921ad1e | ||
|
|
8a6d067481 | ||
|
|
947dd1f1a6 | ||
|
|
e158964c41 | ||
|
|
7dfbd44552 | ||
|
|
d9e60ddd92 | ||
|
|
8d35a729d2 | ||
|
|
e89792b8d8 | ||
|
|
5c3d561152 | ||
|
|
e16dc59955 | ||
|
|
fc95d16536 | ||
|
|
9ce791d1d5 | ||
|
|
5e12d872b8 | ||
|
|
1a9899c696 | ||
|
|
ab18806fa6 | ||
|
|
459511281d | ||
|
|
d58b104027 | ||
|
|
990072e80f | ||
|
|
b92e10e8ae | ||
|
|
1aadbd9c4f | ||
|
|
e2619ef68c | ||
|
|
9350922200 | ||
|
|
1c5b0ac581 | ||
|
|
b4da5d35af | ||
|
|
1886b22cb3 | ||
|
|
db928965e9 | ||
|
|
cff01eb9d1 | ||
|
|
72df5ecb23 | ||
|
|
32593f6736 | ||
|
|
f686fb40a1 | ||
|
|
257e249532 | ||
|
|
87209ab169 | ||
|
|
41f9e5b30a | ||
|
|
32dc8671b2 | ||
|
|
dfd880d4b3 | ||
|
|
6d87bf879d | ||
|
|
c68ed35c59 |
@@ -8,5 +8,4 @@ openedx-release:
|
||||
# The openedx-release key is described in OEP-10:
|
||||
# https://open-edx-proposals.readthedocs.io/en/latest/oep-0010-proc-openedx-releases.html
|
||||
# The FAQ might also be helpful: https://openedx.atlassian.net/wiki/spaces/COMM/pages/1331268879/Open+edX+Release+FAQ
|
||||
maybe: true # Delete this "maybe" line when you have decided about Open edX inclusion.
|
||||
ref: master
|
||||
|
||||
755
package-lock.json
generated
755
package-lock.json
generated
@@ -10,9 +10,9 @@
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
"@edx/brand": "npm:@edx/brand-openedx@1.1.0",
|
||||
"@edx/frontend-component-footer": "11.2.0",
|
||||
"@edx/frontend-component-header": "3.2.0",
|
||||
"@edx/frontend-platform": "2.6.1",
|
||||
"@edx/frontend-component-footer": "12.0.0",
|
||||
"@edx/frontend-component-header": "4.0.0",
|
||||
"@edx/frontend-platform": "4.2.0",
|
||||
"@edx/paragon": "20.15.0",
|
||||
"@reduxjs/toolkit": "1.8.0",
|
||||
"@tinymce/tinymce-react": "3.13.1",
|
||||
@@ -3395,21 +3395,42 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-component-footer": {
|
||||
"version": "11.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-component-footer/-/frontend-component-footer-11.2.0.tgz",
|
||||
"integrity": "sha512-prN6SeoWenbNq6jCqlpmYx57OhNbVGw1wjQFVH+aA5JMjjLUf6PmjPG87fuD9udQyFteb2lvbCyongPEZOozrg==",
|
||||
"version": "12.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-component-footer/-/frontend-component-footer-12.0.0.tgz",
|
||||
"integrity": "sha512-m8Rx6ZPWzIN5XLrz6Ft3aTuFo0rty0jECd79CBYWdm0D9KD1WxoYEG+fElluyOQp/t42T5jLImHTSWjFURx5kw==",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "1.2.36",
|
||||
"@fortawesome/free-brands-svg-icons": "5.15.4",
|
||||
"@fortawesome/free-regular-svg-icons": "5.15.4",
|
||||
"@fortawesome/free-solid-svg-icons": "5.15.4",
|
||||
"@fortawesome/fontawesome-svg-core": "6.4.0",
|
||||
"@fortawesome/free-brands-svg-icons": "6.4.0",
|
||||
"@fortawesome/free-regular-svg-icons": "6.4.0",
|
||||
"@fortawesome/free-solid-svg-icons": "6.4.0",
|
||||
"@fortawesome/react-fontawesome": "0.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@edx/frontend-platform": "^2.3.0",
|
||||
"@edx/frontend-platform": "^4.0.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"react": "^16.9.0",
|
||||
"react-dom": "^16.9.0"
|
||||
"react": "^16.9.0 || ^17.0.0",
|
||||
"react-dom": "^16.9.0 || ^17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-component-footer/node_modules/@fortawesome/fontawesome-common-types": {
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.0.tgz",
|
||||
"integrity": "sha512-HNii132xfomg5QVZw0HwXXpN22s7VBHQBv9CeOu9tfJnhsWQNd2lmTNi8CSrnw5B+5YOmzu1UoPAyxaXsJ6RgQ==",
|
||||
"hasInstallScript": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-component-footer/node_modules/@fortawesome/fontawesome-svg-core": {
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.0.tgz",
|
||||
"integrity": "sha512-Bertv8xOiVELz5raB2FlXDPKt+m94MQ3JgDfsVbrqNpLU9+UE2E18GKjLKw+d3XbeYPqg1pzyQKGsrzbw+pPaw==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-component-footer/node_modules/@fortawesome/react-fontawesome": {
|
||||
@@ -3425,25 +3446,110 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-component-header": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-component-header/-/frontend-component-header-3.2.0.tgz",
|
||||
"integrity": "sha512-ep9yOwe9CG03lSf/QBsBOZO3S/Ksrttgi4MkjpUe/6Sm/KdAnMCOhx2Gbj9jBcFrHqCkpeef26zGjjhpHGDwkQ==",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-component-header/-/frontend-component-header-4.0.0.tgz",
|
||||
"integrity": "sha512-r/L3p2ZSI1DitjxVKAor18GmgJllafYslrdpzGI0vcX/gTemH13jf2Xr9iQqrT921DP2nzZ5GOwGJNptTSjiaA==",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "1.2.36",
|
||||
"@fortawesome/free-brands-svg-icons": "5.15.4",
|
||||
"@fortawesome/free-regular-svg-icons": "5.15.4",
|
||||
"@fortawesome/free-solid-svg-icons": "5.15.4",
|
||||
"@edx/paragon": "20.30.1",
|
||||
"@fortawesome/fontawesome-svg-core": "6.3.0",
|
||||
"@fortawesome/free-brands-svg-icons": "6.3.0",
|
||||
"@fortawesome/free-regular-svg-icons": "6.3.0",
|
||||
"@fortawesome/free-solid-svg-icons": "6.3.0",
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"babel-polyfill": "6.26.0",
|
||||
"react-responsive": "8.2.0",
|
||||
"react-transition-group": "4.4.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@edx/frontend-platform": "^2.0.0",
|
||||
"@edx/paragon": ">= 7.0.0 < 21.0.0",
|
||||
"@edx/frontend-platform": "^4.0.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"react": "^16.9.0",
|
||||
"react-dom": "^16.9.0"
|
||||
"react": "^16.9.0 || ^17.0.0",
|
||||
"react-dom": "^16.9.0 || ^17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-component-header/node_modules/@edx/paragon": {
|
||||
"version": "20.30.1",
|
||||
"resolved": "https://registry.npmjs.org/@edx/paragon/-/paragon-20.30.1.tgz",
|
||||
"integrity": "sha512-v3Ek8deZWqVKi3IWP08Mj4egrvbmbqQEyRA6+qazHZdgHJA4qOP1SST42UKd9XxPeRbLWUgaJWd0iBAOAna/gw==",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^6.1.1",
|
||||
"@fortawesome/react-fontawesome": "^0.1.18",
|
||||
"@popperjs/core": "^2.11.4",
|
||||
"bootstrap": "^4.6.2",
|
||||
"classnames": "^2.3.1",
|
||||
"email-prop-type": "^3.0.0",
|
||||
"file-selector": "^0.6.0",
|
||||
"font-awesome": "^4.7.0",
|
||||
"glob": "^8.0.3",
|
||||
"lodash.uniqby": "^4.7.0",
|
||||
"mailto-link": "^2.0.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"react-bootstrap": "^1.6.5",
|
||||
"react-colorful": "^5.6.1",
|
||||
"react-dropzone": "^14.2.1",
|
||||
"react-focus-on": "^3.5.4",
|
||||
"react-loading-skeleton": "^3.1.0",
|
||||
"react-popper": "^2.2.5",
|
||||
"react-proptype-conditional-require": "^1.0.4",
|
||||
"react-responsive": "^8.2.0",
|
||||
"react-table": "^7.7.0",
|
||||
"react-transition-group": "^4.4.2",
|
||||
"tabbable": "^5.3.3",
|
||||
"uncontrollable": "^7.2.1",
|
||||
"uuid": "^9.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.6 || ^17.0.0",
|
||||
"react-dom": "^16.8.6 || ^17.0.0",
|
||||
"react-intl": "^5.25.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-component-header/node_modules/@edx/paragon/node_modules/@fortawesome/react-fontawesome": {
|
||||
"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==",
|
||||
"dependencies": {
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "~1 || ~6",
|
||||
"react": ">=16.x"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-component-header/node_modules/@fortawesome/free-brands-svg-icons": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.3.0.tgz",
|
||||
"integrity": "sha512-xI0c+a8xnKItAXCN8rZgCNCJQiVAd2Y7p9e2ND6zN3J3ekneu96qrePieJ7yA7073C1JxxoM3vH1RU7rYsaj8w==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-component-header/node_modules/@fortawesome/free-regular-svg-icons": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.3.0.tgz",
|
||||
"integrity": "sha512-cZnwiVHZ51SVzWHOaNCIA+u9wevZjCuAGSvSYpNlm6A4H4Vhwh8481Bf/5rwheIC3fFKlgXxLKaw8Xeroz8Ntg==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-component-header/node_modules/@fortawesome/free-solid-svg-icons": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.3.0.tgz",
|
||||
"integrity": "sha512-x5tMwzF2lTH8pyv8yeZRodItP2IVlzzmBuD1M7BjawWgg9XAvktqJJ91Qjgoaf8qJpHQ8FEU9VxRfOkLhh86QA==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-component-header/node_modules/@fortawesome/react-fontawesome": {
|
||||
@@ -3458,18 +3564,63 @@
|
||||
"react": ">=16.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-component-header/node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-component-header/node_modules/glob": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
|
||||
"integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^5.0.1",
|
||||
"once": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-component-header/node_modules/minimatch": {
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
|
||||
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-component-header/node_modules/uuid": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
|
||||
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-platform": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-platform/-/frontend-platform-2.6.1.tgz",
|
||||
"integrity": "sha512-5ZcHBvwmJRYPPKEqv+H4DbsfW9atr5V2+uY/zX58F/Tqh0T5X8MmgppVjplWFbmon5QV4aNw5C1ViQnirNqUiA==",
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-platform/-/frontend-platform-4.2.0.tgz",
|
||||
"integrity": "sha512-iDoFeccENQKBjqUgdjl5KSwBrjNEj8YW6Ual+6twcHHJUBg3yRoBEphwHIoRREcMgQjhdKVAdWj8eleh4JsEKA==",
|
||||
"dependencies": {
|
||||
"@cospired/i18n-iso-languages": "2.2.0",
|
||||
"@formatjs/intl-pluralrules": "4.3.3",
|
||||
"@formatjs/intl-relativetimeformat": "10.0.1",
|
||||
"axios": "0.26.1",
|
||||
"axios-cache-adapter": "2.7.3",
|
||||
"axios": "0.27.2",
|
||||
"axios-cache-interceptor": "0.10.7",
|
||||
"form-urlencoded": "4.1.4",
|
||||
"glob": "7.2.0",
|
||||
"glob": "7.2.3",
|
||||
"history": "4.10.1",
|
||||
"i18n-iso-countries": "4.3.1",
|
||||
"jwt-decode": "3.1.2",
|
||||
@@ -3484,24 +3635,58 @@
|
||||
"universal-cookie": "4.0.4"
|
||||
},
|
||||
"bin": {
|
||||
"intl-imports.js": "i18n/scripts/intl-imports.js",
|
||||
"transifex-utils.js": "i18n/scripts/transifex-utils.js"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@edx/paragon": ">= 10.0.0 < 21.0.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.9.0",
|
||||
"react-dom": "^16.9.0",
|
||||
"react": "^16.9.0 || ^17.0.0",
|
||||
"react-dom": "^16.9.0 || ^17.0.0",
|
||||
"react-redux": "^7.1.1",
|
||||
"react-router-dom": "^5.0.1",
|
||||
"redux": "^4.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-platform/node_modules/axios": {
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
|
||||
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
|
||||
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.14.8"
|
||||
"follow-redirects": "^1.14.9",
|
||||
"form-data": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-platform/node_modules/form-data": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-platform/node_modules/glob": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.1.1",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/new-relic-source-map-webpack-plugin": {
|
||||
@@ -3548,27 +3733,6 @@
|
||||
"react-intl": "^5.25.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/paragon/node_modules/@fortawesome/fontawesome-common-types": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.0.tgz",
|
||||
"integrity": "sha512-rBevIsj2nclStJ7AxTdfsa3ovHb1H+qApwrxcTVo+NNdeJiB9V75hsKfrkG5AwNcRUNxrPPiScGYCNmLMoh8pg==",
|
||||
"hasInstallScript": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/paragon/node_modules/@fortawesome/fontawesome-svg-core": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.2.0.tgz",
|
||||
"integrity": "sha512-Cf2mAAeMWFMzpLC7Y9H1I4o3wEU+XovVJhTiNG8ZNgSQj53yl7OCJaS80K4YjrABWZzbAHVaoHE1dVJ27AAYXw==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/paragon/node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
@@ -3892,62 +4056,89 @@
|
||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
||||
},
|
||||
"node_modules/@fortawesome/fontawesome-common-types": {
|
||||
"version": "0.2.36",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz",
|
||||
"integrity": "sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg==",
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.3.0.tgz",
|
||||
"integrity": "sha512-4BC1NMoacEBzSXRwKjZ/X/gmnbp/HU5Qqat7E8xqorUtBFZS+bwfGH5/wqOC2K6GV0rgEobp3OjGRMa5fK9pFg==",
|
||||
"hasInstallScript": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/fontawesome-svg-core": {
|
||||
"version": "1.2.36",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.36.tgz",
|
||||
"integrity": "sha512-YUcsLQKYb6DmaJjIHdDWpBIGCcyE/W+p/LMGvjQem55Mm2XWVAP5kWTMKWLv9lwpCVjpLxPyOMOyUocP1GxrtA==",
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.3.0.tgz",
|
||||
"integrity": "sha512-uz9YifyKlixV6AcKlOX8WNdtF7l6nakGyLYxYaCa823bEBqyj/U2ssqtctO38itNEwXb8/lMzjdoJ+aaJuOdrw==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "^0.2.36"
|
||||
"@fortawesome/fontawesome-common-types": "6.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/free-brands-svg-icons": {
|
||||
"version": "5.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.15.4.tgz",
|
||||
"integrity": "sha512-f1witbwycL9cTENJegcmcZRYyawAFbm8+c6IirLmwbbpqz46wyjbQYLuxOc7weXFXfB7QR8/Vd2u5R3q6JYD9g==",
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.4.0.tgz",
|
||||
"integrity": "sha512-qvxTCo0FQ5k2N+VCXb/PZQ+QMhqRVM4OORiO6MXdG6bKolIojGU/srQ1ptvKk0JTbRgaJOfL2qMqGvBEZG7Z6g==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "^0.2.36"
|
||||
"@fortawesome/fontawesome-common-types": "6.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/free-brands-svg-icons/node_modules/@fortawesome/fontawesome-common-types": {
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.0.tgz",
|
||||
"integrity": "sha512-HNii132xfomg5QVZw0HwXXpN22s7VBHQBv9CeOu9tfJnhsWQNd2lmTNi8CSrnw5B+5YOmzu1UoPAyxaXsJ6RgQ==",
|
||||
"hasInstallScript": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/free-regular-svg-icons": {
|
||||
"version": "5.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.15.4.tgz",
|
||||
"integrity": "sha512-9VNNnU3CXHy9XednJ3wzQp6SwNwT3XaM26oS4Rp391GsxVYA+0oDR2J194YCIWf7jNRCYKjUCOduxdceLrx+xw==",
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.4.0.tgz",
|
||||
"integrity": "sha512-ZfycI7D0KWPZtf7wtMFnQxs8qjBXArRzczABuMQqecA/nXohquJ5J/RCR77PmY5qGWkxAZDxpnUFVXKwtY/jPw==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "^0.2.36"
|
||||
"@fortawesome/fontawesome-common-types": "6.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/free-regular-svg-icons/node_modules/@fortawesome/fontawesome-common-types": {
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.0.tgz",
|
||||
"integrity": "sha512-HNii132xfomg5QVZw0HwXXpN22s7VBHQBv9CeOu9tfJnhsWQNd2lmTNi8CSrnw5B+5YOmzu1UoPAyxaXsJ6RgQ==",
|
||||
"hasInstallScript": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/free-solid-svg-icons": {
|
||||
"version": "5.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.4.tgz",
|
||||
"integrity": "sha512-JLmQfz6tdtwxoihXLg6lT78BorrFyCf59SAwBM6qV/0zXyVeDygJVb3fk+j5Qat+Yvcxp1buLTY5iDh1ZSAQ8w==",
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.4.0.tgz",
|
||||
"integrity": "sha512-kutPeRGWm8V5dltFP1zGjQOEAzaLZj4StdQhWVZnfGFCvAPVvHh8qk5bRrU4KXnRRRNni5tKQI9PBAdI6MP8nQ==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "^0.2.36"
|
||||
"@fortawesome/fontawesome-common-types": "6.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/free-solid-svg-icons/node_modules/@fortawesome/fontawesome-common-types": {
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.0.tgz",
|
||||
"integrity": "sha512-HNii132xfomg5QVZw0HwXXpN22s7VBHQBv9CeOu9tfJnhsWQNd2lmTNi8CSrnw5B+5YOmzu1UoPAyxaXsJ6RgQ==",
|
||||
"hasInstallScript": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@fortawesome/react-fontawesome": {
|
||||
"version": "0.1.18",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.18.tgz",
|
||||
@@ -7486,8 +7677,7 @@
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"dev": true
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/at-least-node": {
|
||||
"version": "1.0.0",
|
||||
@@ -7549,20 +7739,22 @@
|
||||
"version": "0.21.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
|
||||
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axios-cache-adapter": {
|
||||
"version": "2.7.3",
|
||||
"resolved": "https://registry.npmjs.org/axios-cache-adapter/-/axios-cache-adapter-2.7.3.tgz",
|
||||
"integrity": "sha512-A+ZKJ9lhpjthOEp4Z3QR/a9xC4du1ALaAsejgRGrH9ef6kSDxdFrhRpulqsh9khsEnwXxGfgpUuDp1YXMNMEiQ==",
|
||||
"node_modules/axios-cache-interceptor": {
|
||||
"version": "0.10.7",
|
||||
"resolved": "https://registry.npmjs.org/axios-cache-interceptor/-/axios-cache-interceptor-0.10.7.tgz",
|
||||
"integrity": "sha512-UjpxChG5DpF6Kf1IPGMLOzRDNL8ZNS6TOn1jTaVvCE7cWFU904jJwi0T1s+IbijpnLEjK2iq5uLIuR8Sj+RsFQ==",
|
||||
"dependencies": {
|
||||
"cache-control-esm": "1.0.0",
|
||||
"md5": "^2.2.1"
|
||||
"cache-parser": "^1.2.4",
|
||||
"fast-defer": "^1.1.7",
|
||||
"object-code": "^1.2.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"axios": "~0.21.1"
|
||||
"funding": {
|
||||
"url": "https://github.com/ArthurFiorette/axios-cache-interceptor?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/axios-mock-adapter": {
|
||||
@@ -8718,10 +8910,10 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cache-control-esm": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cache-control-esm/-/cache-control-esm-1.0.0.tgz",
|
||||
"integrity": "sha512-Fa3UV4+eIk4EOih8FTV6EEsVKO0W5XWtNs6FC3InTfVz+EjurjPfDXY5wZDo/lxjDxg5RjNcurLyxEJBcEUx9g=="
|
||||
"node_modules/cache-parser": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/cache-parser/-/cache-parser-1.2.4.tgz",
|
||||
"integrity": "sha512-O0KwuHuJnbHUrghHi2kGp0SxnWSIBXTYt7M8WVhW0kbPRUNUKoE/Of6e1rRD6AAxmfxFunKnt90yEK09D+sc5g=="
|
||||
},
|
||||
"node_modules/cacheable-request": {
|
||||
"version": "2.1.4",
|
||||
@@ -8954,14 +9146,6 @@
|
||||
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/charenc": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
|
||||
"integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/check-types": {
|
||||
"version": "8.0.3",
|
||||
"resolved": "https://registry.npmjs.org/check-types/-/check-types-8.0.3.tgz",
|
||||
@@ -9404,7 +9588,6 @@
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
@@ -9703,14 +9886,6 @@
|
||||
"semver": "bin/semver"
|
||||
}
|
||||
},
|
||||
"node_modules/crypt": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
|
||||
"integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/css": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz",
|
||||
@@ -10506,7 +10681,6 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
@@ -12349,6 +12523,11 @@
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||
},
|
||||
"node_modules/fast-defer": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/fast-defer/-/fast-defer-1.1.7.tgz",
|
||||
"integrity": "sha512-tJ01ulDWT2WhqxMKS20nXX6wyX2iInBYpbN3GO7yjKwXMY4qvkdBRxak9IFwBLlFDESox+SwSvqMCZDfe1tqeg=="
|
||||
},
|
||||
"node_modules/fast-glob": {
|
||||
"version": "3.2.11",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
|
||||
@@ -13417,6 +13596,7 @@
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
|
||||
"integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
@@ -19703,21 +19883,6 @@
|
||||
"css-mediaquery": "^0.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/md5": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
|
||||
"integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
|
||||
"dependencies": {
|
||||
"charenc": "0.0.2",
|
||||
"crypt": "0.0.2",
|
||||
"is-buffer": "~1.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/md5/node_modules/is-buffer": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
|
||||
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
|
||||
},
|
||||
"node_modules/mdn-data": {
|
||||
"version": "2.0.14",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
|
||||
@@ -20295,6 +20460,11 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/object-code": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/object-code/-/object-code-1.2.4.tgz",
|
||||
"integrity": "sha512-uGq4ETUuWe+GA586NXEriiaozNuff+YNFXlpD8cVrM1GoiuTZpCABP+bZCWDrvQDoCiSTyiWAFHD/HF/iwhb2w=="
|
||||
},
|
||||
"node_modules/object-copy": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
|
||||
@@ -22285,6 +22455,15 @@
|
||||
"react": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-colorful": {
|
||||
"version": "5.6.1",
|
||||
"resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz",
|
||||
"integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==",
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dev-utils": {
|
||||
"version": "12.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.0.tgz",
|
||||
@@ -30022,17 +30201,30 @@
|
||||
}
|
||||
},
|
||||
"@edx/frontend-component-footer": {
|
||||
"version": "11.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-component-footer/-/frontend-component-footer-11.2.0.tgz",
|
||||
"integrity": "sha512-prN6SeoWenbNq6jCqlpmYx57OhNbVGw1wjQFVH+aA5JMjjLUf6PmjPG87fuD9udQyFteb2lvbCyongPEZOozrg==",
|
||||
"version": "12.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-component-footer/-/frontend-component-footer-12.0.0.tgz",
|
||||
"integrity": "sha512-m8Rx6ZPWzIN5XLrz6Ft3aTuFo0rty0jECd79CBYWdm0D9KD1WxoYEG+fElluyOQp/t42T5jLImHTSWjFURx5kw==",
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-svg-core": "1.2.36",
|
||||
"@fortawesome/free-brands-svg-icons": "5.15.4",
|
||||
"@fortawesome/free-regular-svg-icons": "5.15.4",
|
||||
"@fortawesome/free-solid-svg-icons": "5.15.4",
|
||||
"@fortawesome/fontawesome-svg-core": "6.4.0",
|
||||
"@fortawesome/free-brands-svg-icons": "6.4.0",
|
||||
"@fortawesome/free-regular-svg-icons": "6.4.0",
|
||||
"@fortawesome/free-solid-svg-icons": "6.4.0",
|
||||
"@fortawesome/react-fontawesome": "0.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": {
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.0.tgz",
|
||||
"integrity": "sha512-HNii132xfomg5QVZw0HwXXpN22s7VBHQBv9CeOu9tfJnhsWQNd2lmTNi8CSrnw5B+5YOmzu1UoPAyxaXsJ6RgQ=="
|
||||
},
|
||||
"@fortawesome/fontawesome-svg-core": {
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.0.tgz",
|
||||
"integrity": "sha512-Bertv8xOiVELz5raB2FlXDPKt+m94MQ3JgDfsVbrqNpLU9+UE2E18GKjLKw+d3XbeYPqg1pzyQKGsrzbw+pPaw==",
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-common-types": "6.4.0"
|
||||
}
|
||||
},
|
||||
"@fortawesome/react-fontawesome": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz",
|
||||
@@ -30044,20 +30236,87 @@
|
||||
}
|
||||
},
|
||||
"@edx/frontend-component-header": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-component-header/-/frontend-component-header-3.2.0.tgz",
|
||||
"integrity": "sha512-ep9yOwe9CG03lSf/QBsBOZO3S/Ksrttgi4MkjpUe/6Sm/KdAnMCOhx2Gbj9jBcFrHqCkpeef26zGjjhpHGDwkQ==",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-component-header/-/frontend-component-header-4.0.0.tgz",
|
||||
"integrity": "sha512-r/L3p2ZSI1DitjxVKAor18GmgJllafYslrdpzGI0vcX/gTemH13jf2Xr9iQqrT921DP2nzZ5GOwGJNptTSjiaA==",
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-svg-core": "1.2.36",
|
||||
"@fortawesome/free-brands-svg-icons": "5.15.4",
|
||||
"@fortawesome/free-regular-svg-icons": "5.15.4",
|
||||
"@fortawesome/free-solid-svg-icons": "5.15.4",
|
||||
"@edx/paragon": "20.30.1",
|
||||
"@fortawesome/fontawesome-svg-core": "6.3.0",
|
||||
"@fortawesome/free-brands-svg-icons": "6.3.0",
|
||||
"@fortawesome/free-regular-svg-icons": "6.3.0",
|
||||
"@fortawesome/free-solid-svg-icons": "6.3.0",
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"babel-polyfill": "6.26.0",
|
||||
"react-responsive": "8.2.0",
|
||||
"react-transition-group": "4.4.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@edx/paragon": {
|
||||
"version": "20.30.1",
|
||||
"resolved": "https://registry.npmjs.org/@edx/paragon/-/paragon-20.30.1.tgz",
|
||||
"integrity": "sha512-v3Ek8deZWqVKi3IWP08Mj4egrvbmbqQEyRA6+qazHZdgHJA4qOP1SST42UKd9XxPeRbLWUgaJWd0iBAOAna/gw==",
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-svg-core": "^6.1.1",
|
||||
"@fortawesome/react-fontawesome": "^0.1.18",
|
||||
"@popperjs/core": "^2.11.4",
|
||||
"bootstrap": "^4.6.2",
|
||||
"classnames": "^2.3.1",
|
||||
"email-prop-type": "^3.0.0",
|
||||
"file-selector": "^0.6.0",
|
||||
"font-awesome": "^4.7.0",
|
||||
"glob": "^8.0.3",
|
||||
"lodash.uniqby": "^4.7.0",
|
||||
"mailto-link": "^2.0.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"react-bootstrap": "^1.6.5",
|
||||
"react-colorful": "^5.6.1",
|
||||
"react-dropzone": "^14.2.1",
|
||||
"react-focus-on": "^3.5.4",
|
||||
"react-loading-skeleton": "^3.1.0",
|
||||
"react-popper": "^2.2.5",
|
||||
"react-proptype-conditional-require": "^1.0.4",
|
||||
"react-responsive": "^8.2.0",
|
||||
"react-table": "^7.7.0",
|
||||
"react-transition-group": "^4.4.2",
|
||||
"tabbable": "^5.3.3",
|
||||
"uncontrollable": "^7.2.1",
|
||||
"uuid": "^9.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/react-fontawesome": {
|
||||
"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==",
|
||||
"requires": {
|
||||
"prop-types": "^15.8.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@fortawesome/free-brands-svg-icons": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.3.0.tgz",
|
||||
"integrity": "sha512-xI0c+a8xnKItAXCN8rZgCNCJQiVAd2Y7p9e2ND6zN3J3ekneu96qrePieJ7yA7073C1JxxoM3vH1RU7rYsaj8w==",
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-common-types": "6.3.0"
|
||||
}
|
||||
},
|
||||
"@fortawesome/free-regular-svg-icons": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.3.0.tgz",
|
||||
"integrity": "sha512-cZnwiVHZ51SVzWHOaNCIA+u9wevZjCuAGSvSYpNlm6A4H4Vhwh8481Bf/5rwheIC3fFKlgXxLKaw8Xeroz8Ntg==",
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-common-types": "6.3.0"
|
||||
}
|
||||
},
|
||||
"@fortawesome/free-solid-svg-icons": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.3.0.tgz",
|
||||
"integrity": "sha512-x5tMwzF2lTH8pyv8yeZRodItP2IVlzzmBuD1M7BjawWgg9XAvktqJJ91Qjgoaf8qJpHQ8FEU9VxRfOkLhh86QA==",
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-common-types": "6.3.0"
|
||||
}
|
||||
},
|
||||
"@fortawesome/react-fontawesome": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz",
|
||||
@@ -30065,21 +30324,54 @@
|
||||
"requires": {
|
||||
"prop-types": "^15.8.1"
|
||||
}
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"glob": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
|
||||
"integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^5.0.1",
|
||||
"once": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
|
||||
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
|
||||
"requires": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"uuid": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
|
||||
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@edx/frontend-platform": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-platform/-/frontend-platform-2.6.1.tgz",
|
||||
"integrity": "sha512-5ZcHBvwmJRYPPKEqv+H4DbsfW9atr5V2+uY/zX58F/Tqh0T5X8MmgppVjplWFbmon5QV4aNw5C1ViQnirNqUiA==",
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-platform/-/frontend-platform-4.2.0.tgz",
|
||||
"integrity": "sha512-iDoFeccENQKBjqUgdjl5KSwBrjNEj8YW6Ual+6twcHHJUBg3yRoBEphwHIoRREcMgQjhdKVAdWj8eleh4JsEKA==",
|
||||
"requires": {
|
||||
"@cospired/i18n-iso-languages": "2.2.0",
|
||||
"@formatjs/intl-pluralrules": "4.3.3",
|
||||
"@formatjs/intl-relativetimeformat": "10.0.1",
|
||||
"axios": "0.26.1",
|
||||
"axios-cache-adapter": "2.7.3",
|
||||
"axios": "0.27.2",
|
||||
"axios-cache-interceptor": "0.10.7",
|
||||
"form-urlencoded": "4.1.4",
|
||||
"glob": "7.2.0",
|
||||
"glob": "7.2.3",
|
||||
"history": "4.10.1",
|
||||
"i18n-iso-countries": "4.3.1",
|
||||
"jwt-decode": "3.1.2",
|
||||
@@ -30095,11 +30387,35 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": {
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
|
||||
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
|
||||
"version": "0.27.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
|
||||
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.14.8"
|
||||
"follow-redirects": "^1.14.9",
|
||||
"form-data": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"form-data": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.1.1",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30143,19 +30459,6 @@
|
||||
"uncontrollable": "^7.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.0.tgz",
|
||||
"integrity": "sha512-rBevIsj2nclStJ7AxTdfsa3ovHb1H+qApwrxcTVo+NNdeJiB9V75hsKfrkG5AwNcRUNxrPPiScGYCNmLMoh8pg=="
|
||||
},
|
||||
"@fortawesome/fontawesome-svg-core": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.2.0.tgz",
|
||||
"integrity": "sha512-Cf2mAAeMWFMzpLC7Y9H1I4o3wEU+XovVJhTiNG8ZNgSQj53yl7OCJaS80K4YjrABWZzbAHVaoHE1dVJ27AAYXw==",
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-common-types": "6.2.0"
|
||||
}
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
@@ -30479,40 +30782,61 @@
|
||||
}
|
||||
},
|
||||
"@fortawesome/fontawesome-common-types": {
|
||||
"version": "0.2.36",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz",
|
||||
"integrity": "sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg=="
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.3.0.tgz",
|
||||
"integrity": "sha512-4BC1NMoacEBzSXRwKjZ/X/gmnbp/HU5Qqat7E8xqorUtBFZS+bwfGH5/wqOC2K6GV0rgEobp3OjGRMa5fK9pFg=="
|
||||
},
|
||||
"@fortawesome/fontawesome-svg-core": {
|
||||
"version": "1.2.36",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.36.tgz",
|
||||
"integrity": "sha512-YUcsLQKYb6DmaJjIHdDWpBIGCcyE/W+p/LMGvjQem55Mm2XWVAP5kWTMKWLv9lwpCVjpLxPyOMOyUocP1GxrtA==",
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.3.0.tgz",
|
||||
"integrity": "sha512-uz9YifyKlixV6AcKlOX8WNdtF7l6nakGyLYxYaCa823bEBqyj/U2ssqtctO38itNEwXb8/lMzjdoJ+aaJuOdrw==",
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-common-types": "^0.2.36"
|
||||
"@fortawesome/fontawesome-common-types": "6.3.0"
|
||||
}
|
||||
},
|
||||
"@fortawesome/free-brands-svg-icons": {
|
||||
"version": "5.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.15.4.tgz",
|
||||
"integrity": "sha512-f1witbwycL9cTENJegcmcZRYyawAFbm8+c6IirLmwbbpqz46wyjbQYLuxOc7weXFXfB7QR8/Vd2u5R3q6JYD9g==",
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.4.0.tgz",
|
||||
"integrity": "sha512-qvxTCo0FQ5k2N+VCXb/PZQ+QMhqRVM4OORiO6MXdG6bKolIojGU/srQ1ptvKk0JTbRgaJOfL2qMqGvBEZG7Z6g==",
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-common-types": "^0.2.36"
|
||||
"@fortawesome/fontawesome-common-types": "6.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": {
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.0.tgz",
|
||||
"integrity": "sha512-HNii132xfomg5QVZw0HwXXpN22s7VBHQBv9CeOu9tfJnhsWQNd2lmTNi8CSrnw5B+5YOmzu1UoPAyxaXsJ6RgQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@fortawesome/free-regular-svg-icons": {
|
||||
"version": "5.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.15.4.tgz",
|
||||
"integrity": "sha512-9VNNnU3CXHy9XednJ3wzQp6SwNwT3XaM26oS4Rp391GsxVYA+0oDR2J194YCIWf7jNRCYKjUCOduxdceLrx+xw==",
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.4.0.tgz",
|
||||
"integrity": "sha512-ZfycI7D0KWPZtf7wtMFnQxs8qjBXArRzczABuMQqecA/nXohquJ5J/RCR77PmY5qGWkxAZDxpnUFVXKwtY/jPw==",
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-common-types": "^0.2.36"
|
||||
"@fortawesome/fontawesome-common-types": "6.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": {
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.0.tgz",
|
||||
"integrity": "sha512-HNii132xfomg5QVZw0HwXXpN22s7VBHQBv9CeOu9tfJnhsWQNd2lmTNi8CSrnw5B+5YOmzu1UoPAyxaXsJ6RgQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@fortawesome/free-solid-svg-icons": {
|
||||
"version": "5.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.4.tgz",
|
||||
"integrity": "sha512-JLmQfz6tdtwxoihXLg6lT78BorrFyCf59SAwBM6qV/0zXyVeDygJVb3fk+j5Qat+Yvcxp1buLTY5iDh1ZSAQ8w==",
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.4.0.tgz",
|
||||
"integrity": "sha512-kutPeRGWm8V5dltFP1zGjQOEAzaLZj4StdQhWVZnfGFCvAPVvHh8qk5bRrU4KXnRRRNni5tKQI9PBAdI6MP8nQ==",
|
||||
"requires": {
|
||||
"@fortawesome/fontawesome-common-types": "^0.2.36"
|
||||
"@fortawesome/fontawesome-common-types": "6.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": {
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.0.tgz",
|
||||
"integrity": "sha512-HNii132xfomg5QVZw0HwXXpN22s7VBHQBv9CeOu9tfJnhsWQNd2lmTNi8CSrnw5B+5YOmzu1UoPAyxaXsJ6RgQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@fortawesome/react-fontawesome": {
|
||||
@@ -33259,8 +33583,7 @@
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"dev": true
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"at-least-node": {
|
||||
"version": "1.0.0",
|
||||
@@ -33297,17 +33620,19 @@
|
||||
"version": "0.21.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
|
||||
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"follow-redirects": "^1.14.0"
|
||||
}
|
||||
},
|
||||
"axios-cache-adapter": {
|
||||
"version": "2.7.3",
|
||||
"resolved": "https://registry.npmjs.org/axios-cache-adapter/-/axios-cache-adapter-2.7.3.tgz",
|
||||
"integrity": "sha512-A+ZKJ9lhpjthOEp4Z3QR/a9xC4du1ALaAsejgRGrH9ef6kSDxdFrhRpulqsh9khsEnwXxGfgpUuDp1YXMNMEiQ==",
|
||||
"axios-cache-interceptor": {
|
||||
"version": "0.10.7",
|
||||
"resolved": "https://registry.npmjs.org/axios-cache-interceptor/-/axios-cache-interceptor-0.10.7.tgz",
|
||||
"integrity": "sha512-UjpxChG5DpF6Kf1IPGMLOzRDNL8ZNS6TOn1jTaVvCE7cWFU904jJwi0T1s+IbijpnLEjK2iq5uLIuR8Sj+RsFQ==",
|
||||
"requires": {
|
||||
"cache-control-esm": "1.0.0",
|
||||
"md5": "^2.2.1"
|
||||
"cache-parser": "^1.2.4",
|
||||
"fast-defer": "^1.1.7",
|
||||
"object-code": "^1.2.4"
|
||||
}
|
||||
},
|
||||
"axios-mock-adapter": {
|
||||
@@ -34227,10 +34552,10 @@
|
||||
"unset-value": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"cache-control-esm": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cache-control-esm/-/cache-control-esm-1.0.0.tgz",
|
||||
"integrity": "sha512-Fa3UV4+eIk4EOih8FTV6EEsVKO0W5XWtNs6FC3InTfVz+EjurjPfDXY5wZDo/lxjDxg5RjNcurLyxEJBcEUx9g=="
|
||||
"cache-parser": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/cache-parser/-/cache-parser-1.2.4.tgz",
|
||||
"integrity": "sha512-O0KwuHuJnbHUrghHi2kGp0SxnWSIBXTYt7M8WVhW0kbPRUNUKoE/Of6e1rRD6AAxmfxFunKnt90yEK09D+sc5g=="
|
||||
},
|
||||
"cacheable-request": {
|
||||
"version": "2.1.4",
|
||||
@@ -34415,11 +34740,6 @@
|
||||
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
|
||||
"dev": true
|
||||
},
|
||||
"charenc": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
|
||||
"integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA=="
|
||||
},
|
||||
"check-types": {
|
||||
"version": "8.0.3",
|
||||
"resolved": "https://registry.npmjs.org/check-types/-/check-types-8.0.3.tgz",
|
||||
@@ -34778,7 +35098,6 @@
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
}
|
||||
@@ -35012,11 +35331,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"crypt": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
|
||||
"integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow=="
|
||||
},
|
||||
"css": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz",
|
||||
@@ -35620,8 +35934,7 @@
|
||||
"delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
|
||||
},
|
||||
"depd": {
|
||||
"version": "2.0.0",
|
||||
@@ -37087,6 +37400,11 @@
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||
},
|
||||
"fast-defer": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/fast-defer/-/fast-defer-1.1.7.tgz",
|
||||
"integrity": "sha512-tJ01ulDWT2WhqxMKS20nXX6wyX2iInBYpbN3GO7yjKwXMY4qvkdBRxak9IFwBLlFDESox+SwSvqMCZDfe1tqeg=="
|
||||
},
|
||||
"fast-glob": {
|
||||
"version": "3.2.11",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
|
||||
@@ -37870,6 +38188,7 @@
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
|
||||
"integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
@@ -42659,23 +42978,6 @@
|
||||
"css-mediaquery": "^0.1.2"
|
||||
}
|
||||
},
|
||||
"md5": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
|
||||
"integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
|
||||
"requires": {
|
||||
"charenc": "0.0.2",
|
||||
"crypt": "0.0.2",
|
||||
"is-buffer": "~1.1.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-buffer": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
|
||||
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"mdn-data": {
|
||||
"version": "2.0.14",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
|
||||
@@ -43123,6 +43425,11 @@
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
|
||||
},
|
||||
"object-code": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/object-code/-/object-code-1.2.4.tgz",
|
||||
"integrity": "sha512-uGq4ETUuWe+GA586NXEriiaozNuff+YNFXlpD8cVrM1GoiuTZpCABP+bZCWDrvQDoCiSTyiWAFHD/HF/iwhb2w=="
|
||||
},
|
||||
"object-copy": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
|
||||
@@ -44535,6 +44842,12 @@
|
||||
"@babel/runtime": "^7.12.13"
|
||||
}
|
||||
},
|
||||
"react-colorful": {
|
||||
"version": "5.6.1",
|
||||
"resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz",
|
||||
"integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==",
|
||||
"requires": {}
|
||||
},
|
||||
"react-dev-utils": {
|
||||
"version": "12.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.0.tgz",
|
||||
|
||||
@@ -34,9 +34,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@edx/brand": "npm:@edx/brand-openedx@1.1.0",
|
||||
"@edx/frontend-component-footer": "11.2.0",
|
||||
"@edx/frontend-component-header": "3.2.0",
|
||||
"@edx/frontend-platform": "2.6.1",
|
||||
"@edx/frontend-component-footer": "12.0.0",
|
||||
"@edx/frontend-component-header": "4.0.0",
|
||||
"@edx/frontend-platform": "4.2.0",
|
||||
"@edx/paragon": "20.15.0",
|
||||
"@reduxjs/toolkit": "1.8.0",
|
||||
"@tinymce/tinymce-react": "3.13.1",
|
||||
|
||||
@@ -101,7 +101,7 @@ function FilterBar({
|
||||
<span className="text-primary-700 pr-4">
|
||||
{intl.formatMessage(messages.sortFilterStatus, {
|
||||
own: false,
|
||||
type: selectedFilters.type,
|
||||
type: selectedFilters.postType,
|
||||
sort: selectedFilters.orderBy,
|
||||
status: selectedFilters.status,
|
||||
cohortType: selectedCohort?.name ? 'group' : 'all',
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { camelCaseObject } from '@edx/frontend-platform';
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
|
||||
import { API_BASE_URL } from '../../../data/constants';
|
||||
import { getApiBaseUrl } from '../../../data/constants';
|
||||
|
||||
function normalizeCourseHomeCourseMetadata(metadata, rootSlug) {
|
||||
const data = camelCaseObject(metadata);
|
||||
@@ -21,7 +21,7 @@ function normalizeCourseHomeCourseMetadata(metadata, rootSlug) {
|
||||
}
|
||||
|
||||
export async function getCourseHomeCourseMetadata(courseId, rootSlug) {
|
||||
const url = `${API_BASE_URL}/api/course_home/course_metadata/${courseId}`;
|
||||
const url = `${getApiBaseUrl()}/api/course_home/course_metadata/${courseId}`;
|
||||
// don't know the context of adding timezone in url. hence omitting it
|
||||
// url = appendBrowserTimezoneToUrl(url);
|
||||
const { data } = await getAuthenticatedHttpClient().get(url);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useContext, useEffect } from 'react';
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
|
||||
import camelCase from 'lodash/camelCase';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
@@ -14,6 +14,7 @@ import postsMessages from '../discussions/posts/post-actions-bar/messages';
|
||||
import { setFilter as setTopicFilter } from '../discussions/topics/data/slices';
|
||||
|
||||
function Search({ intl }) {
|
||||
const [previousSearchValue, setPreviousSearchValue] = useState('');
|
||||
const dispatch = useDispatch();
|
||||
const { page } = useContext(DiscussionContext);
|
||||
const postSearch = useSelector(({ threads }) => threads.filters.search);
|
||||
@@ -35,6 +36,7 @@ function Search({ intl }) {
|
||||
dispatch(setSearchQuery(''));
|
||||
dispatch(setTopicFilter(''));
|
||||
dispatch(setUsernameSearch(''));
|
||||
setPreviousSearchValue('');
|
||||
};
|
||||
|
||||
const onChange = (query) => {
|
||||
@@ -42,7 +44,7 @@ function Search({ intl }) {
|
||||
};
|
||||
|
||||
const onSubmit = (query) => {
|
||||
if (query === '') {
|
||||
if (query === '' || query === previousSearchValue) {
|
||||
return;
|
||||
}
|
||||
if (isPostSearch) {
|
||||
@@ -52,6 +54,7 @@ function Search({ intl }) {
|
||||
} else if (page === 'learners') {
|
||||
dispatch(setUsernameSearch(query));
|
||||
}
|
||||
setPreviousSearchValue(query);
|
||||
};
|
||||
|
||||
useEffect(() => onClear(), [page]);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
|
||||
import { API_BASE_URL } from './constants';
|
||||
import { getApiBaseUrl } from './constants';
|
||||
|
||||
export const blocksAPIURL = `${API_BASE_URL}/api/courses/v1/blocks/`;
|
||||
export const getBlocksAPIURL = () => `${getApiBaseUrl()}/api/courses/v1/blocks/`;
|
||||
export async function getCourseBlocks(courseId, username) {
|
||||
const params = {
|
||||
course_id: courseId,
|
||||
@@ -14,6 +14,6 @@ export async function getCourseBlocks(courseId, username) {
|
||||
student_view_data: 'discussion',
|
||||
};
|
||||
const { data } = await getAuthenticatedHttpClient()
|
||||
.get(blocksAPIURL, { params });
|
||||
.get(getBlocksAPIURL(), { params });
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
|
||||
export const API_BASE_URL = getConfig().LMS_BASE_URL;
|
||||
export const getApiBaseUrl = () => getConfig().LMS_BASE_URL;
|
||||
|
||||
/**
|
||||
* Enum for thread types.
|
||||
@@ -90,16 +90,6 @@ export const ThreadOrdering = {
|
||||
BY_VOTE_COUNT: 'voteCount',
|
||||
};
|
||||
|
||||
/**
|
||||
* Enum for thread view status filtering.
|
||||
* @readonly
|
||||
* @enum {string}
|
||||
*/
|
||||
export const ThreadViewStatus = {
|
||||
UNREAD: 'unread',
|
||||
UNANSWERED: 'unanswered',
|
||||
};
|
||||
|
||||
/**
|
||||
* Enum for filtering posts by status.
|
||||
* @readonly
|
||||
|
||||
@@ -7,10 +7,11 @@ import { initializeMockApp } from '@edx/frontend-platform/testing';
|
||||
import { initializeStore } from '../store';
|
||||
import { executeThunk } from '../test-utils';
|
||||
import { getBlocksAPIResponse } from './__factories__';
|
||||
import { blocksAPIURL } from './api';
|
||||
import { getBlocksAPIURL } from './api';
|
||||
import { RequestStatus } from './constants';
|
||||
import { fetchCourseBlocks } from './thunks';
|
||||
|
||||
const blocksAPIURL = getBlocksAPIURL();
|
||||
const courseId = 'course-v1:edX+DemoX+Demo_Course';
|
||||
|
||||
let axiosMock;
|
||||
|
||||
@@ -6,9 +6,7 @@ ensureConfig([
|
||||
'LMS_BASE_URL',
|
||||
], 'Comments API service');
|
||||
|
||||
const apiBaseUrl = getConfig().LMS_BASE_URL;
|
||||
|
||||
export const getCohortsApiUrl = courseId => `${apiBaseUrl}/api/cohorts/v1/courses/${courseId}/cohorts/`;
|
||||
export const getCohortsApiUrl = courseId => `${getConfig().LMS_BASE_URL}/api/cohorts/v1/courses/${courseId}/cohorts/`;
|
||||
|
||||
export async function getCourseCohorts(courseId) {
|
||||
const params = snakeCaseObject({ courseId });
|
||||
|
||||
@@ -1,18 +1,28 @@
|
||||
import React, { useEffect, useMemo } from 'react';
|
||||
import React, { useContext, useEffect, useMemo } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useParams } from 'react-router';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Button, Spinner } from '@edx/paragon';
|
||||
import {
|
||||
Button, Icon, IconButton, Spinner,
|
||||
} from '@edx/paragon';
|
||||
import { ArrowBack } from '@edx/paragon/icons';
|
||||
|
||||
import { EndorsementStatus, ThreadType } from '../../data/constants';
|
||||
import {
|
||||
EndorsementStatus, PostsPages, ThreadType,
|
||||
} from '../../data/constants';
|
||||
import { useDispatchWithState } from '../../data/hooks';
|
||||
import { DiscussionContext } from '../common/context';
|
||||
import { useIsOnDesktop } from '../data/hooks';
|
||||
import { EmptyPage } from '../empty-posts';
|
||||
import { Post } from '../posts';
|
||||
import { selectThread } from '../posts/data/selectors';
|
||||
import { fetchThread, markThreadAsRead } from '../posts/data/thunks';
|
||||
import { filterPosts } from '../utils';
|
||||
import { discussionsPath, filterPosts } from '../utils';
|
||||
import { selectThreadComments, selectThreadCurrentPage, selectThreadHasMorePages } from './data/selectors';
|
||||
import { fetchThreadComments } from './data/thunks';
|
||||
import { Comment, ResponseEditor } from './comment';
|
||||
@@ -124,23 +134,74 @@ DiscussionCommentsView.propTypes = {
|
||||
};
|
||||
|
||||
function CommentsView({ intl }) {
|
||||
const [isLoading, submitDispatch] = useDispatchWithState();
|
||||
const { postId } = useParams();
|
||||
const thread = usePost(postId);
|
||||
const dispatch = useDispatch();
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
const isOnDesktop = useIsOnDesktop();
|
||||
const {
|
||||
courseId, learnerUsername, category, topicId, page, inContext,
|
||||
} = useContext(DiscussionContext);
|
||||
|
||||
useEffect(() => {
|
||||
if (!thread) { submitDispatch(fetchThread(postId, courseId, true)); }
|
||||
}, [postId]);
|
||||
|
||||
if (!thread) {
|
||||
dispatch(fetchThread(postId, true));
|
||||
if (!isLoading) {
|
||||
return (
|
||||
<EmptyPage title={intl.formatMessage(messages.noThreadFound)} />
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Spinner animation="border" variant="primary" data-testid="loading-indicator" />
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="discussion-comments d-flex flex-column m-4 p-4.5 card">
|
||||
{!isOnDesktop && (
|
||||
inContext ? (
|
||||
<>
|
||||
<div className="px-4 py-1.5 bg-white">
|
||||
<Button
|
||||
variant="plain"
|
||||
className="px-0 font-weight-light text-primary-500"
|
||||
iconBefore={ArrowBack}
|
||||
onClick={() => history.push(discussionsPath(PostsPages[page], {
|
||||
courseId, learnerUsername, category, topicId,
|
||||
})(location))}
|
||||
size="sm"
|
||||
>
|
||||
{intl.formatMessage(messages.backAlt)}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="border-bottom border-light-400" />
|
||||
</>
|
||||
) : (
|
||||
<IconButton
|
||||
src={ArrowBack}
|
||||
iconAs={Icon}
|
||||
style={{ padding: '18px' }}
|
||||
size="inline"
|
||||
className="ml-4 mt-4"
|
||||
onClick={() => history.push(discussionsPath(PostsPages[page], {
|
||||
courseId, learnerUsername, category, topicId,
|
||||
})(location))}
|
||||
alt={intl.formatMessage(messages.backAlt)}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
<div className={classNames('discussion-comments d-flex flex-column card', {
|
||||
'm-4 p-4.5': !inContext,
|
||||
'p-4 rounded-0 border-0 mb-4': inContext,
|
||||
})}
|
||||
>
|
||||
<Post post={thread} />
|
||||
{!thread.closed && <ResponseEditor postId={postId} /> }
|
||||
</div>
|
||||
{thread.type === ThreadType.DISCUSSION
|
||||
&& (
|
||||
{thread.type === ThreadType.DISCUSSION && (
|
||||
<DiscussionCommentsView
|
||||
postId={postId}
|
||||
intl={intl}
|
||||
@@ -148,7 +209,7 @@ function CommentsView({ intl }) {
|
||||
endorsed={EndorsementStatus.DISCUSSION}
|
||||
isClosed={thread.closed}
|
||||
/>
|
||||
)}
|
||||
)}
|
||||
{thread.type === ThreadType.QUESTION && (
|
||||
<>
|
||||
<DiscussionCommentsView
|
||||
|
||||
@@ -13,16 +13,19 @@ import { AppProvider } from '@edx/frontend-platform/react';
|
||||
import { initializeStore } from '../../store';
|
||||
import { executeThunk } from '../../test-utils';
|
||||
import { DiscussionContext } from '../common/context';
|
||||
import { courseConfigApiUrl } from '../data/api';
|
||||
import { getCourseConfigApiUrl } from '../data/api';
|
||||
import { fetchCourseConfig } from '../data/thunks';
|
||||
import DiscussionContent from '../discussions-home/DiscussionContent';
|
||||
import { threadsApiUrl } from '../posts/data/api';
|
||||
import { getThreadsApiUrl } from '../posts/data/api';
|
||||
import { fetchThreads } from '../posts/data/thunks';
|
||||
import { commentsApiUrl } from './data/api';
|
||||
import { getCommentsApiUrl } from './data/api';
|
||||
|
||||
import '../posts/data/__factories__';
|
||||
import './data/__factories__';
|
||||
|
||||
const courseConfigApiUrl = getCourseConfigApiUrl();
|
||||
const commentsApiUrl = getCommentsApiUrl();
|
||||
const threadsApiUrl = getThreadsApiUrl();
|
||||
const discussionPostId = 'thread-1';
|
||||
const questionPostId = 'thread-2';
|
||||
const closedPostId = 'thread-2';
|
||||
@@ -102,7 +105,7 @@ function renderComponent(postId) {
|
||||
}
|
||||
|
||||
describe('CommentsView', () => {
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
initializeMockApp({
|
||||
authenticatedUser: {
|
||||
userId: 3,
|
||||
@@ -147,7 +150,7 @@ describe('CommentsView', () => {
|
||||
)];
|
||||
});
|
||||
|
||||
await executeThunk(fetchThreads(courseId), store.dispatch, store.getState);
|
||||
executeThunk(fetchThreads(courseId), store.dispatch, store.getState);
|
||||
mockAxiosReturnPagedComments();
|
||||
mockAxiosReturnPagedCommentsResponses();
|
||||
});
|
||||
@@ -449,9 +452,9 @@ describe('CommentsView', () => {
|
||||
describe('for discussion thread', () => {
|
||||
const findLoadMoreCommentsButton = () => screen.findByTestId('load-more-comments');
|
||||
|
||||
it('shown spinner when post isn\'t loaded', async () => {
|
||||
it('shown post not found when post id does not belong to course', async () => {
|
||||
renderComponent('unloaded-id');
|
||||
expect(await screen.findByTestId('loading-indicator'))
|
||||
expect(await screen.findByText('Thread not found', { exact: true }))
|
||||
.toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import classNames from 'classnames';
|
||||
@@ -10,6 +10,7 @@ import { Button, useToggle } from '@edx/paragon';
|
||||
import HTMLLoader from '../../../components/HTMLLoader';
|
||||
import { ContentActions } from '../../../data/constants';
|
||||
import { AlertBanner, DeleteConfirmation, EndorsedAlertBanner } from '../../common';
|
||||
import { DiscussionContext } from '../../common/context';
|
||||
import { selectBlackoutDate } from '../../data/selectors';
|
||||
import { fetchThread } from '../../posts/data/thunks';
|
||||
import { inBlackoutDateRange } from '../../utils';
|
||||
@@ -39,7 +40,9 @@ function Comment({
|
||||
const hasMorePages = useSelector(selectCommentHasMorePages(comment.id));
|
||||
const currentPage = useSelector(selectCommentCurrentPage(comment.id));
|
||||
const blackoutDateRange = useSelector(selectBlackoutDate);
|
||||
|
||||
const {
|
||||
courseId,
|
||||
} = useContext(DiscussionContext);
|
||||
useEffect(() => {
|
||||
// If the comment has a parent comment, it won't have any children, so don't fetch them.
|
||||
if (hasChildren && !currentPage && showFullThread) {
|
||||
@@ -51,7 +54,7 @@ function Comment({
|
||||
[ContentActions.EDIT_CONTENT]: () => setEditing(true),
|
||||
[ContentActions.ENDORSE]: async () => {
|
||||
await dispatch(editComment(comment.id, { endorsed: !comment.endorsed }, ContentActions.ENDORSE));
|
||||
await dispatch(fetchThread(comment.threadId));
|
||||
await dispatch(fetchThread(comment.threadId, courseId));
|
||||
},
|
||||
[ContentActions.DELETE]: showDeleteConfirmation,
|
||||
[ContentActions.REPORT]: () => dispatch(editComment(comment.id, { flagged: !comment.abuseFlagged })),
|
||||
|
||||
@@ -55,7 +55,9 @@ function CommentEditor({
|
||||
|
||||
const initialValues = {
|
||||
comment: comment.rawBody,
|
||||
editReasonCode: comment?.lastEdit?.reasonCode || (userIsStaff ? 'violates-guidelines' : ''),
|
||||
editReasonCode: comment?.lastEdit?.reasonCode || (
|
||||
userIsStaff && canDisplayEditReason ? 'violates-guidelines' : undefined
|
||||
),
|
||||
};
|
||||
|
||||
const handleCloseEditor = (resetForm) => {
|
||||
|
||||
@@ -5,14 +5,17 @@ import classNames from 'classnames';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { injectIntl } from '@edx/frontend-platform/i18n';
|
||||
import { Avatar, Icon } from '@edx/paragon';
|
||||
import { CheckCircle, Verified } from '@edx/paragon/icons';
|
||||
import { logError } from '@edx/frontend-platform/logging';
|
||||
import {
|
||||
Avatar, Icon,
|
||||
} from '@edx/paragon';
|
||||
|
||||
import { AvatarOutlineAndLabelColors, ThreadType } from '../../../data/constants';
|
||||
import { AvatarOutlineAndLabelColors, EndorsementStatus, ThreadType } from '../../../data/constants';
|
||||
import { AuthorLabel } from '../../common';
|
||||
import ActionsDropdown from '../../common/ActionsDropdown';
|
||||
import { useAlertBannerVisible } from '../../data/hooks';
|
||||
import { selectAuthorAvatars } from '../../posts/data/selectors';
|
||||
import { useActions } from '../../utils';
|
||||
import { commentShape } from './proptypes';
|
||||
|
||||
function CommentHeader({
|
||||
@@ -24,6 +27,20 @@ function CommentHeader({
|
||||
const colorClass = AvatarOutlineAndLabelColors[comment.authorLabel];
|
||||
const hasAnyAlert = useAlertBannerVisible(comment);
|
||||
|
||||
const actions = useActions({
|
||||
...comment,
|
||||
postType,
|
||||
});
|
||||
const actionIcons = actions.find(({ action }) => action === EndorsementStatus.ENDORSED);
|
||||
|
||||
const handleIcons = (action) => {
|
||||
const actionFunction = actionHandlers[action];
|
||||
if (actionFunction) {
|
||||
actionFunction();
|
||||
} else {
|
||||
logError(`Unknown or unimplemented action ${action}`);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className={classNames('d-flex flex-row justify-content-between', {
|
||||
'mt-2': hasAnyAlert,
|
||||
@@ -47,11 +64,23 @@ function CommentHeader({
|
||||
/>
|
||||
</div>
|
||||
<div className="d-flex align-items-center">
|
||||
|
||||
{actionIcons && (
|
||||
<span className="btn-icon btn-icon-sm mr-1 align-items-center">
|
||||
{comment.endorsed && (postType === 'question'
|
||||
? <Icon src={CheckCircle} className="text-success" data-testid="check-icon" />
|
||||
: <Icon src={Verified} className="text-dark-500" data-testid="verified-icon" />)}
|
||||
<Icon
|
||||
data-testid="check-icon"
|
||||
onClick={
|
||||
() => {
|
||||
handleIcons(actionIcons.action);
|
||||
}
|
||||
}
|
||||
src={actionIcons.icon}
|
||||
className={['endorse', 'unendorse'].includes(actionIcons.id) ? 'text-dark-500' : 'text-success-500'}
|
||||
size="sm"
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
|
||||
<ActionsDropdown
|
||||
commentOrPost={{
|
||||
...comment,
|
||||
|
||||
@@ -30,7 +30,7 @@ const mockComment = {
|
||||
author: 'abc123',
|
||||
authorLabel: 'ABC 123',
|
||||
endorsed: true,
|
||||
editableFields: [],
|
||||
editableFields: ['endorsed'],
|
||||
};
|
||||
|
||||
describe('Comment Header', () => {
|
||||
@@ -48,7 +48,7 @@ describe('Comment Header', () => {
|
||||
|
||||
it('should render verified icon for endorsed discussion posts', () => {
|
||||
renderComponent(mockComment, 'discussion', {});
|
||||
expect(screen.queryAllByTestId('verified-icon')).toHaveLength(1);
|
||||
expect(screen.queryAllByTestId('check-icon')).toHaveLength(1);
|
||||
});
|
||||
it('should render check icon for endorsed question posts', () => {
|
||||
renderComponent(mockComment, 'question', {});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import classNames from 'classnames';
|
||||
@@ -7,6 +7,7 @@ import { useSelector } from 'react-redux';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Button } from '@edx/paragon';
|
||||
|
||||
import { DiscussionContext } from '../../common/context';
|
||||
import { selectBlackoutDate } from '../../data/selectors';
|
||||
import { inBlackoutDateRange } from '../../utils';
|
||||
import messages from '../messages';
|
||||
@@ -17,6 +18,7 @@ function ResponseEditor({
|
||||
intl,
|
||||
addWrappingDiv,
|
||||
}) {
|
||||
const { inContext } = useContext(DiscussionContext);
|
||||
const [addingResponse, setAddingResponse] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -39,7 +41,7 @@ function ResponseEditor({
|
||||
<div className={classNames({ 'mb-4': addWrappingDiv }, 'actions d-flex')}>
|
||||
<Button
|
||||
variant="primary"
|
||||
className="px-2.5 py-2 font-size-14"
|
||||
className={classNames('px-2.5 py-2 font-size-14', { 'w-100': inContext })}
|
||||
onClick={() => setAddingResponse(true)}
|
||||
style={{
|
||||
lineHeight: '20px',
|
||||
|
||||
@@ -8,9 +8,7 @@ ensureConfig([
|
||||
'LMS_BASE_URL',
|
||||
], 'Comments API service');
|
||||
|
||||
const apiBaseUrl = getConfig().LMS_BASE_URL;
|
||||
|
||||
export const commentsApiUrl = `${apiBaseUrl}/api/discussion/v1/comments/`;
|
||||
export const getCommentsApiUrl = () => `${getConfig().LMS_BASE_URL}/api/discussion/v1/comments/`;
|
||||
|
||||
/**
|
||||
* Returns all the comments for the specified thread.
|
||||
@@ -36,7 +34,7 @@ export async function getThreadComments(
|
||||
});
|
||||
|
||||
const { data } = await getAuthenticatedHttpClient()
|
||||
.get(commentsApiUrl, { params });
|
||||
.get(getCommentsApiUrl(), { params });
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -53,7 +51,7 @@ export async function getCommentResponses(
|
||||
pageSize,
|
||||
} = {},
|
||||
) {
|
||||
const url = `${commentsApiUrl}${commentId}/`;
|
||||
const url = `${getCommentsApiUrl()}${commentId}/`;
|
||||
const params = snakeCaseObject({
|
||||
page,
|
||||
pageSize,
|
||||
@@ -73,7 +71,7 @@ export async function getCommentResponses(
|
||||
*/
|
||||
export async function postComment(comment, threadId, parentId = null) {
|
||||
const { data } = await getAuthenticatedHttpClient()
|
||||
.post(commentsApiUrl, snakeCaseObject({ threadId, raw_body: comment, parentId }));
|
||||
.post(getCommentsApiUrl(), snakeCaseObject({ threadId, raw_body: comment, parentId }));
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -94,7 +92,7 @@ export async function updateComment(commentId, {
|
||||
endorsed,
|
||||
editReasonCode,
|
||||
}) {
|
||||
const url = `${commentsApiUrl}${commentId}/`;
|
||||
const url = `${getCommentsApiUrl()}${commentId}/`;
|
||||
const postData = snakeCaseObject({
|
||||
raw_body: comment,
|
||||
voted,
|
||||
@@ -113,7 +111,7 @@ export async function updateComment(commentId, {
|
||||
* @param {string} commentId ID of comment to delete
|
||||
*/
|
||||
export async function deleteComment(commentId) {
|
||||
const url = `${commentsApiUrl}${commentId}/`;
|
||||
const url = `${getCommentsApiUrl()}${commentId}/`;
|
||||
await getAuthenticatedHttpClient()
|
||||
.delete(url);
|
||||
}
|
||||
|
||||
@@ -7,13 +7,14 @@ import { initializeMockApp } from '@edx/frontend-platform/testing';
|
||||
import { EndorsementStatus } from '../../../data/constants';
|
||||
import { initializeStore } from '../../../store';
|
||||
import { executeThunk } from '../../../test-utils';
|
||||
import { commentsApiUrl } from './api';
|
||||
import { getCommentsApiUrl } from './api';
|
||||
import {
|
||||
addComment, editComment, fetchCommentResponses, fetchThreadComments, removeComment,
|
||||
} from './thunks';
|
||||
|
||||
import './__factories__';
|
||||
|
||||
const commentsApiUrl = getCommentsApiUrl();
|
||||
let axiosMock;
|
||||
let store;
|
||||
|
||||
|
||||
@@ -16,6 +16,11 @@ const messages = defineMessages({
|
||||
defaultMessage: 'Content reported for staff to review',
|
||||
description: 'Alert banner over comment that has been reported for abuse',
|
||||
},
|
||||
backAlt: {
|
||||
id: 'discussions.actions.back.alt',
|
||||
defaultMessage: 'Back to list',
|
||||
description: 'Back to Posts list button text',
|
||||
},
|
||||
responseCount: {
|
||||
id: 'discussions.comments.comment.responseCount',
|
||||
defaultMessage: `{num, plural,
|
||||
@@ -177,6 +182,11 @@ const messages = defineMessages({
|
||||
defaultMessage: '{time} ago',
|
||||
description: 'Time text for endorse banner',
|
||||
},
|
||||
noThreadFound: {
|
||||
id: 'discussion.thread.notFound',
|
||||
defaultMessage: 'Thread not found',
|
||||
description: 'message to show on screen if the request thread is not found in course',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { useSelector } from 'react-redux';
|
||||
@@ -16,6 +16,7 @@ import { selectBlackoutDate } from '../data/selectors';
|
||||
import messages from '../messages';
|
||||
import { postShape } from '../posts/post/proptypes';
|
||||
import { inBlackoutDateRange, useActions } from '../utils';
|
||||
import { DiscussionContext } from './context';
|
||||
|
||||
function ActionsDropdown({
|
||||
intl,
|
||||
@@ -26,6 +27,7 @@ function ActionsDropdown({
|
||||
const [isOpen, open, close] = useToggle(false);
|
||||
const [target, setTarget] = useState(null);
|
||||
const actions = useActions(commentOrPost);
|
||||
const { inContext } = useContext(DiscussionContext);
|
||||
const handleActions = (action) => {
|
||||
const actionFunction = actionHandlers[action];
|
||||
if (actionFunction) {
|
||||
@@ -54,7 +56,7 @@ function ActionsDropdown({
|
||||
onClose={close}
|
||||
positionRef={target}
|
||||
isOpen={isOpen}
|
||||
placement="auto-start"
|
||||
placement={inContext ? 'left' : 'auto-start'}
|
||||
>
|
||||
<div
|
||||
className="bg-white p-1 shadow d-flex flex-column"
|
||||
|
||||
@@ -20,6 +20,7 @@ function AuthorLabel({
|
||||
authorLabel,
|
||||
linkToProfile,
|
||||
labelColor,
|
||||
alert,
|
||||
}) {
|
||||
const location = useLocation();
|
||||
const { courseId } = useContext(DiscussionContext);
|
||||
@@ -46,8 +47,8 @@ function AuthorLabel({
|
||||
<div className={className}>
|
||||
<span
|
||||
className={classNames('mr-1 font-size-14 font-style-normal font-family-inter font-weight-500', {
|
||||
'text-primary-500': !authorLabelMessage && !isRetiredUser,
|
||||
'text-gray-700': isRetiredUser,
|
||||
'text-primary-500': !authorLabelMessage && !isRetiredUser && !alert,
|
||||
})}
|
||||
role="heading"
|
||||
aria-level="2"
|
||||
@@ -65,8 +66,9 @@ function AuthorLabel({
|
||||
)}
|
||||
{authorLabelMessage && (
|
||||
<span
|
||||
className={classNames('mr-3 font-size-14 font-style-normal font-family-inter font-weight-500', {
|
||||
'text-primary-500': !authorLabelMessage,
|
||||
className={classNames('mr-1 font-size-14 font-style-normal font-family-inter font-weight-500', {
|
||||
'text-primary-500': !authorLabelMessage && !isRetiredUser && !alert,
|
||||
'text-gray-700': isRetiredUser,
|
||||
})}
|
||||
style={{ marginLeft: '2px' }}
|
||||
>
|
||||
@@ -97,12 +99,14 @@ AuthorLabel.propTypes = {
|
||||
authorLabel: PropTypes.string,
|
||||
linkToProfile: PropTypes.bool,
|
||||
labelColor: PropTypes.string,
|
||||
alert: PropTypes.bool,
|
||||
};
|
||||
|
||||
AuthorLabel.defaultProps = {
|
||||
linkToProfile: false,
|
||||
authorLabel: null,
|
||||
labelColor: '',
|
||||
alert: false,
|
||||
};
|
||||
|
||||
export default injectIntl(AuthorLabel);
|
||||
|
||||
@@ -10,12 +10,13 @@ import { AppProvider } from '@edx/frontend-platform/react';
|
||||
|
||||
import { initializeStore } from '../../store';
|
||||
import { executeThunk } from '../../test-utils';
|
||||
import { courseConfigApiUrl } from '../data/api';
|
||||
import { getCourseConfigApiUrl } from '../data/api';
|
||||
import { fetchCourseConfig } from '../data/thunks';
|
||||
import AuthorLabel from './AuthorLabel';
|
||||
import { DiscussionContext } from './context';
|
||||
|
||||
const courseId = 'course-v1:edX+DemoX+Demo_Course';
|
||||
const courseConfigApiUrl = getCourseConfigApiUrl();
|
||||
let store;
|
||||
let axiosMock;
|
||||
let container;
|
||||
|
||||
@@ -39,14 +39,19 @@ function EndorsedAlertBanner({
|
||||
)}
|
||||
</strong>
|
||||
<span className="d-flex align-items-center mr-1 flex-wrap">
|
||||
<span className="mr-2">
|
||||
<span className="mr-1">
|
||||
{intl.formatMessage(
|
||||
isQuestion
|
||||
? messages.answeredLabel
|
||||
: messages.endorsedLabel,
|
||||
)}
|
||||
</span>
|
||||
<AuthorLabel author={content.endorsedBy} authorLabel={content.endorsedByLabel} linkToProfile />
|
||||
<AuthorLabel
|
||||
author={content.endorsedBy}
|
||||
authorLabel={content.endorsedByLabel}
|
||||
linkToProfile
|
||||
alert={content.endorsed}
|
||||
/>
|
||||
{intl.formatMessage(messages.time, { time: timeago.format(content.endorsedAt, 'time-locale') })}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -7,16 +7,14 @@ ensureConfig([
|
||||
'LMS_BASE_URL',
|
||||
], 'Posts API service');
|
||||
|
||||
const apiBaseUrl = getConfig().LMS_BASE_URL;
|
||||
|
||||
export const courseConfigApiUrl = `${apiBaseUrl}/api/discussion/v1/courses/`;
|
||||
export const getCourseConfigApiUrl = () => `${getConfig().LMS_BASE_URL}/api/discussion/v1/courses/`;
|
||||
|
||||
/**
|
||||
* Get discussions course config
|
||||
* @param {string} courseId
|
||||
*/
|
||||
export async function getDiscussionsConfig(courseId) {
|
||||
const url = `${courseConfigApiUrl}${courseId}/`;
|
||||
const url = `${getCourseConfigApiUrl()}${courseId}/`;
|
||||
const { data } = await getAuthenticatedHttpClient().get(url);
|
||||
return data;
|
||||
}
|
||||
@@ -26,7 +24,7 @@ export async function getDiscussionsConfig(courseId) {
|
||||
* @param {string} courseId
|
||||
*/
|
||||
export async function getDiscussionsSettings(courseId) {
|
||||
const url = `${courseConfigApiUrl}${courseId}/settings`;
|
||||
const url = `${getCourseConfigApiUrl()}${courseId}/settings`;
|
||||
const { data } = await getAuthenticatedHttpClient().get(url);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ export function useCourseDiscussionData(courseId) {
|
||||
}, [courseId]);
|
||||
}
|
||||
|
||||
export function useRedirectToThread(courseId) {
|
||||
export function useRedirectToThread(courseId, inContext) {
|
||||
const dispatch = useDispatch();
|
||||
const redirectToThread = useSelector(
|
||||
(state) => state.threads.redirectToThread,
|
||||
@@ -85,9 +85,10 @@ export function useRedirectToThread(courseId) {
|
||||
// stored in redirectToThread
|
||||
if (redirectToThread) {
|
||||
dispatch(clearRedirect());
|
||||
const newLocation = discussionsPath(Routes.COMMENTS.PAGES['my-posts'], {
|
||||
const newLocation = discussionsPath(Routes.COMMENTS.PAGES[inContext ? 'topics' : 'my-posts'], {
|
||||
courseId,
|
||||
postId: redirectToThread.threadId,
|
||||
topicId: redirectToThread.topicId,
|
||||
})(location);
|
||||
history.push(newLocation);
|
||||
}
|
||||
@@ -95,7 +96,8 @@ export function useRedirectToThread(courseId) {
|
||||
}
|
||||
|
||||
export function useIsOnDesktop() {
|
||||
return window.outerWidth >= breakpoints.large.minWidth;
|
||||
const windowSize = useWindowSize();
|
||||
return windowSize.width >= breakpoints.large.minWidth;
|
||||
}
|
||||
|
||||
export function useIsOnXLDesktop() {
|
||||
|
||||
@@ -1,46 +1,20 @@
|
||||
import React, { useContext } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Route, Switch } from 'react-router';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Icon, IconButton } from '@edx/paragon';
|
||||
import { ArrowBack } from '@edx/paragon/icons';
|
||||
import { injectIntl } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { PostsPages, Routes } from '../../data/constants';
|
||||
import { Routes } from '../../data/constants';
|
||||
import { CommentsView } from '../comments';
|
||||
import { DiscussionContext } from '../common/context';
|
||||
import { useIsOnDesktop } from '../data/hooks';
|
||||
import messages from '../messages';
|
||||
import { PostEditor } from '../posts';
|
||||
import { discussionsPath } from '../utils';
|
||||
|
||||
function DiscussionContent({ intl }) {
|
||||
const location = useLocation();
|
||||
const history = useHistory();
|
||||
function DiscussionContent() {
|
||||
const postEditorVisible = useSelector((state) => state.threads.postEditorVisible);
|
||||
const isOnDesktop = useIsOnDesktop();
|
||||
const {
|
||||
courseId, learnerUsername, category, topicId, page,
|
||||
} = useContext(DiscussionContext);
|
||||
|
||||
return (
|
||||
<div className="d-flex bg-light-400 flex-column w-75 w-xs-100 w-xl-75 align-items-center">
|
||||
<div className="d-flex flex-column w-100">
|
||||
{!isOnDesktop && (
|
||||
<IconButton
|
||||
src={ArrowBack}
|
||||
iconAs={Icon}
|
||||
style={{ padding: '18px' }}
|
||||
size="inline"
|
||||
className="ml-4 mt-4"
|
||||
onClick={() => history.push(discussionsPath(PostsPages[page], {
|
||||
courseId, learnerUsername, category, topicId,
|
||||
})(location))}
|
||||
alt={intl.formatMessage(messages.backAlt)}
|
||||
/>
|
||||
)}
|
||||
{postEditorVisible ? (
|
||||
<Route path={Routes.POSTS.NEW_POST}>
|
||||
<PostEditor />
|
||||
@@ -60,8 +34,4 @@ function DiscussionContent({ intl }) {
|
||||
);
|
||||
}
|
||||
|
||||
DiscussionContent.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
export default injectIntl(DiscussionContent);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import React, { useContext, useEffect, useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import classNames from 'classnames';
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
import { useWindowSize } from '@edx/paragon';
|
||||
|
||||
import { RequestStatus, Routes } from '../../data/constants';
|
||||
import { DiscussionContext } from '../common/context';
|
||||
import {
|
||||
useContainerSize, useIsOnDesktop, useIsOnXLDesktop, useShowLearnersTab,
|
||||
} from '../data/hooks';
|
||||
@@ -27,26 +28,28 @@ export default function DiscussionSidebar({ displaySidebar, postActionBarRef })
|
||||
const sidebarRef = useRef(null);
|
||||
const postActionBarHeight = useContainerSize(postActionBarRef);
|
||||
const { height: windowHeight } = useWindowSize();
|
||||
const { inContext } = useContext(DiscussionContext);
|
||||
|
||||
useEffect(() => {
|
||||
if (sidebarRef && postActionBarHeight) {
|
||||
if (sidebarRef && postActionBarHeight && !inContext) {
|
||||
if (isOnDesktop) {
|
||||
sidebarRef.current.style.maxHeight = `${windowHeight - postActionBarHeight}px`;
|
||||
}
|
||||
sidebarRef.current.style.minHeight = `${windowHeight - postActionBarHeight}px`;
|
||||
sidebarRef.current.style.top = `${postActionBarHeight}px`;
|
||||
}
|
||||
}, [sidebarRef, postActionBarHeight]);
|
||||
}, [sidebarRef, postActionBarHeight, inContext]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={sidebarRef}
|
||||
className={classNames('flex-column min-content-height position-sticky', {
|
||||
className={classNames('flex-column position-sticky', {
|
||||
'd-none': !displaySidebar,
|
||||
'd-flex overflow-auto': displaySidebar,
|
||||
'w-100': !isOnDesktop,
|
||||
'sidebar-desktop-width': isOnDesktop && !isOnXLDesktop,
|
||||
'w-25 sidebar-XL-width': isOnXLDesktop,
|
||||
'min-content-height': !inContext,
|
||||
})}
|
||||
data-testid="sidebar"
|
||||
>
|
||||
@@ -57,12 +60,11 @@ export default function DiscussionSidebar({ displaySidebar, postActionBarRef })
|
||||
/>
|
||||
<Route path={Routes.TOPICS.PATH} component={TopicsView} />
|
||||
{redirectToLearnersTab && (
|
||||
<Route path={Routes.LEARNERS.POSTS} component={LearnerPostsView} />
|
||||
<Route path={Routes.LEARNERS.POSTS} component={LearnerPostsView} />
|
||||
)}
|
||||
{redirectToLearnersTab && (
|
||||
<Route path={Routes.LEARNERS.PATH} component={LearnersView} />
|
||||
<Route path={Routes.LEARNERS.PATH} component={LearnersView} />
|
||||
)}
|
||||
|
||||
{configStatus === RequestStatus.SUCCESSFUL && (
|
||||
<Redirect
|
||||
from={Routes.DISCUSSIONS.PATH}
|
||||
|
||||
@@ -13,7 +13,7 @@ import { AppProvider } from '@edx/frontend-platform/react';
|
||||
import { initializeStore } from '../../store';
|
||||
import { DiscussionContext } from '../common/context';
|
||||
import { fetchConfigSuccess } from '../data/slices';
|
||||
import { threadsApiUrl } from '../posts/data/api';
|
||||
import { getThreadsApiUrl } from '../posts/data/api';
|
||||
import DiscussionSidebar from './DiscussionSidebar';
|
||||
|
||||
import '../posts/data/__factories__';
|
||||
@@ -21,6 +21,7 @@ import '../posts/data/__factories__';
|
||||
let store;
|
||||
let container;
|
||||
const courseId = 'course-v1:edX+DemoX+Demo_Course';
|
||||
const threadsApiUrl = getThreadsApiUrl();
|
||||
let axiosMock;
|
||||
|
||||
function renderComponent(displaySidebar = true, location = `/${courseId}/`) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { useSelector } from 'react-redux';
|
||||
import {
|
||||
Route, Switch, useLocation, useRouteMatch,
|
||||
@@ -55,9 +56,7 @@ export default function DiscussionsHome() {
|
||||
|
||||
const isOnDesktop = useIsOnDesktop();
|
||||
|
||||
const { courseNumber, courseTitle, org } = useSelector(
|
||||
(state) => state.courseTabs,
|
||||
);
|
||||
const { courseNumber, courseTitle, org } = useSelector((state) => state.courseTabs);
|
||||
if (displayContentArea) {
|
||||
// If the window is larger than a particular size, show the sidebar for navigating between posts/topics.
|
||||
// However, for smaller screens or embeds, only show the sidebar if the content area isn't displayed.
|
||||
@@ -66,7 +65,7 @@ export default function DiscussionsHome() {
|
||||
|
||||
const provider = useSelector(selectDiscussionProvider);
|
||||
useCourseDiscussionData(courseId);
|
||||
useRedirectToThread(courseId);
|
||||
useRedirectToThread(courseId, inContext);
|
||||
useEffect(() => {
|
||||
if (path && path !== 'undefined') {
|
||||
postMessageToParent('discussions.navigate', { path });
|
||||
@@ -84,45 +83,50 @@ export default function DiscussionsHome() {
|
||||
learnerUsername,
|
||||
}}
|
||||
>
|
||||
<Header courseOrg={org} courseNumber={courseNumber} courseTitle={courseTitle} />
|
||||
{!inContext && <Header courseOrg={org} courseNumber={courseNumber} courseTitle={courseTitle} />}
|
||||
<main className="container-fluid d-flex flex-column p-0 w-100" id="main" tabIndex="-1">
|
||||
<CourseTabsNavigation activeTab="discussion" courseId={courseId} />
|
||||
<div className="header-action-bar" ref={postActionBarRef}>
|
||||
{!inContext && <CourseTabsNavigation activeTab="discussion" courseId={courseId} />}
|
||||
<div
|
||||
className={classNames('header-action-bar', { 'shadow-none border-light-300 border-bottom': inContext })}
|
||||
ref={postActionBarRef}
|
||||
>
|
||||
<div
|
||||
className="d-flex flex-row justify-content-between navbar fixed-top"
|
||||
className={classNames('d-flex flex-row justify-content-between navbar fixed-top', {
|
||||
'pl-4 pr-2.5 py-1.5': inContext,
|
||||
})}
|
||||
>
|
||||
{!inContext && (
|
||||
<Route path={Routes.DISCUSSIONS.PATH} component={NavigationBar} />
|
||||
)}
|
||||
{!inContext && <Route path={Routes.DISCUSSIONS.PATH} component={NavigationBar} />}
|
||||
<PostActionsBar inContext={inContext} />
|
||||
</div>
|
||||
{isFeedbackBannerVisible && <InformationBanner />}
|
||||
<BlackoutInformationBanner />
|
||||
</div>
|
||||
<Route
|
||||
path={[Routes.POSTS.PATH, Routes.TOPICS.CATEGORY]}
|
||||
component={provider === DiscussionProvider.LEGACY ? LegacyBreadcrumbMenu : BreadcrumbMenu}
|
||||
/>
|
||||
{!inContext && (
|
||||
<Route
|
||||
path={[Routes.POSTS.PATH, Routes.TOPICS.CATEGORY]}
|
||||
component={provider === DiscussionProvider.LEGACY ? LegacyBreadcrumbMenu : BreadcrumbMenu}
|
||||
/>
|
||||
)}
|
||||
<div className="d-flex flex-row">
|
||||
<DiscussionSidebar displaySidebar={displaySidebar} postActionBarRef={postActionBarRef} />
|
||||
{displayContentArea && <DiscussionContent />}
|
||||
{!displayContentArea && (
|
||||
<Switch>
|
||||
<Route path={Routes.TOPICS.PATH} component={EmptyTopics} />
|
||||
<Route
|
||||
path={Routes.POSTS.MY_POSTS}
|
||||
render={routeProps => <EmptyPosts {...routeProps} subTitleMessage={messages.emptyMyPosts} />}
|
||||
/>
|
||||
<Route
|
||||
path={[Routes.POSTS.PATH, Routes.POSTS.ALL_POSTS, Routes.LEARNERS.POSTS]}
|
||||
render={routeProps => <EmptyPosts {...routeProps} subTitleMessage={messages.emptyAllPosts} />}
|
||||
/>
|
||||
{isRedirectToLearners && <Route path={Routes.LEARNERS.PATH} component={EmptyLearners} /> }
|
||||
</Switch>
|
||||
<Switch>
|
||||
<Route path={Routes.TOPICS.PATH} component={EmptyTopics} />
|
||||
<Route
|
||||
path={Routes.POSTS.MY_POSTS}
|
||||
render={routeProps => <EmptyPosts {...routeProps} subTitleMessage={messages.emptyMyPosts} />}
|
||||
/>
|
||||
<Route
|
||||
path={[Routes.POSTS.PATH, Routes.POSTS.ALL_POSTS, Routes.LEARNERS.POSTS]}
|
||||
render={routeProps => <EmptyPosts {...routeProps} subTitleMessage={messages.emptyAllPosts} />}
|
||||
/>
|
||||
{isRedirectToLearners && <Route path={Routes.LEARNERS.PATH} component={EmptyLearners} /> }
|
||||
</Switch>
|
||||
)}
|
||||
</div>
|
||||
</main>
|
||||
<Footer />
|
||||
{!inContext && <Footer />}
|
||||
</DiscussionContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import { AppProvider } from '@edx/frontend-platform/react';
|
||||
import { initializeStore } from '../../store';
|
||||
import { executeThunk } from '../../test-utils';
|
||||
import messages from '../messages';
|
||||
import { threadsApiUrl } from '../posts/data/api';
|
||||
import { getThreadsApiUrl } from '../posts/data/api';
|
||||
import { fetchThreads } from '../posts/data/thunks';
|
||||
import EmptyPosts from './EmptyPosts';
|
||||
|
||||
@@ -20,6 +20,7 @@ import '../posts/data/__factories__';
|
||||
|
||||
let store;
|
||||
const courseId = 'course-v1:edX+DemoX+Demo_Course';
|
||||
const threadsApiUrl = getThreadsApiUrl();
|
||||
|
||||
function renderComponent(location = `/${courseId}/`) {
|
||||
return render(
|
||||
|
||||
@@ -9,7 +9,7 @@ import { initializeMockApp } from '@edx/frontend-platform';
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
import { AppProvider } from '@edx/frontend-platform/react';
|
||||
|
||||
import { API_BASE_URL } from '../../data/constants';
|
||||
import { getApiBaseUrl } from '../../data/constants';
|
||||
import { initializeStore } from '../../store';
|
||||
import { executeThunk } from '../../test-utils';
|
||||
import messages from '../messages';
|
||||
@@ -20,7 +20,7 @@ import '../topics/data/__factories__';
|
||||
|
||||
let store;
|
||||
const courseId = 'course-v1:edX+DemoX+Demo_Course';
|
||||
const topicsApiUrl = `${API_BASE_URL}/api/discussion/v1/course_topics/${courseId}`;
|
||||
const topicsApiUrl = `${getApiBaseUrl()}/api/discussion/v1/course_topics/${courseId}`;
|
||||
|
||||
function renderComponent(location = `/${courseId}/topics/`) {
|
||||
return render(
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, {
|
||||
useCallback, useContext, useEffect, useMemo,
|
||||
} from 'react';
|
||||
|
||||
import snakeCase from 'lodash.snakecase';
|
||||
import capitalize from 'lodash/capitalize';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
@@ -14,10 +13,8 @@ import {
|
||||
import { ArrowBack } from '@edx/paragon/icons';
|
||||
|
||||
import {
|
||||
PostsStatusFilter,
|
||||
RequestStatus,
|
||||
Routes,
|
||||
ThreadType,
|
||||
} from '../../data/constants';
|
||||
import { DiscussionContext } from '../common/context';
|
||||
import { selectUserHasModerationPrivileges, selectUserIsStaff } from '../data/selectors';
|
||||
@@ -46,46 +43,23 @@ function LearnerPostsView({ intl }) {
|
||||
const nextPage = useSelector(selectThreadNextPage());
|
||||
const userHasModerationPrivileges = useSelector(selectUserHasModerationPrivileges);
|
||||
const userIsStaff = useSelector(selectUserIsStaff);
|
||||
const countFlagged = userHasModerationPrivileges || userIsStaff;
|
||||
const params = {
|
||||
orderBy: snakeCase(postFilter.orderBy),
|
||||
username,
|
||||
page: 1,
|
||||
};
|
||||
if (postFilter.type !== ThreadType.ALL) {
|
||||
params.threadType = postFilter.type;
|
||||
}
|
||||
if (postFilter.status !== PostsStatusFilter.ALL) {
|
||||
const statusMapping = {
|
||||
statusUnread: 'unread',
|
||||
statusReported: 'flagged',
|
||||
statusUnanswered: 'unanswered',
|
||||
statusUnresponded: 'unresponded',
|
||||
};
|
||||
params.status = statusMapping[postFilter.status];
|
||||
}
|
||||
if (postFilter.cohort !== '') {
|
||||
params.groupId = postFilter.cohort;
|
||||
}
|
||||
if (countFlagged) {
|
||||
params.countFlagged = countFlagged;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const loadMorePosts = (pageNum = undefined) => {
|
||||
const params = {
|
||||
author: username,
|
||||
page: pageNum,
|
||||
filters: postFilter,
|
||||
orderBy: postFilter.orderBy,
|
||||
countFlagged: (userHasModerationPrivileges || userIsStaff) || undefined,
|
||||
};
|
||||
|
||||
dispatch(fetchUserPosts(courseId, params));
|
||||
}, [courseId, username]);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(clearPostsPages());
|
||||
dispatch(fetchUserPosts(courseId, params));
|
||||
}, [postFilter]);
|
||||
|
||||
const loadMorePosts = () => (
|
||||
dispatch(fetchUserPosts(courseId, {
|
||||
...params,
|
||||
page: nextPage,
|
||||
}))
|
||||
);
|
||||
loadMorePosts();
|
||||
}, [courseId, postFilter, username]);
|
||||
|
||||
const checkIsSelected = (id) => window.location.pathname.includes(id);
|
||||
const pinnedPosts = useMemo(() => filterPosts(posts, 'pinned'), [posts]);
|
||||
@@ -121,6 +95,7 @@ function LearnerPostsView({ intl }) {
|
||||
</div>
|
||||
<div className="bg-light-400 border border-light-300" />
|
||||
<LearnerPostFilterBar />
|
||||
<div className="border-bottom border-light-400" />
|
||||
<div className="list-group list-group-flush">
|
||||
{postInstances(pinnedPosts)}
|
||||
{postInstances(unpinnedPosts)}
|
||||
@@ -131,7 +106,7 @@ function LearnerPostsView({ intl }) {
|
||||
</div>
|
||||
) : (
|
||||
nextPage && loadingStatus === RequestStatus.SUCCESSFUL && (
|
||||
<Button onClick={() => loadMorePosts()} variant="primary" size="md">
|
||||
<Button onClick={() => loadMorePosts(nextPage)} variant="primary" size="md">
|
||||
{intl.formatMessage(messages.loadMore)}
|
||||
</Button>
|
||||
)
|
||||
|
||||
@@ -14,15 +14,17 @@ import { AppProvider } from '@edx/frontend-platform/react';
|
||||
import { initializeStore } from '../../store';
|
||||
import { executeThunk } from '../../test-utils';
|
||||
import { DiscussionContext } from '../common/context';
|
||||
import { courseConfigApiUrl } from '../data/api';
|
||||
import { getCourseConfigApiUrl } from '../data/api';
|
||||
import { fetchCourseConfig } from '../data/thunks';
|
||||
import { coursesApiUrl } from './data/api';
|
||||
import { getCoursesApiUrl } from './data/api';
|
||||
import LearnerPostsView from './LearnerPostsView';
|
||||
|
||||
import './data/__factories__';
|
||||
|
||||
let store;
|
||||
let axiosMock;
|
||||
const coursesApiUrl = getCoursesApiUrl();
|
||||
const courseConfigApiUrl = getCourseConfigApiUrl();
|
||||
const courseId = 'course-v1:edX+TestX+Test_Course';
|
||||
const username = 'abc123';
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@ import { AppProvider } from '@edx/frontend-platform/react';
|
||||
|
||||
import { initializeStore } from '../../store';
|
||||
import { executeThunk } from '../../test-utils';
|
||||
import { courseConfigApiUrl } from '../data/api';
|
||||
import { getCourseConfigApiUrl } from '../data/api';
|
||||
import { fetchCourseConfig } from '../data/thunks';
|
||||
import { coursesApiUrl, userProfileApiUrl } from './data/api';
|
||||
import { getCoursesApiUrl, getUserProfileApiUrl } from './data/api';
|
||||
import { fetchLearners } from './data/thunks';
|
||||
import LearnersView from './LearnersView';
|
||||
|
||||
@@ -23,6 +23,9 @@ import './data/__factories__';
|
||||
|
||||
let store;
|
||||
let axiosMock;
|
||||
const coursesApiUrl = getCoursesApiUrl();
|
||||
const courseConfigApiUrl = getCourseConfigApiUrl();
|
||||
const userProfileApiUrl = getUserProfileApiUrl();
|
||||
const courseId = 'course-v1:edX+TestX+Test_Course';
|
||||
|
||||
function renderComponent() {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
import snakeCase from 'lodash/snakeCase';
|
||||
|
||||
import { ensureConfig, getConfig, snakeCaseObject } from '@edx/frontend-platform';
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
|
||||
@@ -6,10 +8,8 @@ ensureConfig([
|
||||
'LMS_BASE_URL',
|
||||
], 'Posts API service');
|
||||
|
||||
const apiBaseUrl = getConfig().LMS_BASE_URL;
|
||||
|
||||
export const coursesApiUrl = `${apiBaseUrl}/api/discussion/v1/courses/`;
|
||||
export const userProfileApiUrl = `${apiBaseUrl}/api/user/v1/accounts`;
|
||||
export const getCoursesApiUrl = () => `${getConfig().LMS_BASE_URL}/api/discussion/v1/courses/`;
|
||||
export const getUserProfileApiUrl = () => `${getConfig().LMS_BASE_URL}/api/user/v1/accounts`;
|
||||
|
||||
/**
|
||||
* Fetches all the learners in the given course.
|
||||
@@ -18,7 +18,7 @@ export const userProfileApiUrl = `${apiBaseUrl}/api/user/v1/accounts`;
|
||||
* @returns {Promise<{}>}
|
||||
*/
|
||||
export async function getLearners(courseId, params) {
|
||||
const url = `${coursesApiUrl}${courseId}/activity_stats/`;
|
||||
const url = `${getCoursesApiUrl()}${courseId}/activity_stats/`;
|
||||
const { data } = await getAuthenticatedHttpClient().get(url, { params });
|
||||
return data;
|
||||
}
|
||||
@@ -28,7 +28,7 @@ export async function getLearners(courseId, params) {
|
||||
* @param {string} usernames
|
||||
*/
|
||||
export async function getUserProfiles(usernames) {
|
||||
const url = `${userProfileApiUrl}?username=${usernames.join()}`;
|
||||
const url = `${getUserProfileApiUrl()}?username=${usernames.join()}`;
|
||||
const { data } = await getAuthenticatedHttpClient().get(url);
|
||||
return data;
|
||||
}
|
||||
@@ -37,18 +37,50 @@ export async function getUserProfiles(usernames) {
|
||||
* Get the posts by a specific user in a course's discussions
|
||||
*
|
||||
* @param {string} courseId Course ID of the course
|
||||
* @param {string} username Username of the user
|
||||
* @param {string} author
|
||||
* @param {number} page
|
||||
* @param {number} pageSize
|
||||
* @param {string} textSearch A search string to match.
|
||||
* @param {ThreadOrdering} orderBy The results wil be sorted on this basis.
|
||||
* @param {boolean} following If true, only threads followed by the current user will be returned.
|
||||
* @param {boolean} flagged If true, only threads that have been reported will be returned.
|
||||
* @param {string} threadType Can be 'discussion' or 'question'.
|
||||
* @param {ThreadViewStatus} view Set to "unread" on "unanswered" to filter to only those statuses.
|
||||
* @param {boolean} countFlagged If true, abuseFlaggedCount will be available.
|
||||
* @param {number} cohort
|
||||
* @returns API Response object in the format
|
||||
* {
|
||||
* results: [array of posts],
|
||||
* pagination: {count, num_pages, next, previous}
|
||||
* }
|
||||
*/
|
||||
export async function getUserPosts(courseId, params) {
|
||||
const learnerPostsApiUrl = `${coursesApiUrl}${courseId}/learner/`;
|
||||
const snakeCaseParams = snakeCaseObject(params);
|
||||
export async function getUserPosts(courseId, {
|
||||
page,
|
||||
pageSize,
|
||||
textSearch,
|
||||
orderBy,
|
||||
status,
|
||||
author,
|
||||
threadType,
|
||||
countFlagged,
|
||||
cohort,
|
||||
} = {}) {
|
||||
const learnerPostsApiUrl = `${getCoursesApiUrl()}${courseId}/learner/`;
|
||||
|
||||
const params = snakeCaseObject({
|
||||
page,
|
||||
pageSize,
|
||||
textSearch,
|
||||
threadType,
|
||||
orderBy: orderBy && snakeCase(orderBy),
|
||||
status,
|
||||
requestedFields: 'profile_image',
|
||||
username: author,
|
||||
countFlagged,
|
||||
groupId: cohort,
|
||||
});
|
||||
|
||||
const { data } = await getAuthenticatedHttpClient()
|
||||
.get(learnerPostsApiUrl, { params: snakeCaseParams });
|
||||
.get(learnerPostsApiUrl, { params });
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ const learnersSlice = createSlice({
|
||||
totalLearners: null,
|
||||
sortedBy: LearnersOrdering.BY_LAST_ACTIVITY,
|
||||
postFilter: {
|
||||
type: ThreadType.ALL,
|
||||
postType: ThreadType.ALL,
|
||||
status: PostsStatusFilter.ALL,
|
||||
orderBy: ThreadOrdering.BY_LAST_ACTIVITY,
|
||||
cohort: '',
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
import { camelCaseObject, snakeCaseObject } from '@edx/frontend-platform';
|
||||
import { logError } from '@edx/frontend-platform/logging';
|
||||
|
||||
import {
|
||||
PostsStatusFilter, ThreadType,
|
||||
} from '../../../data/constants';
|
||||
import {
|
||||
fetchLearnerThreadsRequest,
|
||||
fetchThreadsDenied,
|
||||
@@ -67,17 +70,48 @@ export function fetchLearners(courseId, {
|
||||
* @param page
|
||||
* @returns a promise that will update the state with the learner's posts
|
||||
*/
|
||||
export function fetchUserPosts(courseId, params) {
|
||||
export function fetchUserPosts(courseId, {
|
||||
orderBy,
|
||||
filters = {},
|
||||
page = 1,
|
||||
author = null,
|
||||
countFlagged,
|
||||
} = {}) {
|
||||
const options = {
|
||||
orderBy,
|
||||
page,
|
||||
author,
|
||||
countFlagged,
|
||||
};
|
||||
if (filters.status === PostsStatusFilter.UNREAD) {
|
||||
options.status = 'unread';
|
||||
}
|
||||
if (filters.status === PostsStatusFilter.UNANSWERED) {
|
||||
options.status = 'unanswered';
|
||||
}
|
||||
if (filters.status === PostsStatusFilter.REPORTED) {
|
||||
options.status = 'flagged';
|
||||
}
|
||||
if (filters.status === PostsStatusFilter.UNRESPONDED) {
|
||||
options.status = 'unresponded';
|
||||
}
|
||||
if (filters.postType !== ThreadType.ALL) {
|
||||
options.threadType = filters.postType;
|
||||
}
|
||||
if (filters.search) {
|
||||
options.textSearch = filters.search;
|
||||
}
|
||||
if (filters.cohort) {
|
||||
options.cohort = filters.cohort;
|
||||
}
|
||||
return async (dispatch) => {
|
||||
try {
|
||||
dispatch(fetchLearnerThreadsRequest({ courseId, author: params?.username }));
|
||||
const data = await getUserPosts(courseId, params);
|
||||
dispatch(fetchLearnerThreadsRequest({ courseId, author }));
|
||||
|
||||
const data = await getUserPosts(courseId, options);
|
||||
const normalisedData = normaliseThreads(camelCaseObject(data));
|
||||
dispatch(fetchThreadsSuccess({
|
||||
...normalisedData,
|
||||
page: params.page,
|
||||
author: params.username,
|
||||
}));
|
||||
|
||||
dispatch(fetchThreadsSuccess({ ...normalisedData, page, author }));
|
||||
} catch (error) {
|
||||
if (getHttpErrorStatus(error) === 403) {
|
||||
dispatch(fetchThreadsDenied());
|
||||
|
||||
@@ -20,7 +20,7 @@ function LearnerPostFilterBar() {
|
||||
|
||||
const filtersToShow = [
|
||||
{
|
||||
name: 'type',
|
||||
name: 'postType',
|
||||
filters: ['type-all', 'type-discussions', 'type-questions'],
|
||||
},
|
||||
{
|
||||
@@ -39,11 +39,11 @@ function LearnerPostFilterBar() {
|
||||
|
||||
const handleFilterChange = (event) => {
|
||||
const { name, value } = event.currentTarget;
|
||||
if (name === 'type') {
|
||||
if (postFilter.type !== value) {
|
||||
if (name === 'postType') {
|
||||
if (postFilter.postType !== value) {
|
||||
dispatch(setPostFilter({
|
||||
...postFilter,
|
||||
type: value,
|
||||
postType: value,
|
||||
}));
|
||||
}
|
||||
} else if (name === 'status') {
|
||||
|
||||
@@ -45,7 +45,7 @@ const messages = defineMessages({
|
||||
},
|
||||
sortFilterStatus: {
|
||||
id: 'discussions.learner.sortFilterStatus',
|
||||
defaultMessage: `All learners by {sort, select,
|
||||
defaultMessage: `All learners sorted by {sort, select,
|
||||
flagged {reported activity}
|
||||
activity {most activity}
|
||||
other {{sort}}
|
||||
|
||||
@@ -6,11 +6,6 @@ const messages = defineMessages({
|
||||
defaultMessage: 'Actions menu',
|
||||
description: 'Alt-text for dropdown button for actions related to a post or comment',
|
||||
},
|
||||
backAlt: {
|
||||
id: 'discussions.actions.back.alt',
|
||||
defaultMessage: 'Back',
|
||||
description: 'Text on button for back to posts list',
|
||||
},
|
||||
copyLink: {
|
||||
id: 'discussions.actions.copylink',
|
||||
defaultMessage: 'Copy link',
|
||||
@@ -68,7 +63,7 @@ const messages = defineMessages({
|
||||
},
|
||||
markAnsweredAction: {
|
||||
id: 'discussions.actions.markAnswered',
|
||||
defaultMessage: 'Mark as Answered',
|
||||
defaultMessage: 'Mark as answered',
|
||||
description: 'Action to mark a comment as answering a post',
|
||||
},
|
||||
unmarkAnsweredAction: {
|
||||
|
||||
@@ -13,8 +13,8 @@ import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
import { AppProvider } from '@edx/frontend-platform/react';
|
||||
|
||||
import { getBlocksAPIResponse } from '../../../data/__factories__';
|
||||
import { blocksAPIURL } from '../../../data/api';
|
||||
import { API_BASE_URL, Routes } from '../../../data/constants';
|
||||
import { getBlocksAPIURL } from '../../../data/api';
|
||||
import { getApiBaseUrl, Routes } from '../../../data/constants';
|
||||
import { fetchCourseBlocks } from '../../../data/thunks';
|
||||
import { initializeStore } from '../../../store';
|
||||
import { executeThunk } from '../../../test-utils';
|
||||
@@ -25,7 +25,7 @@ import { BreadcrumbMenu } from '../index';
|
||||
import '../../topics/data/__factories__';
|
||||
|
||||
const courseId = 'course-v1:edX+DemoX+Demo_Course';
|
||||
const topicsApiUrl = `${API_BASE_URL}/api/discussion/v2/course_topics/${courseId}`;
|
||||
const topicsApiUrl = `${getApiBaseUrl()}/api/discussion/v2/course_topics/${courseId}`;
|
||||
let store;
|
||||
let axiosMock;
|
||||
|
||||
@@ -78,7 +78,7 @@ describe('BreadcrumbMenu', () => {
|
||||
Factory.resetAll();
|
||||
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
|
||||
blocksAPIResponse = getBlocksAPIResponse();
|
||||
axiosMock.onGet(blocksAPIURL)
|
||||
axiosMock.onGet(getBlocksAPIURL())
|
||||
.reply(200, blocksAPIResponse);
|
||||
await executeThunk(fetchCourseBlocks(courseId, 'test-user'), store.dispatch, store.getState);
|
||||
const data = [
|
||||
|
||||
@@ -12,7 +12,7 @@ import { initializeMockApp } from '@edx/frontend-platform';
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
import { AppProvider } from '@edx/frontend-platform/react';
|
||||
|
||||
import { API_BASE_URL, Routes } from '../../../data/constants';
|
||||
import { getApiBaseUrl, Routes } from '../../../data/constants';
|
||||
import { initializeStore } from '../../../store';
|
||||
import { executeThunk } from '../../../test-utils';
|
||||
import { fetchCourseTopics } from '../../topics/data/thunks';
|
||||
@@ -21,7 +21,7 @@ import { LegacyBreadcrumbMenu } from '../index';
|
||||
import '../../topics/data/__factories__';
|
||||
|
||||
const courseId = 'course-v1:edX+TestX+Test_Course';
|
||||
const topicsApiUrl = `${API_BASE_URL}/api/discussion/v1/course_topics/${courseId}`;
|
||||
const topicsApiUrl = `${getApiBaseUrl()}/api/discussion/v1/course_topics/${courseId}`;
|
||||
let store;
|
||||
let axiosMock;
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import { Button, Spinner } from '@edx/paragon';
|
||||
import { RequestStatus } from '../../data/constants';
|
||||
import { DiscussionContext } from '../common/context';
|
||||
import { selectconfigLoadingStatus, selectUserHasModerationPrivileges, selectUserIsStaff } from '../data/selectors';
|
||||
import { fetchUserPosts } from '../learners/data/thunks';
|
||||
import messages from '../messages';
|
||||
import { filterPosts } from '../utils';
|
||||
import {
|
||||
@@ -37,16 +38,22 @@ function PostsList({ posts, topics, intl }) {
|
||||
const userIsStaff = useSelector(selectUserIsStaff);
|
||||
const configStatus = useSelector(selectconfigLoadingStatus);
|
||||
|
||||
const loadThreads = (topicIds, pageNum = undefined) => (
|
||||
dispatch(fetchThreads(courseId, {
|
||||
topicIds,
|
||||
const loadThreads = (topicIds, pageNum = undefined) => {
|
||||
const params = {
|
||||
orderBy,
|
||||
filters,
|
||||
page: pageNum,
|
||||
author: showOwnPosts ? authenticatedUser.username : null,
|
||||
countFlagged: userHasModerationPrivileges || userIsStaff,
|
||||
}))
|
||||
);
|
||||
countFlagged: (userHasModerationPrivileges || userIsStaff) || undefined,
|
||||
topicIds,
|
||||
};
|
||||
|
||||
if (showOwnPosts && filters.search === '') {
|
||||
dispatch(fetchUserPosts(courseId, params));
|
||||
} else {
|
||||
dispatch(fetchThreads(courseId, params));
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (topics !== undefined && configStatus === RequestStatus.SUCCESSFUL) {
|
||||
|
||||
@@ -18,15 +18,19 @@ import { initializeStore } from '../../store';
|
||||
import { getCohortsApiUrl } from '../cohorts/data/api';
|
||||
import { DiscussionContext } from '../common/context';
|
||||
import { fetchConfigSuccess } from '../data/slices';
|
||||
import { threadsApiUrl } from './data/api';
|
||||
import { getCoursesApiUrl } from '../learners/data/api';
|
||||
import { getThreadsApiUrl } from './data/api';
|
||||
import { PostsView } from './index';
|
||||
|
||||
import './data/__factories__';
|
||||
import '../cohorts/data/__factories__';
|
||||
|
||||
const courseId = 'course-v1:edX+TestX+Test_Course';
|
||||
const coursesApiUrl = getCoursesApiUrl();
|
||||
const threadsApiUrl = getThreadsApiUrl();
|
||||
let store;
|
||||
let axiosMock;
|
||||
const username = 'abc123';
|
||||
|
||||
async function renderComponent({
|
||||
postId, topicId, category, myPosts, inContext = false,
|
||||
@@ -81,7 +85,7 @@ describe('PostsView', () => {
|
||||
initializeMockApp({
|
||||
authenticatedUser: {
|
||||
userId: 3,
|
||||
username: 'abc123',
|
||||
username,
|
||||
administrator: true,
|
||||
roles: [],
|
||||
},
|
||||
@@ -126,9 +130,21 @@ describe('PostsView', () => {
|
||||
|
||||
test('displays a list of user posts', async () => {
|
||||
setupStore();
|
||||
axiosMock.onGet(`${coursesApiUrl}${courseId}/learner/`, { username, count_flagged: true })
|
||||
.reply(() => {
|
||||
const threadAttrs = { previewBody: 'thread preview body', author: username };
|
||||
return [200, Factory.build('threadsResult', {}, {
|
||||
topicId: undefined,
|
||||
count: threadCount,
|
||||
threadAttrs,
|
||||
pageSize: 6,
|
||||
})];
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
await renderComponent({ myPosts: true });
|
||||
});
|
||||
|
||||
expect(screen.getAllByText('abc123')).toHaveLength(threadCount);
|
||||
});
|
||||
|
||||
@@ -185,7 +201,7 @@ describe('PostsView', () => {
|
||||
await renderComponent();
|
||||
});
|
||||
dropDownButton = screen.getByRole('button', {
|
||||
name: /all posts by recent activity/i,
|
||||
name: /all posts sorted by recent activity/i,
|
||||
});
|
||||
await act(async () => {
|
||||
fireEvent.click(dropDownButton);
|
||||
@@ -197,7 +213,7 @@ describe('PostsView', () => {
|
||||
// 5 status filters: any, unread, following, reported, unanswered
|
||||
// 3 sort: activity, comments, likes
|
||||
// 2 cohort: all groups, 1 api mock response cohort
|
||||
expect(screen.queryAllByRole('radio')).toHaveLength(13);
|
||||
expect(screen.queryAllByRole('radio')).toHaveLength(14);
|
||||
});
|
||||
|
||||
test('test that the cohorts filter works', async () => {
|
||||
@@ -206,7 +222,7 @@ describe('PostsView', () => {
|
||||
});
|
||||
|
||||
dropDownButton = screen.getByRole('button', {
|
||||
name: /All posts in Cohort 1 by recent activity/i,
|
||||
name: /All posts in Cohort 1 sorted by recent activity/i,
|
||||
});
|
||||
|
||||
expect(dropDownButton).toBeInTheDocument();
|
||||
|
||||
@@ -8,10 +8,8 @@ ensureConfig([
|
||||
'LMS_BASE_URL',
|
||||
], 'Posts API service');
|
||||
|
||||
const apiBaseUrl = getConfig().LMS_BASE_URL;
|
||||
|
||||
export const threadsApiUrl = `${apiBaseUrl}/api/discussion/v1/threads/`;
|
||||
export const coursesApiUrl = `${apiBaseUrl}/api/discussion/v1/courses/`;
|
||||
export const getThreadsApiUrl = () => `${getConfig().LMS_BASE_URL}/api/discussion/v1/threads/`;
|
||||
export const getCoursesApiUrl = () => `${getConfig().LMS_BASE_URL}/api/discussion/v1/courses/`;
|
||||
|
||||
/**
|
||||
* Fetches all the threads in the given course and topic.
|
||||
@@ -62,7 +60,7 @@ export async function getThreads(
|
||||
countFlagged,
|
||||
groupId: cohort,
|
||||
});
|
||||
const { data } = await getAuthenticatedHttpClient().get(threadsApiUrl, { params });
|
||||
const { data } = await getAuthenticatedHttpClient().get(getThreadsApiUrl(), { params });
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -71,9 +69,9 @@ export async function getThreads(
|
||||
* @param {string} threadId
|
||||
* @returns {Promise<{}>}
|
||||
*/
|
||||
export async function getThread(threadId) {
|
||||
const params = { requested_fields: 'profile_image' };
|
||||
const url = `${threadsApiUrl}${threadId}/`;
|
||||
export async function getThread(threadId, courseId) {
|
||||
const params = { requested_fields: 'profile_image', course_id: courseId };
|
||||
const url = `${getThreadsApiUrl()}${threadId}/`;
|
||||
const { data } = await getAuthenticatedHttpClient().get(url, { params });
|
||||
return data;
|
||||
}
|
||||
@@ -117,7 +115,7 @@ export async function postThread(
|
||||
});
|
||||
|
||||
const { data } = await getAuthenticatedHttpClient()
|
||||
.post(threadsApiUrl, postData);
|
||||
.post(getThreadsApiUrl(), postData);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -152,7 +150,7 @@ export async function updateThread(threadId, {
|
||||
editReasonCode,
|
||||
closeReasonCode,
|
||||
} = {}) {
|
||||
const url = `${threadsApiUrl}${threadId}/`;
|
||||
const url = `${getThreadsApiUrl()}${threadId}/`;
|
||||
const patchData = snakeCaseObject({
|
||||
topicId,
|
||||
abuse_flagged: flagged,
|
||||
@@ -177,7 +175,7 @@ export async function updateThread(threadId, {
|
||||
* @param {string} threadId
|
||||
*/
|
||||
export async function deleteThread(threadId) {
|
||||
const url = `${threadsApiUrl}${threadId}/`;
|
||||
const url = `${getThreadsApiUrl()}${threadId}/`;
|
||||
await getAuthenticatedHttpClient()
|
||||
.delete(url);
|
||||
}
|
||||
@@ -191,7 +189,7 @@ export async function deleteThread(threadId) {
|
||||
* @returns {Promise<{ location: string }>}
|
||||
*/
|
||||
export async function uploadFile(blob, filename, courseId, threadKey) {
|
||||
const uploadUrl = `${coursesApiUrl}${courseId}/upload`;
|
||||
const uploadUrl = `${getCoursesApiUrl()}${courseId}/upload`;
|
||||
const formData = new FormData();
|
||||
formData.append('thread_key', threadKey);
|
||||
formData.append('uploaded_file', blob, filename);
|
||||
|
||||
@@ -3,9 +3,10 @@ import MockAdapter from 'axios-mock-adapter';
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
import { initializeMockApp } from '@edx/frontend-platform/testing';
|
||||
|
||||
import { coursesApiUrl, uploadFile } from './api';
|
||||
import { getCoursesApiUrl, uploadFile } from './api';
|
||||
|
||||
const courseId = 'course-v1:edX+TestX+Test_Course';
|
||||
const coursesApiUrl = getCoursesApiUrl();
|
||||
|
||||
let axiosMock = null;
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { initializeMockApp } from '@edx/frontend-platform/testing';
|
||||
|
||||
import { initializeStore } from '../../../store';
|
||||
import { executeThunk } from '../../../test-utils';
|
||||
import { threadsApiUrl } from './api';
|
||||
import { getThreadsApiUrl } from './api';
|
||||
import {
|
||||
createNewThread, fetchThread, fetchThreads, removeThread, updateExistingThread,
|
||||
} from './thunks';
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
import './__factories__';
|
||||
|
||||
const courseId = 'course-v1:edX+TestX+Test_Course';
|
||||
const threadsApiUrl = getThreadsApiUrl();
|
||||
|
||||
let axiosMock;
|
||||
let store;
|
||||
|
||||
@@ -120,6 +120,9 @@ export function fetchThreads(courseId, {
|
||||
if (filters.status === PostsStatusFilter.UNANSWERED) {
|
||||
options.view = 'unanswered';
|
||||
}
|
||||
if (filters.status === PostsStatusFilter.UNRESPONDED) {
|
||||
options.view = 'unresponded';
|
||||
}
|
||||
if (filters.status === PostsStatusFilter.REPORTED) {
|
||||
options.flagged = true;
|
||||
}
|
||||
@@ -151,18 +154,18 @@ export function fetchThreads(courseId, {
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchThread(threadId, isDirectLinkPost = false) {
|
||||
export function fetchThread(threadId, courseId, isDirectLinkPost = false) {
|
||||
return async (dispatch) => {
|
||||
try {
|
||||
dispatch(fetchThreadRequest({ threadId }));
|
||||
const data = await getThread(threadId);
|
||||
const data = await getThread(threadId, courseId);
|
||||
if (isDirectLinkPost) {
|
||||
dispatch(fetchThreadByDirectLinkSuccess({ ...normaliseThreads(camelCaseObject(data)), page: 1 }));
|
||||
} else {
|
||||
dispatch(fetchThreadSuccess(normaliseThreads(camelCaseObject(data))));
|
||||
}
|
||||
} catch (error) {
|
||||
if (getHttpErrorStatus(error) === 403) {
|
||||
if (getHttpErrorStatus(error) === 403 || getHttpErrorStatus(error) === 404) {
|
||||
dispatch(fetchThreadDenied());
|
||||
} else {
|
||||
dispatch(fetchThreadFailed());
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
@@ -10,7 +11,8 @@ import {
|
||||
import { Close } from '@edx/paragon/icons';
|
||||
|
||||
import Search from '../../../components/Search';
|
||||
import { selectBlackoutDate } from '../../data/selectors';
|
||||
import { RequestStatus } from '../../../data/constants';
|
||||
import { selectBlackoutDate, selectconfigLoadingStatus } from '../../data/selectors';
|
||||
import { inBlackoutDateRange, postMessageToParent } from '../../utils';
|
||||
import { showPostEditor } from '../data';
|
||||
import messages from './messages';
|
||||
@@ -22,38 +24,37 @@ function PostActionsBar({
|
||||
inContext,
|
||||
}) {
|
||||
const dispatch = useDispatch();
|
||||
const loadingStatus = useSelector(selectconfigLoadingStatus);
|
||||
const blackoutDateRange = useSelector(selectBlackoutDate);
|
||||
|
||||
const handleCloseInContext = () => {
|
||||
postMessageToParent('learning.events.sidebar.close');
|
||||
};
|
||||
const blackoutDateRange = useSelector(selectBlackoutDate);
|
||||
|
||||
return (
|
||||
<div className="d-flex justify-content-end py-1 flex-grow-1">
|
||||
{!inContext && (
|
||||
<>
|
||||
<Search />
|
||||
<div className="border-right border-light-400 mx-3" />
|
||||
</>
|
||||
)}
|
||||
<div className={classNames('d-flex justify-content-end flex-grow-1', { 'py-1': !inContext })}>
|
||||
{!inContext && <Search />}
|
||||
{inContext && (
|
||||
<h4 className="d-flex flex-grow-1 font-weight-bold my-0 py-0 align-self-center">
|
||||
{intl.formatMessage(messages.title)}
|
||||
</h4>
|
||||
)}
|
||||
{
|
||||
!inBlackoutDateRange(blackoutDateRange) && (
|
||||
{(!inBlackoutDateRange(blackoutDateRange) && loadingStatus === RequestStatus.SUCCESSFUL) && (
|
||||
<>
|
||||
{!inContext && <div className="border-right border-light-400 mx-3" />}
|
||||
<Button
|
||||
variant={inContext ? 'plain' : 'brand'}
|
||||
className="my-0"
|
||||
className={classNames('my-0', { 'p-0': inContext })}
|
||||
onClick={() => dispatch(showPostEditor())}
|
||||
size="sm"
|
||||
size={inContext ? 'md' : 'sm'}
|
||||
>
|
||||
{intl.formatMessage(messages.addAPost)}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
</>
|
||||
)}
|
||||
{inContext && (
|
||||
<>
|
||||
<div className="border-right mr-3 ml-4" />
|
||||
<div className="border-right border-light-300 mr-2 ml-3.5 my-2" />
|
||||
<IconButton
|
||||
src={Close}
|
||||
iconAs={Icon}
|
||||
@@ -62,7 +63,6 @@ function PostActionsBar({
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import PostPreviewPane from '../../../components/PostPreviewPane';
|
||||
import { useDispatchWithState } from '../../../data/hooks';
|
||||
import { selectCourseCohorts } from '../../cohorts/data/selectors';
|
||||
import { fetchCourseCohorts } from '../../cohorts/data/thunks';
|
||||
import { DiscussionContext } from '../../common/context';
|
||||
import { useCurrentDiscussionTopic } from '../../data/hooks';
|
||||
import {
|
||||
selectAnonymousPostingConfig,
|
||||
@@ -32,6 +33,7 @@ import {
|
||||
selectUserIsGroupTa,
|
||||
selectUserIsStaff,
|
||||
} from '../../data/selectors';
|
||||
import { EmptyPage } from '../../empty-posts';
|
||||
import { selectCoursewareTopics, selectNonCoursewareIds, selectNonCoursewareTopics } from '../../topics/data/selectors';
|
||||
import {
|
||||
discussionsPath, formikCompatibleHandler, isFormikFieldInvalid, useCommentsPagePath,
|
||||
@@ -93,7 +95,6 @@ function PostEditor({
|
||||
postId,
|
||||
} = useParams();
|
||||
const topicId = useCurrentDiscussionTopic();
|
||||
|
||||
const nonCoursewareTopics = useSelector(selectNonCoursewareTopics);
|
||||
const nonCoursewareIds = useSelector(selectNonCoursewareIds);
|
||||
const coursewareTopics = useSelector(selectCoursewareTopics);
|
||||
@@ -105,6 +106,7 @@ function PostEditor({
|
||||
const { allowAnonymous, allowAnonymousToPeers } = useSelector(selectAnonymousPostingConfig);
|
||||
const { reasonCodesEnabled, editReasons } = useSelector(selectModerationSettings);
|
||||
const userIsStaff = useSelector(selectUserIsStaff);
|
||||
const { category, inContext } = useContext(DiscussionContext);
|
||||
|
||||
const canDisplayEditReason = (reasonCodesEnabled && editExisting
|
||||
&& (userHasModerationPrivileges || userIsGroupTa || userIsStaff)
|
||||
@@ -136,7 +138,9 @@ function PostEditor({
|
||||
follow: isEmpty(post?.following) ? true : post?.following,
|
||||
anonymous: allowAnonymous ? false : undefined,
|
||||
anonymousToPeers: allowAnonymousToPeers ? false : undefined,
|
||||
editReasonCode: post?.lastEdit?.reasonCode || (userIsStaff ? 'violates-guidelines' : ''),
|
||||
editReasonCode: post?.lastEdit?.reasonCode || (
|
||||
userIsStaff && canDisplayEditReason ? 'violates-guidelines' : undefined
|
||||
),
|
||||
cohort: post?.cohort || 'default',
|
||||
};
|
||||
|
||||
@@ -148,6 +152,7 @@ function PostEditor({
|
||||
topicId,
|
||||
postId,
|
||||
learnerUsername: post?.author,
|
||||
category,
|
||||
})(location);
|
||||
history.push(newLocation);
|
||||
}
|
||||
@@ -191,16 +196,25 @@ function PostEditor({
|
||||
dispatch(fetchCourseCohorts(courseId));
|
||||
}
|
||||
if (editExisting) {
|
||||
dispatch(fetchThread(postId));
|
||||
dispatchSubmit(fetchThread(postId, courseId));
|
||||
}
|
||||
}, [courseId, editExisting]);
|
||||
|
||||
if (editExisting && !post) {
|
||||
return (
|
||||
<div className="m-4 card p-4 align-items-center">
|
||||
<Spinner animation="border" variant="primary" />
|
||||
</div>
|
||||
);
|
||||
if (submitting) {
|
||||
return (
|
||||
<div className="m-4 card p-4 align-items-center">
|
||||
<Spinner animation="border" variant="primary" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (!submitting) {
|
||||
return (
|
||||
<EmptyPage
|
||||
title={intl.formatMessage(messages.noThreadFound)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
@@ -284,15 +298,20 @@ function PostEditor({
|
||||
onBlur={handleBlur}
|
||||
aria-describedby="topicAreaInput"
|
||||
floatingLabel={intl.formatMessage(messages.topicArea)}
|
||||
disabled={inContext}
|
||||
>
|
||||
{nonCoursewareTopics.map(topic => (
|
||||
<option key={topic.id} value={topic.id}>{topic.name}</option>
|
||||
<option
|
||||
key={topic.id}
|
||||
value={topic.id}
|
||||
>{topic.name || intl.formatMessage(messages.unnamedSubTopics)}
|
||||
</option>
|
||||
))}
|
||||
{coursewareTopics.map(category => (
|
||||
<optgroup label={category.name} key={category.id}>
|
||||
{category.topics.map(subtopic => (
|
||||
{coursewareTopics.map(categoryObj => (
|
||||
<optgroup label={categoryObj.name || intl.formatMessage(messages.unnamedTopics)} key={categoryObj.id}>
|
||||
{categoryObj.topics.map(subtopic => (
|
||||
<option key={subtopic.id} value={subtopic.id}>
|
||||
{subtopic.name}
|
||||
{subtopic.name || intl.formatMessage(messages.unnamedSubTopics)}
|
||||
</option>
|
||||
))}
|
||||
</optgroup>
|
||||
|
||||
@@ -12,12 +12,13 @@ import { initializeMockApp } from '@edx/frontend-platform';
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
import { AppProvider } from '@edx/frontend-platform/react';
|
||||
|
||||
import { API_BASE_URL, Routes } from '../../../data/constants';
|
||||
import { getApiBaseUrl, Routes } from '../../../data/constants';
|
||||
import { initializeStore } from '../../../store';
|
||||
import { executeThunk } from '../../../test-utils';
|
||||
import { getCohortsApiUrl } from '../../cohorts/data/api';
|
||||
import { DiscussionContext } from '../../common/context';
|
||||
import { fetchCourseTopics } from '../../topics/data/thunks';
|
||||
import { threadsApiUrl } from '../data/api';
|
||||
import { getThreadsApiUrl } from '../data/api';
|
||||
import { fetchThread } from '../data/thunks';
|
||||
import { PostEditor } from '../index';
|
||||
|
||||
@@ -27,7 +28,8 @@ import '../../topics/data/__factories__';
|
||||
import '../data/__factories__';
|
||||
|
||||
const courseId = 'course-v1:edX+DemoX+Demo_Course';
|
||||
const topicsApiUrl = `${API_BASE_URL}/api/discussion/v1/course_topics/${courseId}`;
|
||||
const topicsApiUrl = `${getApiBaseUrl()}/api/discussion/v1/course_topics/${courseId}`;
|
||||
const threadsApiUrl = getThreadsApiUrl();
|
||||
let store;
|
||||
let axiosMock;
|
||||
|
||||
@@ -36,11 +38,15 @@ async function renderComponent(editExisting = false, location = `/${courseId}/po
|
||||
await render(
|
||||
<IntlProvider locale="en">
|
||||
<AppProvider store={store}>
|
||||
<MemoryRouter initialEntries={[location]}>
|
||||
<Route path={path}>
|
||||
<PostEditor editExisting={editExisting} />
|
||||
</Route>
|
||||
</MemoryRouter>
|
||||
<DiscussionContext.Provider
|
||||
value={{ courseId, category: null }}
|
||||
>
|
||||
<MemoryRouter initialEntries={[location]}>
|
||||
<Route path={path}>
|
||||
<PostEditor editExisting={editExisting} />
|
||||
</Route>
|
||||
</MemoryRouter>
|
||||
</DiscussionContext.Provider>
|
||||
</AppProvider>
|
||||
</IntlProvider>,
|
||||
);
|
||||
|
||||
@@ -121,6 +121,21 @@ const messages = defineMessages({
|
||||
defaultMessage: 'Actions menu',
|
||||
description: 'Button to see actions for a post or comment',
|
||||
},
|
||||
unnamedTopics: {
|
||||
id: 'discussions.topic.noName.label',
|
||||
defaultMessage: 'Unnamed category',
|
||||
description: 'display string for topics with missing names',
|
||||
},
|
||||
unnamedSubTopics: {
|
||||
id: 'discussions.subtopic.noName.label',
|
||||
defaultMessage: 'Unnamed subcategory',
|
||||
description: 'display string for topics with missing names',
|
||||
},
|
||||
noThreadFound: {
|
||||
id: 'discussion.thread.notFound',
|
||||
defaultMessage: 'Thread not found',
|
||||
description: 'message to show on screen if the request thread is not found in course',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import React, {
|
||||
useContext, useEffect, useMemo, useState,
|
||||
} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import classNames from 'classnames';
|
||||
@@ -18,6 +20,7 @@ import {
|
||||
} from '../../../data/constants';
|
||||
import { selectCourseCohorts } from '../../cohorts/data/selectors';
|
||||
import { fetchCourseCohorts } from '../../cohorts/data/thunks';
|
||||
import { DiscussionContext } from '../../common/context';
|
||||
import { selectUserHasModerationPrivileges, selectUserIsGroupTa } from '../../data/selectors';
|
||||
import {
|
||||
setCohortFilter, setPostsTypeFilter, setSortedBy, setStatusFilter,
|
||||
@@ -60,6 +63,7 @@ function PostFilterBar({
|
||||
}) {
|
||||
const dispatch = useDispatch();
|
||||
const { courseId } = useParams();
|
||||
const { page } = useContext(DiscussionContext);
|
||||
const userHasModerationPrivileges = useSelector(selectUserHasModerationPrivileges);
|
||||
const userIsGroupTa = useSelector(selectUserIsGroupTa);
|
||||
const currentSorting = useSelector(selectThreadSorting());
|
||||
@@ -95,6 +99,10 @@ function PostFilterBar({
|
||||
// You can't filter discussions by unanswered so switch type to questions
|
||||
dispatch(setPostsTypeFilter(ThreadType.QUESTION));
|
||||
}
|
||||
if (value === PostsStatusFilter.UNRESPONDED && currentType !== ThreadType.DISCUSSION) {
|
||||
// You can't filter questions by not responded so switch type to discussion
|
||||
dispatch(setPostsTypeFilter(ThreadType.DISCUSSION));
|
||||
}
|
||||
}
|
||||
if (name === 'sort') {
|
||||
dispatch(setSortedBy(value));
|
||||
@@ -180,12 +188,14 @@ function PostFilterBar({
|
||||
value={PostsStatusFilter.UNREAD}
|
||||
selected={currentFilters.status}
|
||||
/>
|
||||
<ActionItem
|
||||
id="status-following"
|
||||
label={intl.formatMessage(messages.filterFollowing)}
|
||||
value={PostsStatusFilter.FOLLOWING}
|
||||
selected={currentFilters.status}
|
||||
/>
|
||||
{page !== 'my-posts' && (
|
||||
<ActionItem
|
||||
id="status-following"
|
||||
label={intl.formatMessage(messages.filterFollowing)}
|
||||
value={PostsStatusFilter.FOLLOWING}
|
||||
selected={currentFilters.status}
|
||||
/>
|
||||
)}
|
||||
{(userHasModerationPrivileges || userIsGroupTa) && (
|
||||
<ActionItem
|
||||
id="status-reported"
|
||||
@@ -200,6 +210,12 @@ function PostFilterBar({
|
||||
value={PostsStatusFilter.UNANSWERED}
|
||||
selected={currentFilters.status}
|
||||
/>
|
||||
<ActionItem
|
||||
id="status-unresponded"
|
||||
label={intl.formatMessage(messages.filterUnresponded)}
|
||||
value={PostsStatusFilter.UNRESPONDED}
|
||||
selected={currentFilters.status}
|
||||
/>
|
||||
</Form.RadioSet>
|
||||
<Form.RadioSet
|
||||
name="sort"
|
||||
|
||||
@@ -48,7 +48,7 @@ const messages = defineMessages({
|
||||
},
|
||||
filterUnresponded: {
|
||||
id: 'discussions.posts.status.filter.unresponded',
|
||||
defaultMessage: 'Unresponded',
|
||||
defaultMessage: 'Not responded',
|
||||
description: 'Option in dropdown to filter to unresponded posts',
|
||||
},
|
||||
myPosts: {
|
||||
@@ -109,10 +109,10 @@ const messages = defineMessages({
|
||||
all {}
|
||||
group {in {cohort}}
|
||||
other {{cohortType}}
|
||||
} by {sort, select,
|
||||
} sorted by {sort, select,
|
||||
lastActivityAt {recent activity}
|
||||
commentCount {most activity}
|
||||
voteCount {most votes}
|
||||
voteCount {most likes}
|
||||
other {{sort}}
|
||||
}`,
|
||||
description: 'Status message showing current sorting and filtering status',
|
||||
|
||||
@@ -50,8 +50,7 @@ function ClosePostReasonModal({
|
||||
isOpen={isOpen}
|
||||
onClose={onCancel}
|
||||
hasCloseButton={false}
|
||||
isFullscreenOnMobile
|
||||
isFullscreenScroll
|
||||
zIndex={5000}
|
||||
>
|
||||
<ModalDialog.Header>
|
||||
<ModalDialog.Title>
|
||||
|
||||
@@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Hyperlink, useToggle } from '@edx/paragon';
|
||||
|
||||
@@ -35,6 +36,9 @@ function Post({
|
||||
const { reasonCodesEnabled } = useSelector(selectModerationSettings);
|
||||
const [isDeleting, showDeleteConfirmation, hideDeleteConfirmation] = useToggle(false);
|
||||
const [isClosing, showClosePostModal, hideClosePostModal] = useToggle(false);
|
||||
|
||||
const postURL = new URL(`${getConfig().PUBLIC_PATH}${courseId}/posts/${post.id}`, window.location.origin);
|
||||
|
||||
const actionHandlers = {
|
||||
[ContentActions.EDIT_CONTENT]: () => history.push({
|
||||
...location,
|
||||
@@ -50,7 +54,7 @@ function Post({
|
||||
dispatch(updateExistingThread(post.id, { closed: true }));
|
||||
}
|
||||
},
|
||||
[ContentActions.COPY_LINK]: () => { navigator.clipboard.writeText(`${window.location.origin}/${courseId}/posts/${post.id}`); },
|
||||
[ContentActions.COPY_LINK]: () => { navigator.clipboard.writeText(postURL.href); },
|
||||
[ContentActions.PIN]: () => dispatch(updateExistingThread(post.id, { pinned: !post.pinned })),
|
||||
[ContentActions.REPORT]: () => dispatch(updateExistingThread(post.id, { flagged: !post.abuseFlagged })),
|
||||
};
|
||||
|
||||
@@ -93,14 +93,14 @@ function PostFooter({
|
||||
</span>
|
||||
</OverlayTrigger>
|
||||
<span
|
||||
className="text-light-700 mx-1.5 font-weight-500"
|
||||
className="text-gray-700 mx-1.5 font-weight-500"
|
||||
style={{ fontSize: '16px' }}
|
||||
>
|
||||
·
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
<span title={post.createdAt} className="text-gray-500">
|
||||
<span title={post.createdAt} className="text-gray-700">
|
||||
{timeago.format(post.createdAt, 'time-locale')}
|
||||
</span>
|
||||
{!preview && post.closed
|
||||
|
||||
@@ -120,7 +120,7 @@ function PostHeader({
|
||||
</div>
|
||||
{!preview
|
||||
&& (
|
||||
<div className="ml-auto d-flex align-items-center">
|
||||
<div className="ml-auto d-flex">
|
||||
<ActionsDropdown commentOrPost={post} actionHandlers={actionHandlers} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react/no-unknown-property */
|
||||
import React, { useContext } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
@@ -5,7 +6,8 @@ import classNames from 'classnames';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { Badge, Icon } from '@edx/paragon';
|
||||
import { Badge, Icon, Truncate } from '@edx/paragon';
|
||||
import { CheckCircle } from '@edx/paragon/icons';
|
||||
|
||||
import { PushPin } from '../../../components/icons';
|
||||
import { AvatarOutlineAndLabelColors, Routes, ThreadType } from '../../../data/constants';
|
||||
@@ -54,7 +56,7 @@ function PostLink({
|
||||
}
|
||||
to={linkUrl}
|
||||
onClick={() => isSelected(post.id)}
|
||||
style={{ lineHeight: '21px' }}
|
||||
style={{ lineHeight: '22px' }}
|
||||
aria-current={isSelected(post.id) ? 'page' : undefined}
|
||||
role="option"
|
||||
tabIndex={(isSelected(post.id) || idx === 0) ? 0 : -1}
|
||||
@@ -73,20 +75,28 @@ function PostLink({
|
||||
<div className="d-flex flex-column flex-fill" style={{ minWidth: 0 }}>
|
||||
<div className="d-flex flex-column justify-content-start mw-100 flex-fill">
|
||||
<div className="d-flex align-items-center pb-0 mb-0 flex-fill font-weight-500">
|
||||
<div
|
||||
className={
|
||||
classNames('text-truncate font-weight-500 font-size-14 text-primary-500 font-style-normal font-family-inter',
|
||||
{ 'font-weight-bolder': !read })
|
||||
}
|
||||
>
|
||||
{post.title}
|
||||
</div>
|
||||
|
||||
<Truncate lines={1} className="mr-1.5" whiteSpace>
|
||||
<span
|
||||
class={
|
||||
classNames('font-weight-500 font-size-14 text-primary-500 font-style-normal font-family-inter align-bottom',
|
||||
{ 'font-weight-bolder': !read })
|
||||
}
|
||||
>
|
||||
{post.title}
|
||||
</span>
|
||||
<span class="align-bottom"> </span>
|
||||
<span
|
||||
class="text-gray-700 font-weight-normal font-size-14 font-style-normal font-family-inter align-bottom"
|
||||
>
|
||||
{isPostPreviewAvailable(post.previewBody)
|
||||
? post.previewBody
|
||||
: intl.formatMessage(messages.postWithoutPreview)}
|
||||
</span>
|
||||
</Truncate>
|
||||
{showAnsweredBadge && (
|
||||
<Badge variant="success" className="font-weight-500 ml-auto badge-padding">
|
||||
{intl.formatMessage(messages.answered)}
|
||||
<span className="sr-only">{' '}answered</span>
|
||||
</Badge>
|
||||
<Icon src={CheckCircle} className="text-success font-weight-500 ml-auto badge-padding" data-testid="check-icon">
|
||||
<span className="sr-only">{' '}answered</span>
|
||||
</Icon>
|
||||
)}
|
||||
|
||||
{canSeeReportedBadge && (
|
||||
@@ -113,17 +123,7 @@ function PostLink({
|
||||
authorLabel={post.authorLabel}
|
||||
labelColor={authorLabelColor && `text-${authorLabelColor}`}
|
||||
/>
|
||||
<div
|
||||
className="text-truncate text-primary-500 font-weight-normal font-size-14 font-style-normal font-family-inter"
|
||||
style={{ maxHeight: '1.5rem' }}
|
||||
>
|
||||
{isPostPreviewAvailable(post.previewBody)
|
||||
? post.previewBody
|
||||
: intl.formatMessage(messages.postWithoutPreview)}
|
||||
</div>
|
||||
<div className="mt-1">
|
||||
<PostFooter post={post} preview intl={intl} showNewCountLabel={read} />
|
||||
</div>
|
||||
<PostFooter post={post} preview intl={intl} showNewCountLabel={read} />
|
||||
</div>
|
||||
</div>
|
||||
{!showDivider && post.pinned && <div className="pt-1 bg-light-500 border-top border-light-700" />}
|
||||
|
||||
@@ -11,11 +11,12 @@ import { AppProvider } from '@edx/frontend-platform/react';
|
||||
import { initializeStore } from '../../../store';
|
||||
import { executeThunk } from '../../../test-utils';
|
||||
import { DiscussionContext } from '../../common/context';
|
||||
import { courseConfigApiUrl } from '../../data/api';
|
||||
import { getCourseConfigApiUrl } from '../../data/api';
|
||||
import { fetchCourseConfig } from '../../data/thunks';
|
||||
import PostLink from './PostLink';
|
||||
|
||||
const courseId = 'course-v1:edX+DemoX+Demo_Course';
|
||||
const courseConfigApiUrl = getCourseConfigApiUrl();
|
||||
let store;
|
||||
let axiosMock;
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
import { AppProvider } from '@edx/frontend-platform/react';
|
||||
|
||||
import { getBlocksAPIResponse } from '../../data/__factories__';
|
||||
import { blocksAPIURL } from '../../data/api';
|
||||
import { API_BASE_URL, DiscussionProvider } from '../../data/constants';
|
||||
import { getBlocksAPIURL } from '../../data/api';
|
||||
import { DiscussionProvider, getApiBaseUrl } from '../../data/constants';
|
||||
import { selectSequences } from '../../data/selectors';
|
||||
import { fetchCourseBlocks } from '../../data/thunks';
|
||||
import { initializeStore } from '../../store';
|
||||
@@ -26,8 +26,8 @@ import './data/__factories__';
|
||||
|
||||
const courseId = 'course-v1:edX+DemoX+Demo_Course';
|
||||
|
||||
const topicsApiUrl = `${API_BASE_URL}/api/discussion/v1/course_topics/${courseId}`;
|
||||
const topicsv2ApiUrl = `${API_BASE_URL}/api/discussion/v2/course_topics/${courseId}`;
|
||||
const topicsApiUrl = `${getApiBaseUrl()}/api/discussion/v1/course_topics/${courseId}`;
|
||||
const topicsv2ApiUrl = `${getApiBaseUrl()}/api/discussion/v2/course_topics/${courseId}`;
|
||||
let store;
|
||||
let axiosMock;
|
||||
let lastLocation;
|
||||
@@ -113,7 +113,7 @@ describe('TopicsView', () => {
|
||||
axiosMock
|
||||
.onGet(topicsv2ApiUrl)
|
||||
.reply(200, data);
|
||||
axiosMock.onGet(blocksAPIURL)
|
||||
axiosMock.onGet(getBlocksAPIURL())
|
||||
.reply(200, getBlocksAPIResponse(true));
|
||||
axiosMock.onAny().networkError();
|
||||
await executeThunk(fetchCourseBlocks(courseId, 'abc123'), store.dispatch, store.getState);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
|
||||
import { API_BASE_URL } from '../../../data/constants';
|
||||
import { getApiBaseUrl } from '../../../data/constants';
|
||||
|
||||
export async function getCourseTopics(courseId, topicIds) {
|
||||
const url = `${API_BASE_URL}/api/discussion/v1/course_topics/${courseId}`;
|
||||
const url = `${getApiBaseUrl()}/api/discussion/v1/course_topics/${courseId}`;
|
||||
const params = {};
|
||||
if (topicIds) {
|
||||
params.topic_id = topicIds.join(',');
|
||||
@@ -15,7 +15,7 @@ export async function getCourseTopics(courseId, topicIds) {
|
||||
}
|
||||
|
||||
export async function getCourseTopicsV2(courseId, topicIds) {
|
||||
const url = `${API_BASE_URL}/api/discussion/v2/course_topics/${courseId}`;
|
||||
const url = `${getApiBaseUrl()}/api/discussion/v2/course_topics/${courseId}`;
|
||||
const params = {};
|
||||
if (topicIds) {
|
||||
params.topic_id = topicIds.join(',');
|
||||
|
||||
@@ -45,6 +45,7 @@ export const selectNonCoursewareTopics = state => state.topics.nonCoursewareIds.
|
||||
|
||||
export const selectTopic = topicId => state => state.topics.topics[topicId];
|
||||
|
||||
export const selectTopicsById = topicIds => state => topicIds.map(topicId => state.topics.topics[topicId]);
|
||||
export const selectTopicsById = topicIds => state => topicIds.map(topicId => state.topics.topics[topicId])
|
||||
.filter(Boolean);
|
||||
|
||||
export const topicsLoadingStatus = state => state.topics.status;
|
||||
|
||||
@@ -61,7 +61,12 @@ const messages = defineMessages({
|
||||
},
|
||||
unnamedTopicCategories: {
|
||||
id: 'discussions.topics.unnamed.label',
|
||||
defaultMessage: 'Unnamed Topic',
|
||||
defaultMessage: 'Unnamed category',
|
||||
description: 'Text to display in place of topic name if topic name is empty',
|
||||
},
|
||||
unnamedTopicSubCategories: {
|
||||
id: 'discussions.subtopics.unnamed.label',
|
||||
defaultMessage: 'Unnamed subcategory',
|
||||
description: 'Text to display in place of topic name if topic name is empty',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -51,7 +51,7 @@ function Topic({
|
||||
<div className="d-flex flex-column flex-fill" style={{ minWidth: 0 }}>
|
||||
<div className="d-flex flex-column justify-content-start mw-100 flex-fill">
|
||||
<div className="topic-name text-truncate">
|
||||
{topic.name}
|
||||
{topic.name || intl.formatMessage(messages.unnamedTopicSubCategories)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="d-flex align-items-center mt-2.5" style={{ marginBottom: '2px' }}>
|
||||
|
||||
@@ -5,7 +5,9 @@ import { generatePath, useRouteMatch } from 'react-router';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import {
|
||||
Delete, Edit, Pin, QuestionAnswer, Report, VerifiedBadge,
|
||||
CheckCircle,
|
||||
CheckCircleOutline,
|
||||
Delete, Edit, Pin, QuestionAnswer, Report, Verified, VerifiedOutline,
|
||||
} from '@edx/paragon/icons';
|
||||
|
||||
import { InsertLink } from '../components/icons';
|
||||
@@ -101,7 +103,7 @@ export const ACTIONS_LIST = [
|
||||
{
|
||||
id: 'endorse',
|
||||
action: ContentActions.ENDORSE,
|
||||
icon: VerifiedBadge,
|
||||
icon: VerifiedOutline,
|
||||
label: messages.endorseAction,
|
||||
conditions: {
|
||||
endorsed: false,
|
||||
@@ -111,7 +113,7 @@ export const ACTIONS_LIST = [
|
||||
{
|
||||
id: 'unendorse',
|
||||
action: ContentActions.ENDORSE,
|
||||
icon: VerifiedBadge,
|
||||
icon: Verified,
|
||||
label: messages.unendorseAction,
|
||||
conditions: {
|
||||
endorsed: true,
|
||||
@@ -121,7 +123,7 @@ export const ACTIONS_LIST = [
|
||||
{
|
||||
id: 'answer',
|
||||
action: ContentActions.ENDORSE,
|
||||
icon: VerifiedBadge,
|
||||
icon: CheckCircleOutline,
|
||||
label: messages.markAnsweredAction,
|
||||
conditions: {
|
||||
endorsed: false,
|
||||
@@ -131,7 +133,7 @@ export const ACTIONS_LIST = [
|
||||
{
|
||||
id: 'unanswer',
|
||||
action: ContentActions.ENDORSE,
|
||||
icon: VerifiedBadge,
|
||||
icon: CheckCircle,
|
||||
label: messages.unmarkAnsweredAction,
|
||||
conditions: {
|
||||
endorsed: true,
|
||||
@@ -183,6 +185,7 @@ export function useActions(content) {
|
||||
.every(condition => condition === true)
|
||||
: true
|
||||
);
|
||||
|
||||
return ACTIONS_LIST.filter(
|
||||
({
|
||||
action,
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"discussions.comments.comment.addResponse": "Add a response",
|
||||
"discussions.comments.comment.addComment": "Add a comment",
|
||||
"discussions.comments.comment.abuseFlaggedMessage": "Content reported for staff to review",
|
||||
"discussions.actions.back.alt": "Back to list",
|
||||
"discussions.comments.comment.responseCount": "{num, plural,\n =0 {No responses}\n one {Showing # response}\n other {Showing # responses}\n }",
|
||||
"discussions.comments.comment.endorsedResponseCount": "{num, plural,\n =0 {No endorsed responses}\n one {Showing # endorsed response}\n other {Showing # endorsed responses}\n }",
|
||||
"discussions.comments.comment.loadMoreComments": "Load more comments",
|
||||
@@ -42,11 +43,11 @@
|
||||
"discussions.learner.activityForLearner": "Activity for {username}",
|
||||
"discussions.learner.mostActivity": "Most activity",
|
||||
"discussions.learner.reportedActivity": "Reported activity",
|
||||
"discussions.learner.sortFilterStatus": "All learners by {sort, select,\n flagged {reported activity}\n activity {most activity}\n other {{sort}}\n }",
|
||||
"discussions.learner.recentActivity": "Recent activity",
|
||||
"discussions.learner.sortFilterStatus": "All learners sorted by {sort, select,\n flagged {reported activity}\n activity {most activity}\n other {{sort}}\n }",
|
||||
"discussion.learner.allActivity": "All activity",
|
||||
"discussion.learner.posts": "Posts",
|
||||
"discussions.actions.button.alt": "Actions menu",
|
||||
"discussions.actions.back.alt": "Back",
|
||||
"discussions.actions.copylink": "Copy link",
|
||||
"discussions.actions.unpin": "Unpin",
|
||||
"discussions.actions.close": "Close",
|
||||
@@ -55,7 +56,7 @@
|
||||
"discussions.actions.unreport": "Unreport",
|
||||
"discussions.actions.endorse": "Endorse",
|
||||
"discussions.actions.unendorse": "Unendorse",
|
||||
"discussions.actions.markAnswered": "Mark as Answered",
|
||||
"discussions.actions.markAnswered": "Mark as answered",
|
||||
"discussions.actions.unMarkAnswered": "Unmark as answered",
|
||||
"discussions.delete.confirmation.button.cancel": "Cancel",
|
||||
"discussions.delete.confirmation.button.delete": "Delete",
|
||||
@@ -80,6 +81,9 @@
|
||||
"discussion.banner.learnMore": "Learn more",
|
||||
"discussion.banner.shareFeedback": "Share feedback",
|
||||
"discussion.blackoutBanner.information": "Blackout dates are currently active. Posting in discussions is unavailable at this time.",
|
||||
"discussions.editor.image.warning.message": "Images having width or height greater than 999px will not be visible when the post, response or comment is viewed using in-line course discussions",
|
||||
"discussions.editor.image.warning.title": "Warning!",
|
||||
"discussions.editor.image.warning.dismiss": "Ok",
|
||||
"discussions.navigation.breadcrumbMenu.allTopics": "Topics",
|
||||
"discussions.navigation.breadcrumbMenu.showAll": "Show all",
|
||||
"discussions.navigation.navigationBar.allPosts": "All posts",
|
||||
@@ -119,6 +123,8 @@
|
||||
"discussions.post.editor.anonymousToPeersPost": "Post anonymously to peers",
|
||||
"discussions.editor.posts.editReasonCode": "Reason for editing",
|
||||
"discussions.editor.posts.showPreview.button": "Show Preview",
|
||||
"discussions.topic.noName.label": "Unnamed category",
|
||||
"discussions.subtopic.noName.label": "Unnamed subcategory",
|
||||
"discussions.posts.filter.showALl": "Show all",
|
||||
"discussions.posts.filter.discussions": "Discussions",
|
||||
"discussions.posts.filter.questions": "Questions",
|
||||
@@ -128,7 +134,7 @@
|
||||
"discussions.posts.status.filter.following": "Following",
|
||||
"discussions.posts.status.filter.reported": "Reported",
|
||||
"discussions.posts.status.filter.unanswered": "Unanswered",
|
||||
"discussions.posts.status.filter.unresponded": "Unresponded",
|
||||
"discussions.posts.status.filter.unresponded": "Not responded",
|
||||
"discussions.posts.filter.myPosts": "My posts",
|
||||
"discussions.posts.filter.myDiscussions": "My discussions",
|
||||
"discussions.posts.filter.myQuestions": "My questions",
|
||||
@@ -136,7 +142,7 @@
|
||||
"discussions.posts.sort.lastActivity": "Recent activity",
|
||||
"discussions.posts.sort.commentCount": "Most activity",
|
||||
"discussions.posts.sort.voteCount": "Most likes",
|
||||
"discussions.posts.sort-filter.sortFilterStatus": "{own, select,\n false {All}\n true {Own}\n other {{own}}\n } {status, select,\n statusAll {}\n statusUnread {unread}\n statusFollowing {followed}\n statusReported {reported}\n statusUnanswered {unanswered}\n statusUnresponded {unresponded}\n other {{status}}\n } {type, select,\n discussion {discussions}\n question {questions}\n all {posts}\n other {{type}}\n } {cohortType, select,\n all {}\n group {in {cohort}}\n other {{cohortType}}\n } by {sort, select,\n lastActivityAt {recent activity}\n commentCount {most activity}\n voteCount {most votes}\n other {{sort}}\n }",
|
||||
"discussions.posts.sort-filter.sortFilterStatus": "{own, select,\n false {All}\n true {Own}\n other {{own}}\n } {status, select,\n statusAll {}\n statusUnread {unread}\n statusFollowing {followed}\n statusReported {reported}\n statusUnanswered {unanswered}\n statusUnresponded {unresponded}\n other {{status}}\n } {type, select,\n discussion {discussions}\n question {questions}\n all {posts}\n other {{type}}\n } {cohortType, select,\n all {}\n group {in {cohort}}\n other {{cohortType}}\n } sorted by {sort, select,\n lastActivityAt {recent activity}\n commentCount {most activity}\n voteCount {most likes}\n other {{sort}}\n }",
|
||||
"discussions.post.author.anonymous": "anonymous",
|
||||
"discussions.post.lastResponse": "Last response {time}",
|
||||
"discussions.post.postedOn": "Posted {time} by {author} {authorLabel}",
|
||||
@@ -171,5 +177,6 @@
|
||||
"discussions.topics.sort.courseStructure": "Course Structure",
|
||||
"discussions.topics.find.label": "Search topics",
|
||||
"discussions.topics.archived.label": "Archived",
|
||||
"discussions.topics.unnamed.label": "Unnamed Topic"
|
||||
"discussions.topics.unnamed.label": "Unnamed category",
|
||||
"discussions.subtopics.unnamed.label": "Unnamed subcategory"
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
"discussions.comments.comment.addResponse": "Add a response",
|
||||
"discussions.comments.comment.addComment": "Add a comment",
|
||||
"discussions.comments.comment.abuseFlaggedMessage": "Content reported for staff to review",
|
||||
"discussions.actions.back.alt": "Back to list",
|
||||
"discussions.comments.comment.responseCount": "{num, plural,\n =0 {No responses}\n one {Showing # response}\n other {Showing # responses}\n }",
|
||||
"discussions.comments.comment.endorsedResponseCount": "{num, plural,\n =0 {No endorsed responses}\n one {Showing # endorsed response}\n other {Showing # endorsed responses}\n }",
|
||||
"discussions.comments.comment.loadMoreComments": "Load more comments",
|
||||
@@ -42,11 +43,11 @@
|
||||
"discussions.learner.activityForLearner": "Activity for {username}",
|
||||
"discussions.learner.mostActivity": "Most activity",
|
||||
"discussions.learner.reportedActivity": "Reported activity",
|
||||
"discussions.learner.sortFilterStatus": "All learners by {sort, select,\n flagged {reported activity}\n activity {most activity}\n other {{sort}}\n }",
|
||||
"discussions.learner.recentActivity": "Recent activity",
|
||||
"discussions.learner.sortFilterStatus": "All learners sorted by {sort, select,\n flagged {reported activity}\n activity {most activity}\n other {{sort}}\n }",
|
||||
"discussion.learner.allActivity": "All activity",
|
||||
"discussion.learner.posts": "Posts",
|
||||
"discussions.actions.button.alt": "Actions menu",
|
||||
"discussions.actions.back.alt": "Back",
|
||||
"discussions.actions.copylink": "Copy link",
|
||||
"discussions.actions.unpin": "Unpin",
|
||||
"discussions.actions.close": "Close",
|
||||
@@ -55,7 +56,7 @@
|
||||
"discussions.actions.unreport": "Unreport",
|
||||
"discussions.actions.endorse": "Endorse",
|
||||
"discussions.actions.unendorse": "Unendorse",
|
||||
"discussions.actions.markAnswered": "Mark as Answered",
|
||||
"discussions.actions.markAnswered": "Mark as answered",
|
||||
"discussions.actions.unMarkAnswered": "Unmark as answered",
|
||||
"discussions.delete.confirmation.button.cancel": "Cancel",
|
||||
"discussions.delete.confirmation.button.delete": "Delete",
|
||||
@@ -80,6 +81,9 @@
|
||||
"discussion.banner.learnMore": "Learn more",
|
||||
"discussion.banner.shareFeedback": "Share feedback",
|
||||
"discussion.blackoutBanner.information": "Blackout dates are currently active. Posting in discussions is unavailable at this time.",
|
||||
"discussions.editor.image.warning.message": "Images having width or height greater than 999px will not be visible when the post, response or comment is viewed using in-line course discussions",
|
||||
"discussions.editor.image.warning.title": "Warning!",
|
||||
"discussions.editor.image.warning.dismiss": "Ok",
|
||||
"discussions.navigation.breadcrumbMenu.allTopics": "Topics",
|
||||
"discussions.navigation.breadcrumbMenu.showAll": "Show all",
|
||||
"discussions.navigation.navigationBar.allPosts": "All posts",
|
||||
@@ -119,6 +123,8 @@
|
||||
"discussions.post.editor.anonymousToPeersPost": "Post anonymously to peers",
|
||||
"discussions.editor.posts.editReasonCode": "Reason for editing",
|
||||
"discussions.editor.posts.showPreview.button": "Show Preview",
|
||||
"discussions.topic.noName.label": "Unnamed category",
|
||||
"discussions.subtopic.noName.label": "Unnamed subcategory",
|
||||
"discussions.posts.filter.showALl": "Show all",
|
||||
"discussions.posts.filter.discussions": "Discussions",
|
||||
"discussions.posts.filter.questions": "Questions",
|
||||
@@ -128,7 +134,7 @@
|
||||
"discussions.posts.status.filter.following": "Following",
|
||||
"discussions.posts.status.filter.reported": "Reported",
|
||||
"discussions.posts.status.filter.unanswered": "Unanswered",
|
||||
"discussions.posts.status.filter.unresponded": "Unresponded",
|
||||
"discussions.posts.status.filter.unresponded": "Not responded",
|
||||
"discussions.posts.filter.myPosts": "My posts",
|
||||
"discussions.posts.filter.myDiscussions": "My discussions",
|
||||
"discussions.posts.filter.myQuestions": "My questions",
|
||||
@@ -136,7 +142,7 @@
|
||||
"discussions.posts.sort.lastActivity": "Recent activity",
|
||||
"discussions.posts.sort.commentCount": "Most activity",
|
||||
"discussions.posts.sort.voteCount": "Most likes",
|
||||
"discussions.posts.sort-filter.sortFilterStatus": "{own, select,\n false {All}\n true {Own}\n other {{own}}\n } {status, select,\n statusAll {}\n statusUnread {unread}\n statusFollowing {followed}\n statusReported {reported}\n statusUnanswered {unanswered}\n statusUnresponded {unresponded}\n other {{status}}\n } {type, select,\n discussion {discussions}\n question {questions}\n all {posts}\n other {{type}}\n } {cohortType, select,\n all {}\n group {in {cohort}}\n other {{cohortType}}\n } by {sort, select,\n lastActivityAt {recent activity}\n commentCount {most activity}\n voteCount {most votes}\n other {{sort}}\n }",
|
||||
"discussions.posts.sort-filter.sortFilterStatus": "{own, select,\n false {All}\n true {Own}\n other {{own}}\n } {status, select,\n statusAll {}\n statusUnread {unread}\n statusFollowing {followed}\n statusReported {reported}\n statusUnanswered {unanswered}\n statusUnresponded {unresponded}\n other {{status}}\n } {type, select,\n discussion {discussions}\n question {questions}\n all {posts}\n other {{type}}\n } {cohortType, select,\n all {}\n group {in {cohort}}\n other {{cohortType}}\n } sorted by {sort, select,\n lastActivityAt {recent activity}\n commentCount {most activity}\n voteCount {most likes}\n other {{sort}}\n }",
|
||||
"discussions.post.author.anonymous": "anonymous",
|
||||
"discussions.post.lastResponse": "Last response {time}",
|
||||
"discussions.post.postedOn": "Posted {time} by {author} {authorLabel}",
|
||||
@@ -171,5 +177,6 @@
|
||||
"discussions.topics.sort.courseStructure": "Course Structure",
|
||||
"discussions.topics.find.label": "Search topics",
|
||||
"discussions.topics.archived.label": "Archived",
|
||||
"discussions.topics.unnamed.label": "Unnamed Topic"
|
||||
"discussions.topics.unnamed.label": "Unnamed category",
|
||||
"discussions.subtopics.unnamed.label": "Unnamed subcategory"
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
"discussions.comments.comment.addResponse": "Agregar una respuesta",
|
||||
"discussions.comments.comment.addComment": "Agregar un comentario",
|
||||
"discussions.comments.comment.abuseFlaggedMessage": "Contenido informado para que el personal lo revise",
|
||||
"discussions.actions.back.alt": "Back to list",
|
||||
"discussions.comments.comment.responseCount": "{num, plural, =0 {No responses} one {Showing # response} other {Showing # responses} }",
|
||||
"discussions.comments.comment.endorsedResponseCount": "{num, plural, =0 {Sin respuestas respaldadas} one {Mostrando # respuesta respaldada} other {Mostrando # respuestas respaldadas} }",
|
||||
"discussions.comments.comment.loadMoreComments": "Cargar más comentarios",
|
||||
@@ -42,11 +43,11 @@
|
||||
"discussions.learner.activityForLearner": "Actividad para {username}",
|
||||
"discussions.learner.mostActivity": "La mayoría de la actividad",
|
||||
"discussions.learner.reportedActivity": "Actividad reportada",
|
||||
"discussions.learner.sortFilterStatus": "Todos los alumnos por {sort, select,\n flagged {reported activity}\n activity {most activity}\n other {{sort}}\n }",
|
||||
"discussions.learner.recentActivity": "Recent activity",
|
||||
"discussions.learner.sortFilterStatus": "All learners sorted by {sort, select,\n flagged {reported activity}\n activity {most activity}\n other {{sort}}\n }",
|
||||
"discussion.learner.allActivity": "Toda la actividad",
|
||||
"discussion.learner.posts": "Publicaciones",
|
||||
"discussions.actions.button.alt": "Menú de acciones",
|
||||
"discussions.actions.back.alt": "Volver atrás",
|
||||
"discussions.actions.copylink": "Copiar link",
|
||||
"discussions.actions.unpin": "Desmarcar",
|
||||
"discussions.actions.close": "Cerrar",
|
||||
@@ -55,7 +56,7 @@
|
||||
"discussions.actions.unreport": "Dejar de denunciar",
|
||||
"discussions.actions.endorse": "Validar",
|
||||
"discussions.actions.unendorse": "Invalidar",
|
||||
"discussions.actions.markAnswered": "Marcar como respondida",
|
||||
"discussions.actions.markAnswered": "Mark as answered",
|
||||
"discussions.actions.unMarkAnswered": "Desmarcar como respondida",
|
||||
"discussions.delete.confirmation.button.cancel": "Cancelar",
|
||||
"discussions.delete.confirmation.button.delete": "Borrar",
|
||||
@@ -80,6 +81,9 @@
|
||||
"discussion.banner.learnMore": "Aprender más",
|
||||
"discussion.banner.shareFeedback": "Compartir comentarios",
|
||||
"discussion.blackoutBanner.information": "Blackout dates are currently active. Posting in discussions is unavailable at this time.",
|
||||
"discussions.editor.image.warning.message": "Images having width or height greater than 999px will not be visible when the post, response or comment is viewed using in-line course discussions",
|
||||
"discussions.editor.image.warning.title": "Warning!",
|
||||
"discussions.editor.image.warning.dismiss": "Ok",
|
||||
"discussions.navigation.breadcrumbMenu.allTopics": "Temas",
|
||||
"discussions.navigation.breadcrumbMenu.showAll": "Mostrar todo",
|
||||
"discussions.navigation.navigationBar.allPosts": "Todos los mensajes",
|
||||
@@ -119,6 +123,8 @@
|
||||
"discussions.post.editor.anonymousToPeersPost": "Publicar de forma anónima para tus compañeros",
|
||||
"discussions.editor.posts.editReasonCode": "Motivo de la edición",
|
||||
"discussions.editor.posts.showPreview.button": "Mostrar vista previa",
|
||||
"discussions.topic.noName.label": "Unnamed category",
|
||||
"discussions.subtopic.noName.label": "Unnamed subcategory",
|
||||
"discussions.posts.filter.showALl": "Mostrar todo",
|
||||
"discussions.posts.filter.discussions": "Debates\n",
|
||||
"discussions.posts.filter.questions": "Preguntas",
|
||||
@@ -128,7 +134,7 @@
|
||||
"discussions.posts.status.filter.following": "Siguiendo",
|
||||
"discussions.posts.status.filter.reported": "Informado",
|
||||
"discussions.posts.status.filter.unanswered": "Sin responder",
|
||||
"discussions.posts.status.filter.unresponded": "Unresponded",
|
||||
"discussions.posts.status.filter.unresponded": "Not responded",
|
||||
"discussions.posts.filter.myPosts": "Mis publicaciones",
|
||||
"discussions.posts.filter.myDiscussions": "Mis debates",
|
||||
"discussions.posts.filter.myQuestions": "Mis preguntas",
|
||||
@@ -136,7 +142,7 @@
|
||||
"discussions.posts.sort.lastActivity": "Actividad reciente",
|
||||
"discussions.posts.sort.commentCount": "La mayoría de la actividad",
|
||||
"discussions.posts.sort.voteCount": "La mayoría me gusta",
|
||||
"discussions.posts.sort-filter.sortFilterStatus": "{own, select,\n false {All}\n true {Own}\n other {{own}}\n } {status, select,\n statusAll {}\n statusUnread {unread}\n statusFollowing {followed}\n statusReported {reported}\n statusUnanswered {unanswered}\n statusUnresponded {unresponded}\n other {{status}}\n } {type, select,\n discussion {discussions}\n question {questions}\n all {posts}\n other {{type}}\n } {cohortType, select,\n all {}\n group {in {cohort}}\n other {{cohortType}}\n } by {sort, select,\n lastActivityAt {recent activity}\n commentCount {most activity}\n voteCount {most votes}\n other {{sort}}\n }",
|
||||
"discussions.posts.sort-filter.sortFilterStatus": "{own, select,\n false {All}\n true {Own}\n other {{own}}\n } {status, select,\n statusAll {}\n statusUnread {unread}\n statusFollowing {followed}\n statusReported {reported}\n statusUnanswered {unanswered}\n statusUnresponded {unresponded}\n other {{status}}\n } {type, select,\n discussion {discussions}\n question {questions}\n all {posts}\n other {{type}}\n } {cohortType, select,\n all {}\n group {in {cohort}}\n other {{cohortType}}\n } sorted by {sort, select,\n lastActivityAt {recent activity}\n commentCount {most activity}\n voteCount {most likes}\n other {{sort}}\n }",
|
||||
"discussions.post.author.anonymous": "anónimo",
|
||||
"discussions.post.lastResponse": "Última respuesta {time}",
|
||||
"discussions.post.postedOn": "Publicado {time} por {author} {authorLabel}",
|
||||
@@ -149,7 +155,7 @@
|
||||
"discussions.post.removeLike": "Dejar de gustar",
|
||||
"discussions.post.viewActivity": "Ver actividad",
|
||||
"discussions.post.closed": "Publicación cerrada por respuestas y comentarios.",
|
||||
"discussions.post.relatedTo": "Relacionado con",
|
||||
"discussions.post.relatedTo": "Related to",
|
||||
"discussions.editor.delete.post.title": "Eliminar mensaje",
|
||||
"discussions.editor.delete.post.description": "¿Seguro que quieres eliminar esta publicación de forma permanente?",
|
||||
"discussions.post.closePostModal.title": "Cerrar publicación",
|
||||
@@ -171,5 +177,6 @@
|
||||
"discussions.topics.sort.courseStructure": "Estructura del curso",
|
||||
"discussions.topics.find.label": "Buscar temas",
|
||||
"discussions.topics.archived.label": "Archivado",
|
||||
"discussions.topics.unnamed.label": "Tema sin nombre"
|
||||
"discussions.topics.unnamed.label": "Unnamed category",
|
||||
"discussions.subtopics.unnamed.label": "Unnamed subcategory"
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
"discussions.comments.comment.addResponse": "Ajouter une réponse",
|
||||
"discussions.comments.comment.addComment": "Ajouter un commentaire",
|
||||
"discussions.comments.comment.abuseFlaggedMessage": "Contenu signalé au personnel pour examen",
|
||||
"discussions.actions.back.alt": "Back to list",
|
||||
"discussions.comments.comment.responseCount": "{num, plural,\n =0 {No responses}\n one {Showing # response}\n other {Showing # responses}\n }",
|
||||
"discussions.comments.comment.endorsedResponseCount": "{num, plural,\n =0 {No endorsed responses}\n one {Showing # endorsed response}\n other {Showing # endorsed responses}\n }",
|
||||
"discussions.comments.comment.loadMoreComments": "Charger plus de commentaires",
|
||||
@@ -42,11 +43,11 @@
|
||||
"discussions.learner.activityForLearner": "Activité pour {username}",
|
||||
"discussions.learner.mostActivity": "Most activity",
|
||||
"discussions.learner.reportedActivity": "Reported activity",
|
||||
"discussions.learner.sortFilterStatus": "All learners by {sort, select,\n flagged {reported activity}\n activity {most activity}\n other {{sort}}\n }",
|
||||
"discussions.learner.recentActivity": "Recent activity",
|
||||
"discussions.learner.sortFilterStatus": "All learners sorted by {sort, select,\n flagged {reported activity}\n activity {most activity}\n other {{sort}}\n }",
|
||||
"discussion.learner.allActivity": "All activity",
|
||||
"discussion.learner.posts": "Posts",
|
||||
"discussions.actions.button.alt": "Actions menu",
|
||||
"discussions.actions.back.alt": "Back",
|
||||
"discussions.actions.copylink": "Copy link",
|
||||
"discussions.actions.unpin": "Unpin",
|
||||
"discussions.actions.close": "Close",
|
||||
@@ -55,7 +56,7 @@
|
||||
"discussions.actions.unreport": "Unreport",
|
||||
"discussions.actions.endorse": "Endorse",
|
||||
"discussions.actions.unendorse": "Unendorse",
|
||||
"discussions.actions.markAnswered": "Mark as Answered",
|
||||
"discussions.actions.markAnswered": "Mark as answered",
|
||||
"discussions.actions.unMarkAnswered": "Unmark as answered",
|
||||
"discussions.delete.confirmation.button.cancel": "Cancel",
|
||||
"discussions.delete.confirmation.button.delete": "Delete",
|
||||
@@ -80,6 +81,9 @@
|
||||
"discussion.banner.learnMore": "Learn more",
|
||||
"discussion.banner.shareFeedback": "Share feedback",
|
||||
"discussion.blackoutBanner.information": "Blackout dates are currently active. Posting in discussions is unavailable at this time.",
|
||||
"discussions.editor.image.warning.message": "Images having width or height greater than 999px will not be visible when the post, response or comment is viewed using in-line course discussions",
|
||||
"discussions.editor.image.warning.title": "Warning!",
|
||||
"discussions.editor.image.warning.dismiss": "Ok",
|
||||
"discussions.navigation.breadcrumbMenu.allTopics": "Topics",
|
||||
"discussions.navigation.breadcrumbMenu.showAll": "Show all",
|
||||
"discussions.navigation.navigationBar.allPosts": "All posts",
|
||||
@@ -119,6 +123,8 @@
|
||||
"discussions.post.editor.anonymousToPeersPost": "Post anonymously to peers",
|
||||
"discussions.editor.posts.editReasonCode": "Reason for editing",
|
||||
"discussions.editor.posts.showPreview.button": "Show Preview",
|
||||
"discussions.topic.noName.label": "Unnamed category",
|
||||
"discussions.subtopic.noName.label": "Unnamed subcategory",
|
||||
"discussions.posts.filter.showALl": "Show all",
|
||||
"discussions.posts.filter.discussions": "Discussions",
|
||||
"discussions.posts.filter.questions": "Questions",
|
||||
@@ -128,7 +134,7 @@
|
||||
"discussions.posts.status.filter.following": "Following",
|
||||
"discussions.posts.status.filter.reported": "Reported",
|
||||
"discussions.posts.status.filter.unanswered": "Unanswered",
|
||||
"discussions.posts.status.filter.unresponded": "Unresponded",
|
||||
"discussions.posts.status.filter.unresponded": "Not responded",
|
||||
"discussions.posts.filter.myPosts": "My posts",
|
||||
"discussions.posts.filter.myDiscussions": "My discussions",
|
||||
"discussions.posts.filter.myQuestions": "My questions",
|
||||
@@ -136,7 +142,7 @@
|
||||
"discussions.posts.sort.lastActivity": "Recent activity",
|
||||
"discussions.posts.sort.commentCount": "Most activity",
|
||||
"discussions.posts.sort.voteCount": "Most likes",
|
||||
"discussions.posts.sort-filter.sortFilterStatus": "{own, select,\n false {All}\n true {Own}\n other {{own}}\n } {status, select,\n statusAll {}\n statusUnread {unread}\n statusFollowing {followed}\n statusReported {reported}\n statusUnanswered {unanswered}\n statusUnresponded {unresponded}\n other {{status}}\n } {type, select,\n discussion {discussions}\n question {questions}\n all {posts}\n other {{type}}\n } {cohortType, select,\n all {}\n group {in {cohort}}\n other {{cohortType}}\n } by {sort, select,\n lastActivityAt {recent activity}\n commentCount {most activity}\n voteCount {most votes}\n other {{sort}}\n }",
|
||||
"discussions.posts.sort-filter.sortFilterStatus": "{own, select,\n false {All}\n true {Own}\n other {{own}}\n } {status, select,\n statusAll {}\n statusUnread {unread}\n statusFollowing {followed}\n statusReported {reported}\n statusUnanswered {unanswered}\n statusUnresponded {unresponded}\n other {{status}}\n } {type, select,\n discussion {discussions}\n question {questions}\n all {posts}\n other {{type}}\n } {cohortType, select,\n all {}\n group {in {cohort}}\n other {{cohortType}}\n } sorted by {sort, select,\n lastActivityAt {recent activity}\n commentCount {most activity}\n voteCount {most likes}\n other {{sort}}\n }",
|
||||
"discussions.post.author.anonymous": "anonymous",
|
||||
"discussions.post.lastResponse": "Last response {time}",
|
||||
"discussions.post.postedOn": "Posted {time} by {author} {authorLabel}",
|
||||
@@ -171,5 +177,6 @@
|
||||
"discussions.topics.sort.courseStructure": "Course Structure",
|
||||
"discussions.topics.find.label": "Search topics",
|
||||
"discussions.topics.archived.label": "Archived",
|
||||
"discussions.topics.unnamed.label": "Unnamed Topic"
|
||||
"discussions.topics.unnamed.label": "Unnamed category",
|
||||
"discussions.subtopics.unnamed.label": "Unnamed subcategory"
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
"discussions.comments.comment.addResponse": "Ajouter une réponse",
|
||||
"discussions.comments.comment.addComment": "Ajouter un commentaire",
|
||||
"discussions.comments.comment.abuseFlaggedMessage": "Contenu signalé au personnel pour examen",
|
||||
"discussions.actions.back.alt": "Retour à la liste",
|
||||
"discussions.comments.comment.responseCount": "{num, plural,\n =0 {Aucune réponse}\n one {Affiche # réponse}\n other {Affiche # réponses}\n }",
|
||||
"discussions.comments.comment.endorsedResponseCount": "{num, plural,\n =0 {No endorsed responses}\n one {Showing # endorsed response}\n other {Showing # endorsed responses}\n }",
|
||||
"discussions.comments.comment.loadMoreComments": "Charger plus de commentaires",
|
||||
@@ -42,11 +43,11 @@
|
||||
"discussions.learner.activityForLearner": "Activité pour {username}",
|
||||
"discussions.learner.mostActivity": "La plupart des activités",
|
||||
"discussions.learner.reportedActivity": "Activité signalée",
|
||||
"discussions.learner.sortFilterStatus": "Tous les apprenants par {sort, select,\n flagged {reported activity}\n activity {most activity}\n other {{sort}}\n }",
|
||||
"discussions.learner.recentActivity": "Activité récente",
|
||||
"discussions.learner.sortFilterStatus": "All learners sorted by {sort, select,\n flagged {reported activity}\n activity {most activity}\n other {{sort}}\n }",
|
||||
"discussion.learner.allActivity": "Toutes les activités",
|
||||
"discussion.learner.posts": "Posts",
|
||||
"discussions.actions.button.alt": "Menu Actions",
|
||||
"discussions.actions.back.alt": "Retour",
|
||||
"discussions.actions.copylink": "Copier le lien",
|
||||
"discussions.actions.unpin": "Détacher",
|
||||
"discussions.actions.close": "Fermer",
|
||||
@@ -55,7 +56,7 @@
|
||||
"discussions.actions.unreport": "Ne pas signaler",
|
||||
"discussions.actions.endorse": "Approuver",
|
||||
"discussions.actions.unendorse": "Ne plus approuver",
|
||||
"discussions.actions.markAnswered": "Marquer comme répondu",
|
||||
"discussions.actions.markAnswered": "Mark as answered",
|
||||
"discussions.actions.unMarkAnswered": "Décocher comme répondu",
|
||||
"discussions.delete.confirmation.button.cancel": "Annuler",
|
||||
"discussions.delete.confirmation.button.delete": "Supprimer",
|
||||
@@ -80,6 +81,9 @@
|
||||
"discussion.banner.learnMore": "En savoir plus",
|
||||
"discussion.banner.shareFeedback": "Partager vos commentaires",
|
||||
"discussion.blackoutBanner.information": "Les dates d'interdiction sont actuellement actives. La publication dans les discussions n'est pas disponible pour le moment.",
|
||||
"discussions.editor.image.warning.message": "Les images dont la largeur ou la hauteur est supérieure à 999 pixels ne seront pas visibles lorsque la publication, la réponse ou le commentaire est affiché à l'aide de discussions de cours en ligne",
|
||||
"discussions.editor.image.warning.title": "Avertissement!",
|
||||
"discussions.editor.image.warning.dismiss": "Ok",
|
||||
"discussions.navigation.breadcrumbMenu.allTopics": "Sujets",
|
||||
"discussions.navigation.breadcrumbMenu.showAll": "Tout afficher",
|
||||
"discussions.navigation.navigationBar.allPosts": "Tous les messages",
|
||||
@@ -119,6 +123,8 @@
|
||||
"discussions.post.editor.anonymousToPeersPost": "Publiez anonymement à vos pairs",
|
||||
"discussions.editor.posts.editReasonCode": "Raison de la modification",
|
||||
"discussions.editor.posts.showPreview.button": "Afficher l'aperçu",
|
||||
"discussions.topic.noName.label": "Catégorie sans nom",
|
||||
"discussions.subtopic.noName.label": "Sous-catégorie sans nom",
|
||||
"discussions.posts.filter.showALl": "Tout afficher",
|
||||
"discussions.posts.filter.discussions": "Discussions",
|
||||
"discussions.posts.filter.questions": "Questions",
|
||||
@@ -128,7 +134,7 @@
|
||||
"discussions.posts.status.filter.following": "Suivi",
|
||||
"discussions.posts.status.filter.reported": "Reporté",
|
||||
"discussions.posts.status.filter.unanswered": "Non répondu",
|
||||
"discussions.posts.status.filter.unresponded": "Unresponded",
|
||||
"discussions.posts.status.filter.unresponded": "Pas répondu",
|
||||
"discussions.posts.filter.myPosts": "Mes messages",
|
||||
"discussions.posts.filter.myDiscussions": "Mes discussions",
|
||||
"discussions.posts.filter.myQuestions": "Mes questions",
|
||||
@@ -136,7 +142,7 @@
|
||||
"discussions.posts.sort.lastActivity": "Activité récente",
|
||||
"discussions.posts.sort.commentCount": "La plupart des activités",
|
||||
"discussions.posts.sort.voteCount": "La plupart des aimés",
|
||||
"discussions.posts.sort-filter.sortFilterStatus": "{own, select,\n false {All}\n true {Own}\n other {{own}}\n } {status, select,\n statusAll {}\n statusUnread {unread}\n statusFollowing {followed}\n statusReported {reported}\n statusUnanswered {unanswered}\n statusUnresponded {unresponded}\n other {{status}}\n } {type, select,\n discussion {discussions}\n question {questions}\n all {posts}\n other {{type}}\n } {cohortType, select,\n all {}\n group {in {cohort}}\n other {{cohortType}}\n } by {sort, select,\n lastActivityAt {recent activity}\n commentCount {most activity}\n voteCount {most votes}\n other {{sort}}\n }",
|
||||
"discussions.posts.sort-filter.sortFilterStatus": "{own, select,\n false {All}\n true {Own}\n other {{own}}\n } {status, select,\n statusAll {}\n statusUnread {unread}\n statusFollowing {followed}\n statusReported {reported}\n statusUnanswered {unanswered}\n statusUnresponded {unresponded}\n other {{status}}\n } {type, select,\n discussion {discussions}\n question {questions}\n all {posts}\n other {{type}}\n } {cohortType, select,\n all {}\n group {in {cohort}}\n other {{cohortType}}\n } sorted by {sort, select,\n lastActivityAt {recent activity}\n commentCount {most activity}\n voteCount {most likes}\n other {{sort}}\n }",
|
||||
"discussions.post.author.anonymous": "anonyme",
|
||||
"discussions.post.lastResponse": "Dernière réponse {time}",
|
||||
"discussions.post.postedOn": "Publié {time} par {author} {authorLabel}",
|
||||
@@ -171,5 +177,6 @@
|
||||
"discussions.topics.sort.courseStructure": "Structure du cours",
|
||||
"discussions.topics.find.label": "Rechercher des sujets",
|
||||
"discussions.topics.archived.label": "Archivé",
|
||||
"discussions.topics.unnamed.label": "Sujet sans nom"
|
||||
"discussions.topics.unnamed.label": "Catégorie sans nom",
|
||||
"discussions.subtopics.unnamed.label": "Sous-catégorie sans nom"
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
"discussions.comments.comment.addResponse": "Add a response",
|
||||
"discussions.comments.comment.addComment": "Add a comment",
|
||||
"discussions.comments.comment.abuseFlaggedMessage": "Content reported for staff to review",
|
||||
"discussions.actions.back.alt": "Back to list",
|
||||
"discussions.comments.comment.responseCount": "{num, plural,\n =0 {No responses}\n one {Showing # response}\n other {Showing # responses}\n }",
|
||||
"discussions.comments.comment.endorsedResponseCount": "{num, plural,\n =0 {No endorsed responses}\n one {Showing # endorsed response}\n other {Showing # endorsed responses}\n }",
|
||||
"discussions.comments.comment.loadMoreComments": "Load more comments",
|
||||
@@ -42,11 +43,11 @@
|
||||
"discussions.learner.activityForLearner": "Activity for {username}",
|
||||
"discussions.learner.mostActivity": "Most activity",
|
||||
"discussions.learner.reportedActivity": "Reported activity",
|
||||
"discussions.learner.sortFilterStatus": "All learners by {sort, select,\n flagged {reported activity}\n activity {most activity}\n other {{sort}}\n }",
|
||||
"discussions.learner.recentActivity": "Recent activity",
|
||||
"discussions.learner.sortFilterStatus": "All learners sorted by {sort, select,\n flagged {reported activity}\n activity {most activity}\n other {{sort}}\n }",
|
||||
"discussion.learner.allActivity": "All activity",
|
||||
"discussion.learner.posts": "Posts",
|
||||
"discussions.actions.button.alt": "Actions menu",
|
||||
"discussions.actions.back.alt": "Back",
|
||||
"discussions.actions.copylink": "Copy link",
|
||||
"discussions.actions.unpin": "Unpin",
|
||||
"discussions.actions.close": "Close",
|
||||
@@ -55,7 +56,7 @@
|
||||
"discussions.actions.unreport": "Unreport",
|
||||
"discussions.actions.endorse": "Endorse",
|
||||
"discussions.actions.unendorse": "Unendorse",
|
||||
"discussions.actions.markAnswered": "Mark as Answered",
|
||||
"discussions.actions.markAnswered": "Mark as answered",
|
||||
"discussions.actions.unMarkAnswered": "Unmark as answered",
|
||||
"discussions.delete.confirmation.button.cancel": "Cancel",
|
||||
"discussions.delete.confirmation.button.delete": "Delete",
|
||||
@@ -80,6 +81,9 @@
|
||||
"discussion.banner.learnMore": "Learn more",
|
||||
"discussion.banner.shareFeedback": "Share feedback",
|
||||
"discussion.blackoutBanner.information": "Blackout dates are currently active. Posting in discussions is unavailable at this time.",
|
||||
"discussions.editor.image.warning.message": "Images having width or height greater than 999px will not be visible when the post, response or comment is viewed using in-line course discussions",
|
||||
"discussions.editor.image.warning.title": "Warning!",
|
||||
"discussions.editor.image.warning.dismiss": "Ok",
|
||||
"discussions.navigation.breadcrumbMenu.allTopics": "Topics",
|
||||
"discussions.navigation.breadcrumbMenu.showAll": "Show all",
|
||||
"discussions.navigation.navigationBar.allPosts": "All posts",
|
||||
@@ -119,6 +123,8 @@
|
||||
"discussions.post.editor.anonymousToPeersPost": "Post anonymously to peers",
|
||||
"discussions.editor.posts.editReasonCode": "Reason for editing",
|
||||
"discussions.editor.posts.showPreview.button": "Show Preview",
|
||||
"discussions.topic.noName.label": "Unnamed category",
|
||||
"discussions.subtopic.noName.label": "Unnamed subcategory",
|
||||
"discussions.posts.filter.showALl": "Show all",
|
||||
"discussions.posts.filter.discussions": "Discussions",
|
||||
"discussions.posts.filter.questions": "Questions",
|
||||
@@ -128,7 +134,7 @@
|
||||
"discussions.posts.status.filter.following": "Following",
|
||||
"discussions.posts.status.filter.reported": "Reported",
|
||||
"discussions.posts.status.filter.unanswered": "Unanswered",
|
||||
"discussions.posts.status.filter.unresponded": "Unresponded",
|
||||
"discussions.posts.status.filter.unresponded": "Not responded",
|
||||
"discussions.posts.filter.myPosts": "My posts",
|
||||
"discussions.posts.filter.myDiscussions": "My discussions",
|
||||
"discussions.posts.filter.myQuestions": "My questions",
|
||||
@@ -136,7 +142,7 @@
|
||||
"discussions.posts.sort.lastActivity": "Recent activity",
|
||||
"discussions.posts.sort.commentCount": "Most activity",
|
||||
"discussions.posts.sort.voteCount": "Most likes",
|
||||
"discussions.posts.sort-filter.sortFilterStatus": "{own, select,\n false {All}\n true {Own}\n other {{own}}\n } {status, select,\n statusAll {}\n statusUnread {unread}\n statusFollowing {followed}\n statusReported {reported}\n statusUnanswered {unanswered}\n statusUnresponded {unresponded}\n other {{status}}\n } {type, select,\n discussion {discussions}\n question {questions}\n all {posts}\n other {{type}}\n } {cohortType, select,\n all {}\n group {in {cohort}}\n other {{cohortType}}\n } by {sort, select,\n lastActivityAt {recent activity}\n commentCount {most activity}\n voteCount {most votes}\n other {{sort}}\n }",
|
||||
"discussions.posts.sort-filter.sortFilterStatus": "{own, select,\n false {All}\n true {Own}\n other {{own}}\n } {status, select,\n statusAll {}\n statusUnread {unread}\n statusFollowing {followed}\n statusReported {reported}\n statusUnanswered {unanswered}\n statusUnresponded {unresponded}\n other {{status}}\n } {type, select,\n discussion {discussions}\n question {questions}\n all {posts}\n other {{type}}\n } {cohortType, select,\n all {}\n group {in {cohort}}\n other {{cohortType}}\n } sorted by {sort, select,\n lastActivityAt {recent activity}\n commentCount {most activity}\n voteCount {most likes}\n other {{sort}}\n }",
|
||||
"discussions.post.author.anonymous": "anonymous",
|
||||
"discussions.post.lastResponse": "Last response {time}",
|
||||
"discussions.post.postedOn": "Posted {time} by {author} {authorLabel}",
|
||||
@@ -171,5 +177,6 @@
|
||||
"discussions.topics.sort.courseStructure": "Course Structure",
|
||||
"discussions.topics.find.label": "Search topics",
|
||||
"discussions.topics.archived.label": "Archived",
|
||||
"discussions.topics.unnamed.label": "Unnamed Topic"
|
||||
"discussions.topics.unnamed.label": "Unnamed category",
|
||||
"discussions.subtopics.unnamed.label": "Unnamed subcategory"
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
"discussions.comments.comment.addResponse": "Aggiungi una risposta",
|
||||
"discussions.comments.comment.addComment": "Aggiungi un commento",
|
||||
"discussions.comments.comment.abuseFlaggedMessage": "Contenuto segnalato per la revisione da parte del personale",
|
||||
"discussions.actions.back.alt": "Back to list",
|
||||
"discussions.comments.comment.responseCount": "{num, plural, =0 {Nessuna risposta} one {Mostra # risposte} other {Mostra # risposte} }",
|
||||
"discussions.comments.comment.endorsedResponseCount": "{num, plural, =0 {Nessuna risposta approvata} one {Mostra # risposta approvata} other {Mostra # risposte approvate} }",
|
||||
"discussions.comments.comment.loadMoreComments": "Carica più commenti",
|
||||
@@ -42,11 +43,11 @@
|
||||
"discussions.learner.activityForLearner": "Attività per {username}",
|
||||
"discussions.learner.mostActivity": "La maggior parte delle attività",
|
||||
"discussions.learner.reportedActivity": "Attività segnalata",
|
||||
"discussions.learner.sortFilterStatus": "Tutti gli studenti di {sort, select, flagged {attività segnalata} activity {più attività} other {{sort}} }",
|
||||
"discussions.learner.recentActivity": "Recent activity",
|
||||
"discussions.learner.sortFilterStatus": "All learners sorted by {sort, select,\n flagged {reported activity}\n activity {most activity}\n other {{sort}}\n }",
|
||||
"discussion.learner.allActivity": "All activity",
|
||||
"discussion.learner.posts": "Posts",
|
||||
"discussions.actions.button.alt": "Menù Azioni",
|
||||
"discussions.actions.back.alt": "Indietro",
|
||||
"discussions.actions.copylink": "Copia link",
|
||||
"discussions.actions.unpin": "Sblocca ",
|
||||
"discussions.actions.close": "Chiudi",
|
||||
@@ -55,7 +56,7 @@
|
||||
"discussions.actions.unreport": "Annulla segnalazione",
|
||||
"discussions.actions.endorse": "Promuovi ",
|
||||
"discussions.actions.unendorse": "Annulla promozione ",
|
||||
"discussions.actions.markAnswered": "Segna come risposta",
|
||||
"discussions.actions.markAnswered": "Mark as answered",
|
||||
"discussions.actions.unMarkAnswered": "Deseleziona come risposta",
|
||||
"discussions.delete.confirmation.button.cancel": "Annulla",
|
||||
"discussions.delete.confirmation.button.delete": "Cancella",
|
||||
@@ -80,6 +81,9 @@
|
||||
"discussion.banner.learnMore": "Per saperne di più",
|
||||
"discussion.banner.shareFeedback": "Condividi feedback",
|
||||
"discussion.blackoutBanner.information": "Blackout dates are currently active. Posting in discussions is unavailable at this time.",
|
||||
"discussions.editor.image.warning.message": "Images having width or height greater than 999px will not be visible when the post, response or comment is viewed using in-line course discussions",
|
||||
"discussions.editor.image.warning.title": "Warning!",
|
||||
"discussions.editor.image.warning.dismiss": "Ok",
|
||||
"discussions.navigation.breadcrumbMenu.allTopics": "Argomenti",
|
||||
"discussions.navigation.breadcrumbMenu.showAll": "Mostra tutto",
|
||||
"discussions.navigation.navigationBar.allPosts": "Tutti i post",
|
||||
@@ -119,6 +123,8 @@
|
||||
"discussions.post.editor.anonymousToPeersPost": "Pubblica in modo anonimo ai colleghi",
|
||||
"discussions.editor.posts.editReasonCode": "Motivo della modifica",
|
||||
"discussions.editor.posts.showPreview.button": "Anteprima dello spettacolo",
|
||||
"discussions.topic.noName.label": "Unnamed category",
|
||||
"discussions.subtopic.noName.label": "Unnamed subcategory",
|
||||
"discussions.posts.filter.showALl": "Mostra tutto",
|
||||
"discussions.posts.filter.discussions": "Discussioni",
|
||||
"discussions.posts.filter.questions": "Domande",
|
||||
@@ -128,7 +134,7 @@
|
||||
"discussions.posts.status.filter.following": "Seguente",
|
||||
"discussions.posts.status.filter.reported": "Segnalato ",
|
||||
"discussions.posts.status.filter.unanswered": "Senza Risposta",
|
||||
"discussions.posts.status.filter.unresponded": "Unresponded",
|
||||
"discussions.posts.status.filter.unresponded": "Not responded",
|
||||
"discussions.posts.filter.myPosts": "I miei post",
|
||||
"discussions.posts.filter.myDiscussions": "Le mie discussioni",
|
||||
"discussions.posts.filter.myQuestions": "Le mie domande",
|
||||
@@ -136,7 +142,7 @@
|
||||
"discussions.posts.sort.lastActivity": "Attività Recente",
|
||||
"discussions.posts.sort.commentCount": "La maggior parte delle attività",
|
||||
"discussions.posts.sort.voteCount": "La maggior parte dei Mi piace",
|
||||
"discussions.posts.sort-filter.sortFilterStatus": "{own, select,\n false {All}\n true {Own}\n other {{own}}\n } {status, select,\n statusAll {}\n statusUnread {unread}\n statusFollowing {followed}\n statusReported {reported}\n statusUnanswered {unanswered}\n statusUnresponded {unresponded}\n other {{status}}\n } {type, select,\n discussion {discussions}\n question {questions}\n all {posts}\n other {{type}}\n } {cohortType, select,\n all {}\n group {in {cohort}}\n other {{cohortType}}\n } by {sort, select,\n lastActivityAt {recent activity}\n commentCount {most activity}\n voteCount {most votes}\n other {{sort}}\n }",
|
||||
"discussions.posts.sort-filter.sortFilterStatus": "{own, select,\n false {All}\n true {Own}\n other {{own}}\n } {status, select,\n statusAll {}\n statusUnread {unread}\n statusFollowing {followed}\n statusReported {reported}\n statusUnanswered {unanswered}\n statusUnresponded {unresponded}\n other {{status}}\n } {type, select,\n discussion {discussions}\n question {questions}\n all {posts}\n other {{type}}\n } {cohortType, select,\n all {}\n group {in {cohort}}\n other {{cohortType}}\n } sorted by {sort, select,\n lastActivityAt {recent activity}\n commentCount {most activity}\n voteCount {most likes}\n other {{sort}}\n }",
|
||||
"discussions.post.author.anonymous": "anonimo",
|
||||
"discussions.post.lastResponse": "Ultima risposta {time}",
|
||||
"discussions.post.postedOn": "Inserito {time} da {author} {authorLabel}",
|
||||
@@ -149,7 +155,7 @@
|
||||
"discussions.post.removeLike": "A differenza di",
|
||||
"discussions.post.viewActivity": "Visualizza attività",
|
||||
"discussions.post.closed": "Post chiuso per risposte e commenti",
|
||||
"discussions.post.relatedTo": "Relativo a",
|
||||
"discussions.post.relatedTo": "Related to",
|
||||
"discussions.editor.delete.post.title": "Elimina messaggio",
|
||||
"discussions.editor.delete.post.description": "Sei sicuro di voler eliminare definitivamente questo post?",
|
||||
"discussions.post.closePostModal.title": "Chiudi messaggio",
|
||||
@@ -171,5 +177,6 @@
|
||||
"discussions.topics.sort.courseStructure": "Struttura Corso",
|
||||
"discussions.topics.find.label": "Search topics",
|
||||
"discussions.topics.archived.label": "Archiviati",
|
||||
"discussions.topics.unnamed.label": "Unnamed Topic"
|
||||
"discussions.topics.unnamed.label": "Unnamed category",
|
||||
"discussions.subtopics.unnamed.label": "Unnamed subcategory"
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
"discussions.comments.comment.addResponse": "Dodaj odpowiedź",
|
||||
"discussions.comments.comment.addComment": "Add a comment",
|
||||
"discussions.comments.comment.abuseFlaggedMessage": "Content reported for staff to review",
|
||||
"discussions.actions.back.alt": "Back to list",
|
||||
"discussions.comments.comment.responseCount": "{num, plural,\n=0 {No responses}\none {Showing # response}\nother {Showing # responses}\n}",
|
||||
"discussions.comments.comment.endorsedResponseCount": "{num, plural,\n=0 {No endorsed responses}\none {Showing # endorsed response}\nother {Showing # endorsed responses}\n}",
|
||||
"discussions.comments.comment.loadMoreComments": "Załaduj więcej komentarzy",
|
||||
@@ -42,11 +43,11 @@
|
||||
"discussions.learner.activityForLearner": "Aktywność dla {username}",
|
||||
"discussions.learner.mostActivity": "Największa aktywność",
|
||||
"discussions.learner.reportedActivity": "Zgłoszona aktywność",
|
||||
"discussions.learner.sortFilterStatus": "All learners by {sort, select,\n flagged {reported activity}\n activity {most activity}\n other {{sort}}\n }",
|
||||
"discussions.learner.recentActivity": "Recent activity",
|
||||
"discussions.learner.sortFilterStatus": "All learners sorted by {sort, select,\n flagged {reported activity}\n activity {most activity}\n other {{sort}}\n }",
|
||||
"discussion.learner.allActivity": "All activity",
|
||||
"discussion.learner.posts": "Posts",
|
||||
"discussions.actions.button.alt": "Menu czynności",
|
||||
"discussions.actions.back.alt": "Back",
|
||||
"discussions.actions.copylink": "Copy link",
|
||||
"discussions.actions.unpin": "Unpin",
|
||||
"discussions.actions.close": "Close",
|
||||
@@ -55,7 +56,7 @@
|
||||
"discussions.actions.unreport": "Unreport",
|
||||
"discussions.actions.endorse": "Endorse",
|
||||
"discussions.actions.unendorse": "Unendorse",
|
||||
"discussions.actions.markAnswered": "Oznacz jako odpowiedziane",
|
||||
"discussions.actions.markAnswered": "Mark as answered",
|
||||
"discussions.actions.unMarkAnswered": "Nie oznaczaj jako odpowiedziane",
|
||||
"discussions.delete.confirmation.button.cancel": "Cancel",
|
||||
"discussions.delete.confirmation.button.delete": "Delete",
|
||||
@@ -80,6 +81,9 @@
|
||||
"discussion.banner.learnMore": "Learn more",
|
||||
"discussion.banner.shareFeedback": "Share feedback",
|
||||
"discussion.blackoutBanner.information": "Blackout dates are currently active. Posting in discussions is unavailable at this time.",
|
||||
"discussions.editor.image.warning.message": "Images having width or height greater than 999px will not be visible when the post, response or comment is viewed using in-line course discussions",
|
||||
"discussions.editor.image.warning.title": "Warning!",
|
||||
"discussions.editor.image.warning.dismiss": "Ok",
|
||||
"discussions.navigation.breadcrumbMenu.allTopics": "Topics",
|
||||
"discussions.navigation.breadcrumbMenu.showAll": "Show all",
|
||||
"discussions.navigation.navigationBar.allPosts": "Wszystkie posty",
|
||||
@@ -119,6 +123,8 @@
|
||||
"discussions.post.editor.anonymousToPeersPost": "Post anonymously to peers",
|
||||
"discussions.editor.posts.editReasonCode": "Powód edycji",
|
||||
"discussions.editor.posts.showPreview.button": "Show Preview",
|
||||
"discussions.topic.noName.label": "Unnamed category",
|
||||
"discussions.subtopic.noName.label": "Unnamed subcategory",
|
||||
"discussions.posts.filter.showALl": "Show all",
|
||||
"discussions.posts.filter.discussions": "Discussions",
|
||||
"discussions.posts.filter.questions": "Pytania",
|
||||
@@ -128,7 +134,7 @@
|
||||
"discussions.posts.status.filter.following": "Following",
|
||||
"discussions.posts.status.filter.reported": "Reported",
|
||||
"discussions.posts.status.filter.unanswered": "Unanswered",
|
||||
"discussions.posts.status.filter.unresponded": "Unresponded",
|
||||
"discussions.posts.status.filter.unresponded": "Not responded",
|
||||
"discussions.posts.filter.myPosts": "Moje posty",
|
||||
"discussions.posts.filter.myDiscussions": "Moje dyskusje",
|
||||
"discussions.posts.filter.myQuestions": "Moje pytania",
|
||||
@@ -136,7 +142,7 @@
|
||||
"discussions.posts.sort.lastActivity": "Ostatnia aktywność",
|
||||
"discussions.posts.sort.commentCount": "Most activity",
|
||||
"discussions.posts.sort.voteCount": "Most likes",
|
||||
"discussions.posts.sort-filter.sortFilterStatus": "{own, select,\n false {All}\n true {Own}\n other {{own}}\n } {status, select,\n statusAll {}\n statusUnread {unread}\n statusFollowing {followed}\n statusReported {reported}\n statusUnanswered {unanswered}\n statusUnresponded {unresponded}\n other {{status}}\n } {type, select,\n discussion {discussions}\n question {questions}\n all {posts}\n other {{type}}\n } {cohortType, select,\n all {}\n group {in {cohort}}\n other {{cohortType}}\n } by {sort, select,\n lastActivityAt {recent activity}\n commentCount {most activity}\n voteCount {most votes}\n other {{sort}}\n }",
|
||||
"discussions.posts.sort-filter.sortFilterStatus": "{own, select,\n false {All}\n true {Own}\n other {{own}}\n } {status, select,\n statusAll {}\n statusUnread {unread}\n statusFollowing {followed}\n statusReported {reported}\n statusUnanswered {unanswered}\n statusUnresponded {unresponded}\n other {{status}}\n } {type, select,\n discussion {discussions}\n question {questions}\n all {posts}\n other {{type}}\n } {cohortType, select,\n all {}\n group {in {cohort}}\n other {{cohortType}}\n } sorted by {sort, select,\n lastActivityAt {recent activity}\n commentCount {most activity}\n voteCount {most likes}\n other {{sort}}\n }",
|
||||
"discussions.post.author.anonymous": "anonymous",
|
||||
"discussions.post.lastResponse": "Ostatnia odpowiedź {time}",
|
||||
"discussions.post.postedOn": "Posted {time} by {author} {authorLabel}",
|
||||
@@ -171,5 +177,6 @@
|
||||
"discussions.topics.sort.courseStructure": "Course Structure",
|
||||
"discussions.topics.find.label": "Search topics",
|
||||
"discussions.topics.archived.label": "Archived",
|
||||
"discussions.topics.unnamed.label": "Unnamed Topic"
|
||||
"discussions.topics.unnamed.label": "Unnamed category",
|
||||
"discussions.subtopics.unnamed.label": "Unnamed subcategory"
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
"discussions.comments.comment.addResponse": "Bir cevap ekle",
|
||||
"discussions.comments.comment.addComment": "Bir yorum ekle",
|
||||
"discussions.comments.comment.abuseFlaggedMessage": "Personelin incelemesi için bildirilen içerik",
|
||||
"discussions.actions.back.alt": "Back to list",
|
||||
"discussions.comments.comment.responseCount": "{num, plural,\n =0 {No responses}\n one {Showing # response}\n other {Showing # responses}\n }",
|
||||
"discussions.comments.comment.endorsedResponseCount": "{num, plural,\n =0 {No endorsed responses}\n one {Showing # endorsed response}\n other {Showing # endorsed responses}\n }",
|
||||
"discussions.comments.comment.loadMoreComments": "Daha fazla yorum yükle",
|
||||
@@ -42,11 +43,11 @@
|
||||
"discussions.learner.activityForLearner": "{username} için etkinlik",
|
||||
"discussions.learner.mostActivity": "En çok etkinlik",
|
||||
"discussions.learner.reportedActivity": "Rapor edilen etkinlik",
|
||||
"discussions.learner.sortFilterStatus": "All learners by {sort, select,\n flagged {reported activity}\n activity {most activity}\n other {{sort}}\n }",
|
||||
"discussions.learner.recentActivity": "Recent activity",
|
||||
"discussions.learner.sortFilterStatus": "All learners sorted by {sort, select,\n flagged {reported activity}\n activity {most activity}\n other {{sort}}\n }",
|
||||
"discussion.learner.allActivity": "All activity",
|
||||
"discussion.learner.posts": "Gönderiler",
|
||||
"discussions.actions.button.alt": "Eylemler menüsü",
|
||||
"discussions.actions.back.alt": "Geri",
|
||||
"discussions.actions.copylink": "Copy link",
|
||||
"discussions.actions.unpin": "İşareti kaldır",
|
||||
"discussions.actions.close": "Kapat",
|
||||
@@ -55,7 +56,7 @@
|
||||
"discussions.actions.unreport": "Bildirme",
|
||||
"discussions.actions.endorse": "Destekle",
|
||||
"discussions.actions.unendorse": "Destekleme",
|
||||
"discussions.actions.markAnswered": "Cevaplandı olarak işaretle",
|
||||
"discussions.actions.markAnswered": "Mark as answered",
|
||||
"discussions.actions.unMarkAnswered": "Cevaplandı olarak işaretini kaldır",
|
||||
"discussions.delete.confirmation.button.cancel": "İptal",
|
||||
"discussions.delete.confirmation.button.delete": "Sil",
|
||||
@@ -80,6 +81,9 @@
|
||||
"discussion.banner.learnMore": "Daha fazlasını öğren",
|
||||
"discussion.banner.shareFeedback": "Share feedback",
|
||||
"discussion.blackoutBanner.information": "Blackout dates are currently active. Posting in discussions is unavailable at this time.",
|
||||
"discussions.editor.image.warning.message": "Images having width or height greater than 999px will not be visible when the post, response or comment is viewed using in-line course discussions",
|
||||
"discussions.editor.image.warning.title": "Warning!",
|
||||
"discussions.editor.image.warning.dismiss": "Ok",
|
||||
"discussions.navigation.breadcrumbMenu.allTopics": "Konular",
|
||||
"discussions.navigation.breadcrumbMenu.showAll": "Tümünü göster",
|
||||
"discussions.navigation.navigationBar.allPosts": "Tüm iletiler",
|
||||
@@ -119,6 +123,8 @@
|
||||
"discussions.post.editor.anonymousToPeersPost": "Akranlarına anonim olarak gönder",
|
||||
"discussions.editor.posts.editReasonCode": "Düzenleme nedeni",
|
||||
"discussions.editor.posts.showPreview.button": "Önizlemeyi Göster",
|
||||
"discussions.topic.noName.label": "Unnamed category",
|
||||
"discussions.subtopic.noName.label": "Unnamed subcategory",
|
||||
"discussions.posts.filter.showALl": "Tümünü göster",
|
||||
"discussions.posts.filter.discussions": "Forumlar",
|
||||
"discussions.posts.filter.questions": "Sorular",
|
||||
@@ -128,7 +134,7 @@
|
||||
"discussions.posts.status.filter.following": "Takip ediliyor",
|
||||
"discussions.posts.status.filter.reported": "Rapor edildi",
|
||||
"discussions.posts.status.filter.unanswered": "Cevaplanmamış",
|
||||
"discussions.posts.status.filter.unresponded": "Unresponded",
|
||||
"discussions.posts.status.filter.unresponded": "Not responded",
|
||||
"discussions.posts.filter.myPosts": "Gönderilerim",
|
||||
"discussions.posts.filter.myDiscussions": "Tartışmalarım",
|
||||
"discussions.posts.filter.myQuestions": "Sorularım",
|
||||
@@ -136,7 +142,7 @@
|
||||
"discussions.posts.sort.lastActivity": "Son etkinlik",
|
||||
"discussions.posts.sort.commentCount": "En çok etkinlik",
|
||||
"discussions.posts.sort.voteCount": "En çok beğenilenler",
|
||||
"discussions.posts.sort-filter.sortFilterStatus": "{own, select,\n false {All}\n true {Own}\n other {{own}}\n } {status, select,\n statusAll {}\n statusUnread {unread}\n statusFollowing {followed}\n statusReported {reported}\n statusUnanswered {unanswered}\n statusUnresponded {unresponded}\n other {{status}}\n } {type, select,\n discussion {discussions}\n question {questions}\n all {posts}\n other {{type}}\n } {cohortType, select,\n all {}\n group {in {cohort}}\n other {{cohortType}}\n } by {sort, select,\n lastActivityAt {recent activity}\n commentCount {most activity}\n voteCount {most votes}\n other {{sort}}\n }",
|
||||
"discussions.posts.sort-filter.sortFilterStatus": "{own, select,\n false {All}\n true {Own}\n other {{own}}\n } {status, select,\n statusAll {}\n statusUnread {unread}\n statusFollowing {followed}\n statusReported {reported}\n statusUnanswered {unanswered}\n statusUnresponded {unresponded}\n other {{status}}\n } {type, select,\n discussion {discussions}\n question {questions}\n all {posts}\n other {{type}}\n } {cohortType, select,\n all {}\n group {in {cohort}}\n other {{cohortType}}\n } sorted by {sort, select,\n lastActivityAt {recent activity}\n commentCount {most activity}\n voteCount {most likes}\n other {{sort}}\n }",
|
||||
"discussions.post.author.anonymous": "anonim",
|
||||
"discussions.post.lastResponse": "Son yanıt {time}",
|
||||
"discussions.post.postedOn": "Posted {time} by {author} {authorLabel}",
|
||||
@@ -171,5 +177,6 @@
|
||||
"discussions.topics.sort.courseStructure": "Ders Yapısı",
|
||||
"discussions.topics.find.label": "Search topics",
|
||||
"discussions.topics.archived.label": "Arşivlenmiş",
|
||||
"discussions.topics.unnamed.label": "Unnamed Topic"
|
||||
"discussions.topics.unnamed.label": "Unnamed category",
|
||||
"discussions.subtopics.unnamed.label": "Unnamed subcategory"
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
"discussions.comments.comment.addResponse": "Add a response",
|
||||
"discussions.comments.comment.addComment": "Add a comment",
|
||||
"discussions.comments.comment.abuseFlaggedMessage": "Content reported for staff to review",
|
||||
"discussions.actions.back.alt": "Back to list",
|
||||
"discussions.comments.comment.responseCount": "{num, plural,\n =0 {No responses}\n one {Showing # response}\n other {Showing # responses}\n }",
|
||||
"discussions.comments.comment.endorsedResponseCount": "{num, plural,\n =0 {No endorsed responses}\n one {Showing # endorsed response}\n other {Showing # endorsed responses}\n }",
|
||||
"discussions.comments.comment.loadMoreComments": "Load more comments",
|
||||
@@ -42,11 +43,11 @@
|
||||
"discussions.learner.activityForLearner": "Activity for {username}",
|
||||
"discussions.learner.mostActivity": "Most activity",
|
||||
"discussions.learner.reportedActivity": "Reported activity",
|
||||
"discussions.learner.sortFilterStatus": "All learners by {sort, select,\n flagged {reported activity}\n activity {most activity}\n other {{sort}}\n }",
|
||||
"discussions.learner.recentActivity": "Recent activity",
|
||||
"discussions.learner.sortFilterStatus": "All learners sorted by {sort, select,\n flagged {reported activity}\n activity {most activity}\n other {{sort}}\n }",
|
||||
"discussion.learner.allActivity": "All activity",
|
||||
"discussion.learner.posts": "Posts",
|
||||
"discussions.actions.button.alt": "Actions menu",
|
||||
"discussions.actions.back.alt": "Back",
|
||||
"discussions.actions.copylink": "Copy link",
|
||||
"discussions.actions.unpin": "Unpin",
|
||||
"discussions.actions.close": "Close",
|
||||
@@ -55,7 +56,7 @@
|
||||
"discussions.actions.unreport": "Unreport",
|
||||
"discussions.actions.endorse": "Endorse",
|
||||
"discussions.actions.unendorse": "Unendorse",
|
||||
"discussions.actions.markAnswered": "Mark as Answered",
|
||||
"discussions.actions.markAnswered": "Mark as answered",
|
||||
"discussions.actions.unMarkAnswered": "Unmark as answered",
|
||||
"discussions.delete.confirmation.button.cancel": "Cancel",
|
||||
"discussions.delete.confirmation.button.delete": "Delete",
|
||||
@@ -80,6 +81,9 @@
|
||||
"discussion.banner.learnMore": "Learn more",
|
||||
"discussion.banner.shareFeedback": "Share feedback",
|
||||
"discussion.blackoutBanner.information": "Blackout dates are currently active. Posting in discussions is unavailable at this time.",
|
||||
"discussions.editor.image.warning.message": "Images having width or height greater than 999px will not be visible when the post, response or comment is viewed using in-line course discussions",
|
||||
"discussions.editor.image.warning.title": "Warning!",
|
||||
"discussions.editor.image.warning.dismiss": "Ok",
|
||||
"discussions.navigation.breadcrumbMenu.allTopics": "Topics",
|
||||
"discussions.navigation.breadcrumbMenu.showAll": "Show all",
|
||||
"discussions.navigation.navigationBar.allPosts": "All posts",
|
||||
@@ -119,6 +123,8 @@
|
||||
"discussions.post.editor.anonymousToPeersPost": "Post anonymously to peers",
|
||||
"discussions.editor.posts.editReasonCode": "Reason for editing",
|
||||
"discussions.editor.posts.showPreview.button": "Show Preview",
|
||||
"discussions.topic.noName.label": "Unnamed category",
|
||||
"discussions.subtopic.noName.label": "Unnamed subcategory",
|
||||
"discussions.posts.filter.showALl": "Show all",
|
||||
"discussions.posts.filter.discussions": "Discussions",
|
||||
"discussions.posts.filter.questions": "Questions",
|
||||
@@ -128,7 +134,7 @@
|
||||
"discussions.posts.status.filter.following": "Following",
|
||||
"discussions.posts.status.filter.reported": "Reported",
|
||||
"discussions.posts.status.filter.unanswered": "Unanswered",
|
||||
"discussions.posts.status.filter.unresponded": "Unresponded",
|
||||
"discussions.posts.status.filter.unresponded": "Not responded",
|
||||
"discussions.posts.filter.myPosts": "My posts",
|
||||
"discussions.posts.filter.myDiscussions": "My discussions",
|
||||
"discussions.posts.filter.myQuestions": "My questions",
|
||||
@@ -136,7 +142,7 @@
|
||||
"discussions.posts.sort.lastActivity": "Recent activity",
|
||||
"discussions.posts.sort.commentCount": "Most activity",
|
||||
"discussions.posts.sort.voteCount": "Most likes",
|
||||
"discussions.posts.sort-filter.sortFilterStatus": "{own, select,\n false {All}\n true {Own}\n other {{own}}\n } {status, select,\n statusAll {}\n statusUnread {unread}\n statusFollowing {followed}\n statusReported {reported}\n statusUnanswered {unanswered}\n statusUnresponded {unresponded}\n other {{status}}\n } {type, select,\n discussion {discussions}\n question {questions}\n all {posts}\n other {{type}}\n } {cohortType, select,\n all {}\n group {in {cohort}}\n other {{cohortType}}\n } by {sort, select,\n lastActivityAt {recent activity}\n commentCount {most activity}\n voteCount {most votes}\n other {{sort}}\n }",
|
||||
"discussions.posts.sort-filter.sortFilterStatus": "{own, select,\n false {All}\n true {Own}\n other {{own}}\n } {status, select,\n statusAll {}\n statusUnread {unread}\n statusFollowing {followed}\n statusReported {reported}\n statusUnanswered {unanswered}\n statusUnresponded {unresponded}\n other {{status}}\n } {type, select,\n discussion {discussions}\n question {questions}\n all {posts}\n other {{type}}\n } {cohortType, select,\n all {}\n group {in {cohort}}\n other {{cohortType}}\n } sorted by {sort, select,\n lastActivityAt {recent activity}\n commentCount {most activity}\n voteCount {most likes}\n other {{sort}}\n }",
|
||||
"discussions.post.author.anonymous": "anonymous",
|
||||
"discussions.post.lastResponse": "Last response {time}",
|
||||
"discussions.post.postedOn": "Posted {time} by {author} {authorLabel}",
|
||||
@@ -171,5 +177,6 @@
|
||||
"discussions.topics.sort.courseStructure": "Course Structure",
|
||||
"discussions.topics.find.label": "Search topics",
|
||||
"discussions.topics.archived.label": "Archived",
|
||||
"discussions.topics.unnamed.label": "Unnamed Topic"
|
||||
"discussions.topics.unnamed.label": "Unnamed category",
|
||||
"discussions.subtopics.unnamed.label": "Unnamed subcategory"
|
||||
}
|
||||
@@ -247,4 +247,19 @@ header {
|
||||
|
||||
#paragon-portal-root .pgn__modal-layer {
|
||||
z-index: 1500 !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 767px) {
|
||||
body:not(.tox-force-desktop) .tox .tox-dialog {
|
||||
align-self: center;
|
||||
}
|
||||
}
|
||||
|
||||
.post-preview,
|
||||
.discussion-comments {
|
||||
blockquote {
|
||||
border-left: 2px solid #ccc;
|
||||
margin-left: 1.5rem;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user