Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b8f67e8d2 | ||
|
|
c6e33307ba | ||
|
|
a4df8f7238 | ||
|
|
15b76edb5d |
@@ -1,6 +1,13 @@
|
||||
const { createConfig } = require('@edx/frontend-build');
|
||||
|
||||
const config = createConfig('eslint');
|
||||
const config = createConfig('eslint', {
|
||||
rules: {
|
||||
'import/no-named-as-default': 'off',
|
||||
'import/no-named-as-default-member': 'off',
|
||||
'import/no-self-import': 'off',
|
||||
'spaced-comment': ['error', 'always', { 'block': { 'exceptions': ['*'] } }],
|
||||
},
|
||||
});
|
||||
|
||||
config.settings = {
|
||||
"import/resolver": {
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -17,3 +17,7 @@ dist/
|
||||
### Development environments ###
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
### transifex ###
|
||||
src/i18n/transifex_input.json
|
||||
temp
|
||||
|
||||
8
.tx/config
Normal file
8
.tx/config
Normal file
@@ -0,0 +1,8 @@
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
|
||||
[edx-platform.frontend-app-gradebook]
|
||||
file_filter = src/i18n/messages/<lang>.json
|
||||
source_file = src/i18n/transifex_input.json
|
||||
source_lang = en
|
||||
type = KEYVALUEJSON
|
||||
64
Makefile
64
Makefile
@@ -2,8 +2,64 @@ npm-install-%: ## install specified % npm package
|
||||
npm install $* --save-dev
|
||||
git add package.json
|
||||
|
||||
validate-no-uncommitted-package-lock-changes:
|
||||
git diff --exit-code package-lock.json
|
||||
transifex_resource = frontend-app-gradebook
|
||||
transifex_langs = "ar,fr,es_419,zh_CN"
|
||||
|
||||
test:
|
||||
npm run test
|
||||
transifex_utils = ./node_modules/.bin/transifex-utils.js
|
||||
i18n = ./src/i18n
|
||||
transifex_input = $(i18n)/transifex_input.json
|
||||
tx_url1 = https://www.transifex.com/api/2/project/edx-platform/resource/$(transifex_resource)/translation/en/strings/
|
||||
tx_url2 = https://www.transifex.com/api/2/project/edx-platform/resource/$(transifex_resource)/source/
|
||||
|
||||
# This directory must match .babelrc .
|
||||
transifex_temp = ./temp/babel-plugin-react-intl
|
||||
|
||||
NPM_TESTS=build i18n_extract lint test is-es5
|
||||
|
||||
.PHONY: test
|
||||
test: $(addprefix test.npm.,$(NPM_TESTS)) ## validate ci suite
|
||||
|
||||
.PHONY: test.npm.*
|
||||
test.npm.%: validate-no-uncommitted-package-lock-changes
|
||||
test -d node_modules || $(MAKE) requirements
|
||||
npm run $(*)
|
||||
|
||||
.PHONY: requirements
|
||||
requirements: ## install ci requirements
|
||||
npm ci
|
||||
|
||||
i18n.extract:
|
||||
# Pulling display strings from .jsx files into .json files...
|
||||
rm -rf $(transifex_temp)
|
||||
npm run-script i18n_extract
|
||||
|
||||
i18n.concat:
|
||||
# Gathering JSON messages into one file...
|
||||
$(transifex_utils) $(transifex_temp) $(transifex_input)
|
||||
|
||||
extract_translations: | requirements i18n.extract i18n.concat
|
||||
|
||||
# Despite the name, we actually need this target to detect changes in the incoming translated message files as well.
|
||||
detect_changed_source_translations:
|
||||
# Checking for changed translations...
|
||||
git diff --exit-code $(i18n)
|
||||
|
||||
# Pushes translations to Transifex. You must run make extract_translations first.
|
||||
push_translations:
|
||||
# Pushing strings to Transifex...
|
||||
tx push -s
|
||||
# Fetching hashes from Transifex...
|
||||
./node_modules/reactifex/bash_scripts/get_hashed_strings.sh $(tx_url1)
|
||||
# Writing out comments to file...
|
||||
$(transifex_utils) $(transifex_temp) --comments
|
||||
# Pushing comments to Transifex...
|
||||
./node_modules/reactifex/bash_scripts/put_comments.sh $(tx_url2)
|
||||
|
||||
# Pulls translations from Transifex.
|
||||
pull_translations:
|
||||
tx pull -f --mode reviewed --language=$(transifex_langs)
|
||||
|
||||
# This target is used by Travis.
|
||||
validate-no-uncommitted-package-lock-changes:
|
||||
# Checking for package-lock.json changes...
|
||||
git diff --exit-code package-lock.json
|
||||
|
||||
@@ -8,4 +8,8 @@ module.exports = createConfig('jest', {
|
||||
snapshotSerializers: [
|
||||
'enzyme-to-json/serializer',
|
||||
],
|
||||
coveragePathIgnorePatterns: [
|
||||
'src/segment.js',
|
||||
'src/postcss.config.js',
|
||||
],
|
||||
});
|
||||
|
||||
874
package-lock.json
generated
874
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@edx/frontend-app-gradebook",
|
||||
"version": "1.4.36",
|
||||
"version": "1.4.43",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -18156,7 +18156,7 @@
|
||||
"dependencies": {
|
||||
"JSONStream": {
|
||||
"version": "1.3.5",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18166,13 +18166,13 @@
|
||||
},
|
||||
"abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
|
||||
"dev": true
|
||||
},
|
||||
"agent-base": {
|
||||
"version": "4.3.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18181,7 +18181,7 @@
|
||||
},
|
||||
"agentkeepalive": {
|
||||
"version": "3.5.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18190,7 +18190,7 @@
|
||||
},
|
||||
"ajv": {
|
||||
"version": "5.5.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18202,7 +18202,7 @@
|
||||
},
|
||||
"ansi-align": {
|
||||
"version": "2.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18211,13 +18211,13 @@
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18226,31 +18226,31 @@
|
||||
},
|
||||
"ansicolors": {
|
||||
"version": "0.3.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=",
|
||||
"dev": true
|
||||
},
|
||||
"ansistyles": {
|
||||
"version": "0.1.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-XeYEFb2gcbs3EnhUyGT0GyMlRTk=",
|
||||
"dev": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "2.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"archy": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=",
|
||||
"dev": true
|
||||
},
|
||||
"are-we-there-yet": {
|
||||
"version": "1.1.4",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18260,7 +18260,7 @@
|
||||
"dependencies": {
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18275,7 +18275,7 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18286,13 +18286,13 @@
|
||||
},
|
||||
"asap": {
|
||||
"version": "2.0.6",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=",
|
||||
"dev": true
|
||||
},
|
||||
"asn1": {
|
||||
"version": "0.2.4",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18301,37 +18301,37 @@
|
||||
},
|
||||
"assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
|
||||
"dev": true
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
|
||||
"dev": true
|
||||
},
|
||||
"aws-sign2": {
|
||||
"version": "0.7.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
|
||||
"dev": true
|
||||
},
|
||||
"aws4": {
|
||||
"version": "1.8.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
|
||||
"dev": true
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
||||
"dev": true
|
||||
},
|
||||
"bcrypt-pbkdf": {
|
||||
"version": "1.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
@@ -18341,7 +18341,7 @@
|
||||
},
|
||||
"bin-links": {
|
||||
"version": "1.1.8",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-KgmVfx+QqggqP9dA3iIc5pA4T1qEEEL+hOhOhNPaUm77OTrJoOXE/C05SJLNJe6m/2wUK7F1tDSou7n5TfCDzQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18355,13 +18355,13 @@
|
||||
},
|
||||
"bluebird": {
|
||||
"version": "3.5.5",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==",
|
||||
"dev": true
|
||||
},
|
||||
"boxen": {
|
||||
"version": "1.3.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18376,7 +18376,7 @@
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18386,31 +18386,31 @@
|
||||
},
|
||||
"buffer-from": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==",
|
||||
"dev": true
|
||||
},
|
||||
"builtins": {
|
||||
"version": "1.0.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=",
|
||||
"dev": true
|
||||
},
|
||||
"byline": {
|
||||
"version": "5.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE=",
|
||||
"dev": true
|
||||
},
|
||||
"byte-size": {
|
||||
"version": "5.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-/XuKeqWocKsYa/cBY1YbSJSWWqTi4cFgr9S6OyM7PBaPbr9zvNGwWP33vt0uqGhwDdN+y3yhbXVILEUpnwEWGw==",
|
||||
"dev": true
|
||||
},
|
||||
"cacache": {
|
||||
"version": "12.0.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18433,31 +18433,31 @@
|
||||
},
|
||||
"call-limit": {
|
||||
"version": "1.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-5twvci5b9eRBw2wCfPtN0GmlR2/gadZqyFpPhOK6CvMFoFgA+USnZ6Jpu1lhG9h85pQ3Ouil3PfXWRD4EUaRiQ==",
|
||||
"dev": true
|
||||
},
|
||||
"camelcase": {
|
||||
"version": "4.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
|
||||
"dev": true
|
||||
},
|
||||
"capture-stack-trace": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=",
|
||||
"dev": true
|
||||
},
|
||||
"caseless": {
|
||||
"version": "0.12.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
|
||||
"dev": true
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18468,19 +18468,19 @@
|
||||
},
|
||||
"chownr": {
|
||||
"version": "1.1.4",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
|
||||
"dev": true
|
||||
},
|
||||
"ci-info": {
|
||||
"version": "2.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
|
||||
"dev": true
|
||||
},
|
||||
"cidr-regex": {
|
||||
"version": "2.0.10",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-sB3ogMQXWvreNPbJUZMRApxuRYd+KoIo4RGQ81VatjmMW6WJPo+IJZ2846FGItr9VzKo5w7DXzijPLGtSd0N3Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18489,13 +18489,13 @@
|
||||
},
|
||||
"cli-boxes": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=",
|
||||
"dev": true
|
||||
},
|
||||
"cli-columns": {
|
||||
"version": "3.1.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-ZzLZcpee/CrkRKHwjgj6E5yWoY4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18505,7 +18505,7 @@
|
||||
},
|
||||
"cli-table3": {
|
||||
"version": "0.5.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18516,7 +18516,7 @@
|
||||
},
|
||||
"cliui": {
|
||||
"version": "5.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18527,19 +18527,19 @@
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "4.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
||||
"dev": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "2.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
|
||||
"dev": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "3.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18550,7 +18550,7 @@
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "5.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18561,13 +18561,13 @@
|
||||
},
|
||||
"clone": {
|
||||
"version": "1.0.4",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
|
||||
"dev": true
|
||||
},
|
||||
"cmd-shim": {
|
||||
"version": "3.0.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-DtGg+0xiFhQIntSBRzL2fRQBnmtAVwXIDo4Qq46HPpObYquxMaZS4sb82U9nH91qJrlosC1wa9gwr0QyL/HypA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18577,19 +18577,19 @@
|
||||
},
|
||||
"co": {
|
||||
"version": "4.6.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
|
||||
"dev": true
|
||||
},
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
|
||||
"dev": true
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "1.9.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18598,20 +18598,20 @@
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||
"dev": true
|
||||
},
|
||||
"colors": {
|
||||
"version": "1.3.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"columnify": {
|
||||
"version": "1.5.4",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18621,7 +18621,7 @@
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.6",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18630,13 +18630,13 @@
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||
"dev": true
|
||||
},
|
||||
"concat-stream": {
|
||||
"version": "1.6.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18648,7 +18648,7 @@
|
||||
"dependencies": {
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18663,7 +18663,7 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18674,7 +18674,7 @@
|
||||
},
|
||||
"config-chain": {
|
||||
"version": "1.1.12",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18684,7 +18684,7 @@
|
||||
},
|
||||
"configstore": {
|
||||
"version": "3.1.5",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-nlOhI4+fdzoK5xmJ+NY+1gZK56bwEaWZr8fYuXohZ9Vkc1o3a4T/R3M+yE/w7x/ZVJ1zF8c+oaOvF0dztdUgmA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18698,13 +18698,13 @@
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
|
||||
"dev": true
|
||||
},
|
||||
"copy-concurrently": {
|
||||
"version": "1.0.5",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18718,13 +18718,13 @@
|
||||
"dependencies": {
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
|
||||
"dev": true
|
||||
},
|
||||
"iferr": {
|
||||
"version": "0.1.5",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=",
|
||||
"dev": true
|
||||
}
|
||||
@@ -18732,13 +18732,13 @@
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
||||
"dev": true
|
||||
},
|
||||
"create-error-class": {
|
||||
"version": "3.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18747,7 +18747,7 @@
|
||||
},
|
||||
"cross-spawn": {
|
||||
"version": "5.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18758,7 +18758,7 @@
|
||||
"dependencies": {
|
||||
"lru-cache": {
|
||||
"version": "4.1.5",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18768,7 +18768,7 @@
|
||||
},
|
||||
"yallist": {
|
||||
"version": "2.1.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
|
||||
"dev": true
|
||||
}
|
||||
@@ -18776,19 +18776,19 @@
|
||||
},
|
||||
"crypto-random-string": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=",
|
||||
"dev": true
|
||||
},
|
||||
"cyclist": {
|
||||
"version": "0.2.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=",
|
||||
"dev": true
|
||||
},
|
||||
"dashdash": {
|
||||
"version": "1.14.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18797,7 +18797,7 @@
|
||||
},
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18806,7 +18806,7 @@
|
||||
"dependencies": {
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
|
||||
"dev": true
|
||||
}
|
||||
@@ -18814,31 +18814,31 @@
|
||||
},
|
||||
"debuglog": {
|
||||
"version": "1.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=",
|
||||
"dev": true
|
||||
},
|
||||
"decamelize": {
|
||||
"version": "1.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
|
||||
"dev": true
|
||||
},
|
||||
"decode-uri-component": {
|
||||
"version": "0.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
|
||||
"dev": true
|
||||
},
|
||||
"deep-extend": {
|
||||
"version": "0.6.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
|
||||
"dev": true
|
||||
},
|
||||
"defaults": {
|
||||
"version": "1.0.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18847,7 +18847,7 @@
|
||||
},
|
||||
"define-properties": {
|
||||
"version": "1.1.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18856,31 +18856,31 @@
|
||||
},
|
||||
"delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
|
||||
"dev": true
|
||||
},
|
||||
"delegates": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
|
||||
"dev": true
|
||||
},
|
||||
"detect-indent": {
|
||||
"version": "5.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=",
|
||||
"dev": true
|
||||
},
|
||||
"detect-newline": {
|
||||
"version": "2.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=",
|
||||
"dev": true
|
||||
},
|
||||
"dezalgo": {
|
||||
"version": "1.0.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18890,7 +18890,7 @@
|
||||
},
|
||||
"dot-prop": {
|
||||
"version": "4.2.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-l0p4+mIuJIua0mhxGoh4a+iNL9bmeK5DvnSVQa6T0OhrVmaEa1XScX5Etc673FePCJOArq/4Pa2cLGODUWTPOQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18899,19 +18899,19 @@
|
||||
},
|
||||
"dotenv": {
|
||||
"version": "5.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow==",
|
||||
"dev": true
|
||||
},
|
||||
"duplexer3": {
|
||||
"version": "0.1.4",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=",
|
||||
"dev": true
|
||||
},
|
||||
"duplexify": {
|
||||
"version": "3.6.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18923,7 +18923,7 @@
|
||||
"dependencies": {
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18938,7 +18938,7 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18949,7 +18949,7 @@
|
||||
},
|
||||
"ecc-jsbn": {
|
||||
"version": "0.1.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
@@ -18960,19 +18960,19 @@
|
||||
},
|
||||
"editor": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-YMf4e9YrzGqJT6jM1q+3gjok90I=",
|
||||
"dev": true
|
||||
},
|
||||
"emoji-regex": {
|
||||
"version": "7.0.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
|
||||
"dev": true
|
||||
},
|
||||
"encoding": {
|
||||
"version": "0.1.12",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18981,7 +18981,7 @@
|
||||
},
|
||||
"end-of-stream": {
|
||||
"version": "1.4.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -18990,19 +18990,19 @@
|
||||
},
|
||||
"env-paths": {
|
||||
"version": "2.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==",
|
||||
"dev": true
|
||||
},
|
||||
"err-code": {
|
||||
"version": "1.1.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=",
|
||||
"dev": true
|
||||
},
|
||||
"errno": {
|
||||
"version": "0.1.7",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19011,7 +19011,7 @@
|
||||
},
|
||||
"es-abstract": {
|
||||
"version": "1.12.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19024,7 +19024,7 @@
|
||||
},
|
||||
"es-to-primitive": {
|
||||
"version": "1.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19035,13 +19035,13 @@
|
||||
},
|
||||
"es6-promise": {
|
||||
"version": "4.2.8",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
|
||||
"dev": true
|
||||
},
|
||||
"es6-promisify": {
|
||||
"version": "5.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19050,13 +19050,13 @@
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
|
||||
"dev": true
|
||||
},
|
||||
"execa": {
|
||||
"version": "0.7.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19071,7 +19071,7 @@
|
||||
"dependencies": {
|
||||
"get-stream": {
|
||||
"version": "3.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
|
||||
"dev": true
|
||||
}
|
||||
@@ -19079,43 +19079,43 @@
|
||||
},
|
||||
"extend": {
|
||||
"version": "3.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
|
||||
"dev": true
|
||||
},
|
||||
"extsprintf": {
|
||||
"version": "1.3.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
|
||||
"dev": true
|
||||
},
|
||||
"fast-deep-equal": {
|
||||
"version": "1.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=",
|
||||
"dev": true
|
||||
},
|
||||
"fast-json-stable-stringify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
|
||||
"dev": true
|
||||
},
|
||||
"figgy-pudding": {
|
||||
"version": "3.5.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==",
|
||||
"dev": true
|
||||
},
|
||||
"find-npm-prefix": {
|
||||
"version": "1.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-KEftzJ+H90x6pcKtdXZEPsQse8/y/UnvzRKrOSQFprnrGaFuJ62fVkP34Iu2IYuMvyauCyoLTNkJZgrrGA2wkA==",
|
||||
"dev": true
|
||||
},
|
||||
"flush-write-stream": {
|
||||
"version": "1.0.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19125,7 +19125,7 @@
|
||||
"dependencies": {
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19140,7 +19140,7 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19151,13 +19151,13 @@
|
||||
},
|
||||
"forever-agent": {
|
||||
"version": "0.6.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
|
||||
"dev": true
|
||||
},
|
||||
"form-data": {
|
||||
"version": "2.3.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19168,7 +19168,7 @@
|
||||
},
|
||||
"from2": {
|
||||
"version": "2.3.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19178,7 +19178,7 @@
|
||||
"dependencies": {
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19193,7 +19193,7 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19204,7 +19204,7 @@
|
||||
},
|
||||
"fs-minipass": {
|
||||
"version": "1.2.7",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19213,7 +19213,7 @@
|
||||
"dependencies": {
|
||||
"minipass": {
|
||||
"version": "2.9.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19225,7 +19225,7 @@
|
||||
},
|
||||
"fs-vacuum": {
|
||||
"version": "1.2.10",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-t2Kb7AekAxolSP35n17PHMizHjY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19236,7 +19236,7 @@
|
||||
},
|
||||
"fs-write-stream-atomic": {
|
||||
"version": "1.0.10",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19248,13 +19248,13 @@
|
||||
"dependencies": {
|
||||
"iferr": {
|
||||
"version": "0.1.5",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=",
|
||||
"dev": true
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19269,7 +19269,7 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19280,19 +19280,19 @@
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
||||
"dev": true
|
||||
},
|
||||
"function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
||||
"dev": true
|
||||
},
|
||||
"gauge": {
|
||||
"version": "2.7.4",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19308,13 +19308,13 @@
|
||||
"dependencies": {
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
|
||||
"dev": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "1.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19327,13 +19327,13 @@
|
||||
},
|
||||
"genfun": {
|
||||
"version": "5.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==",
|
||||
"dev": true
|
||||
},
|
||||
"gentle-fs": {
|
||||
"version": "2.3.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-OlwBBwqCFPcjm33rF2BjW+Pr6/ll2741l+xooiwTCeaX2CA1ZuclavyMBe0/KlR21/XGsgY6hzEQZ15BdNa13Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19352,13 +19352,13 @@
|
||||
"dependencies": {
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
|
||||
"dev": true
|
||||
},
|
||||
"iferr": {
|
||||
"version": "0.1.5",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=",
|
||||
"dev": true
|
||||
}
|
||||
@@ -19366,13 +19366,13 @@
|
||||
},
|
||||
"get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"dev": true
|
||||
},
|
||||
"get-stream": {
|
||||
"version": "4.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19381,7 +19381,7 @@
|
||||
},
|
||||
"getpass": {
|
||||
"version": "0.1.7",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19390,7 +19390,7 @@
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.6",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19404,7 +19404,7 @@
|
||||
},
|
||||
"global-dirs": {
|
||||
"version": "0.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19413,7 +19413,7 @@
|
||||
},
|
||||
"got": {
|
||||
"version": "6.7.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19432,7 +19432,7 @@
|
||||
"dependencies": {
|
||||
"get-stream": {
|
||||
"version": "3.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
|
||||
"dev": true
|
||||
}
|
||||
@@ -19440,19 +19440,19 @@
|
||||
},
|
||||
"graceful-fs": {
|
||||
"version": "4.2.4",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
|
||||
"dev": true
|
||||
},
|
||||
"har-schema": {
|
||||
"version": "2.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
|
||||
"dev": true
|
||||
},
|
||||
"har-validator": {
|
||||
"version": "5.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19462,7 +19462,7 @@
|
||||
},
|
||||
"has": {
|
||||
"version": "1.0.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19471,37 +19471,37 @@
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
||||
"dev": true
|
||||
},
|
||||
"has-symbols": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=",
|
||||
"dev": true
|
||||
},
|
||||
"has-unicode": {
|
||||
"version": "2.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
|
||||
"dev": true
|
||||
},
|
||||
"hosted-git-info": {
|
||||
"version": "2.8.8",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
|
||||
"dev": true
|
||||
},
|
||||
"http-cache-semantics": {
|
||||
"version": "3.8.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==",
|
||||
"dev": true
|
||||
},
|
||||
"http-proxy-agent": {
|
||||
"version": "2.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19511,7 +19511,7 @@
|
||||
},
|
||||
"http-signature": {
|
||||
"version": "1.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19522,7 +19522,7 @@
|
||||
},
|
||||
"https-proxy-agent": {
|
||||
"version": "2.2.4",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19532,7 +19532,7 @@
|
||||
},
|
||||
"humanize-ms": {
|
||||
"version": "1.2.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19541,7 +19541,7 @@
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.4.23",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19550,13 +19550,13 @@
|
||||
},
|
||||
"iferr": {
|
||||
"version": "1.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-9AfeLfji44r5TKInjhz3W9DyZI1zR1JAf2hVBMGhddAKPqBsupb89jGfbCTHIGZd6fGZl9WlHdn4AObygyMKwg==",
|
||||
"dev": true
|
||||
},
|
||||
"ignore-walk": {
|
||||
"version": "3.0.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19565,25 +19565,25 @@
|
||||
},
|
||||
"import-lazy": {
|
||||
"version": "2.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=",
|
||||
"dev": true
|
||||
},
|
||||
"imurmurhash": {
|
||||
"version": "0.1.4",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
|
||||
"dev": true
|
||||
},
|
||||
"infer-owner": {
|
||||
"version": "1.0.4",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==",
|
||||
"dev": true
|
||||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19593,19 +19593,19 @@
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"dev": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
|
||||
"dev": true
|
||||
},
|
||||
"init-package-json": {
|
||||
"version": "1.10.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-zKSiXKhQveNteyhcj1CoOP8tqp1QuxPIPBl8Bid99DGLFqA1p87M6lNgfjJHSBoWJJlidGOv5rWjyYKEB3g2Jw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19621,25 +19621,25 @@
|
||||
},
|
||||
"ip": {
|
||||
"version": "1.1.5",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=",
|
||||
"dev": true
|
||||
},
|
||||
"ip-regex": {
|
||||
"version": "2.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=",
|
||||
"dev": true
|
||||
},
|
||||
"is-callable": {
|
||||
"version": "1.1.4",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==",
|
||||
"dev": true
|
||||
},
|
||||
"is-ci": {
|
||||
"version": "1.2.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19648,7 +19648,7 @@
|
||||
"dependencies": {
|
||||
"ci-info": {
|
||||
"version": "1.6.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==",
|
||||
"dev": true
|
||||
}
|
||||
@@ -19656,7 +19656,7 @@
|
||||
},
|
||||
"is-cidr": {
|
||||
"version": "3.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-8Xnnbjsb0x462VoYiGlhEi+drY8SFwrHiSYuzc/CEwco55vkehTaxAyIjEdpi3EMvLPPJAJi9FlzP+h+03gp0Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19665,13 +19665,13 @@
|
||||
},
|
||||
"is-date-object": {
|
||||
"version": "1.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
|
||||
"dev": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19680,7 +19680,7 @@
|
||||
},
|
||||
"is-installed-globally": {
|
||||
"version": "0.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19690,19 +19690,19 @@
|
||||
},
|
||||
"is-npm": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=",
|
||||
"dev": true
|
||||
},
|
||||
"is-obj": {
|
||||
"version": "1.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
|
||||
"dev": true
|
||||
},
|
||||
"is-path-inside": {
|
||||
"version": "1.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19711,13 +19711,13 @@
|
||||
},
|
||||
"is-redirect": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=",
|
||||
"dev": true
|
||||
},
|
||||
"is-regex": {
|
||||
"version": "1.0.4",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19726,19 +19726,19 @@
|
||||
},
|
||||
"is-retry-allowed": {
|
||||
"version": "1.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==",
|
||||
"dev": true
|
||||
},
|
||||
"is-stream": {
|
||||
"version": "1.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
|
||||
"dev": true
|
||||
},
|
||||
"is-symbol": {
|
||||
"version": "1.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19747,68 +19747,68 @@
|
||||
},
|
||||
"is-typedarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
|
||||
"dev": true
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
|
||||
"dev": true
|
||||
},
|
||||
"isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
|
||||
"dev": true
|
||||
},
|
||||
"isstream": {
|
||||
"version": "0.1.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
|
||||
"dev": true
|
||||
},
|
||||
"jsbn": {
|
||||
"version": "0.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"json-parse-better-errors": {
|
||||
"version": "1.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
|
||||
"dev": true
|
||||
},
|
||||
"json-schema": {
|
||||
"version": "0.2.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
|
||||
"dev": true
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.3.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
|
||||
"dev": true
|
||||
},
|
||||
"json-stringify-safe": {
|
||||
"version": "5.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
|
||||
"dev": true
|
||||
},
|
||||
"jsonparse": {
|
||||
"version": "1.3.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=",
|
||||
"dev": true
|
||||
},
|
||||
"jsprim": {
|
||||
"version": "1.4.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19820,7 +19820,7 @@
|
||||
},
|
||||
"latest-version": {
|
||||
"version": "3.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19829,13 +19829,13 @@
|
||||
},
|
||||
"lazy-property": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-hN3Es3Bnm6i9TNz6TAa0PVcREUc=",
|
||||
"dev": true
|
||||
},
|
||||
"libcipm": {
|
||||
"version": "4.0.8",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-IN3hh2yDJQtZZ5paSV4fbvJg4aHxCCg5tcZID/dSVlTuUiWktsgaldVljJv6Z5OUlYspx6xQkbR0efNodnIrOA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19858,7 +19858,7 @@
|
||||
},
|
||||
"libnpm": {
|
||||
"version": "3.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-d7jU5ZcMiTfBqTUJVZ3xid44fE5ERBm9vBnmhp2ECD2Ls+FNXWxHSkO7gtvrnbLO78gwPdNPz1HpsF3W4rjkBQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19886,7 +19886,7 @@
|
||||
},
|
||||
"libnpmaccess": {
|
||||
"version": "3.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-01512AK7MqByrI2mfC7h5j8N9V4I7MHJuk9buo8Gv+5QgThpOgpjB7sQBDDkeZqRteFb1QM/6YNdHfG7cDvfAQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19898,7 +19898,7 @@
|
||||
},
|
||||
"libnpmconfig": {
|
||||
"version": "1.2.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-9esX8rTQAHqarx6qeZqmGQKBNZR5OIbl/Ayr0qQDy3oXja2iFVQQI81R6GZ2a02bSNZ9p3YOGX1O6HHCb1X7kA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19909,7 +19909,7 @@
|
||||
"dependencies": {
|
||||
"find-up": {
|
||||
"version": "3.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19918,7 +19918,7 @@
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19928,7 +19928,7 @@
|
||||
},
|
||||
"p-limit": {
|
||||
"version": "2.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19937,7 +19937,7 @@
|
||||
},
|
||||
"p-locate": {
|
||||
"version": "3.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19946,7 +19946,7 @@
|
||||
},
|
||||
"p-try": {
|
||||
"version": "2.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
|
||||
"dev": true
|
||||
}
|
||||
@@ -19954,7 +19954,7 @@
|
||||
},
|
||||
"libnpmhook": {
|
||||
"version": "5.0.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-UdNLMuefVZra/wbnBXECZPefHMGsVDTq5zaM/LgKNE9Keyl5YXQTnGAzEo+nFOpdRqTWI9LYi4ApqF9uVCCtuA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19966,7 +19966,7 @@
|
||||
},
|
||||
"libnpmorg": {
|
||||
"version": "1.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-0sRUXLh+PLBgZmARvthhYXQAWn0fOsa6T5l3JSe2n9vKG/lCVK4nuG7pDsa7uMq+uTt2epdPK+a2g6btcY11Ww==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19978,7 +19978,7 @@
|
||||
},
|
||||
"libnpmpublish": {
|
||||
"version": "1.1.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-2yIwaXrhTTcF7bkJKIKmaCV9wZOALf/gsTDxVSu/Gu/6wiG3fA8ce8YKstiWKTxSFNC0R7isPUb6tXTVFZHt2g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -19995,7 +19995,7 @@
|
||||
},
|
||||
"libnpmsearch": {
|
||||
"version": "2.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-VTBbV55Q6fRzTdzziYCr64+f8AopQ1YZ+BdPOv16UegIEaE8C0Kch01wo4s3kRTFV64P121WZJwgmBwrq68zYg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20006,7 +20006,7 @@
|
||||
},
|
||||
"libnpmteam": {
|
||||
"version": "1.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-p420vM28Us04NAcg1rzgGW63LMM6rwe+6rtZpfDxCcXxM0zUTLl7nPFEnRF3JfFBF5skF/yuZDUthTsHgde8QA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20018,7 +20018,7 @@
|
||||
},
|
||||
"libnpx": {
|
||||
"version": "10.2.4",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-BPc0D1cOjBeS8VIBKUu5F80s6njm0wbVt7CsGMrIcJ+SI7pi7V0uVPGpEMH9H5L8csOcclTxAXFE2VAsJXUhfA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20034,7 +20034,7 @@
|
||||
},
|
||||
"lock-verify": {
|
||||
"version": "2.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-vcLpxnGvrqisKvLQ2C2v0/u7LVly17ak2YSgoK4PrdsYBXQIax19vhKiLfvKNFx7FRrpTnitrpzF/uuCMuorIg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20044,7 +20044,7 @@
|
||||
},
|
||||
"lockfile": {
|
||||
"version": "1.0.4",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20053,13 +20053,13 @@
|
||||
},
|
||||
"lodash._baseindexof": {
|
||||
"version": "3.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash._baseuniq": {
|
||||
"version": "4.6.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-DrtE5FaBSveQXGIS+iybLVG4Qeg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20069,19 +20069,19 @@
|
||||
},
|
||||
"lodash._bindcallback": {
|
||||
"version": "3.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash._cacheindexof": {
|
||||
"version": "3.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash._createcache": {
|
||||
"version": "3.1.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20090,61 +20090,61 @@
|
||||
},
|
||||
"lodash._createset": {
|
||||
"version": "4.0.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash._getnative": {
|
||||
"version": "3.9.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash._root": {
|
||||
"version": "3.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.clonedeep": {
|
||||
"version": "4.5.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.restparam": {
|
||||
"version": "3.6.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.union": {
|
||||
"version": "4.6.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.uniq": {
|
||||
"version": "4.5.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.without": {
|
||||
"version": "4.4.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-PNRXSgC2e643OpS3SHcmQFB7eqw=",
|
||||
"dev": true
|
||||
},
|
||||
"lowercase-keys": {
|
||||
"version": "1.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==",
|
||||
"dev": true
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "5.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20153,7 +20153,7 @@
|
||||
},
|
||||
"make-dir": {
|
||||
"version": "1.3.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20162,7 +20162,7 @@
|
||||
},
|
||||
"make-fetch-happen": {
|
||||
"version": "5.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20181,19 +20181,19 @@
|
||||
},
|
||||
"meant": {
|
||||
"version": "1.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-KN+1uowN/NK+sT/Lzx7WSGIj2u+3xe5n2LbwObfjOhPZiA+cCfCm6idVl0RkEfjThkw5XJ96CyRcanq6GmKtUg==",
|
||||
"dev": true
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.35.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==",
|
||||
"dev": true
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.19",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20202,7 +20202,7 @@
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20211,13 +20211,13 @@
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
},
|
||||
"minizlib": {
|
||||
"version": "1.3.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20226,7 +20226,7 @@
|
||||
"dependencies": {
|
||||
"minipass": {
|
||||
"version": "2.9.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20238,7 +20238,7 @@
|
||||
},
|
||||
"mississippi": {
|
||||
"version": "3.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20256,7 +20256,7 @@
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20265,7 +20265,7 @@
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
}
|
||||
@@ -20273,7 +20273,7 @@
|
||||
},
|
||||
"move-concurrently": {
|
||||
"version": "1.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20287,7 +20287,7 @@
|
||||
"dependencies": {
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
|
||||
"dev": true
|
||||
}
|
||||
@@ -20295,19 +20295,19 @@
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
|
||||
"dev": true
|
||||
},
|
||||
"mute-stream": {
|
||||
"version": "0.0.7",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
|
||||
"dev": true
|
||||
},
|
||||
"node-fetch-npm": {
|
||||
"version": "2.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20318,7 +20318,7 @@
|
||||
},
|
||||
"node-gyp": {
|
||||
"version": "5.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-OUTryc5bt/P8zVgNUmC6xdXiDJxLMAW8cF5tLQOT9E5sOQj+UeQxnnPy74K3CLCa/SOjjBlbuzDLR8ANwA+wmw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20337,7 +20337,7 @@
|
||||
},
|
||||
"nopt": {
|
||||
"version": "4.0.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20347,7 +20347,7 @@
|
||||
},
|
||||
"normalize-package-data": {
|
||||
"version": "2.5.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20359,7 +20359,7 @@
|
||||
"dependencies": {
|
||||
"resolve": {
|
||||
"version": "1.10.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20370,7 +20370,7 @@
|
||||
},
|
||||
"npm-audit-report": {
|
||||
"version": "1.3.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-8nH/JjsFfAWMvn474HB9mpmMjrnKb1Hx/oTAdjv4PT9iZBvBxiZ+wtDUapHCJwLqYGQVPaAfs+vL5+5k9QndXw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20380,7 +20380,7 @@
|
||||
},
|
||||
"npm-bundled": {
|
||||
"version": "1.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20389,13 +20389,13 @@
|
||||
},
|
||||
"npm-cache-filename": {
|
||||
"version": "1.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-3tMGxbC/yHCp6fr4I7xfKD4FrhE=",
|
||||
"dev": true
|
||||
},
|
||||
"npm-install-checks": {
|
||||
"version": "3.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-E4kzkyZDIWoin6uT5howP8VDvkM+E8IQDcHAycaAxMbwkqhIg5eEYALnXOl3Hq9MrkdQB/2/g1xwBINXdKSRkg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20404,7 +20404,7 @@
|
||||
},
|
||||
"npm-lifecycle": {
|
||||
"version": "3.1.5",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-lDLVkjfZmvmfvpvBzA4vzee9cn+Me4orq0QF8glbswJVEbIcSNWib7qGOffolysc3teCqbbPZZkzbr3GQZTL1g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20420,19 +20420,19 @@
|
||||
},
|
||||
"npm-logical-tree": {
|
||||
"version": "1.2.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-AJI/qxDB2PWI4LG1CYN579AY1vCiNyWfkiquCsJWqntRu/WwimVrC8yXeILBFHDwxfOejxewlmnvW9XXjMlYIg==",
|
||||
"dev": true
|
||||
},
|
||||
"npm-normalize-package-bin": {
|
||||
"version": "1.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==",
|
||||
"dev": true
|
||||
},
|
||||
"npm-package-arg": {
|
||||
"version": "6.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20444,7 +20444,7 @@
|
||||
},
|
||||
"npm-packlist": {
|
||||
"version": "1.4.8",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20455,7 +20455,7 @@
|
||||
},
|
||||
"npm-pick-manifest": {
|
||||
"version": "3.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20466,7 +20466,7 @@
|
||||
},
|
||||
"npm-profile": {
|
||||
"version": "4.0.4",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-Ta8xq8TLMpqssF0H60BXS1A90iMoM6GeKwsmravJ6wYjWwSzcYBTdyWa3DZCYqPutacBMEm7cxiOkiIeCUAHDQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20477,7 +20477,7 @@
|
||||
},
|
||||
"npm-registry-fetch": {
|
||||
"version": "4.0.7",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-cny9v0+Mq6Tjz+e0erFAB+RYJ/AVGzkjnISiobqP8OWj9c9FLoZZu8/SPSKJWE17F1tk4018wfjV+ZbIbqC7fQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20492,7 +20492,7 @@
|
||||
"dependencies": {
|
||||
"safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"dev": true
|
||||
}
|
||||
@@ -20500,7 +20500,7 @@
|
||||
},
|
||||
"npm-run-path": {
|
||||
"version": "2.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20509,13 +20509,13 @@
|
||||
},
|
||||
"npm-user-validate": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-jOyg9c6gTU6TUZ73LQVXp1Ei6VE=",
|
||||
"dev": true
|
||||
},
|
||||
"npmlog": {
|
||||
"version": "4.1.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20527,31 +20527,31 @@
|
||||
},
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
|
||||
"dev": true
|
||||
},
|
||||
"oauth-sign": {
|
||||
"version": "0.9.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
|
||||
"dev": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||
"dev": true
|
||||
},
|
||||
"object-keys": {
|
||||
"version": "1.0.12",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==",
|
||||
"dev": true
|
||||
},
|
||||
"object.getownpropertydescriptors": {
|
||||
"version": "2.0.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20561,7 +20561,7 @@
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20570,25 +20570,25 @@
|
||||
},
|
||||
"opener": {
|
||||
"version": "1.5.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==",
|
||||
"dev": true
|
||||
},
|
||||
"os-homedir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
|
||||
"dev": true
|
||||
},
|
||||
"os-tmpdir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
|
||||
"dev": true
|
||||
},
|
||||
"osenv": {
|
||||
"version": "0.1.5",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20598,13 +20598,13 @@
|
||||
},
|
||||
"p-finally": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
|
||||
"dev": true
|
||||
},
|
||||
"package-json": {
|
||||
"version": "4.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20616,7 +20616,7 @@
|
||||
},
|
||||
"pacote": {
|
||||
"version": "9.5.12",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-BUIj/4kKbwWg4RtnBncXPJd15piFSVNpTzY0rysSr3VnMowTYgkGKcaHrbReepAkjTr8lH2CVWRi58Spg2CicQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20654,7 +20654,7 @@
|
||||
"dependencies": {
|
||||
"minipass": {
|
||||
"version": "2.9.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20666,7 +20666,7 @@
|
||||
},
|
||||
"parallel-transform": {
|
||||
"version": "1.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20677,7 +20677,7 @@
|
||||
"dependencies": {
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20692,7 +20692,7 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20703,67 +20703,67 @@
|
||||
},
|
||||
"path-exists": {
|
||||
"version": "3.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
|
||||
"dev": true
|
||||
},
|
||||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
||||
"dev": true
|
||||
},
|
||||
"path-is-inside": {
|
||||
"version": "1.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
|
||||
"dev": true
|
||||
},
|
||||
"path-key": {
|
||||
"version": "2.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
|
||||
"dev": true
|
||||
},
|
||||
"path-parse": {
|
||||
"version": "1.0.6",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
|
||||
"dev": true
|
||||
},
|
||||
"performance-now": {
|
||||
"version": "2.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
|
||||
"dev": true
|
||||
},
|
||||
"pify": {
|
||||
"version": "3.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
|
||||
"dev": true
|
||||
},
|
||||
"prepend-http": {
|
||||
"version": "1.0.4",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
|
||||
"dev": true
|
||||
},
|
||||
"process-nextick-args": {
|
||||
"version": "2.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
|
||||
"dev": true
|
||||
},
|
||||
"promise-inflight": {
|
||||
"version": "1.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=",
|
||||
"dev": true
|
||||
},
|
||||
"promise-retry": {
|
||||
"version": "1.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20773,7 +20773,7 @@
|
||||
"dependencies": {
|
||||
"retry": {
|
||||
"version": "0.10.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=",
|
||||
"dev": true
|
||||
}
|
||||
@@ -20781,7 +20781,7 @@
|
||||
},
|
||||
"promzard": {
|
||||
"version": "0.3.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-JqXW7ox97kyxIggwWs+5O6OCqe4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20790,13 +20790,13 @@
|
||||
},
|
||||
"proto-list": {
|
||||
"version": "1.2.4",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=",
|
||||
"dev": true
|
||||
},
|
||||
"protoduck": {
|
||||
"version": "5.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20805,25 +20805,25 @@
|
||||
},
|
||||
"prr": {
|
||||
"version": "1.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
|
||||
"dev": true
|
||||
},
|
||||
"pseudomap": {
|
||||
"version": "1.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
|
||||
"dev": true
|
||||
},
|
||||
"psl": {
|
||||
"version": "1.1.29",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==",
|
||||
"dev": true
|
||||
},
|
||||
"pump": {
|
||||
"version": "3.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20833,7 +20833,7 @@
|
||||
},
|
||||
"pumpify": {
|
||||
"version": "1.5.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20844,7 +20844,7 @@
|
||||
"dependencies": {
|
||||
"pump": {
|
||||
"version": "2.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20856,25 +20856,25 @@
|
||||
},
|
||||
"punycode": {
|
||||
"version": "1.4.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
|
||||
"dev": true
|
||||
},
|
||||
"qrcode-terminal": {
|
||||
"version": "0.12.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==",
|
||||
"dev": true
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.5.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
|
||||
"dev": true
|
||||
},
|
||||
"query-string": {
|
||||
"version": "6.8.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-J3Qi8XZJXh93t2FiKyd/7Ec6GNifsjKXUsVFkSBj/kjLsDylWhnCz4NT1bkPcKotttPW+QbKGqqPH8OoI2pdqw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20885,13 +20885,13 @@
|
||||
},
|
||||
"qw": {
|
||||
"version": "1.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-77/cdA+a0FQwRCassYNBLMi5ltQ=",
|
||||
"dev": true
|
||||
},
|
||||
"rc": {
|
||||
"version": "1.2.8",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20903,7 +20903,7 @@
|
||||
},
|
||||
"read": {
|
||||
"version": "1.0.7",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20912,7 +20912,7 @@
|
||||
},
|
||||
"read-cmd-shim": {
|
||||
"version": "1.0.5",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-v5yCqQ/7okKoZZkBQUAfTsQ3sVJtXdNfbPnI5cceppoxEVLYA3k+VtV2omkeo8MS94JCy4fSiUwlRBAwCVRPUA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20921,7 +20921,7 @@
|
||||
},
|
||||
"read-installed": {
|
||||
"version": "4.0.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20936,7 +20936,7 @@
|
||||
},
|
||||
"read-package-json": {
|
||||
"version": "2.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20949,7 +20949,7 @@
|
||||
},
|
||||
"read-package-tree": {
|
||||
"version": "5.3.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20960,7 +20960,7 @@
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20971,7 +20971,7 @@
|
||||
},
|
||||
"readdir-scoped-modules": {
|
||||
"version": "1.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20983,7 +20983,7 @@
|
||||
},
|
||||
"registry-auth-token": {
|
||||
"version": "3.4.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -20993,7 +20993,7 @@
|
||||
},
|
||||
"registry-url": {
|
||||
"version": "3.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21002,7 +21002,7 @@
|
||||
},
|
||||
"request": {
|
||||
"version": "2.88.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21030,31 +21030,31 @@
|
||||
},
|
||||
"require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
|
||||
"dev": true
|
||||
},
|
||||
"require-main-filename": {
|
||||
"version": "2.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
|
||||
"dev": true
|
||||
},
|
||||
"resolve-from": {
|
||||
"version": "4.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
|
||||
"dev": true
|
||||
},
|
||||
"retry": {
|
||||
"version": "0.12.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=",
|
||||
"dev": true
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.7.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21063,7 +21063,7 @@
|
||||
},
|
||||
"run-queue": {
|
||||
"version": "1.0.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21072,7 +21072,7 @@
|
||||
"dependencies": {
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
|
||||
"dev": true
|
||||
}
|
||||
@@ -21080,25 +21080,25 @@
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"dev": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||
"dev": true
|
||||
},
|
||||
"semver-diff": {
|
||||
"version": "2.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21107,13 +21107,13 @@
|
||||
},
|
||||
"set-blocking": {
|
||||
"version": "2.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
|
||||
"dev": true
|
||||
},
|
||||
"sha": {
|
||||
"version": "3.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-DOYnM37cNsLNSGIG/zZWch5CKIRNoLdYUQTQlcgkRkoYIUwDYjqDyye16YcDZg/OPdcbUgTKMjc4SY6TB7ZAPw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21122,7 +21122,7 @@
|
||||
},
|
||||
"shebang-command": {
|
||||
"version": "1.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21131,31 +21131,31 @@
|
||||
},
|
||||
"shebang-regex": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
|
||||
"dev": true
|
||||
},
|
||||
"signal-exit": {
|
||||
"version": "3.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
|
||||
"dev": true
|
||||
},
|
||||
"slide": {
|
||||
"version": "1.1.6",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=",
|
||||
"dev": true
|
||||
},
|
||||
"smart-buffer": {
|
||||
"version": "4.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==",
|
||||
"dev": true
|
||||
},
|
||||
"socks": {
|
||||
"version": "2.3.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21165,7 +21165,7 @@
|
||||
},
|
||||
"socks-proxy-agent": {
|
||||
"version": "4.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21175,7 +21175,7 @@
|
||||
"dependencies": {
|
||||
"agent-base": {
|
||||
"version": "4.2.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21186,13 +21186,13 @@
|
||||
},
|
||||
"sorted-object": {
|
||||
"version": "2.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-fWMfS9OnmKJK8d/8+/6DM3pd9fw=",
|
||||
"dev": true
|
||||
},
|
||||
"sorted-union-stream": {
|
||||
"version": "2.1.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-x3lMfgd4gAUv9xqNSi27Sppjisc=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21202,7 +21202,7 @@
|
||||
"dependencies": {
|
||||
"from2": {
|
||||
"version": "1.3.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-iEE7qqX5pZfP3pIh2GmGzTwGHf0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21212,13 +21212,13 @@
|
||||
},
|
||||
"isarray": {
|
||||
"version": "0.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
|
||||
"dev": true
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "1.1.14",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21230,7 +21230,7 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "0.10.31",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
|
||||
"dev": true
|
||||
}
|
||||
@@ -21238,7 +21238,7 @@
|
||||
},
|
||||
"spdx-correct": {
|
||||
"version": "3.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21248,13 +21248,13 @@
|
||||
},
|
||||
"spdx-exceptions": {
|
||||
"version": "2.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==",
|
||||
"dev": true
|
||||
},
|
||||
"spdx-expression-parse": {
|
||||
"version": "3.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21264,19 +21264,19 @@
|
||||
},
|
||||
"spdx-license-ids": {
|
||||
"version": "3.0.5",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
|
||||
"dev": true
|
||||
},
|
||||
"split-on-first": {
|
||||
"version": "1.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==",
|
||||
"dev": true
|
||||
},
|
||||
"sshpk": {
|
||||
"version": "1.14.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21293,7 +21293,7 @@
|
||||
},
|
||||
"ssri": {
|
||||
"version": "6.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21302,7 +21302,7 @@
|
||||
},
|
||||
"stream-each": {
|
||||
"version": "1.2.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-mc1dbFhGBxvTM3bIWmAAINbqiuAk9TATcfIQC8P+/+HJefgaiTlMn2dHvkX8qlI12KeYKSQ1Ua9RrIqrn1VPoA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21312,7 +21312,7 @@
|
||||
},
|
||||
"stream-iterate": {
|
||||
"version": "1.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-K9fHcpbBcCpGSIuK1B95hl7s1OE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21322,7 +21322,7 @@
|
||||
"dependencies": {
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21337,7 +21337,7 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21348,19 +21348,19 @@
|
||||
},
|
||||
"stream-shift": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=",
|
||||
"dev": true
|
||||
},
|
||||
"strict-uri-encode": {
|
||||
"version": "2.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=",
|
||||
"dev": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "2.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21370,19 +21370,19 @@
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
|
||||
"dev": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "2.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
|
||||
"dev": true
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "4.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21393,7 +21393,7 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21402,7 +21402,7 @@
|
||||
"dependencies": {
|
||||
"safe-buffer": {
|
||||
"version": "5.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==",
|
||||
"dev": true
|
||||
}
|
||||
@@ -21410,13 +21410,13 @@
|
||||
},
|
||||
"stringify-package": {
|
||||
"version": "1.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg==",
|
||||
"dev": true
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21425,19 +21425,19 @@
|
||||
},
|
||||
"strip-eof": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
|
||||
"dev": true
|
||||
},
|
||||
"strip-json-comments": {
|
||||
"version": "2.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.4.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21446,7 +21446,7 @@
|
||||
},
|
||||
"tar": {
|
||||
"version": "4.4.13",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21461,7 +21461,7 @@
|
||||
"dependencies": {
|
||||
"minipass": {
|
||||
"version": "2.9.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21473,7 +21473,7 @@
|
||||
},
|
||||
"term-size": {
|
||||
"version": "1.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21482,19 +21482,19 @@
|
||||
},
|
||||
"text-table": {
|
||||
"version": "0.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
|
||||
"dev": true
|
||||
},
|
||||
"through": {
|
||||
"version": "2.3.8",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
|
||||
"dev": true
|
||||
},
|
||||
"through2": {
|
||||
"version": "2.0.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21504,7 +21504,7 @@
|
||||
"dependencies": {
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21519,7 +21519,7 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21530,19 +21530,19 @@
|
||||
},
|
||||
"timed-out": {
|
||||
"version": "4.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=",
|
||||
"dev": true
|
||||
},
|
||||
"tiny-relative-date": {
|
||||
"version": "1.3.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A==",
|
||||
"dev": true
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "2.4.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21552,7 +21552,7 @@
|
||||
},
|
||||
"tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21561,32 +21561,32 @@
|
||||
},
|
||||
"tweetnacl": {
|
||||
"version": "0.14.5",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"typedarray": {
|
||||
"version": "0.0.6",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
|
||||
"dev": true
|
||||
},
|
||||
"uid-number": {
|
||||
"version": "0.0.6",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=",
|
||||
"dev": true
|
||||
},
|
||||
"umask": {
|
||||
"version": "1.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0=",
|
||||
"dev": true
|
||||
},
|
||||
"unique-filename": {
|
||||
"version": "1.1.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21595,7 +21595,7 @@
|
||||
},
|
||||
"unique-slug": {
|
||||
"version": "2.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21604,7 +21604,7 @@
|
||||
},
|
||||
"unique-string": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21613,19 +21613,19 @@
|
||||
},
|
||||
"unpipe": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
|
||||
"dev": true
|
||||
},
|
||||
"unzip-response": {
|
||||
"version": "2.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=",
|
||||
"dev": true
|
||||
},
|
||||
"update-notifier": {
|
||||
"version": "2.5.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21643,7 +21643,7 @@
|
||||
},
|
||||
"url-parse-lax": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21652,19 +21652,19 @@
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
|
||||
"dev": true
|
||||
},
|
||||
"util-extend": {
|
||||
"version": "1.0.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=",
|
||||
"dev": true
|
||||
},
|
||||
"util-promisify": {
|
||||
"version": "2.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21673,13 +21673,13 @@
|
||||
},
|
||||
"uuid": {
|
||||
"version": "3.3.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==",
|
||||
"dev": true
|
||||
},
|
||||
"validate-npm-package-license": {
|
||||
"version": "3.0.4",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21689,7 +21689,7 @@
|
||||
},
|
||||
"validate-npm-package-name": {
|
||||
"version": "3.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21698,7 +21698,7 @@
|
||||
},
|
||||
"verror": {
|
||||
"version": "1.10.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21709,7 +21709,7 @@
|
||||
},
|
||||
"wcwidth": {
|
||||
"version": "1.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21718,7 +21718,7 @@
|
||||
},
|
||||
"which": {
|
||||
"version": "1.3.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21727,13 +21727,13 @@
|
||||
},
|
||||
"which-module": {
|
||||
"version": "2.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
|
||||
"dev": true
|
||||
},
|
||||
"wide-align": {
|
||||
"version": "1.1.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21742,7 +21742,7 @@
|
||||
"dependencies": {
|
||||
"string-width": {
|
||||
"version": "1.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21755,7 +21755,7 @@
|
||||
},
|
||||
"widest-line": {
|
||||
"version": "2.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21764,7 +21764,7 @@
|
||||
},
|
||||
"worker-farm": {
|
||||
"version": "1.7.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21773,7 +21773,7 @@
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"version": "5.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21784,19 +21784,19 @@
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "4.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
||||
"dev": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "2.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
|
||||
"dev": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "3.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21807,7 +21807,7 @@
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "5.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21818,13 +21818,13 @@
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"dev": true
|
||||
},
|
||||
"write-file-atomic": {
|
||||
"version": "2.4.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21835,31 +21835,31 @@
|
||||
},
|
||||
"xdg-basedir": {
|
||||
"version": "3.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=",
|
||||
"dev": true
|
||||
},
|
||||
"xtend": {
|
||||
"version": "4.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
|
||||
"dev": true
|
||||
},
|
||||
"y18n": {
|
||||
"version": "4.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
|
||||
"dev": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
|
||||
"dev": true
|
||||
},
|
||||
"yargs": {
|
||||
"version": "14.2.3",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21878,13 +21878,13 @@
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "4.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
|
||||
"dev": true
|
||||
},
|
||||
"find-up": {
|
||||
"version": "3.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21893,13 +21893,13 @@
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "2.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
|
||||
"dev": true
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21909,7 +21909,7 @@
|
||||
},
|
||||
"p-limit": {
|
||||
"version": "2.3.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21918,7 +21918,7 @@
|
||||
},
|
||||
"p-locate": {
|
||||
"version": "3.0.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21927,13 +21927,13 @@
|
||||
},
|
||||
"p-try": {
|
||||
"version": "2.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
|
||||
"dev": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "3.1.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21944,7 +21944,7 @@
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "5.2.0",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21955,7 +21955,7 @@
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "15.0.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -21965,7 +21965,7 @@
|
||||
"dependencies": {
|
||||
"camelcase": {
|
||||
"version": "5.3.1",
|
||||
"resolved": false,
|
||||
"resolved": "",
|
||||
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
|
||||
"dev": true
|
||||
}
|
||||
@@ -24779,6 +24779,12 @@
|
||||
"prop-types": "^15.6.2"
|
||||
}
|
||||
},
|
||||
"reactifex": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/reactifex/-/reactifex-1.1.1.tgz",
|
||||
"integrity": "sha512-HH2N/b5tRxh7ypIgCRsiBl/CTxRkTEPf9DhIstaM6hne4WiwM5/bBbWuvVlRZc/i3FdqZED3pZ//6n4mtxma4w==",
|
||||
"dev": true
|
||||
},
|
||||
"read-pkg": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@edx/frontend-app-gradebook",
|
||||
"version": "1.4.39",
|
||||
"version": "1.4.43",
|
||||
"description": "edx editable gradebook-ui to manipulate grade overrides on subsections",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -10,6 +10,7 @@
|
||||
"build": "fedx-scripts webpack",
|
||||
"coveralls": "cat ./coverage/lcov.info | coveralls",
|
||||
"is-es5": "es-check es5 ./dist/*.js",
|
||||
"i18n_extract": "BABEL_ENV=i18n fedx-scripts babel src --quiet > /dev/null",
|
||||
"lint": "fedx-scripts eslint --ext .jsx,.js src/",
|
||||
"lint-fix": "fedx-scripts eslint --fix --ext .jsx,.js src/",
|
||||
"prepush": "npm run lint",
|
||||
@@ -75,6 +76,7 @@
|
||||
"jest": "24.9.0",
|
||||
"react-dev-utils": "^5.0.3",
|
||||
"react-test-renderer": "^16.10.1",
|
||||
"reactifex": "1.1.1",
|
||||
"redux-mock-store": "^1.5.3",
|
||||
"semantic-release": "^17.2.3",
|
||||
"travis-deploy-once": "^5.0.11"
|
||||
|
||||
36
src/App.jsx
Executable file
36
src/App.jsx
Executable file
@@ -0,0 +1,36 @@
|
||||
import React from 'react';
|
||||
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
|
||||
import { Provider } from 'react-redux';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
|
||||
import Footer from '@edx/frontend-component-footer';
|
||||
|
||||
import { routePath } from 'data/constants/app';
|
||||
import store from 'data/store';
|
||||
import GradebookPage from 'containers/GradebookPage';
|
||||
import EdxHeader from 'components/EdxHeader';
|
||||
import './App.scss';
|
||||
|
||||
const App = () => (
|
||||
<IntlProvider locale="en">
|
||||
<Provider store={store}>
|
||||
<Router>
|
||||
<div>
|
||||
<EdxHeader />
|
||||
<main>
|
||||
<Switch>
|
||||
<Route
|
||||
exact
|
||||
path={routePath}
|
||||
component={GradebookPage}
|
||||
/>
|
||||
</Switch>
|
||||
</main>
|
||||
<Footer logo={process.env.LOGO_POWERED_BY_OPEN_EDX_URL_SVG} />
|
||||
</div>
|
||||
</Router>
|
||||
</Provider>
|
||||
</IntlProvider>
|
||||
);
|
||||
|
||||
export default App;
|
||||
86
src/App.test.jsx
Normal file
86
src/App.test.jsx
Normal file
@@ -0,0 +1,86 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
|
||||
import { Provider } from 'react-redux';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
|
||||
import Footer from '@edx/frontend-component-footer';
|
||||
|
||||
import { routePath } from 'data/constants/app';
|
||||
import store from 'data/store';
|
||||
import GradebookPage from 'containers/GradebookPage';
|
||||
import EdxHeader from 'components/EdxHeader';
|
||||
|
||||
import App from './App';
|
||||
|
||||
jest.mock('react-router-dom', () => ({
|
||||
BrowserRouter: () => 'BrowserRouter',
|
||||
Route: () => 'Route',
|
||||
Switch: () => 'Switch',
|
||||
}));
|
||||
jest.mock('react-redux', () => ({
|
||||
Provider: () => 'Provider',
|
||||
}));
|
||||
jest.mock('react-intl', () => ({
|
||||
IntlProvider: () => 'IntlProvider',
|
||||
}));
|
||||
jest.mock('data/constants/app', () => ({
|
||||
routePath: '/:courseId',
|
||||
}));
|
||||
jest.mock('@edx/frontend-component-footer', () => 'Footer');
|
||||
jest.mock('data/store', () => 'testStore');
|
||||
jest.mock('containers/GradebookPage', () => 'GradebookPage');
|
||||
jest.mock('components/EdxHeader', () => 'EdxHeader');
|
||||
|
||||
const logo = 'fakeLogo.png';
|
||||
let el;
|
||||
let router;
|
||||
|
||||
describe('App router component', () => {
|
||||
test('snapshot', () => {
|
||||
expect(shallow(<App />)).toMatchSnapshot();
|
||||
});
|
||||
describe('component', () => {
|
||||
beforeEach(() => {
|
||||
process.env.LOGO_POWERED_BY_OPEN_EDX_URL_SVG = logo;
|
||||
el = shallow(<App />);
|
||||
router = el.childAt(0).childAt(0);
|
||||
});
|
||||
describe('IntlProvider', () => {
|
||||
test('outer-wrapper component', () => {
|
||||
expect(el.type()).toBe(IntlProvider);
|
||||
});
|
||||
test('"en" locale', () => {
|
||||
expect(el.props().locale).toEqual('en');
|
||||
});
|
||||
});
|
||||
describe('Provider, inside IntlProvider', () => {
|
||||
test('first child, passed the redux store props', () => {
|
||||
expect(el.childAt(0).type()).toBe(Provider);
|
||||
expect(el.childAt(0).props().store).toEqual(store);
|
||||
});
|
||||
});
|
||||
describe('Router', () => {
|
||||
test('first child of Provider', () => {
|
||||
expect(router.type()).toBe(Router);
|
||||
});
|
||||
test('EdxHeader is above/outside-of the routing', () => {
|
||||
expect(router.childAt(0).childAt(0).type()).toBe(EdxHeader);
|
||||
expect(router.childAt(0).childAt(1).type()).toBe('main');
|
||||
});
|
||||
test('Routing - GradebookPage is only route', () => {
|
||||
expect(router.find('main')).toEqual(shallow(
|
||||
<main>
|
||||
<Switch>
|
||||
<Route exact path={routePath} component={GradebookPage} />
|
||||
</Switch>
|
||||
</main>,
|
||||
));
|
||||
});
|
||||
});
|
||||
test('Footer logo drawn from env variable', () => {
|
||||
expect(router.find(Footer).props().logo).toEqual(logo);
|
||||
});
|
||||
});
|
||||
});
|
||||
27
src/__snapshots__/App.test.jsx.snap
Normal file
27
src/__snapshots__/App.test.jsx.snap
Normal file
@@ -0,0 +1,27 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`App router component snapshot 1`] = `
|
||||
<IntlProvider
|
||||
locale="en"
|
||||
>
|
||||
<Provider
|
||||
store="testStore"
|
||||
>
|
||||
<BrowserRouter>
|
||||
<div>
|
||||
<EdxHeader />
|
||||
<main>
|
||||
<Switch>
|
||||
<Route
|
||||
component="GradebookPage"
|
||||
exact={true}
|
||||
path="/:courseId"
|
||||
/>
|
||||
</Switch>
|
||||
</main>
|
||||
<Footer />
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
</Provider>
|
||||
</IntlProvider>
|
||||
`;
|
||||
@@ -1,20 +1,22 @@
|
||||
/* eslint-disable react/sort-comp, react/button-has-type */
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { Alert } from '@edx/paragon';
|
||||
|
||||
import * as appConstants from 'data/constants/app';
|
||||
import selectors from 'data/selectors';
|
||||
|
||||
const { messages: { BulkManagementTab: messages } } = appConstants;
|
||||
import messages from './messages';
|
||||
|
||||
/**
|
||||
* <BulkManagementAlerts />
|
||||
* Alerts to display at the top of the BulkManagement tab
|
||||
*/
|
||||
export const BulkManagementAlerts = ({ bulkImportError, uploadSuccess }) => (
|
||||
export const BulkManagementAlerts = ({
|
||||
bulkImportError,
|
||||
uploadSuccess,
|
||||
}) => (
|
||||
<>
|
||||
<Alert
|
||||
variant="danger"
|
||||
@@ -28,7 +30,7 @@ export const BulkManagementAlerts = ({ bulkImportError, uploadSuccess }) => (
|
||||
show={uploadSuccess}
|
||||
dismissible={false}
|
||||
>
|
||||
{messages.successDialog}
|
||||
<FormattedMessage {...messages.successDialog} />
|
||||
</Alert>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { Alert } from '@edx/paragon';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import selectors from 'data/selectors';
|
||||
import * as appConstants from 'data/constants/app';
|
||||
import messages from './messages';
|
||||
|
||||
import { BulkManagementAlerts, mapStateToProps } from './BulkManagementAlerts';
|
||||
|
||||
jest.mock('@edx/frontend-platform/i18n', () => ({
|
||||
defineMessages: m => m,
|
||||
FormattedMessage: () => 'FormattedMessage',
|
||||
}));
|
||||
jest.mock('@edx/paragon', () => ({
|
||||
Alert: () => 'Alert',
|
||||
}));
|
||||
@@ -61,8 +66,8 @@ describe('BulkManagementAlerts', () => {
|
||||
});
|
||||
test('open success alert with messages.successDialog content', () => {
|
||||
expect(el.childAt(1).is(Alert)).toEqual(true);
|
||||
expect(el.childAt(1).children().text()).toEqual(
|
||||
appConstants.messages.BulkManagementTab.successDialog,
|
||||
expect(el.childAt(1).children().getElement()).toEqual(
|
||||
<FormattedMessage {...messages.successDialog} />,
|
||||
);
|
||||
expect(el.childAt(1).props().show).toEqual(true);
|
||||
});
|
||||
|
||||
@@ -3,6 +3,8 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
@@ -10,11 +12,9 @@ import {
|
||||
FormGroup,
|
||||
} from '@edx/paragon';
|
||||
|
||||
import { messages } from 'data/constants/app';
|
||||
import selectors from 'data/selectors';
|
||||
import thunkActions from 'data/thunkActions';
|
||||
|
||||
const { csvUploadLabel, importBtnText } = messages.BulkManagementTab;
|
||||
import messages from './messages';
|
||||
|
||||
/**
|
||||
* <FileUploadForm />
|
||||
@@ -56,14 +56,15 @@ export class FileUploadForm extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { gradeExportUrl } = this.props;
|
||||
return (
|
||||
<>
|
||||
<Form action={this.props.gradeExportUrl} method="post">
|
||||
<Form action={gradeExportUrl} method="post">
|
||||
<FormGroup controlId="csv">
|
||||
<FormControl
|
||||
className="d-none"
|
||||
type="file"
|
||||
label={csvUploadLabel}
|
||||
label={<FormattedMessage {...messages.csvUploadLabel} />}
|
||||
onChange={this.handleFileInputChange}
|
||||
ref={this.fileInputRef}
|
||||
/>
|
||||
@@ -71,7 +72,7 @@ export class FileUploadForm extends React.Component {
|
||||
</Form>
|
||||
|
||||
<Button variant="primary" onClick={this.handleClickImportGrades}>
|
||||
{importBtnText}
|
||||
<FormattedMessage {...messages.importBtnText} />
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,23 +1,25 @@
|
||||
/* eslint-disable import/no-named-as-default */
|
||||
import React from 'react';
|
||||
import { shallow, mount } from 'enzyme';
|
||||
import { shallow } from 'enzyme';
|
||||
import TestRenderer from 'react-test-renderer';
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
FormControl,
|
||||
FormGroup,
|
||||
} from '@edx/paragon';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import selectors from 'data/selectors';
|
||||
import thunkActions from 'data/thunkActions';
|
||||
import * as appConstants from 'data/constants/app';
|
||||
|
||||
import { FileUploadForm, mapStateToProps, mapDispatchToProps } from './FileUploadForm';
|
||||
|
||||
const {
|
||||
messages: { BulkManagementTab: messages },
|
||||
} = appConstants;
|
||||
import messages from './messages';
|
||||
|
||||
jest.mock('@edx/frontend-platform/i18n', () => ({
|
||||
defineMessages: m => m,
|
||||
FormattedMessage: () => 'FormattedMessage',
|
||||
}));
|
||||
jest.mock('data/selectors', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
@@ -39,10 +41,16 @@ jest.mock('data/thunkActions', () => ({
|
||||
jest.mock('./BulkManagementAlerts', () => 'BulkManagementAlerts');
|
||||
jest.mock('./ResultsSummary', () => 'ResultsSummary');
|
||||
|
||||
const mockRef = { click: jest.fn(), files: [] };
|
||||
|
||||
describe('FileUploadForm', () => {
|
||||
beforeEach(() => {
|
||||
mockRef.click.mockClear();
|
||||
});
|
||||
describe('component', () => {
|
||||
let props;
|
||||
let el;
|
||||
let inst;
|
||||
beforeEach(() => {
|
||||
props = {
|
||||
gradeExportUrl: 'fakeUrl',
|
||||
@@ -71,87 +79,105 @@ describe('FileUploadForm', () => {
|
||||
});
|
||||
describe('render', () => {
|
||||
beforeEach(() => {
|
||||
el = mount(<FileUploadForm {...props} />);
|
||||
el = TestRenderer.create(
|
||||
<FileUploadForm {...props} />,
|
||||
{ createNodeMock: () => mockRef },
|
||||
);
|
||||
inst = el.root;
|
||||
});
|
||||
describe('alert form', () => {
|
||||
let form;
|
||||
beforeEach(() => {
|
||||
form = el.find(Form);
|
||||
form = inst.findByType(Form);
|
||||
});
|
||||
test('post action points to gradeExportUrl', () => {
|
||||
expect(form.props().action).toEqual(props.gradeExportUrl);
|
||||
expect(form.props().method).toEqual('post');
|
||||
expect(form.props.action).toEqual(props.gradeExportUrl);
|
||||
expect(form.props.method).toEqual('post');
|
||||
});
|
||||
describe('file input', () => {
|
||||
let formGroup;
|
||||
beforeEach(() => {
|
||||
formGroup = el.find(FormGroup);
|
||||
formGroup = inst.findByType(FormGroup);
|
||||
});
|
||||
test('group with controlId="csv"', () => {
|
||||
expect(formGroup.props().controlId).toEqual('csv');
|
||||
expect(formGroup.props.controlId).toEqual('csv');
|
||||
});
|
||||
test('file control with onChange from handleFileInputChange', () => {
|
||||
const control = el.find(FormControl);
|
||||
const control = inst.findByType(FormControl);
|
||||
expect(
|
||||
control.props().onChange,
|
||||
).toEqual(el.instance().handleFileInputChange);
|
||||
control.props.onChange,
|
||||
).toEqual(el.getInstance().handleFileInputChange);
|
||||
});
|
||||
test('fileInputRef points to control', () => {
|
||||
expect(el.find(FormControl).getElement().ref).toBe(el.instance().fileInputRef);
|
||||
expect(
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
inst.findByType(FormControl)._fiber.ref,
|
||||
).toEqual(el.getInstance().fileInputRef);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('import button', () => {
|
||||
let btn;
|
||||
beforeEach(() => {
|
||||
btn = el.find(Button);
|
||||
btn = inst.findByType(Button);
|
||||
});
|
||||
test('handleClickImportGrade on click', () => {
|
||||
expect(btn.props().onClick).toEqual(el.instance().handleClickImportGrades);
|
||||
expect(btn.props.onClick).toEqual(el.getInstance().handleClickImportGrades);
|
||||
});
|
||||
test('text from messages.importBtn', () => {
|
||||
expect(btn.children().text()).toEqual(messages.importBtnText);
|
||||
const messageEl = btn.findByType(FormattedMessage);
|
||||
expect(messageEl.props).toEqual(messages.importBtnText);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('fileInput helper', () => {
|
||||
test('links to fileInputRef.current', () => {
|
||||
el = TestRenderer.create(
|
||||
<FileUploadForm {...props} />,
|
||||
{ createNodeMock: () => mockRef },
|
||||
);
|
||||
expect(el.getInstance().fileInput).not.toEqual(undefined);
|
||||
expect(el.getInstance().fileInput).toEqual(el.getInstance().fileInputRef.current);
|
||||
});
|
||||
});
|
||||
describe('behavior', () => {
|
||||
let fileInput;
|
||||
beforeEach(() => {
|
||||
el = mount(<FileUploadForm {...props} />);
|
||||
fileInput = jest.spyOn(el.instance(), 'fileInput', 'get');
|
||||
el = TestRenderer.create(
|
||||
<FileUploadForm {...props} />,
|
||||
{ createNodeMock: () => mockRef },
|
||||
);
|
||||
fileInput = jest.spyOn(el.getInstance(), 'fileInput', 'get');
|
||||
});
|
||||
describe('handleFileInputChange', () => {
|
||||
it('does nothing (does not fail) if fileInput has not loaded', () => {
|
||||
fileInput.mockReturnValue(null);
|
||||
el.instance().handleClickImportGrades();
|
||||
el.getInstance().handleClickImportGrades();
|
||||
expect(mockRef.click).not.toHaveBeenCalled();
|
||||
});
|
||||
it('calls fileInput.click if is loaded', () => {
|
||||
const click = jest.fn();
|
||||
fileInput.mockReturnValue({ click });
|
||||
el.instance().handleClickImportGrades();
|
||||
expect(click).toHaveBeenCalled();
|
||||
el.getInstance().handleClickImportGrades();
|
||||
expect(mockRef.click).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
describe('handleClickImportGrades', () => {
|
||||
it('does nothing if file input has not loaded with files', () => {
|
||||
fileInput.mockReturnValue(null);
|
||||
el.instance().handleFileInputChange();
|
||||
el.getInstance().handleFileInputChange();
|
||||
expect(props.submitFileUploadFormData).not.toHaveBeenCalled();
|
||||
fileInput.mockReturnValue({ files: [] });
|
||||
el.instance().handleFileInputChange();
|
||||
el.getInstance().handleFileInputChange();
|
||||
expect(props.submitFileUploadFormData).not.toHaveBeenCalled();
|
||||
});
|
||||
it('calls submitFileUploadFormData and then clears fileInput if has files', () => {
|
||||
fileInput.mockReturnValue({ files: ['some', 'files'], value: 'a value' });
|
||||
const formData = { fake: 'form data' };
|
||||
jest.spyOn(el.instance(), 'formData', 'get').mockReturnValue(formData);
|
||||
jest.spyOn(el.getInstance(), 'formData', 'get').mockReturnValue(formData);
|
||||
const submit = jest.fn(() => ({ then: (thenCB) => { thenCB(); } }));
|
||||
el.setProps({
|
||||
submitFileUploadFormData: submit,
|
||||
});
|
||||
el.instance().handleFileInputChange();
|
||||
el.update(<FileUploadForm {...props} submitFileUploadFormData={submit} />);
|
||||
el.getInstance().handleFileInputChange();
|
||||
expect(submit).toHaveBeenCalledWith(formData);
|
||||
expect(el.instance().fileInput.value).toEqual(null);
|
||||
expect(el.getInstance().fileInput.value).toEqual(null);
|
||||
});
|
||||
});
|
||||
describe('formData', () => {
|
||||
@@ -161,7 +187,7 @@ describe('FileUploadForm', () => {
|
||||
fileInput.mockReturnValue({ files: [file], value });
|
||||
const expected = new FormData();
|
||||
expected.append('csv', file);
|
||||
expect([...el.instance().formData.entries()]).toEqual([...expected.entries()]);
|
||||
expect([...el.getInstance().formData.entries()]).toEqual([...expected.entries()]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,11 +3,14 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
import { Table } from '@edx/paragon';
|
||||
|
||||
import { bulkManagementColumns, messages } from 'data/constants/app';
|
||||
import { bulkManagementColumns } from 'data/constants/app';
|
||||
import selectors from 'data/selectors';
|
||||
|
||||
import ResultsSummary from './ResultsSummary';
|
||||
import messages from './messages';
|
||||
|
||||
export const mapHistoryRows = ({
|
||||
resultsSummary,
|
||||
@@ -21,19 +24,19 @@ export const mapHistoryRows = ({
|
||||
...rest,
|
||||
});
|
||||
|
||||
const { hints } = messages.BulkManagementTab;
|
||||
|
||||
/**
|
||||
* <HistoryTable />
|
||||
* Table with history of bulk management uploads, including a results summary which
|
||||
* displays total, skipped, and failed uploads
|
||||
*/
|
||||
export const HistoryTable = ({ bulkManagementHistory }) => (
|
||||
export const HistoryTable = ({
|
||||
bulkManagementHistory,
|
||||
}) => (
|
||||
<>
|
||||
<p>
|
||||
{hints[0]}
|
||||
<FormattedMessage {...messages.hint1} />
|
||||
<br />
|
||||
{hints[1]}
|
||||
<FormattedMessage {...messages.hint2} />
|
||||
</p>
|
||||
|
||||
<Table
|
||||
@@ -55,7 +58,6 @@ HistoryTable.propTypes = {
|
||||
timeUploaded: PropTypes.string.isRequired,
|
||||
resultsSummary: PropTypes.shape({
|
||||
rowId: PropTypes.number.isRequired,
|
||||
courseId: PropTypes.string.isRequired,
|
||||
text: PropTypes.string.isRequired,
|
||||
}),
|
||||
})),
|
||||
|
||||
@@ -2,13 +2,19 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { Table } from '@edx/paragon';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import selectors from 'data/selectors';
|
||||
import { bulkManagementColumns, messages } from 'data/constants/app';
|
||||
import { bulkManagementColumns } from 'data/constants/app';
|
||||
|
||||
import ResultsSummary from './ResultsSummary';
|
||||
import { HistoryTable, mapStateToProps } from './HistoryTable';
|
||||
import messages from './messages';
|
||||
|
||||
jest.mock('@edx/frontend-platform/i18n', () => ({
|
||||
defineMessages: m => m,
|
||||
FormattedMessage: () => 'FormattedMessage',
|
||||
}));
|
||||
jest.mock('@edx/paragon', () => ({
|
||||
Table: () => 'Table',
|
||||
}));
|
||||
@@ -61,9 +67,9 @@ describe('HistoryTable', () => {
|
||||
});
|
||||
test('hints with break in between', () => {
|
||||
const hints = el.find('p');
|
||||
expect(hints.childAt(0).text()).toEqual(messages.BulkManagementTab.hints[0]);
|
||||
expect(hints.childAt(0).getElement()).toEqual(<FormattedMessage {...messages.hint1} />);
|
||||
expect(hints.childAt(1).is('br')).toEqual(true);
|
||||
expect(hints.childAt(2).text()).toEqual(messages.BulkManagementTab.hints[1]);
|
||||
expect(hints.childAt(2).getElement()).toEqual(<FormattedMessage {...messages.hint2} />);
|
||||
});
|
||||
describe('history table', () => {
|
||||
let table;
|
||||
|
||||
@@ -5,7 +5,7 @@ import PropTypes from 'prop-types';
|
||||
import { Hyperlink, Icon } from '@edx/paragon';
|
||||
import { Download } from '@edx/paragon/icons';
|
||||
|
||||
import { bulkGradesUrlByCourseAndRow } from 'data/constants/api';
|
||||
import lms from 'data/services/lms';
|
||||
|
||||
/**
|
||||
* <ResultsSummary {...{ courseId, rowId, text }} />
|
||||
@@ -15,12 +15,11 @@ import { bulkGradesUrlByCourseAndRow } from 'data/constants/api';
|
||||
* @param {string} text - summary string
|
||||
*/
|
||||
const ResultsSummary = ({
|
||||
courseId,
|
||||
rowId,
|
||||
text,
|
||||
}) => (
|
||||
<Hyperlink
|
||||
href={bulkGradesUrlByCourseAndRow(courseId, rowId)}
|
||||
href={lms.urls.bulkGradesUrlByRow(rowId)}
|
||||
destination="www.edx.org"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
@@ -32,7 +31,6 @@ const ResultsSummary = ({
|
||||
);
|
||||
|
||||
ResultsSummary.propTypes = {
|
||||
courseId: PropTypes.string.isRequired,
|
||||
rowId: PropTypes.number.isRequired,
|
||||
text: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@ import { shallow } from 'enzyme';
|
||||
import { Icon } from '@edx/paragon';
|
||||
import { Download } from '@edx/paragon/icons';
|
||||
|
||||
import * as api from 'data/constants/api';
|
||||
import lms from 'data/services/lms';
|
||||
import ResultsSummary from './ResultsSummary';
|
||||
|
||||
jest.mock('@edx/paragon', () => ({
|
||||
@@ -14,13 +14,14 @@ jest.mock('@edx/paragon', () => ({
|
||||
jest.mock('@edx/paragon/icons', () => ({
|
||||
Download: 'DownloadIcon',
|
||||
}));
|
||||
jest.mock('data/constants/api', () => ({
|
||||
bulkGradesUrlByCourseAndRow: jest.fn((courseId, rowId) => ({ url: { courseId, rowId } })),
|
||||
jest.mock('data/services/lms', () => ({
|
||||
urls: {
|
||||
bulkGradesUrlByRow: jest.fn((rowId) => ({ url: { rowId } })),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('ResultsSummary component', () => {
|
||||
const props = {
|
||||
courseId: 'classy',
|
||||
rowId: 42,
|
||||
text: 'texty',
|
||||
};
|
||||
@@ -41,7 +42,7 @@ describe('ResultsSummary component', () => {
|
||||
expect(el.props().rel).toEqual('noopener noreferrer');
|
||||
});
|
||||
test('Hyperlink has href to bulkGradesUrl', () => {
|
||||
expect(el.props().href).toEqual(api.bulkGradesUrlByCourseAndRow(props.courseId, props.rowId));
|
||||
expect(el.props().href).toEqual(lms.urls.bulkGradesUrlByRow(props.rowId));
|
||||
});
|
||||
test('displays Download Icon and text', () => {
|
||||
const icon = el.childAt(0);
|
||||
|
||||
@@ -12,7 +12,11 @@ exports[`BulkManagementAlerts component no errer, no upload success snapshot - b
|
||||
show={false}
|
||||
variant="success"
|
||||
>
|
||||
CSV processing. File uploads may take several minutes to complete.
|
||||
<FormattedMessage
|
||||
defaultMessage="CSV processing. File uploads may take several minutes to complete."
|
||||
description="Success Dialog message in BulkManagement Tab File Upload Form"
|
||||
id="gradebook.BulkManagementTab.successDialog"
|
||||
/>
|
||||
</Alert>
|
||||
</Fragment>
|
||||
`;
|
||||
@@ -31,7 +35,11 @@ exports[`BulkManagementAlerts component no errer, no upload success snapshot - d
|
||||
show={true}
|
||||
variant="success"
|
||||
>
|
||||
CSV processing. File uploads may take several minutes to complete.
|
||||
<FormattedMessage
|
||||
defaultMessage="CSV processing. File uploads may take several minutes to complete."
|
||||
description="Success Dialog message in BulkManagement Tab File Upload Form"
|
||||
id="gradebook.BulkManagementTab.successDialog"
|
||||
/>
|
||||
</Alert>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
@@ -16,7 +16,13 @@ exports[`FileUploadForm component snapshot snapshot - loads export form w/ alert
|
||||
<ForwardRef
|
||||
as="input"
|
||||
className="d-none"
|
||||
label="Upload Grade CSV"
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Upload Grade CSV"
|
||||
description="Button in BulkManagementTab Alerts"
|
||||
id="gradebook.BulkManagementTab.csvUploadLabel"
|
||||
/>
|
||||
}
|
||||
onChange={[MockFunction this.handleFileInputChange]}
|
||||
plaintext={false}
|
||||
type="file"
|
||||
@@ -29,7 +35,11 @@ exports[`FileUploadForm component snapshot snapshot - loads export form w/ alert
|
||||
onClick={[MockFunction this.handleClickImportGrades]}
|
||||
variant="primary"
|
||||
>
|
||||
Import Grades
|
||||
<FormattedMessage
|
||||
defaultMessage="Import Grades"
|
||||
description="Button in BulkManagement Tab File Upload Form"
|
||||
id="gradebook.BulkManagementTab.importBtnText"
|
||||
/>
|
||||
</ForwardRef>
|
||||
</React.Fragment>
|
||||
`;
|
||||
|
||||
@@ -44,9 +44,17 @@ Array [
|
||||
exports[`HistoryTable component snapshot snapshot - loads hints display, formatted table 1`] = `
|
||||
<Fragment>
|
||||
<p>
|
||||
Results appear in the table below.
|
||||
<FormattedMessage
|
||||
defaultMessage="Results appear in the table below."
|
||||
description="Hint text on BulkManagement Tab History Table"
|
||||
id="gradebook.BulkManagementTab.hint1"
|
||||
/>
|
||||
<br />
|
||||
Grade processing may take a few seconds.
|
||||
<FormattedMessage
|
||||
defaultMessage="Grade processing may take a few seconds."
|
||||
description="Hint text on BulkManagement Tab History Table"
|
||||
id="gradebook.BulkManagementTab.hint2"
|
||||
/>
|
||||
</p>
|
||||
<Table
|
||||
className="table-striped"
|
||||
|
||||
@@ -6,7 +6,6 @@ exports[`ResultsSummary component snapshot - safe hyperlink with bulkGradesUrl w
|
||||
href={
|
||||
Object {
|
||||
"url": Object {
|
||||
"courseId": "classy",
|
||||
"rowId": 42,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
exports[`BulkManagementTab component snapshot snapshot - loads heading from messages.BulkManagementTab.heading, <BulkManagementAlerts />, <FileUploadForm />, <HistoryTable /> 1`] = `
|
||||
<div>
|
||||
<h4>
|
||||
Use this feature by downloading a CSV for bulk management, overriding grades locally, and coming back here to upload.
|
||||
<FormattedMessage
|
||||
defaultMessage="Use this feature by downloading a CSV for bulk management, overriding grades locally, and coming back here to upload."
|
||||
description="Heading text for BulkManagement Tab"
|
||||
id="gradebook.BulkManagementTab.heading"
|
||||
/>
|
||||
</h4>
|
||||
<BulkManagementAlerts />
|
||||
<FileUploadForm />
|
||||
@@ -1,7 +1,8 @@
|
||||
/* eslint-disable react/button-has-type, import/no-named-as-default */
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { messages } from 'data/constants/app';
|
||||
import messages from './messages';
|
||||
import BulkManagementAlerts from './BulkManagementAlerts';
|
||||
import FileUploadForm from './FileUploadForm';
|
||||
import HistoryTable from './HistoryTable';
|
||||
@@ -12,7 +13,7 @@ import HistoryTable from './HistoryTable';
|
||||
*/
|
||||
export const BulkManagementTab = () => (
|
||||
<div>
|
||||
<h4>{messages.BulkManagementTab.heading}</h4>
|
||||
<h4><FormattedMessage {...(messages.heading)} /></h4>
|
||||
<BulkManagementAlerts />
|
||||
<FileUploadForm />
|
||||
<HistoryTable />
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
/* eslint-disable import/no-named-as-default */
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { messages } from 'data/constants/app';
|
||||
import { BulkManagementTab } from '.';
|
||||
import BulkManagementAlerts from './BulkManagementAlerts';
|
||||
import FileUploadForm from './FileUploadForm';
|
||||
import HistoryTable from './HistoryTable';
|
||||
import messages from './messages';
|
||||
|
||||
jest.mock('./BulkManagementAlerts', () => 'BulkManagementAlerts');
|
||||
jest.mock('./FileUploadForm', () => 'FileUploadForm');
|
||||
@@ -30,7 +31,11 @@ describe('BulkManagementTab', () => {
|
||||
});
|
||||
test('heading - h4 loaded from messages', () => {
|
||||
const heading = el.find('h4');
|
||||
expect(heading.text()).toEqual(messages.BulkManagementTab.heading);
|
||||
expect(heading.getElement()).toEqual((
|
||||
<h4>
|
||||
<FormattedMessage {...messages.heading} />
|
||||
</h4>
|
||||
));
|
||||
});
|
||||
test('heading, then alerts, then upload form, then table', () => {
|
||||
expect(el.childAt(0).is('h4')).toEqual(true);
|
||||
36
src/components/BulkManagementTab/messages.js
Normal file
36
src/components/BulkManagementTab/messages.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
csvUploadLabel: {
|
||||
id: 'gradebook.BulkManagementTab.csvUploadLabel',
|
||||
defaultMessage: 'Upload Grade CSV',
|
||||
description: 'Button in BulkManagementTab Alerts',
|
||||
},
|
||||
heading: {
|
||||
id: 'gradebook.BulkManagementTab.heading',
|
||||
defaultMessage: 'Use this feature by downloading a CSV for bulk management, overriding grades locally, and coming back here to upload.',
|
||||
description: 'Heading text for BulkManagement Tab',
|
||||
},
|
||||
hint1: {
|
||||
id: 'gradebook.BulkManagementTab.hint1',
|
||||
defaultMessage: 'Results appear in the table below.',
|
||||
description: 'Hint text on BulkManagement Tab History Table',
|
||||
},
|
||||
hint2: {
|
||||
id: 'gradebook.BulkManagementTab.hint2',
|
||||
defaultMessage: 'Grade processing may take a few seconds.',
|
||||
description: 'Hint text on BulkManagement Tab History Table',
|
||||
},
|
||||
importBtnText: {
|
||||
id: 'gradebook.BulkManagementTab.importBtnText',
|
||||
defaultMessage: 'Import Grades',
|
||||
description: 'Button in BulkManagement Tab File Upload Form',
|
||||
},
|
||||
successDialog: {
|
||||
id: 'gradebook.BulkManagementTab.successDialog',
|
||||
defaultMessage: 'CSV processing. File uploads may take several minutes to complete.',
|
||||
description: 'Success Dialog message in BulkManagement Tab File Upload Form',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
@@ -7,7 +7,13 @@ exports[`AssignmentFilter Component snapshots basic snapshot 1`] = `
|
||||
<SelectGroup
|
||||
disabled={false}
|
||||
id="assignment"
|
||||
label="Assignment"
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Assignment"
|
||||
description="Assignment filter select label in Gradebook Filters"
|
||||
id="gradebook.GradebookFilters.assignmentFilterLabel"
|
||||
/>
|
||||
}
|
||||
onChange={[MockFunction handleChange]}
|
||||
options={
|
||||
Array [
|
||||
|
||||
@@ -3,10 +3,13 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import selectors from 'data/selectors';
|
||||
import actions from 'data/actions';
|
||||
import thunkActions from 'data/thunkActions';
|
||||
|
||||
import messages from '../messages';
|
||||
import SelectGroup from '../SelectGroup';
|
||||
|
||||
const { fetchGradesIfAssignmentGradeFiltersSet } = thunkActions.grades;
|
||||
@@ -46,7 +49,7 @@ export class AssignmentFilter extends React.Component {
|
||||
<div className="student-filters">
|
||||
<SelectGroup
|
||||
id="assignment"
|
||||
label="Assignment"
|
||||
label={<FormattedMessage {...messages.assignment} />}
|
||||
value={this.props.selectedAssignment}
|
||||
onChange={this.handleChange}
|
||||
disabled={this.props.assignmentFilterOptions.length === 0}
|
||||
@@ -64,7 +67,6 @@ AssignmentFilter.defaultProps = {
|
||||
|
||||
AssignmentFilter.propTypes = {
|
||||
updateQueryParams: PropTypes.func.isRequired,
|
||||
|
||||
// redux
|
||||
assignmentFilterOptions: PropTypes.arrayOf(PropTypes.shape({
|
||||
label: PropTypes.string,
|
||||
|
||||
@@ -69,7 +69,6 @@ describe('AssignmentFilter', () => {
|
||||
el = mount(<AssignmentFilter {...props} />);
|
||||
el.instance().handleChange(event);
|
||||
});
|
||||
|
||||
it('calls props.updateAssignmentFilter with selection', () => {
|
||||
expect(props.updateAssignmentFilter).toHaveBeenCalledWith({
|
||||
label: newAssgn,
|
||||
@@ -87,6 +86,30 @@ describe('AssignmentFilter', () => {
|
||||
const method = props.fetchGradesIfAssignmentGradeFiltersSet;
|
||||
expect(method).toHaveBeenCalledWith();
|
||||
});
|
||||
describe('no selected option', () => {
|
||||
const value = 'fake';
|
||||
beforeEach(() => {
|
||||
el = mount(<AssignmentFilter {...props} />);
|
||||
el.instance().handleChange({ target: { value } });
|
||||
});
|
||||
it('calls props.updateAssignmentFilter with selection', () => {
|
||||
expect(props.updateAssignmentFilter).toHaveBeenCalledWith({
|
||||
label: value,
|
||||
type: undefined,
|
||||
id: undefined,
|
||||
});
|
||||
});
|
||||
it('calls props.updateQueryParams with selected assignment id',
|
||||
() => {
|
||||
expect(props.updateQueryParams).toHaveBeenCalledWith({
|
||||
assignment: undefined,
|
||||
});
|
||||
});
|
||||
it('calls props.fetchGradesIfAssignmentGradeFiltersSet', () => {
|
||||
const method = props.fetchGradesIfAssignmentGradeFiltersSet;
|
||||
expect(method).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('snapshots', () => {
|
||||
|
||||
@@ -7,14 +7,26 @@ exports[`AssignmentGradeFilter Component snapshots buttons and groups disabled i
|
||||
<PercentGroup
|
||||
disabled={true}
|
||||
id="assignmentGradeMin"
|
||||
label="Min Grade"
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Min Grade"
|
||||
description="Min-grade filter select label in Gradebook Filters"
|
||||
id="gradebook.GradebookFilters.minGradeFilterLabel"
|
||||
/>
|
||||
}
|
||||
onChange={[MockFunction handleSetMin]}
|
||||
value="2"
|
||||
/>
|
||||
<PercentGroup
|
||||
disabled={true}
|
||||
id="assignmentGradeMax"
|
||||
label="Max Grade"
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Max Grade"
|
||||
description="Max-grade filter select label in Gradebook Filters"
|
||||
id="gradebook.GradebookFilters.maxGradeFilterLabel"
|
||||
/>
|
||||
}
|
||||
onChange={[MockFunction handleSetMax]}
|
||||
value="98"
|
||||
/>
|
||||
@@ -42,14 +54,26 @@ exports[`AssignmentGradeFilter Component snapshots smoke test 1`] = `
|
||||
<PercentGroup
|
||||
disabled={false}
|
||||
id="assignmentGradeMin"
|
||||
label="Min Grade"
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Min Grade"
|
||||
description="Min-grade filter select label in Gradebook Filters"
|
||||
id="gradebook.GradebookFilters.minGradeFilterLabel"
|
||||
/>
|
||||
}
|
||||
onChange={[MockFunction handleSetMin]}
|
||||
value="2"
|
||||
/>
|
||||
<PercentGroup
|
||||
disabled={false}
|
||||
id="assignmentGradeMax"
|
||||
label="Max Grade"
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Max Grade"
|
||||
description="Max-grade filter select label in Gradebook Filters"
|
||||
id="gradebook.GradebookFilters.maxGradeFilterLabel"
|
||||
/>
|
||||
}
|
||||
onChange={[MockFunction handleSetMax]}
|
||||
value="98"
|
||||
/>
|
||||
|
||||
@@ -3,12 +3,14 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
import { Button } from '@edx/paragon';
|
||||
|
||||
import selectors from 'data/selectors';
|
||||
import actions from 'data/actions';
|
||||
import thunkActions from 'data/thunkActions';
|
||||
|
||||
import messages from '../messages';
|
||||
import PercentGroup from '../PercentGroup';
|
||||
|
||||
export class AssignmentGradeFilter extends React.Component {
|
||||
@@ -34,19 +36,21 @@ export class AssignmentGradeFilter extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { assignmentGradeMin, assignmentGradeMax } = this.props.localAssignmentLimits;
|
||||
const {
|
||||
localAssignmentLimits: { assignmentGradeMax, assignmentGradeMin },
|
||||
} = this.props;
|
||||
return (
|
||||
<div className="grade-filter-inputs">
|
||||
<PercentGroup
|
||||
id="assignmentGradeMin"
|
||||
label="Min Grade"
|
||||
label={<FormattedMessage {...messages.minGrade} />}
|
||||
value={assignmentGradeMin}
|
||||
disabled={!this.props.selectedAssignment}
|
||||
onChange={this.handleSetMin}
|
||||
/>
|
||||
<PercentGroup
|
||||
id="assignmentGradeMax"
|
||||
label="Max Grade"
|
||||
label={<FormattedMessage {...messages.maxGrade} />}
|
||||
value={assignmentGradeMax}
|
||||
disabled={!this.props.selectedAssignment}
|
||||
onChange={this.handleSetMax}
|
||||
|
||||
@@ -7,7 +7,13 @@ exports[`AssignmentTypeFilter Component snapshots SelectGroup disabled if no ass
|
||||
<SelectGroup
|
||||
disabled={true}
|
||||
id="assignment-types"
|
||||
label="Assignment Types"
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Assignment Types"
|
||||
description="Assignment Types filter select label in Gradebook Filters"
|
||||
id="gradebook.GradebookFilters.assignmentTypesLabel"
|
||||
/>
|
||||
}
|
||||
onChange={[MockFunction handleChange]}
|
||||
options={
|
||||
Array [
|
||||
@@ -40,7 +46,13 @@ exports[`AssignmentTypeFilter Component snapshots smoke test 1`] = `
|
||||
<SelectGroup
|
||||
disabled={false}
|
||||
id="assignment-types"
|
||||
label="Assignment Types"
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Assignment Types"
|
||||
description="Assignment Types filter select label in Gradebook Filters"
|
||||
id="gradebook.GradebookFilters.assignmentTypesLabel"
|
||||
/>
|
||||
}
|
||||
onChange={[MockFunction handleChange]}
|
||||
options={
|
||||
Array [
|
||||
|
||||
@@ -3,9 +3,13 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import selectors from 'data/selectors';
|
||||
import actions from 'data/actions';
|
||||
|
||||
import SelectGroup from '../SelectGroup';
|
||||
import messages from '../messages';
|
||||
|
||||
export class AssignmentTypeFilter extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -34,7 +38,7 @@ export class AssignmentTypeFilter extends React.Component {
|
||||
<div className="student-filters">
|
||||
<SelectGroup
|
||||
id="assignment-types"
|
||||
label="Assignment Types"
|
||||
label={<FormattedMessage {...messages.assignmentTypes} />}
|
||||
value={this.props.selectedAssignmentType}
|
||||
onChange={this.handleChange}
|
||||
disabled={this.props.assignmentFilterOptions.length === 0}
|
||||
|
||||
@@ -7,13 +7,25 @@ exports[`CourseGradeFilter Component snapshots basic snapshot 1`] = `
|
||||
>
|
||||
<PercentGroup
|
||||
id="minimum-grade"
|
||||
label="Min Grade"
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Min Grade"
|
||||
description="Min-grade filter select label in Gradebook Filters"
|
||||
id="gradebook.GradebookFilters.minGradeFilterLabel"
|
||||
/>
|
||||
}
|
||||
onChange={[MockFunction handleUpdateMin]}
|
||||
value="5"
|
||||
/>
|
||||
<PercentGroup
|
||||
id="maximum-grade"
|
||||
label="Max Grade"
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Max Grade"
|
||||
description="Max-grade filter select label in Gradebook Filters"
|
||||
id="gradebook.GradebookFilters.maxGradeFilterLabel"
|
||||
/>
|
||||
}
|
||||
onChange={[MockFunction handleUpdateMax]}
|
||||
value="92"
|
||||
/>
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Button,
|
||||
} from '@edx/paragon';
|
||||
|
||||
import { Button } from '@edx/paragon';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import selectors from 'data/selectors';
|
||||
import actions from 'data/actions';
|
||||
import thunkActions from 'data/thunkActions';
|
||||
|
||||
import messages from '../messages';
|
||||
import PercentGroup from '../PercentGroup';
|
||||
|
||||
export class CourseGradeFilter extends React.Component {
|
||||
@@ -41,19 +43,21 @@ export class CourseGradeFilter extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { courseGradeMin, courseGradeMax } = this.props.localCourseLimits;
|
||||
const {
|
||||
localCourseLimits: { courseGradeMin, courseGradeMax },
|
||||
} = this.props;
|
||||
return (
|
||||
<>
|
||||
<div className="grade-filter-inputs">
|
||||
<PercentGroup
|
||||
id="minimum-grade"
|
||||
label="Min Grade"
|
||||
label={<FormattedMessage {...messages.minGrade} />}
|
||||
value={courseGradeMin}
|
||||
onChange={this.handleUpdateMin}
|
||||
/>
|
||||
<PercentGroup
|
||||
id="maximum-grade"
|
||||
label="Max Grade"
|
||||
label={<FormattedMessage {...messages.maxGrade} />}
|
||||
value={courseGradeMax}
|
||||
onChange={this.handleUpdateMax}
|
||||
/>
|
||||
|
||||
@@ -30,7 +30,7 @@ PercentGroup.defaultProps = {
|
||||
};
|
||||
PercentGroup.propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
label: PropTypes.node.isRequired,
|
||||
value: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
disabled: PropTypes.bool,
|
||||
|
||||
@@ -23,7 +23,7 @@ const SelectGroup = ({
|
||||
);
|
||||
SelectGroup.propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
label: PropTypes.node.isRequired,
|
||||
value: PropTypes.string.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
disabled: PropTypes.bool,
|
||||
|
||||
@@ -3,10 +3,13 @@ import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import actions from 'data/actions';
|
||||
import selectors from 'data/selectors';
|
||||
import thunkActions from 'data/thunkActions';
|
||||
|
||||
import messages from '../messages';
|
||||
import SelectGroup from '../SelectGroup';
|
||||
|
||||
export const optionFactory = ({ data, defaultOption, key }) => [
|
||||
@@ -28,7 +31,7 @@ export class StudentGroupsFilter extends React.Component {
|
||||
mapCohortsEntries() {
|
||||
return optionFactory({
|
||||
data: this.props.cohorts,
|
||||
defaultOption: 'Cohort-All',
|
||||
defaultOption: this.translate(messages.cohortAll),
|
||||
key: 'id',
|
||||
});
|
||||
}
|
||||
@@ -36,7 +39,7 @@ export class StudentGroupsFilter extends React.Component {
|
||||
mapTracksEntries() {
|
||||
return optionFactory({
|
||||
data: this.props.tracks,
|
||||
defaultOption: 'Track-All',
|
||||
defaultOption: this.translate(messages.trackAll),
|
||||
key: 'slug',
|
||||
});
|
||||
}
|
||||
@@ -65,19 +68,23 @@ export class StudentGroupsFilter extends React.Component {
|
||||
this.props.fetchGrades();
|
||||
}
|
||||
|
||||
translate(message) {
|
||||
return this.props.intl.formatMessage(message);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<SelectGroup
|
||||
id="Tracks"
|
||||
label="Tracks"
|
||||
label={this.translate(messages.tracks)}
|
||||
value={this.props.selectedTrackEntry.name}
|
||||
onChange={this.updateTracks}
|
||||
options={this.mapTracksEntries()}
|
||||
/>
|
||||
<SelectGroup
|
||||
id="Cohorts"
|
||||
label="Cohorts"
|
||||
label={this.translate(messages.cohorts)}
|
||||
value={this.props.selectedCohortEntry.name}
|
||||
disabled={this.props.cohorts.length === 0}
|
||||
onChange={this.updateCohorts}
|
||||
@@ -100,6 +107,9 @@ StudentGroupsFilter.defaultProps = {
|
||||
StudentGroupsFilter.propTypes = {
|
||||
updateQueryParams: PropTypes.func.isRequired,
|
||||
|
||||
// injected
|
||||
intl: intlShape.isRequired,
|
||||
|
||||
// redux
|
||||
cohorts: PropTypes.arrayOf(PropTypes.shape({
|
||||
name: PropTypes.string,
|
||||
@@ -139,4 +149,4 @@ export const mapDispatchToProps = {
|
||||
updateTrack: actions.filters.update.track,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(StudentGroupsFilter);
|
||||
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(StudentGroupsFilter));
|
||||
|
||||
@@ -63,6 +63,7 @@ describe('StudentGroupsFilter', () => {
|
||||
beforeEach(() => {
|
||||
props = {
|
||||
...props,
|
||||
intl: { formatMessage: (msg) => msg.defaultMessage },
|
||||
cohortsByName: {
|
||||
[props.cohorts[0].name]: props.cohorts[0],
|
||||
[props.cohorts[1].name]: props.cohorts[1],
|
||||
|
||||
@@ -22,7 +22,13 @@ exports[`GradebookFilters Component snapshots basic snapshot 1`] = `
|
||||
<Collapsible
|
||||
className="filter-group mb-3"
|
||||
defaultOpen={true}
|
||||
title="Assignments"
|
||||
title={
|
||||
<FormattedMessage
|
||||
defaultMessage="Assignments"
|
||||
description="Assignment filter group label in Gradebook Filters"
|
||||
id="gradebook.GradebookFilters.assignmentsFilterLabel"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div>
|
||||
<Connect(AssignmentTypeFilter)
|
||||
@@ -39,7 +45,13 @@ exports[`GradebookFilters Component snapshots basic snapshot 1`] = `
|
||||
<Collapsible
|
||||
className="filter-group mb-3"
|
||||
defaultOpen={true}
|
||||
title="Overall Grade"
|
||||
title={
|
||||
<FormattedMessage
|
||||
defaultMessage="Overall Grade"
|
||||
description="Overall Grade filter group label in Gradebook Filters"
|
||||
id="gradebook.GradebookFilters.overallGradeFilterLabel"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Connect(CourseGradeFilter)
|
||||
updateQueryParams={[MockFunction]}
|
||||
@@ -48,22 +60,38 @@ exports[`GradebookFilters Component snapshots basic snapshot 1`] = `
|
||||
<Collapsible
|
||||
className="filter-group mb-3"
|
||||
defaultOpen={true}
|
||||
title="Student Groups"
|
||||
title={
|
||||
<FormattedMessage
|
||||
defaultMessage="Student Groups"
|
||||
description="Student Groups filter group label in Gradebook Filters"
|
||||
id="gradebook.GradebookFilters.studentGroupsFilterLabel"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Connect(StudentGroupsFilter)
|
||||
<InjectIntl(ShimmedIntlComponent)
|
||||
updateQueryParams={[MockFunction]}
|
||||
/>
|
||||
</Collapsible>
|
||||
<Collapsible
|
||||
className="filter-group mb-3"
|
||||
defaultOpen={true}
|
||||
title="Include Course Team Members"
|
||||
title={
|
||||
<FormattedMessage
|
||||
defaultMessage="Include Course Team Members"
|
||||
description="Include Course Team Members filter label in Gradebook Filters"
|
||||
id="gradebook.GradebookFilters.includeCourseTeamMembersFilterLabel"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Checkbox
|
||||
checked={true}
|
||||
onChange={[MockFunction handleIncludeTeamMembersChange]}
|
||||
>
|
||||
Include Course Team Members
|
||||
<FormattedMessage
|
||||
defaultMessage="Include Course Team Members"
|
||||
description="Include Course Team Members filter label in Gradebook Filters"
|
||||
id="gradebook.GradebookFilters.includeCourseTeamMembersFilterLabel"
|
||||
/>
|
||||
</Checkbox>
|
||||
</Collapsible>
|
||||
</React.Fragment>
|
||||
|
||||
@@ -10,11 +10,13 @@ import {
|
||||
Form,
|
||||
} from '@edx/paragon';
|
||||
import { Close } from '@edx/paragon/icons';
|
||||
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import actions from 'data/actions';
|
||||
import selectors from 'data/selectors';
|
||||
import thunkActions from 'data/thunkActions';
|
||||
|
||||
import messages from './messages';
|
||||
import AssignmentTypeFilter from './AssignmentTypeFilter';
|
||||
import AssignmentFilter from './AssignmentFilter';
|
||||
import AssignmentGradeFilter from './AssignmentGradeFilter';
|
||||
@@ -39,13 +41,18 @@ export class GradebookFilters extends React.Component {
|
||||
}
|
||||
|
||||
collapsibleGroup = (title, content) => (
|
||||
<Collapsible title={title} defaultOpen className="filter-group mb-3">
|
||||
<Collapsible
|
||||
title={<FormattedMessage {...title} />}
|
||||
defaultOpen
|
||||
className="filter-group mb-3"
|
||||
>
|
||||
{content}
|
||||
</Collapsible>
|
||||
);
|
||||
|
||||
render() {
|
||||
const {
|
||||
intl,
|
||||
updateQueryParams,
|
||||
} = this.props;
|
||||
return (
|
||||
@@ -57,12 +64,12 @@ export class GradebookFilters extends React.Component {
|
||||
onClick={this.props.closeMenu}
|
||||
iconAs={Icon}
|
||||
src={Close}
|
||||
alt="Close Filters"
|
||||
aria-label="Close Filters"
|
||||
alt={intl.formatMessage(messages.closeFilters)}
|
||||
aria-label={intl.formatMessage(messages.closeFilters)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{this.collapsibleGroup('Assignments', (
|
||||
{this.collapsibleGroup(messages.assignments, (
|
||||
<div>
|
||||
<AssignmentTypeFilter updateQueryParams={updateQueryParams} />
|
||||
<AssignmentFilter updateQueryParams={updateQueryParams} />
|
||||
@@ -70,20 +77,20 @@ export class GradebookFilters extends React.Component {
|
||||
</div>
|
||||
))}
|
||||
|
||||
{this.collapsibleGroup('Overall Grade', (
|
||||
{this.collapsibleGroup(messages.overallGrade, (
|
||||
<CourseGradeFilter updateQueryParams={updateQueryParams} />
|
||||
))}
|
||||
|
||||
{this.collapsibleGroup('Student Groups', (
|
||||
{this.collapsibleGroup(messages.studentGroups, (
|
||||
<StudentGroupsFilter updateQueryParams={updateQueryParams} />
|
||||
))}
|
||||
|
||||
{this.collapsibleGroup('Include Course Team Members', (
|
||||
{this.collapsibleGroup(messages.includeCourseTeamMembers, (
|
||||
<Form.Checkbox
|
||||
checked={this.state.includeCourseRoleMembers}
|
||||
onChange={this.handleIncludeTeamMembersChange}
|
||||
>
|
||||
Include Course Team Members
|
||||
<FormattedMessage {...messages.includeCourseTeamMembers} />
|
||||
</Form.Checkbox>
|
||||
))}
|
||||
</>
|
||||
@@ -95,6 +102,8 @@ GradebookFilters.defaultProps = {
|
||||
};
|
||||
GradebookFilters.propTypes = {
|
||||
updateQueryParams: PropTypes.func.isRequired,
|
||||
// injected
|
||||
intl: intlShape.isRequired,
|
||||
// redux
|
||||
closeMenu: PropTypes.func.isRequired,
|
||||
fetchGrades: PropTypes.func.isRequired,
|
||||
@@ -112,4 +121,4 @@ export const mapDispatchToProps = {
|
||||
updateIncludeCourseRoleMembers: actions.filters.update.includeCourseRoleMembers,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(GradebookFilters);
|
||||
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(GradebookFilters));
|
||||
|
||||
71
src/components/GradebookFilters/messages.js
Normal file
71
src/components/GradebookFilters/messages.js
Normal file
@@ -0,0 +1,71 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
assignments: {
|
||||
id: 'gradebook.GradebookFilters.assignmentsFilterLabel',
|
||||
defaultMessage: 'Assignments',
|
||||
description: 'Assignment filter group label in Gradebook Filters',
|
||||
},
|
||||
overallGrade: {
|
||||
id: 'gradebook.GradebookFilters.overallGradeFilterLabel',
|
||||
defaultMessage: 'Overall Grade',
|
||||
description: 'Overall Grade filter group label in Gradebook Filters',
|
||||
},
|
||||
studentGroups: {
|
||||
id: 'gradebook.GradebookFilters.studentGroupsFilterLabel',
|
||||
defaultMessage: 'Student Groups',
|
||||
description: 'Student Groups filter group label in Gradebook Filters',
|
||||
},
|
||||
includeCourseTeamMembers: {
|
||||
id: 'gradebook.GradebookFilters.includeCourseTeamMembersFilterLabel',
|
||||
defaultMessage: 'Include Course Team Members',
|
||||
description: 'Include Course Team Members filter label in Gradebook Filters',
|
||||
},
|
||||
assignment: {
|
||||
id: 'gradebook.GradebookFilters.assignmentFilterLabel',
|
||||
defaultMessage: 'Assignment',
|
||||
description: 'Assignment filter select label in Gradebook Filters',
|
||||
},
|
||||
assignmentTypes: {
|
||||
id: 'gradebook.GradebookFilters.assignmentTypesLabel',
|
||||
defaultMessage: 'Assignment Types',
|
||||
description: 'Assignment Types filter select label in Gradebook Filters',
|
||||
},
|
||||
maxGrade: {
|
||||
id: 'gradebook.GradebookFilters.maxGradeFilterLabel',
|
||||
defaultMessage: 'Max Grade',
|
||||
description: 'Max-grade filter select label in Gradebook Filters',
|
||||
},
|
||||
minGrade: {
|
||||
id: 'gradebook.GradebookFilters.minGradeFilterLabel',
|
||||
defaultMessage: 'Min Grade',
|
||||
description: 'Min-grade filter select label in Gradebook Filters',
|
||||
},
|
||||
cohorts: {
|
||||
id: 'gradebook.GradebookFilters.cohorts',
|
||||
defaultMessage: 'Cohorts',
|
||||
description: 'Cohorts filter select label in Gradebook Filters',
|
||||
},
|
||||
cohortAll: {
|
||||
id: 'gradebook.GradebookFilters.cohortsAll',
|
||||
defaultMessage: 'Cohort-All',
|
||||
description: 'Cohorts filter select default in Gradebook Filters',
|
||||
},
|
||||
tracks: {
|
||||
id: 'gradebook.GradebookFilters.tracks',
|
||||
defaultMessage: 'Tracks',
|
||||
description: 'Tracks filter select label in Gradebook Filters',
|
||||
},
|
||||
trackAll: {
|
||||
id: 'gradebook.GradebookFilters.trackAll',
|
||||
defaultMessage: 'Track-All',
|
||||
description: 'Tracks filter select default in Gradebook Filters',
|
||||
},
|
||||
closeFilters: {
|
||||
id: 'gradebook.GradebookFilters.closeFilters',
|
||||
defaultMessage: 'Close Filters',
|
||||
description: 'Button label for Close button in Gradebook Filters',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
@@ -46,6 +46,7 @@ describe('GradebookFilters', () => {
|
||||
beforeEach(() => {
|
||||
props = {
|
||||
...props,
|
||||
intl: { formatMessage: (msg) => msg.defaultMessage },
|
||||
closeMenu: jest.fn().mockName('this.props.closeMenu'),
|
||||
fetchGrades: jest.fn(),
|
||||
updateIncludeCourseRoleMembers: jest.fn(),
|
||||
|
||||
@@ -13,20 +13,31 @@ exports[`GradebookHeader component snapshots default values (grades frozen, cann
|
||||
>
|
||||
<<
|
||||
</span>
|
||||
Back to Dashboard
|
||||
<FormattedMessage
|
||||
defaultMessage="Back to Dashboard"
|
||||
description="Button text to take user back to LMS dashboard in Gradebook Header"
|
||||
id="gradebook.GradebookHeader.backButton"
|
||||
/>
|
||||
</a>
|
||||
<h1>
|
||||
Gradebook
|
||||
<FormattedMessage
|
||||
defaultMessage="Gradebook"
|
||||
description="Top-level app title in Gradebook Header component"
|
||||
id="gradebook.GradebookHeader.appLabel"
|
||||
/>
|
||||
</h1>
|
||||
<h3>
|
||||
|
||||
fakeID
|
||||
</h3>
|
||||
<div
|
||||
className="alert alert-warning"
|
||||
role="alert"
|
||||
>
|
||||
You are not authorized to view the gradebook for this course.
|
||||
<FormattedMessage
|
||||
defaultMessage="You are not authorized to view the gradebook for this course."
|
||||
description="Warning message in Gradebook Header when user is not allowed to view the app"
|
||||
id="gradebook.GradebookHeader.unauthorizedWarning"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -44,20 +55,31 @@ exports[`GradebookHeader component snapshots grades frozen, can view. grades fro
|
||||
>
|
||||
<<
|
||||
</span>
|
||||
Back to Dashboard
|
||||
<FormattedMessage
|
||||
defaultMessage="Back to Dashboard"
|
||||
description="Button text to take user back to LMS dashboard in Gradebook Header"
|
||||
id="gradebook.GradebookHeader.backButton"
|
||||
/>
|
||||
</a>
|
||||
<h1>
|
||||
Gradebook
|
||||
<FormattedMessage
|
||||
defaultMessage="Gradebook"
|
||||
description="Top-level app title in Gradebook Header component"
|
||||
id="gradebook.GradebookHeader.appLabel"
|
||||
/>
|
||||
</h1>
|
||||
<h3>
|
||||
|
||||
fakeID
|
||||
</h3>
|
||||
<div
|
||||
className="alert alert-warning"
|
||||
role="alert"
|
||||
>
|
||||
The grades for this course are now frozen. Editing of grades is no longer allowed.
|
||||
<FormattedMessage
|
||||
defaultMessage="The grades for this course are now frozen. Editing of grades is no longer allowed."
|
||||
description="Warning message in Gradebook Header for frozen messages"
|
||||
id="gradebook.GradebookHeader.frozenWarning"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -75,26 +97,41 @@ exports[`GradebookHeader component snapshots grades frozen, cannot view unauthor
|
||||
>
|
||||
<<
|
||||
</span>
|
||||
Back to Dashboard
|
||||
<FormattedMessage
|
||||
defaultMessage="Back to Dashboard"
|
||||
description="Button text to take user back to LMS dashboard in Gradebook Header"
|
||||
id="gradebook.GradebookHeader.backButton"
|
||||
/>
|
||||
</a>
|
||||
<h1>
|
||||
Gradebook
|
||||
<FormattedMessage
|
||||
defaultMessage="Gradebook"
|
||||
description="Top-level app title in Gradebook Header component"
|
||||
id="gradebook.GradebookHeader.appLabel"
|
||||
/>
|
||||
</h1>
|
||||
<h3>
|
||||
|
||||
fakeID
|
||||
</h3>
|
||||
<div
|
||||
className="alert alert-warning"
|
||||
role="alert"
|
||||
>
|
||||
The grades for this course are now frozen. Editing of grades is no longer allowed.
|
||||
<FormattedMessage
|
||||
defaultMessage="The grades for this course are now frozen. Editing of grades is no longer allowed."
|
||||
description="Warning message in Gradebook Header for frozen messages"
|
||||
id="gradebook.GradebookHeader.frozenWarning"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="alert alert-warning"
|
||||
role="alert"
|
||||
>
|
||||
You are not authorized to view the gradebook for this course.
|
||||
<FormattedMessage
|
||||
defaultMessage="You are not authorized to view the gradebook for this course."
|
||||
description="Warning message in Gradebook Header when user is not allowed to view the app"
|
||||
id="gradebook.GradebookHeader.unauthorizedWarning"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -2,9 +2,13 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { configuration } from 'config';
|
||||
import selectors from 'data/selectors';
|
||||
|
||||
import messages from './messages';
|
||||
|
||||
export class GradebookHeader extends React.Component {
|
||||
lmsInstructorDashboardUrl = courseId => (
|
||||
`${configuration.LMS_BASE_URL}/courses/${courseId}/instructor`
|
||||
@@ -17,19 +21,22 @@ export class GradebookHeader extends React.Component {
|
||||
href={this.lmsInstructorDashboardUrl(this.props.courseId)}
|
||||
className="mb-3"
|
||||
>
|
||||
<span aria-hidden="true">{'<< '}</span> Back to Dashboard
|
||||
<span aria-hidden="true">{'<< '}</span>
|
||||
<FormattedMessage {...messages.backToDashboard} />
|
||||
</a>
|
||||
<h1>Gradebook</h1>
|
||||
<h3> {this.props.courseId}</h3>
|
||||
<h1>
|
||||
<FormattedMessage {...messages.gradebook} />
|
||||
</h1>
|
||||
<h3>{this.props.courseId}</h3>
|
||||
{this.props.areGradesFrozen
|
||||
&& (
|
||||
<div className="alert alert-warning" role="alert">
|
||||
The grades for this course are now frozen. Editing of grades is no longer allowed.
|
||||
<FormattedMessage {...messages.frozenWarning} />
|
||||
</div>
|
||||
)}
|
||||
{(this.props.canUserViewGradebook === false) && (
|
||||
<div className="alert alert-warning" role="alert">
|
||||
You are not authorized to view the gradebook for this course.
|
||||
<FormattedMessage {...messages.unauthorizedWarning} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
26
src/components/GradebookHeader/messages.js
Normal file
26
src/components/GradebookHeader/messages.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
backToDashboard: {
|
||||
id: 'gradebook.GradebookHeader.backButton',
|
||||
defaultMessage: 'Back to Dashboard',
|
||||
description: 'Button text to take user back to LMS dashboard in Gradebook Header',
|
||||
},
|
||||
gradebook: {
|
||||
id: 'gradebook.GradebookHeader.appLabel',
|
||||
defaultMessage: 'Gradebook',
|
||||
description: 'Top-level app title in Gradebook Header component',
|
||||
},
|
||||
frozenWarning: {
|
||||
id: 'gradebook.GradebookHeader.frozenWarning',
|
||||
defaultMessage: 'The grades for this course are now frozen. Editing of grades is no longer allowed.',
|
||||
description: 'Warning message in Gradebook Header for frozen messages',
|
||||
},
|
||||
unauthorizedWarning: {
|
||||
id: 'gradebook.GradebookHeader.unauthorizedWarning',
|
||||
defaultMessage: 'You are not authorized to view the gradebook for this course.',
|
||||
description: 'Warning message in Gradebook Header when user is not allowed to view the app',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
@@ -4,6 +4,11 @@ import { shallow } from 'enzyme';
|
||||
import selectors from 'data/selectors';
|
||||
import { GradebookHeader, mapStateToProps } from '.';
|
||||
|
||||
jest.mock('@edx/frontend-platform/i18n', () => ({
|
||||
defineMessages: messages => messages,
|
||||
FormattedMessage: 'FormattedMessage',
|
||||
}));
|
||||
|
||||
jest.mock('data/selectors', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
|
||||
@@ -4,11 +4,14 @@ import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { StatefulButton, Icon } from '@edx/paragon';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { StrictDict } from 'utils';
|
||||
import actions from 'data/actions';
|
||||
import selectors from 'data/selectors';
|
||||
|
||||
import messages from './messages';
|
||||
|
||||
export const basicButtonProps = () => ({
|
||||
variant: 'outline-primary',
|
||||
icons: {
|
||||
@@ -63,11 +66,11 @@ export class BulkManagementControls extends React.Component {
|
||||
return this.props.showBulkManagement && (
|
||||
<div>
|
||||
<StatefulButton
|
||||
{...this.buttonProps('Bulk Management')}
|
||||
{...this.buttonProps(<FormattedMessage {...messages.bulkManagement} />)}
|
||||
onClick={this.handleClickExportGrades}
|
||||
/>
|
||||
<StatefulButton
|
||||
{...this.buttonProps('Interventions')}
|
||||
{...this.buttonProps(<FormattedMessage {...messages.interventions} />)}
|
||||
onClick={this.handleClickDownloadInterventions}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,7 @@ HistoryHeader.defaultProps = {
|
||||
};
|
||||
HistoryHeader.propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
label: PropTypes.node.isRequired,
|
||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,11 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import selectors from 'data/selectors';
|
||||
|
||||
import messages from './messages';
|
||||
import HistoryHeader from './HistoryHeader';
|
||||
|
||||
/**
|
||||
@@ -18,22 +22,22 @@ export const ModalHeaders = ({
|
||||
<div>
|
||||
<HistoryHeader
|
||||
id="assignment"
|
||||
label="Assignment"
|
||||
label={<FormattedMessage {...messages.assignmentHeader} />}
|
||||
value={modalState.assignmentName}
|
||||
/>
|
||||
<HistoryHeader
|
||||
id="student"
|
||||
label="Student"
|
||||
label={<FormattedMessage {...messages.studentHeader} />}
|
||||
value={modalState.updateUserName}
|
||||
/>
|
||||
<HistoryHeader
|
||||
id="original-grade"
|
||||
label="Original Grade"
|
||||
label={<FormattedMessage {...messages.originalGradeHeader} />}
|
||||
value={originalGrade}
|
||||
/>
|
||||
<HistoryHeader
|
||||
id="current-grade"
|
||||
label="Current Grade"
|
||||
label={<FormattedMessage {...messages.currentGradeHeader} />}
|
||||
value={currentGrade}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -6,19 +6,35 @@ exports[`OverrideTable Component snapshots basic snapshot shows a row for each e
|
||||
Array [
|
||||
Object {
|
||||
"key": "date",
|
||||
"label": "Date",
|
||||
"label": <FormattedMessage
|
||||
defaultMessage="Date"
|
||||
description="Edit Modal Override Table Date column header"
|
||||
id="gradebook.GradesTab.EditModal.Overrides.dateHeader"
|
||||
/>,
|
||||
},
|
||||
Object {
|
||||
"key": "grader",
|
||||
"label": "Grader",
|
||||
"label": <FormattedMessage
|
||||
defaultMessage="Grader"
|
||||
description="Edit Modal Override Table Grader column header"
|
||||
id="gradebook.GradesTab.EditModal.Overrides.graderHeader"
|
||||
/>,
|
||||
},
|
||||
Object {
|
||||
"key": "reason",
|
||||
"label": "Reason",
|
||||
"label": <FormattedMessage
|
||||
defaultMessage="Reason"
|
||||
description="Edit Modal Override Table Reason column header"
|
||||
id="gradebook.GradesTab.EditModal.Overrides.reasonHeader"
|
||||
/>,
|
||||
},
|
||||
Object {
|
||||
"key": "adjustedGrade",
|
||||
"label": "Adjusted grade",
|
||||
"label": <FormattedMessage
|
||||
defaultMessage="Adjusted grade"
|
||||
description="Edit Modal Override Table Adjusted grade column header"
|
||||
id="gradebook.GradesTab.EditModal.Overrides.adjustedGradeHeader"
|
||||
/>,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -4,18 +4,15 @@ import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { Table } from '@edx/paragon';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { gradeOverrideHistoryColumns as columns } from 'data/constants/app';
|
||||
import selectors from 'data/selectors';
|
||||
|
||||
import messages from './messages';
|
||||
import ReasonInput from './ReasonInput';
|
||||
import AdjustedGradeInput from './AdjustedGradeInput';
|
||||
|
||||
const GRADE_OVERRIDE_HISTORY_COLUMNS = [
|
||||
{ label: 'Date', key: 'date' },
|
||||
{ label: 'Grader', key: 'grader' },
|
||||
{ label: 'Reason', key: 'reason' },
|
||||
{ label: 'Adjusted grade', key: 'adjustedGrade' },
|
||||
];
|
||||
|
||||
/**
|
||||
* <OverrideTable />
|
||||
* Table containing previous grade override entries, and an "edit" row
|
||||
@@ -31,7 +28,15 @@ export const OverrideTable = ({
|
||||
}
|
||||
return (
|
||||
<Table
|
||||
columns={GRADE_OVERRIDE_HISTORY_COLUMNS}
|
||||
columns={[
|
||||
{ label: <FormattedMessage {...messages.dateHeader} />, key: columns.date },
|
||||
{ label: <FormattedMessage {...messages.graderHeader} />, key: columns.grader },
|
||||
{ label: <FormattedMessage {...messages.reasonHeader} />, key: columns.reason },
|
||||
{
|
||||
label: <FormattedMessage {...messages.adjustedGradeHeader} />,
|
||||
key: columns.adjustedGrade,
|
||||
},
|
||||
]}
|
||||
data={[
|
||||
...gradeOverrides,
|
||||
{
|
||||
|
||||
26
src/components/GradesTab/EditModal/OverrideTable/messages.js
Normal file
26
src/components/GradesTab/EditModal/OverrideTable/messages.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
adjustedGradeHeader: {
|
||||
id: 'gradebook.GradesTab.EditModal.Overrides.adjustedGradeHeader',
|
||||
defaultMessage: 'Adjusted grade',
|
||||
description: 'Edit Modal Override Table Adjusted grade column header',
|
||||
},
|
||||
dateHeader: {
|
||||
id: 'gradebook.GradesTab.EditModal.Overrides.dateHeader',
|
||||
defaultMessage: 'Date',
|
||||
description: 'Edit Modal Override Table Date column header',
|
||||
},
|
||||
graderHeader: {
|
||||
id: 'gradebook.GradesTab.EditModal.Overrides.graderHeader',
|
||||
defaultMessage: 'Grader',
|
||||
description: 'Edit Modal Override Table Grader column header',
|
||||
},
|
||||
reasonHeader: {
|
||||
id: 'gradebook.GradesTab.EditModal.Overrides.reasonHeader',
|
||||
defaultMessage: 'Reason',
|
||||
description: 'Edit Modal Override Table Reason column header',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
@@ -4,22 +4,46 @@ exports[`ModalHeaders Component snapshots gradeOverrideHistoryError is and empty
|
||||
<div>
|
||||
<HistoryHeader
|
||||
id="assignment"
|
||||
label="Assignment"
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Assignment"
|
||||
description="Edit Modal Assignment header"
|
||||
id="gradebook.GradesTab.EditModal.headers.assignment"
|
||||
/>
|
||||
}
|
||||
value="Qwerty"
|
||||
/>
|
||||
<HistoryHeader
|
||||
id="student"
|
||||
label="Student"
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Student"
|
||||
description="Edit Modal Student header"
|
||||
id="gradebook.GradesTab.EditModal.headers.student"
|
||||
/>
|
||||
}
|
||||
value="Uiop"
|
||||
/>
|
||||
<HistoryHeader
|
||||
id="original-grade"
|
||||
label="Original Grade"
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Original Grade"
|
||||
description="Edit Modal Original Grade header"
|
||||
id="gradebook.GradesTab.EditModal.headers.originalGrade"
|
||||
/>
|
||||
}
|
||||
value={20}
|
||||
/>
|
||||
<HistoryHeader
|
||||
id="current-grade"
|
||||
label="Current Grade"
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Current Grade"
|
||||
description="Edit Modal Current Grade header"
|
||||
id="gradebook.GradesTab.EditModal.headers.currentGrade"
|
||||
/>
|
||||
}
|
||||
value={2}
|
||||
/>
|
||||
</div>
|
||||
@@ -29,22 +53,46 @@ exports[`ModalHeaders Component snapshots gradeOverrideHistoryError is empty and
|
||||
<div>
|
||||
<HistoryHeader
|
||||
id="assignment"
|
||||
label="Assignment"
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Assignment"
|
||||
description="Edit Modal Assignment header"
|
||||
id="gradebook.GradesTab.EditModal.headers.assignment"
|
||||
/>
|
||||
}
|
||||
value="Qwerty"
|
||||
/>
|
||||
<HistoryHeader
|
||||
id="student"
|
||||
label="Student"
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Student"
|
||||
description="Edit Modal Student header"
|
||||
id="gradebook.GradesTab.EditModal.headers.student"
|
||||
/>
|
||||
}
|
||||
value="Uiop"
|
||||
/>
|
||||
<HistoryHeader
|
||||
id="original-grade"
|
||||
label="Original Grade"
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Original Grade"
|
||||
description="Edit Modal Original Grade header"
|
||||
id="gradebook.GradesTab.EditModal.headers.originalGrade"
|
||||
/>
|
||||
}
|
||||
value={20}
|
||||
/>
|
||||
<HistoryHeader
|
||||
id="current-grade"
|
||||
label="Current Grade"
|
||||
label={
|
||||
<FormattedMessage
|
||||
defaultMessage="Current Grade"
|
||||
description="Edit Modal Current Grade header"
|
||||
id="gradebook.GradesTab.EditModal.headers.currentGrade"
|
||||
/>
|
||||
}
|
||||
value={2}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -13,10 +13,18 @@ exports[`EditMoal Component snapshots gradeOverrideHistoryError is and empty and
|
||||
/>
|
||||
<OverrideTable />
|
||||
<div>
|
||||
Showing most recent actions (max 5). To see more, please contact support.
|
||||
<FormattedMessage
|
||||
defaultMessage="Showing most recent actions (max 5). To see more, please contact support"
|
||||
description="Edit Modal visibility hint message"
|
||||
id="gradebook.GradesTab.EditModal.contactSupport"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
Note: Once you save, your changes will be visible to students.
|
||||
<FormattedMessage
|
||||
defaultMessage="Note: Once you save, your changes will be visible to students."
|
||||
description="Edit Modal saved changes effect hint"
|
||||
id="gradebook.GradesTab.EditModal.saveVisibility"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -26,14 +34,30 @@ exports[`EditMoal Component snapshots gradeOverrideHistoryError is and empty and
|
||||
onClick={[MockFunction this.handleAdjustedGradeClick]}
|
||||
variant="primary"
|
||||
>
|
||||
Save Grade
|
||||
<FormattedMessage
|
||||
defaultMessage="Save Grades"
|
||||
description="Edit Modal Save button label"
|
||||
id="gradebook.GradesTab.EditModal.saveGrade"
|
||||
/>
|
||||
</Button>,
|
||||
]
|
||||
}
|
||||
closeText="Cancel"
|
||||
closeText={
|
||||
<FormattedMessage
|
||||
defaultMessage="Cancel"
|
||||
description="Edit Modal close button text"
|
||||
id="gradebook.GradesTab.EditModal.closeText"
|
||||
/>
|
||||
}
|
||||
onClose={[MockFunction this.closeAssignmentModal]}
|
||||
open={true}
|
||||
title="Edit Grades"
|
||||
title={
|
||||
<FormattedMessage
|
||||
defaultMessage="Edit Grades"
|
||||
description="Edit Modal title"
|
||||
id="gradebook.GradesTab.EditModal.title"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
`;
|
||||
|
||||
@@ -50,10 +74,18 @@ exports[`EditMoal Component snapshots gradeOverrideHistoryError is empty and ope
|
||||
/>
|
||||
<OverrideTable />
|
||||
<div>
|
||||
Showing most recent actions (max 5). To see more, please contact support.
|
||||
<FormattedMessage
|
||||
defaultMessage="Showing most recent actions (max 5). To see more, please contact support"
|
||||
description="Edit Modal visibility hint message"
|
||||
id="gradebook.GradesTab.EditModal.contactSupport"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
Note: Once you save, your changes will be visible to students.
|
||||
<FormattedMessage
|
||||
defaultMessage="Note: Once you save, your changes will be visible to students."
|
||||
description="Edit Modal saved changes effect hint"
|
||||
id="gradebook.GradesTab.EditModal.saveVisibility"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -63,13 +95,29 @@ exports[`EditMoal Component snapshots gradeOverrideHistoryError is empty and ope
|
||||
onClick={[MockFunction this.handleAdjustedGradeClick]}
|
||||
variant="primary"
|
||||
>
|
||||
Save Grade
|
||||
<FormattedMessage
|
||||
defaultMessage="Save Grades"
|
||||
description="Edit Modal Save button label"
|
||||
id="gradebook.GradesTab.EditModal.saveGrade"
|
||||
/>
|
||||
</Button>,
|
||||
]
|
||||
}
|
||||
closeText="Cancel"
|
||||
closeText={
|
||||
<FormattedMessage
|
||||
defaultMessage="Cancel"
|
||||
description="Edit Modal close button text"
|
||||
id="gradebook.GradesTab.EditModal.closeText"
|
||||
/>
|
||||
}
|
||||
onClose={[MockFunction this.closeAssignmentModal]}
|
||||
open={false}
|
||||
title="Edit Grades"
|
||||
title={
|
||||
<FormattedMessage
|
||||
defaultMessage="Edit Grades"
|
||||
description="Edit Modal title"
|
||||
id="gradebook.GradesTab.EditModal.title"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
`;
|
||||
|
||||
@@ -8,11 +8,13 @@ import {
|
||||
Modal,
|
||||
StatusAlert,
|
||||
} from '@edx/paragon';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import selectors from 'data/selectors';
|
||||
import actions from 'data/actions';
|
||||
import thunkActions from 'data/thunkActions';
|
||||
|
||||
import messages from './messages';
|
||||
import OverrideTable from './OverrideTable';
|
||||
import ModalHeaders from './ModalHeaders';
|
||||
|
||||
@@ -46,8 +48,8 @@ export class EditModal extends React.Component {
|
||||
return (
|
||||
<Modal
|
||||
open={this.props.open}
|
||||
title="Edit Grades"
|
||||
closeText="Cancel"
|
||||
title={<FormattedMessage {...messages.title} />}
|
||||
closeText={<FormattedMessage {...messages.closeText} />}
|
||||
body={(
|
||||
<div>
|
||||
<ModalHeaders />
|
||||
@@ -58,15 +60,13 @@ export class EditModal extends React.Component {
|
||||
dismissible={false}
|
||||
/>
|
||||
<OverrideTable />
|
||||
<div>Showing most recent actions (max 5). To see more, please contact
|
||||
support.
|
||||
</div>
|
||||
<div>Note: Once you save, your changes will be visible to students.</div>
|
||||
<div><FormattedMessage {...messages.visibility} /></div>
|
||||
<div><FormattedMessage {...messages.saveVisibility} /></div>
|
||||
</div>
|
||||
)}
|
||||
buttons={[
|
||||
<Button variant="primary" onClick={this.handleAdjustedGradeClick}>
|
||||
Save Grade
|
||||
<FormattedMessage {...messages.saveGrade} />
|
||||
</Button>,
|
||||
]}
|
||||
onClose={this.closeAssignmentModal}
|
||||
|
||||
51
src/components/GradesTab/EditModal/messages.js
Normal file
51
src/components/GradesTab/EditModal/messages.js
Normal file
@@ -0,0 +1,51 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
assignmentHeader: {
|
||||
id: 'gradebook.GradesTab.EditModal.headers.assignment',
|
||||
defaultMessage: 'Assignment',
|
||||
description: 'Edit Modal Assignment header',
|
||||
},
|
||||
currentGradeHeader: {
|
||||
id: 'gradebook.GradesTab.EditModal.headers.currentGrade',
|
||||
defaultMessage: 'Current Grade',
|
||||
description: 'Edit Modal Current Grade header',
|
||||
},
|
||||
originalGradeHeader: {
|
||||
id: 'gradebook.GradesTab.EditModal.headers.originalGrade',
|
||||
defaultMessage: 'Original Grade',
|
||||
description: 'Edit Modal Original Grade header',
|
||||
},
|
||||
studentHeader: {
|
||||
id: 'gradebook.GradesTab.EditModal.headers.student',
|
||||
defaultMessage: 'Student',
|
||||
description: 'Edit Modal Student header',
|
||||
},
|
||||
title: {
|
||||
id: 'gradebook.GradesTab.EditModal.title',
|
||||
defaultMessage: 'Edit Grades',
|
||||
description: 'Edit Modal title',
|
||||
},
|
||||
closeText: {
|
||||
id: 'gradebook.GradesTab.EditModal.closeText',
|
||||
defaultMessage: 'Cancel',
|
||||
description: 'Edit Modal close button text',
|
||||
},
|
||||
visibility: {
|
||||
id: 'gradebook.GradesTab.EditModal.contactSupport',
|
||||
defaultMessage: 'Showing most recent actions (max 5). To see more, please contact support',
|
||||
description: 'Edit Modal visibility hint message',
|
||||
},
|
||||
saveVisibility: {
|
||||
id: 'gradebook.GradesTab.EditModal.saveVisibility',
|
||||
defaultMessage: 'Note: Once you save, your changes will be visible to students.',
|
||||
description: 'Edit Modal saved changes effect hint',
|
||||
},
|
||||
saveGrade: {
|
||||
id: 'gradebook.GradesTab.EditModal.saveGrade',
|
||||
defaultMessage: 'Save Grades',
|
||||
description: 'Edit Modal Save button label',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
@@ -3,6 +3,7 @@ import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { Button } from '@edx/paragon';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import selectors from 'data/selectors';
|
||||
|
||||
@@ -15,7 +16,6 @@ import selectors from 'data/selectors';
|
||||
* @param {string} filterName - api filter name (for redux connector)
|
||||
*/
|
||||
export const FilterBadge = ({
|
||||
handleClose,
|
||||
config: {
|
||||
displayName,
|
||||
isDefault,
|
||||
@@ -23,11 +23,15 @@ export const FilterBadge = ({
|
||||
value,
|
||||
connectedFilters,
|
||||
},
|
||||
handleClose,
|
||||
}) => !isDefault && (
|
||||
<div>
|
||||
<span className="badge badge-info">
|
||||
<span>
|
||||
{displayName}{!hideValue && `: ${value}`}
|
||||
<FormattedMessage {...displayName} />
|
||||
</span>
|
||||
<span>
|
||||
{!hideValue ? `: ${value}` : ''}
|
||||
</span>
|
||||
<Button
|
||||
className="btn-info"
|
||||
@@ -48,7 +52,9 @@ FilterBadge.propTypes = {
|
||||
// redux
|
||||
config: PropTypes.shape({
|
||||
connectedFilters: PropTypes.arrayOf(PropTypes.string),
|
||||
displayName: PropTypes.string.isRequired,
|
||||
displayName: PropTypes.shape({
|
||||
defaultMessage: PropTypes.string,
|
||||
}).isRequired,
|
||||
isDefault: PropTypes.bool.isRequired,
|
||||
hideValue: PropTypes.bool,
|
||||
value: PropTypes.oneOfType([
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { Button } from '@edx/paragon';
|
||||
import selectors from 'data/selectors';
|
||||
@@ -20,7 +21,9 @@ jest.mock('data/selectors', () => ({
|
||||
describe('FilterBadge', () => {
|
||||
describe('component', () => {
|
||||
const config = {
|
||||
displayName: 'a common name',
|
||||
displayName: {
|
||||
defaultMessage: 'a common name',
|
||||
},
|
||||
isDefault: false,
|
||||
hideValue: false,
|
||||
value: 'a common value',
|
||||
@@ -58,7 +61,11 @@ describe('FilterBadge', () => {
|
||||
expect(el).toMatchSnapshot();
|
||||
});
|
||||
it('shows displayName but not value in span', () => {
|
||||
expect(el.find('span.badge').childAt(0).text()).toEqual(config.displayName);
|
||||
expect(el.find('span.badge').childAt(0).getElement()).toEqual(
|
||||
<span>
|
||||
<FormattedMessage {...config.displayName} />
|
||||
</span>,
|
||||
);
|
||||
});
|
||||
it('calls a handleClose event for connected filters on button click', () => {
|
||||
expect(el.find(Button).props().onClick).toEqual(handleClose(config.connectedFilters));
|
||||
@@ -72,8 +79,15 @@ describe('FilterBadge', () => {
|
||||
expect(el).toMatchSnapshot();
|
||||
});
|
||||
it('shows displayName and value in span', () => {
|
||||
expect(el.find('span.badge').childAt(0).text()).toEqual(
|
||||
`${config.displayName}: ${config.value}`,
|
||||
expect(el.find('span.badge').childAt(0).getElement()).toEqual(
|
||||
<span>
|
||||
<FormattedMessage {...config.displayName} />
|
||||
</span>,
|
||||
);
|
||||
expect(el.find('span.badge').childAt(1).getElement()).toEqual(
|
||||
<span>
|
||||
{`: ${config.value}`}
|
||||
</span>,
|
||||
);
|
||||
});
|
||||
it('calls a handleClose event for connected filters on button click', () => {
|
||||
|
||||
@@ -8,7 +8,11 @@ exports[`FilterBadge component with non-default value (active) if hideValue is f
|
||||
className="badge badge-info"
|
||||
>
|
||||
<span>
|
||||
a common name
|
||||
<FormattedMessage
|
||||
defaultMessage="a common name"
|
||||
/>
|
||||
</span>
|
||||
<span>
|
||||
: a common value
|
||||
</span>
|
||||
<Button
|
||||
@@ -40,8 +44,11 @@ exports[`FilterBadge component with non-default value (active) if hideValue is t
|
||||
className="badge badge-info"
|
||||
>
|
||||
<span>
|
||||
a common name
|
||||
<FormattedMessage
|
||||
defaultMessage="a common name"
|
||||
/>
|
||||
</span>
|
||||
<span />
|
||||
<Button
|
||||
aria-label="close"
|
||||
className="btn-info"
|
||||
|
||||
@@ -7,8 +7,9 @@ import {
|
||||
OverlayTrigger,
|
||||
Tooltip,
|
||||
} from '@edx/paragon';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { Headings } from 'data/constants/grades';
|
||||
import messages from './messages';
|
||||
|
||||
export const totalGradePercentageMessage = 'Total Grade values are always displayed as a percentage.';
|
||||
|
||||
@@ -23,12 +24,21 @@ const TotalGradeLabelReplacement = () => (
|
||||
trigger={['hover', 'focus']}
|
||||
key="left-basic"
|
||||
placement="left"
|
||||
overlay={(<Tooltip id="course-grade-tooltip">{totalGradePercentageMessage}</Tooltip>)}
|
||||
overlay={(
|
||||
<Tooltip id="course-grade-tooltip">
|
||||
<FormattedMessage {...messages.totalGradePercentage} />
|
||||
</Tooltip>
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
{Headings.totalGrade}
|
||||
<FormattedMessage {...messages.totalGradeHeading} />
|
||||
<div id="courseGradeTooltipIcon">
|
||||
<Icon className="fa fa-info-circle" screenReaderText={totalGradePercentageMessage} />
|
||||
<Icon
|
||||
className="fa fa-info-circle"
|
||||
screenReaderText={(
|
||||
<FormattedMessage {...messages.totalGradePercentage} />
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
@@ -41,8 +51,12 @@ const TotalGradeLabelReplacement = () => (
|
||||
*/
|
||||
const UsernameLabelReplacement = () => (
|
||||
<div>
|
||||
<div>Username</div>
|
||||
<div className="font-weight-normal student-key">Student Key*</div>
|
||||
<div>
|
||||
<FormattedMessage {...messages.usernameHeading} />
|
||||
</div>
|
||||
<div className="font-weight-normal student-key">
|
||||
<FormattedMessage {...messages.studentKeyLabel} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
@@ -4,7 +4,11 @@ exports[`LabelReplacements TotalGradeLabelReplacement displays overlay tooltip 1
|
||||
<Tooltip
|
||||
id="course-grade-tooltip"
|
||||
>
|
||||
Total Grade values are always displayed as a percentage.
|
||||
<FormattedMessage
|
||||
defaultMessage="Total Grade values are always displayed as a percentage"
|
||||
description="Gradebook table message that total grades are displayed in percent format"
|
||||
id="gradebook.GradesTab.table.totalGradePercentage"
|
||||
/>
|
||||
</Tooltip>
|
||||
`;
|
||||
|
||||
@@ -16,7 +20,11 @@ exports[`LabelReplacements TotalGradeLabelReplacement snapshot 1`] = `
|
||||
<Tooltip
|
||||
id="course-grade-tooltip"
|
||||
>
|
||||
Total Grade values are always displayed as a percentage.
|
||||
<FormattedMessage
|
||||
defaultMessage="Total Grade values are always displayed as a percentage"
|
||||
description="Gradebook table message that total grades are displayed in percent format"
|
||||
id="gradebook.GradesTab.table.totalGradePercentage"
|
||||
/>
|
||||
</Tooltip>
|
||||
}
|
||||
placement="left"
|
||||
@@ -28,13 +36,23 @@ exports[`LabelReplacements TotalGradeLabelReplacement snapshot 1`] = `
|
||||
}
|
||||
>
|
||||
<div>
|
||||
Total Grade (%)
|
||||
<FormattedMessage
|
||||
defaultMessage="Total Grade (%)"
|
||||
description="Gradebook table total grade column header"
|
||||
id="gradebook.GradesTab.table.headings.totalGrade"
|
||||
/>
|
||||
<div
|
||||
id="courseGradeTooltipIcon"
|
||||
>
|
||||
<Icon
|
||||
className="fa fa-info-circle"
|
||||
screenReaderText="Total Grade values are always displayed as a percentage."
|
||||
screenReaderText={
|
||||
<FormattedMessage
|
||||
defaultMessage="Total Grade values are always displayed as a percentage"
|
||||
description="Gradebook table message that total grades are displayed in percent format"
|
||||
id="gradebook.GradesTab.table.totalGradePercentage"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -45,12 +63,20 @@ exports[`LabelReplacements TotalGradeLabelReplacement snapshot 1`] = `
|
||||
exports[`LabelReplacements UsernameLabelReplacement snapshot 1`] = `
|
||||
<div>
|
||||
<div>
|
||||
Username
|
||||
<FormattedMessage
|
||||
defaultMessage="Username"
|
||||
description="Gradebook table username column header"
|
||||
id="gradebook.GradesTab.table.headings.username"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="font-weight-normal student-key"
|
||||
>
|
||||
Student Key*
|
||||
<FormattedMessage
|
||||
defaultMessage="Student Key*"
|
||||
description="Gradebook table Student Key label"
|
||||
id="gradebook.GradesTab.table.labels.studentKey"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -16,7 +16,11 @@ exports[`GradebookTable component snapshot - fields1 and 2 between email and tot
|
||||
},
|
||||
Object {
|
||||
"key": "Email",
|
||||
"label": "Email",
|
||||
"label": <FormattedMessage
|
||||
defaultMessage="Email"
|
||||
description="Gradebook table email column header"
|
||||
id="gradebook.GradesTab.table.headings.email"
|
||||
/>,
|
||||
},
|
||||
Object {
|
||||
"key": "field1",
|
||||
|
||||
@@ -4,10 +4,12 @@ import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { Table } from '@edx/paragon';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { Headings } from 'data/constants/grades';
|
||||
import selectors from 'data/selectors';
|
||||
import { Headings } from 'data/constants/grades';
|
||||
|
||||
import messages from './messages';
|
||||
import Fields from './Fields';
|
||||
import LabelReplacements from './LabelReplacements';
|
||||
import GradeButton from './GradeButton';
|
||||
@@ -28,14 +30,17 @@ export class GradebookTable extends React.Component {
|
||||
}
|
||||
|
||||
mapHeaders(heading) {
|
||||
const replacement = {
|
||||
[Headings.totalGrade]: <LabelReplacements.TotalGradeLabelReplacement />,
|
||||
[Headings.username]: <LabelReplacements.UsernameLabelReplacement />,
|
||||
}[heading];
|
||||
return {
|
||||
label: replacement !== undefined ? replacement : heading,
|
||||
key: heading,
|
||||
};
|
||||
let label;
|
||||
if (heading === Headings.totalGrade) {
|
||||
label = <LabelReplacements.TotalGradeLabelReplacement />;
|
||||
} else if (heading === Headings.username) {
|
||||
label = <LabelReplacements.UsernameLabelReplacement />;
|
||||
} else if (heading === Headings.email) {
|
||||
label = <FormattedMessage {...messages.emailHeading} />;
|
||||
} else {
|
||||
label = heading;
|
||||
}
|
||||
return { label, key: heading };
|
||||
}
|
||||
|
||||
mapRows(entry) {
|
||||
|
||||
36
src/components/GradesTab/GradebookTable/messages.js
Normal file
36
src/components/GradesTab/GradebookTable/messages.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
emailHeading: {
|
||||
id: 'gradebook.GradesTab.table.headings.email',
|
||||
defaultMessage: 'Email',
|
||||
description: 'Gradebook table email column header',
|
||||
},
|
||||
totalGradeHeading: {
|
||||
id: 'gradebook.GradesTab.table.headings.totalGrade',
|
||||
defaultMessage: 'Total Grade (%)',
|
||||
description: 'Gradebook table total grade column header',
|
||||
},
|
||||
usernameHeading: {
|
||||
id: 'gradebook.GradesTab.table.headings.username',
|
||||
defaultMessage: 'Username',
|
||||
description: 'Gradebook table username column header',
|
||||
},
|
||||
studentKeyLabel: {
|
||||
id: 'gradebook.GradesTab.table.labels.studentKey',
|
||||
defaultMessage: 'Student Key*',
|
||||
description: 'Gradebook table Student Key label',
|
||||
},
|
||||
usernameLabel: {
|
||||
id: 'gradebook.GradesTab.table.labels.username',
|
||||
defaultMessage: 'Username',
|
||||
description: 'Gradebook table username label',
|
||||
},
|
||||
totalGradePercentage: {
|
||||
id: 'gradebook.GradesTab.table.totalGradePercentage',
|
||||
defaultMessage: 'Total Grade values are always displayed as a percentage',
|
||||
description: 'Gradebook table message that total grades are displayed in percent format',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
@@ -2,11 +2,13 @@ import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { Table } from '@edx/paragon';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import selectors from 'data/selectors';
|
||||
import { Headings } from 'data/constants/grades';
|
||||
import LabelReplacements from './LabelReplacements';
|
||||
import Fields from './Fields';
|
||||
import messages from './messages';
|
||||
import { GradebookTable, mapStateToProps } from '.';
|
||||
|
||||
jest.mock('@edx/paragon', () => ({
|
||||
@@ -94,7 +96,7 @@ describe('GradebookTable', () => {
|
||||
test('email sets key and label from header', () => {
|
||||
const heading = headings[1];
|
||||
expect(heading.key).toEqual(Headings.email);
|
||||
expect(heading.label).toEqual(Headings.email);
|
||||
expect(heading.label).toEqual(<FormattedMessage {...messages.emailHeading} />);
|
||||
});
|
||||
test('subsections set key and label from header', () => {
|
||||
expect(headings[2]).toEqual({ key: fields.field1, label: fields.field1 });
|
||||
|
||||
@@ -19,7 +19,11 @@ exports[`PageButtons component snapshots buttons enabled with both endpoints pro
|
||||
}
|
||||
variant="outline-primary"
|
||||
>
|
||||
Previous Page
|
||||
<FormattedMessage
|
||||
defaultMessage="Previous Page"
|
||||
description="Grades tab Previous Page button text"
|
||||
id="gradebook.GradesTab.PageButtons.prevPage"
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
disabled={false}
|
||||
@@ -31,7 +35,11 @@ exports[`PageButtons component snapshots buttons enabled with both endpoints pro
|
||||
}
|
||||
variant="outline-primary"
|
||||
>
|
||||
Next Page
|
||||
<FormattedMessage
|
||||
defaultMessage="Next Page"
|
||||
description="Grades tab Next Page button text"
|
||||
id="gradebook.GradesTab.PageButtons.nextPage"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
`;
|
||||
@@ -55,7 +63,11 @@ exports[`PageButtons component snapshots nextPage disabled if not provided 1`] =
|
||||
}
|
||||
variant="outline-primary"
|
||||
>
|
||||
Previous Page
|
||||
<FormattedMessage
|
||||
defaultMessage="Previous Page"
|
||||
description="Grades tab Previous Page button text"
|
||||
id="gradebook.GradesTab.PageButtons.prevPage"
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
disabled={true}
|
||||
@@ -67,7 +79,11 @@ exports[`PageButtons component snapshots nextPage disabled if not provided 1`] =
|
||||
}
|
||||
variant="outline-primary"
|
||||
>
|
||||
Next Page
|
||||
<FormattedMessage
|
||||
defaultMessage="Next Page"
|
||||
description="Grades tab Next Page button text"
|
||||
id="gradebook.GradesTab.PageButtons.nextPage"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
`;
|
||||
@@ -91,7 +107,11 @@ exports[`PageButtons component snapshots prevPage disabled if not provided 1`] =
|
||||
}
|
||||
variant="outline-primary"
|
||||
>
|
||||
Previous Page
|
||||
<FormattedMessage
|
||||
defaultMessage="Previous Page"
|
||||
description="Grades tab Previous Page button text"
|
||||
id="gradebook.GradesTab.PageButtons.prevPage"
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
disabled={false}
|
||||
@@ -103,7 +123,11 @@ exports[`PageButtons component snapshots prevPage disabled if not provided 1`] =
|
||||
}
|
||||
variant="outline-primary"
|
||||
>
|
||||
Next Page
|
||||
<FormattedMessage
|
||||
defaultMessage="Next Page"
|
||||
description="Grades tab Next Page button text"
|
||||
id="gradebook.GradesTab.PageButtons.nextPage"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -3,9 +3,11 @@ import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { Button } from '@edx/paragon';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import selectors from 'data/selectors';
|
||||
import thunkActions from 'data/thunkActions';
|
||||
import messages from './messages';
|
||||
|
||||
export class PageButtons extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -34,7 +36,7 @@ export class PageButtons extends React.Component {
|
||||
disabled={!this.props.prevPage}
|
||||
onClick={this.getPrevGrades}
|
||||
>
|
||||
Previous Page
|
||||
<FormattedMessage {...messages.prevPage} />
|
||||
</Button>
|
||||
<Button
|
||||
style={{ margin: '20px' }}
|
||||
@@ -42,7 +44,7 @@ export class PageButtons extends React.Component {
|
||||
disabled={!this.props.nextPage}
|
||||
onClick={this.getNextGrades}
|
||||
>
|
||||
Next Page
|
||||
<FormattedMessage {...messages.nextPage} />
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
|
||||
16
src/components/GradesTab/PageButtons/messages.js
Normal file
16
src/components/GradesTab/PageButtons/messages.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
prevPage: {
|
||||
id: 'gradebook.GradesTab.PageButtons.prevPage',
|
||||
defaultMessage: 'Previous Page',
|
||||
description: 'Grades tab Previous Page button text',
|
||||
},
|
||||
nextPage: {
|
||||
id: 'gradebook.GradesTab.PageButtons.nextPage',
|
||||
defaultMessage: 'Next Page',
|
||||
description: 'Grades tab Next Page button text',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
@@ -3,29 +3,37 @@ import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { FormControl, FormGroup, FormLabel } from '@edx/paragon';
|
||||
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import actions from 'data/actions';
|
||||
import selectors from 'data/selectors';
|
||||
import messages from './messages';
|
||||
|
||||
/**
|
||||
* <ScoreViewInput />
|
||||
* redux-connected select control for grade format (percent vs absolute)
|
||||
*/
|
||||
export const ScoreViewInput = ({ format, toggleFormat }) => (
|
||||
export const ScoreViewInput = ({ format, intl, toggleFormat }) => (
|
||||
<FormGroup controlId="ScoreView">
|
||||
<FormLabel>Score View:</FormLabel>
|
||||
<FormLabel><FormattedMessage {...messages.scoreView} />:</FormLabel>
|
||||
<FormControl
|
||||
as="select"
|
||||
value={format}
|
||||
onChange={toggleFormat}
|
||||
>
|
||||
<option value="percent">Percent</option>
|
||||
<option value="absolute">Absolute</option>
|
||||
<option value="percent">{intl.formatMessage(messages.percent)}</option>
|
||||
<option value="absolute">{intl.formatMessage(messages.absolute)}</option>
|
||||
</FormControl>
|
||||
</FormGroup>
|
||||
);
|
||||
ScoreViewInput.defaultProps = {
|
||||
format: 'percent',
|
||||
};
|
||||
ScoreViewInput.propTypes = {
|
||||
format: PropTypes.string.isRequired,
|
||||
// injected
|
||||
intl: intlShape.isRequired,
|
||||
// redux
|
||||
format: PropTypes.string,
|
||||
toggleFormat: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
@@ -37,4 +45,4 @@ export const mapDispatchToProps = {
|
||||
toggleFormat: actions.grades.toggleGradeFormat,
|
||||
};
|
||||
|
||||
export default connect(() => ({}), mapDispatchToProps)(ScoreViewInput);
|
||||
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(ScoreViewInput));
|
||||
|
||||
@@ -35,6 +35,7 @@ describe('ScoreViewInput', () => {
|
||||
let el;
|
||||
beforeEach(() => {
|
||||
props.toggleFormat = jest.fn();
|
||||
props.intl = { formatMessage: (msg) => msg.defaultMessage };
|
||||
el = shallow(<ScoreViewInput {...props} />);
|
||||
});
|
||||
const assertions = [
|
||||
|
||||
@@ -3,11 +3,14 @@ import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { Button, Icon, SearchField } from '@edx/paragon';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import actions from 'data/actions';
|
||||
import selectors from 'data/selectors';
|
||||
import thunkActions from 'data/thunkActions';
|
||||
|
||||
import messages from './messages';
|
||||
|
||||
/**
|
||||
* Controls for filtering the GradebookTable. Contains the "Edit Filters" button for opening the filter drawer
|
||||
* as well as the search box for searching by username/email.
|
||||
@@ -32,25 +35,25 @@ export class SearchControls extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<h4>Step 1: Filter the Grade Report</h4>
|
||||
<h4><FormattedMessage {...messages.filterStepHeading} /></h4>
|
||||
<div className="d-flex justify-content-between">
|
||||
<Button
|
||||
id="edit-filters-btn"
|
||||
className="btn-primary align-self-start"
|
||||
onClick={this.props.toggleFilterDrawer}
|
||||
>
|
||||
<Icon className="fa fa-filter" /> Edit Filters
|
||||
<Icon className="fa fa-filter" /> <FormattedMessage {...messages.editFilters} />
|
||||
</Button>
|
||||
<div>
|
||||
<SearchField
|
||||
onSubmit={this.props.fetchGrades}
|
||||
inputLabel="Search for a learner"
|
||||
inputLabel={<FormattedMessage {...messages.searchLabel} />}
|
||||
onChange={this.onChange}
|
||||
onClear={this.onClear}
|
||||
value={this.props.searchValue}
|
||||
/>
|
||||
<small className="form-text text-muted search-help-text">
|
||||
Search by username, email, or student key
|
||||
<FormattedMessage {...messages.searchHint} />
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,12 +3,11 @@ import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { StatusAlert } from '@edx/paragon';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import selectors from 'data/selectors';
|
||||
import actions from 'data/actions';
|
||||
|
||||
export const maxCourseGradeInvalidMessage = 'Maximum course grade value must be between 0 and 100. ';
|
||||
export const minCourseGradeInvalidMessage = 'Minimum course grade value must be between 0 and 100. ';
|
||||
import messages from './messages';
|
||||
|
||||
export class StatusAlerts extends React.Component {
|
||||
get isCourseGradeFilterAlertOpen() {
|
||||
@@ -18,15 +17,24 @@ export class StatusAlerts extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
get minValidityMessage() {
|
||||
return (this.props.limitValidity.isMinValid)
|
||||
? ''
|
||||
: <FormattedMessage {...messages.minGradeInvalid} />;
|
||||
}
|
||||
|
||||
get maxValidityMessage() {
|
||||
return (this.props.limitValidity.isMaxValid)
|
||||
? ''
|
||||
: <FormattedMessage {...messages.maxGradeInvalid} />;
|
||||
}
|
||||
|
||||
get courseGradeFilterAlertDialogText() {
|
||||
let dialogText = '';
|
||||
if (!this.props.limitValidity.isMinValid) {
|
||||
dialogText += minCourseGradeInvalidMessage;
|
||||
}
|
||||
if (!this.props.limitValidity.isMaxValid) {
|
||||
dialogText += maxCourseGradeInvalidMessage;
|
||||
}
|
||||
return dialogText;
|
||||
return (
|
||||
<>
|
||||
{this.minValidityMessage}{this.maxValidityMessage}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -34,7 +42,7 @@ export class StatusAlerts extends React.Component {
|
||||
<>
|
||||
<StatusAlert
|
||||
alertType="success"
|
||||
dialog="The grade has been successfully edited. You may see a slight delay before updates appear in the Gradebook."
|
||||
dialog={<FormattedMessage {...messages.editSuccessAlert} />}
|
||||
onClose={this.props.handleCloseSuccessBanner}
|
||||
open={this.props.showSuccessBanner}
|
||||
/>
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import actions from 'data/actions';
|
||||
import selectors from 'data/selectors';
|
||||
import messages from './messages';
|
||||
import {
|
||||
StatusAlerts,
|
||||
mapDispatchToProps,
|
||||
mapStateToProps,
|
||||
maxCourseGradeInvalidMessage,
|
||||
minCourseGradeInvalidMessage,
|
||||
} from './StatusAlerts';
|
||||
|
||||
jest.mock('@edx/paragon', () => ({
|
||||
@@ -77,18 +78,24 @@ describe('StatusAlerts', () => {
|
||||
!isMinValid || !isMaxValid,
|
||||
);
|
||||
if (!isMaxValid) {
|
||||
if (!isMinValid) {
|
||||
expect(el.instance().courseGradeFilterAlertDialogText).toEqual(
|
||||
<>
|
||||
<FormattedMessage {...messages.minGradeInvalid} />
|
||||
<FormattedMessage {...messages.maxGradeInvalid} />
|
||||
</>,
|
||||
);
|
||||
} else {
|
||||
expect(
|
||||
el.instance().courseGradeFilterAlertDialogText,
|
||||
// eslint-disable-next-line react/jsx-curly-brace-presence
|
||||
).toEqual(<>{''}<FormattedMessage {...messages.maxGradeInvalid} /></>);
|
||||
}
|
||||
} else if (!isMinValid) {
|
||||
expect(
|
||||
el.instance().courseGradeFilterAlertDialogText,
|
||||
).toEqual(
|
||||
expect.stringContaining(maxCourseGradeInvalidMessage),
|
||||
);
|
||||
}
|
||||
if (!isMinValid) {
|
||||
expect(
|
||||
el.instance().courseGradeFilterAlertDialogText,
|
||||
).toEqual(
|
||||
expect.stringContaining(minCourseGradeInvalidMessage),
|
||||
);
|
||||
// eslint-disable-next-line react/jsx-curly-brace-presence
|
||||
).toEqual(<><FormattedMessage {...messages.minGradeInvalid} />{''}</>);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,6 +3,8 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import selectors from 'data/selectors';
|
||||
|
||||
/**
|
||||
@@ -18,9 +20,15 @@ export const UsersLabel = ({
|
||||
}
|
||||
const bold = (val) => (<span className="font-weight-bold">{val}</span>);
|
||||
return (
|
||||
<>
|
||||
Showing {bold(filteredUsersCount)} of {bold(totalUsersCount)} total learners
|
||||
</>
|
||||
<FormattedMessage
|
||||
id="gradebook.GradesTab.usersVisibilityLabel'"
|
||||
defaultMessage="Showing {filteredUsers} of {totalUsers} total learners"
|
||||
description="Users visibility label"
|
||||
values={{
|
||||
filteredUsers: bold(filteredUsersCount),
|
||||
totalUsers: bold(totalUsersCount),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
UsersLabel.propTypes = {
|
||||
|
||||
@@ -5,7 +5,12 @@ exports[`ScoreViewInput component snapshot - select box with percent and absolut
|
||||
controlId="ScoreView"
|
||||
>
|
||||
<FormLabel>
|
||||
Score View:
|
||||
<FormattedMessage
|
||||
defaultMessage="Score View"
|
||||
description="Score format select dropdown label"
|
||||
id="gradebook.GradesTab.scoreViewLabel"
|
||||
/>
|
||||
:
|
||||
</FormLabel>
|
||||
<FormControl
|
||||
as="select"
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
exports[`SearchControls Component Snapshots basic snapshot 1`] = `
|
||||
<React.Fragment>
|
||||
<h4>
|
||||
Step 1: Filter the Grade Report
|
||||
<FormattedMessage
|
||||
defaultMessage="Step 1: Filter the Grade Report"
|
||||
description="Filter controls container heading string"
|
||||
id="gradebook.GradesTab.filterHeading"
|
||||
/>
|
||||
</h4>
|
||||
<div
|
||||
className="d-flex justify-content-between"
|
||||
@@ -16,11 +20,22 @@ exports[`SearchControls Component Snapshots basic snapshot 1`] = `
|
||||
<Icon
|
||||
className="fa fa-filter"
|
||||
/>
|
||||
Edit Filters
|
||||
|
||||
<FormattedMessage
|
||||
defaultMessage="Edit Filters"
|
||||
description="Button text on Grades tab to open/close the Filters tab"
|
||||
id="gradebook.GradesTab.editFilterLabel"
|
||||
/>
|
||||
</Button>
|
||||
<div>
|
||||
<SearchField
|
||||
inputLabel="Search for a learner"
|
||||
inputLabel={
|
||||
<FormattedMessage
|
||||
defaultMessage="Search for a learner"
|
||||
description="Search description label"
|
||||
id="gradebook.GradesTab.search.label"
|
||||
/>
|
||||
}
|
||||
onChange={[MockFunction onChange]}
|
||||
onClear={[MockFunction onClear]}
|
||||
onSubmit={[MockFunction fetchGrades]}
|
||||
@@ -29,7 +44,11 @@ exports[`SearchControls Component Snapshots basic snapshot 1`] = `
|
||||
<small
|
||||
className="form-text text-muted search-help-text"
|
||||
>
|
||||
Search by username, email, or student key
|
||||
<FormattedMessage
|
||||
defaultMessage="Search by username, email, or student key"
|
||||
description="Search hint label"
|
||||
id="gradebook.GradesTab.search.hint"
|
||||
/>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,13 @@ exports[`StatusAlerts snapshots basic snapshot 1`] = `
|
||||
<React.Fragment>
|
||||
<StatusAlert
|
||||
alertType="success"
|
||||
dialog="The grade has been successfully edited. You may see a slight delay before updates appear in the Gradebook."
|
||||
dialog={
|
||||
<FormattedMessage
|
||||
defaultMessage="The grade has been successfully edited. You may see a slight delay before updates appear in the Gradebook."
|
||||
description="Alert text for successful edit action"
|
||||
id="gradebook.GradesTab.editSuccessAlert"
|
||||
/>
|
||||
}
|
||||
onClose={[MockFunction handleCloseSuccessBanner]}
|
||||
open={true}
|
||||
/>
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`UsersLabel component snapshot - displays label with number of filtered users out of total 1`] = `
|
||||
<Fragment>
|
||||
Showing
|
||||
<span
|
||||
className="font-weight-bold"
|
||||
>
|
||||
23
|
||||
</span>
|
||||
of
|
||||
<span
|
||||
className="font-weight-bold"
|
||||
>
|
||||
140
|
||||
</span>
|
||||
total learners
|
||||
</Fragment>
|
||||
<FormattedMessage
|
||||
defaultMessage="Showing {filteredUsers} of {totalUsers} total learners"
|
||||
description="Users visibility label"
|
||||
id="gradebook.GradesTab.usersVisibilityLabel'"
|
||||
values={
|
||||
Object {
|
||||
"filteredUsers": <span
|
||||
className="font-weight-bold"
|
||||
>
|
||||
23
|
||||
</span>,
|
||||
"totalUsers": <span
|
||||
className="font-weight-bold"
|
||||
>
|
||||
140
|
||||
</span>,
|
||||
}
|
||||
}
|
||||
/>
|
||||
`;
|
||||
|
||||
@@ -9,7 +9,11 @@ exports[`GradesTab Component snapshots basic snapshot 1`] = `
|
||||
/>
|
||||
<StatusAlerts />
|
||||
<h4>
|
||||
Step 2: View or Modify Individual Grades
|
||||
<FormattedMessage
|
||||
defaultMessage="Step 2: View or Modify Individual Grades"
|
||||
description="Alert text for invalid minimum course grade"
|
||||
id="gradebook.GradesTab.gradebookStepHeading"
|
||||
/>
|
||||
</h4>
|
||||
<UsersLabel />
|
||||
<div
|
||||
@@ -21,7 +25,12 @@ exports[`GradesTab Component snapshots basic snapshot 1`] = `
|
||||
<GradebookTable />
|
||||
<PageButtons />
|
||||
<p>
|
||||
* available for learners in the Master's track only
|
||||
*
|
||||
<FormattedMessage
|
||||
defaultMessage="available for learners in the Master's track only"
|
||||
description="Masters feature availability hint on Grades Tab"
|
||||
id="gradebook.GradesTab.mastersHint"
|
||||
/>
|
||||
</p>
|
||||
<EditModal />
|
||||
</React.Fragment>
|
||||
|
||||
@@ -3,6 +3,8 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import actions from 'data/actions';
|
||||
import thunkActions from 'data/thunkActions';
|
||||
|
||||
@@ -17,6 +19,7 @@ import StatusAlerts from './StatusAlerts';
|
||||
import SpinnerIcon from './SpinnerIcon';
|
||||
import ScoreViewInput from './ScoreViewInput';
|
||||
import UsersLabel from './UsersLabel';
|
||||
import messages from './messages';
|
||||
|
||||
export class GradesTab extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -43,7 +46,7 @@ export class GradesTab extends React.Component {
|
||||
<FilterBadges handleClose={this.handleFilterBadgeClose} />
|
||||
<StatusAlerts />
|
||||
|
||||
<h4>Step 2: View or Modify Individual Grades</h4>
|
||||
<h4><FormattedMessage {...messages.gradebookStepHeading} /></h4>
|
||||
<UsersLabel />
|
||||
|
||||
<div className="d-flex justify-content-between align-items-center mb-2">
|
||||
@@ -54,7 +57,7 @@ export class GradesTab extends React.Component {
|
||||
<GradebookTable />
|
||||
|
||||
<PageButtons />
|
||||
<p>* available for learners in the Master's track only</p>
|
||||
<p>* <FormattedMessage {...messages.mastersHint} /></p>
|
||||
<EditModal />
|
||||
</>
|
||||
);
|
||||
|
||||
76
src/components/GradesTab/messages.js
Normal file
76
src/components/GradesTab/messages.js
Normal file
@@ -0,0 +1,76 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
bulkManagement: {
|
||||
id: 'gradebook.GradesTab.BulkManagementControls.bulkManagementLabel',
|
||||
defaultMessage: 'Bulk Management',
|
||||
description: 'Button text for bulk grades download control in GradesTab',
|
||||
},
|
||||
interventions: {
|
||||
id: 'gradebook.GradesTab.BulkManagementControls.interventionsLabel',
|
||||
defaultMessage: 'Interventions',
|
||||
description: 'Button text for intervention report download control in GradesTab',
|
||||
},
|
||||
scoreView: {
|
||||
id: 'gradebook.GradesTab.scoreViewLabel',
|
||||
defaultMessage: 'Score View',
|
||||
description: 'Score format select dropdown label',
|
||||
},
|
||||
absolute: {
|
||||
id: 'gradebook.GradesTab.absoluteOption',
|
||||
defaultMessage: 'Absolute',
|
||||
description: 'Score format select dropdown option',
|
||||
},
|
||||
percent: {
|
||||
id: 'gradebook.GradesTab.percentOption',
|
||||
defaultMessage: 'Percent',
|
||||
description: 'Score format select dropdown option',
|
||||
},
|
||||
filterStepHeading: {
|
||||
id: 'gradebook.GradesTab.filterHeading',
|
||||
defaultMessage: 'Step 1: Filter the Grade Report',
|
||||
description: 'Filter controls container heading string',
|
||||
},
|
||||
editFilters: {
|
||||
id: 'gradebook.GradesTab.editFilterLabel',
|
||||
defaultMessage: 'Edit Filters',
|
||||
description: 'Button text on Grades tab to open/close the Filters tab',
|
||||
},
|
||||
searchLabel: {
|
||||
id: 'gradebook.GradesTab.search.label',
|
||||
defaultMessage: 'Search for a learner',
|
||||
description: 'Search description label',
|
||||
},
|
||||
searchHint: {
|
||||
id: 'gradebook.GradesTab.search.hint',
|
||||
defaultMessage: 'Search by username, email, or student key',
|
||||
description: 'Search hint label',
|
||||
},
|
||||
editSuccessAlert: {
|
||||
id: 'gradebook.GradesTab.editSuccessAlert',
|
||||
defaultMessage: 'The grade has been successfully edited. You may see a slight delay before updates appear in the Gradebook.',
|
||||
description: 'Alert text for successful edit action',
|
||||
},
|
||||
maxGradeInvalid: {
|
||||
id: 'gradebook.GradesTab.maxCourseGradeInvalid',
|
||||
defaultMessage: 'Maximum course grade must be between 0 and 100',
|
||||
description: 'Alert text for invalid maximum course grade',
|
||||
},
|
||||
minGradeInvalid: {
|
||||
id: 'gradebook.GradesTab.minCourseGradeInvalid',
|
||||
defaultMessage: 'Minimum course grade must be between 0 and 100',
|
||||
description: 'Alert text for invalid minimum course grade',
|
||||
},
|
||||
gradebookStepHeading: {
|
||||
id: 'gradebook.GradesTab.gradebookStepHeading',
|
||||
defaultMessage: 'Step 2: View or Modify Individual Grades',
|
||||
description: 'Alert text for invalid minimum course grade',
|
||||
},
|
||||
mastersHint: {
|
||||
id: 'gradebook.GradesTab.mastersHint',
|
||||
defaultMessage: "available for learners in the Master's track only",
|
||||
description: 'Masters feature availability hint on Grades Tab',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
@@ -6,6 +6,7 @@ import thunkActions from 'data/thunkActions';
|
||||
|
||||
import {
|
||||
GradesTab,
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
} from '.';
|
||||
|
||||
@@ -78,6 +79,9 @@ describe('GradesTab', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
test('mapStateToProps is empty', () => {
|
||||
expect(mapStateToProps({ some: 'state' })).toEqual({});
|
||||
});
|
||||
describe('mapDispatchToProps', () => {
|
||||
describe('fetchGrades', () => {
|
||||
test('from thunkActions.grades.fetchGrades', () => {
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
|
||||
export const options = {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
timeZone: 'UTC',
|
||||
};
|
||||
export const timeOptions = {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
timeZone: 'UTC',
|
||||
timeZoneName: 'short',
|
||||
};
|
||||
|
||||
const formatDateForDisplay = (inputDate) => {
|
||||
const options = {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
timeZone: 'UTC',
|
||||
};
|
||||
const timeOptions = {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
timeZone: 'UTC',
|
||||
timeZoneName: 'short',
|
||||
};
|
||||
return `${inputDate.toLocaleDateString('en-US', options)} at ${inputDate.toLocaleTimeString('en-US', timeOptions)}`;
|
||||
const date = inputDate.toLocaleDateString('en-US', options);
|
||||
const time = inputDate.toLocaleTimeString('en-US', timeOptions);
|
||||
return `${date} at ${time}`;
|
||||
};
|
||||
|
||||
const sortAlphaAsc = (gradeRowA, gradeRowB) => {
|
||||
|
||||
34
src/data/actions/utils.test.js
Normal file
34
src/data/actions/utils.test.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
import * as utils from './utils';
|
||||
|
||||
jest.mock('@reduxjs/toolkit', () => ({
|
||||
createAction: (key, ...args) => ({ action: key, args }),
|
||||
}));
|
||||
|
||||
describe('redux action utils', () => {
|
||||
describe('formatDateForDisplay', () => {
|
||||
it('returns the datetime as a formatted string', () => {
|
||||
expect(utils.formatDateForDisplay(new Date('Jun 3 2021 11:59 AM EDT'))).toEqual(
|
||||
'June 3, 2021 at 03:59 PM UTC',
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('sortAlphaAsc', () => {
|
||||
it('returns sorting value (-1, 0, 1) by uppercase username', () => {
|
||||
const sort = (v1, v2) => utils.sortAlphaAsc({ username: v1 }, { username: v2 });
|
||||
expect(sort('aName', 'ANAme')).toEqual(0);
|
||||
expect(sort('aName', 'laterName')).toEqual(-1);
|
||||
expect(sort('laterName', 'aName')).toEqual(1);
|
||||
});
|
||||
});
|
||||
describe('createActionFactory', () => {
|
||||
it('returns an action creator with the data key', () => {
|
||||
const dataKey = 'part-of-the-model';
|
||||
const actionKey = 'an-action';
|
||||
const args = ['some', 'args'];
|
||||
expect(utils.createActionFactory(dataKey)(actionKey, ...args)).toEqual(
|
||||
createAction(`${dataKey}/${actionKey}`, ...args),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,14 +0,0 @@
|
||||
import { configuration } from 'config';
|
||||
|
||||
export const baseUrl = `${configuration.LMS_BASE_URL}/api`;
|
||||
|
||||
/**
|
||||
* bulkGradesUrlByCourseAndRow(courseId, rowId)
|
||||
* returns the bulkGrades url with the given courseId and rowId.
|
||||
* @param {string} courseId - course identifier
|
||||
* @param {string} rowId - row/error identifier
|
||||
* @return {string} - bulk grades fetch url
|
||||
*/
|
||||
export const bulkGradesUrlByCourseAndRow = (courseId, rowId) => (
|
||||
`${baseUrl}/bulkGrades/course/${courseId}/?error_id=${rowId}`
|
||||
);
|
||||
@@ -1,4 +1,7 @@
|
||||
import { StrictDict } from 'utils';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
|
||||
export const routePath = `${getConfig().PUBLIC_PATH}:courseId`;
|
||||
|
||||
export const modalFieldKeys = StrictDict({
|
||||
adjustedGradePossible: 'adjustedGradePossible',
|
||||
@@ -49,6 +52,13 @@ export const bulkManagementColumns = [
|
||||
},
|
||||
];
|
||||
|
||||
export const gradeOverrideHistoryColumns = StrictDict({
|
||||
adjustedGrade: 'adjustedGrade',
|
||||
date: 'date',
|
||||
grader: 'grader',
|
||||
reason: 'reason',
|
||||
});
|
||||
|
||||
/**
|
||||
* Display strings for various app components.
|
||||
* Note: this is a temporary storage location for these strings, before we put them in
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { StrictDict } from 'utils';
|
||||
|
||||
import messages from './filters.messages';
|
||||
|
||||
export const filters = StrictDict({
|
||||
assignment: 'assignment',
|
||||
assignmentGrade: 'assignmentGrade',
|
||||
@@ -28,34 +30,34 @@ const initialFilters = {
|
||||
|
||||
export const filterConfig = StrictDict({
|
||||
[filters.assignment]: {
|
||||
displayName: 'Assignment',
|
||||
displayName: messages[filters.assignment],
|
||||
connectedFilters: ['assignment', 'assignmentGradeMax', 'assignmentGradeMax'],
|
||||
},
|
||||
[filters.assignmentType]: {
|
||||
displayName: 'Assignment Type',
|
||||
displayName: messages[filters.assignmentType],
|
||||
connectedFilters: ['assignmentType'],
|
||||
},
|
||||
[filters.assignmentGrade]: {
|
||||
displayName: 'Assignment Grade',
|
||||
filterOrder: ['courseGradeMin', 'courseGradeMax'],
|
||||
connectedFilters: ['courseGradeMax', 'courseGradeMin'],
|
||||
displayName: messages[filters.assignmentGrade],
|
||||
filterOrder: ['assignmentGradeMin', 'assignmentGradeMax'],
|
||||
connectedFilters: ['assignmentGradeMax', 'assignmentGradeMin'],
|
||||
},
|
||||
[filters.cohort]: {
|
||||
displayName: 'Cohort',
|
||||
displayName: messages[filters.cohort],
|
||||
connectedFilters: ['cohort'],
|
||||
},
|
||||
[filters.courseGrade]: {
|
||||
displayName: 'Course Grade',
|
||||
displayName: messages[filters.courseGrade],
|
||||
filterOrder: ['courseGradeMin', 'courseGradeMax'],
|
||||
connectedFilters: ['courseGradeMax', 'courseGradeMin'],
|
||||
},
|
||||
[filters.includeCourseRoleMembers]: {
|
||||
displayName: 'Includeing Course Team Members',
|
||||
displayName: messages[filters.includeCourseRoleMembers],
|
||||
connectedFilters: ['includeCourseRoleMembers'],
|
||||
hideValue: true,
|
||||
},
|
||||
[filters.track]: {
|
||||
displayName: 'Track',
|
||||
displayName: messages[filters.track],
|
||||
connectedFilters: ['track'],
|
||||
},
|
||||
});
|
||||
|
||||
41
src/data/constants/filters.messages.js
Normal file
41
src/data/constants/filters.messages.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
assignment: {
|
||||
id: 'gradebook.GradesTab.FilterBadges.assignment',
|
||||
defaultMessage: 'Assignment',
|
||||
description: 'Assignment FilterBadge label',
|
||||
},
|
||||
assignmentGrade: {
|
||||
id: 'gradebook.GradesTab.FilterBadges.assignmentGrade',
|
||||
defaultMessage: 'Assignment Grade',
|
||||
description: 'Assignment Grade FilterBadge label',
|
||||
},
|
||||
assignmentType: {
|
||||
id: 'gradebook.GradesTab.FilterBadges.assignmentType',
|
||||
defaultMessage: 'Assignment Type',
|
||||
description: 'Assignment Type FilterBadge label',
|
||||
},
|
||||
cohort: {
|
||||
id: 'gradebook.GradesTab.FilterBadges.cohort',
|
||||
defaultMessage: 'Cohort',
|
||||
description: 'Cohort FilterBadge label',
|
||||
},
|
||||
courseGrade: {
|
||||
id: 'gradebook.GradesTab.FilterBadges.courseGrade',
|
||||
defaultMessage: 'Course Grade',
|
||||
description: 'Course Grade FilterBadge label',
|
||||
},
|
||||
includeCourseRoleMembers: {
|
||||
id: 'gradebook.GradesTab.FilterBadges.includeCourseRoleMembers',
|
||||
defaultMessage: 'Include Course Team Members',
|
||||
description: 'Include Course Team Members FilterBadge label',
|
||||
},
|
||||
track: {
|
||||
id: 'gradebook.GradesTab.FilterBadges.track',
|
||||
defaultMessage: 'Track',
|
||||
description: 'Track FilterBadge label',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
@@ -42,6 +42,37 @@ describe('app reducer', () => {
|
||||
).toEqual({ ...testingState, courseId: testValue });
|
||||
});
|
||||
});
|
||||
describe('appActions.filterMenu.startTransition', () => {
|
||||
it('sets filterMenu.transitioning to true', () => {
|
||||
expect(
|
||||
app(testingState, appActions.filterMenu.startTransition()),
|
||||
).toEqual({
|
||||
...testingState,
|
||||
filterMenu: { ...testingState.filterMenu, transitioning: true },
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('appActions.filterMenu.endTransition', () => {
|
||||
it('sets filterMenu.transitioning to false', () => {
|
||||
const transitioningState = {
|
||||
...testingState,
|
||||
filterMenu: { ...testingState.filterMenu, transitioning: true },
|
||||
};
|
||||
expect(
|
||||
app(transitioningState, appActions.filterMenu.endTransition()),
|
||||
).toEqual(testingState);
|
||||
});
|
||||
});
|
||||
describe('appActions.filterMenu.toggle', () => {
|
||||
it('toggles filterMenu.open', () => {
|
||||
const openState = {
|
||||
...testingState,
|
||||
filterMenu: { ...testingState.filterMenu, open: true },
|
||||
};
|
||||
expect(app(testingState, appActions.filterMenu.toggle())).toEqual(openState);
|
||||
expect(app(openState, appActions.filterMenu.toggle())).toEqual(testingState);
|
||||
});
|
||||
});
|
||||
describe('appActions.setLocalFilter', () => {
|
||||
it('loads filter values from the payload', () => {
|
||||
expect(
|
||||
|
||||
@@ -30,17 +30,13 @@ const reducer = (state = initialState, { type: actionType, payload }) => {
|
||||
assignmentGradeMax: payload.assignmentGradeMax,
|
||||
assignmentGradeMin: payload.assignmentGradeMin,
|
||||
};
|
||||
case actions.update.assignmentType.toString():
|
||||
return {
|
||||
...state,
|
||||
assignmentType: payload,
|
||||
assignment: (
|
||||
(
|
||||
payload !== ''
|
||||
&& (state.assignment || {}).type !== payload
|
||||
) ? '' : state.assignment
|
||||
),
|
||||
};
|
||||
case actions.update.assignmentType.toString(): {
|
||||
const newState = { ...state, assignmentType: payload };
|
||||
if (payload !== '' && state.assignment && payload !== state.assignment.type) {
|
||||
newState.assignment = '';
|
||||
}
|
||||
return newState;
|
||||
}
|
||||
case actions.update.cohort.toString():
|
||||
return { ...state, cohort: payload };
|
||||
case actions.update.courseGradeLimits.toString():
|
||||
|
||||
@@ -9,6 +9,7 @@ import grades from './grades';
|
||||
import roles from './roles';
|
||||
import tracks from './tracks';
|
||||
|
||||
/* istanbul ignore next */
|
||||
const rootReducer = combineReducers({
|
||||
app,
|
||||
assignmentTypes,
|
||||
|
||||
@@ -105,11 +105,11 @@ export const headingMapper = (category, label = 'All') => {
|
||||
filter = filters.byLabel;
|
||||
}
|
||||
const { username, email, totalGrade } = Headings;
|
||||
const fillerLabels = (entry) => entry.filter(filter).map(s => s.label);
|
||||
const filteredLabels = (entry) => entry.filter(filter).map(s => s.label);
|
||||
|
||||
return (entry) => (
|
||||
entry
|
||||
? [username, email, ...fillerLabels(entry), totalGrade]
|
||||
? [username, email, ...filteredLabels(entry), totalGrade]
|
||||
: []
|
||||
);
|
||||
};
|
||||
@@ -133,7 +133,6 @@ export const transformHistoryEntry = ({
|
||||
originalFilename,
|
||||
resultsSummary: {
|
||||
rowId: id,
|
||||
courseId,
|
||||
text: module.getRowsProcessed(data),
|
||||
},
|
||||
...rest,
|
||||
@@ -188,7 +187,7 @@ export const allGrades = ({ grades: { results } }) => results;
|
||||
*/
|
||||
export const bulkImportError = ({ grades: { bulkManagement } }) => (
|
||||
(!!bulkManagement && bulkManagement.errorMessages)
|
||||
? `Errors while processing: ${bulkManagement.errorMessages.join(', ')}`
|
||||
? `Errors while processing: ${bulkManagement.errorMessages.join('; ')};`
|
||||
: ''
|
||||
);
|
||||
|
||||
|
||||
@@ -87,6 +87,44 @@ describe('grades selectors', () => {
|
||||
describe('grade formatters', () => {
|
||||
const selectedAssignment = { assignmentId: 'block-v1:edX+type@sequential+block@abcde' };
|
||||
|
||||
describe('formatGradeOverrideForDisplay', () => {
|
||||
it('maps history entries with formatted date, grader, reason, and adjusted grade', () => {
|
||||
const historyArray = [
|
||||
{
|
||||
history_date: 'Jan 01 2021',
|
||||
history_user: 'Grog',
|
||||
override_reason: 'rage',
|
||||
earned_graded_override: 0,
|
||||
},
|
||||
{
|
||||
history_date: 'Jan 02 2021',
|
||||
history_user: 'Keyleth',
|
||||
override_reason: 'nature',
|
||||
earned_graded_override: 10,
|
||||
},
|
||||
{
|
||||
history_date: 'Jan 03 2021',
|
||||
history_user: 'Pike',
|
||||
override_reason: 'Sarenrae',
|
||||
earned_graded_override: 9001,
|
||||
},
|
||||
];
|
||||
const mapped = selectors.formatGradeOverrideForDisplay(historyArray);
|
||||
const testEntry = (index) => {
|
||||
const entry = historyArray[index];
|
||||
expect(mapped[index]).toEqual({
|
||||
date: formatDateForDisplay(new Date(entry.history_date)),
|
||||
grader: entry.history_user,
|
||||
reason: entry.override_reason,
|
||||
adjustedGrade: entry.earned_graded_override,
|
||||
});
|
||||
};
|
||||
testEntry(0);
|
||||
testEntry(1);
|
||||
testEntry(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatMinAssignmentGrade', () => {
|
||||
const modifiedGrade = '1';
|
||||
const selector = selectors.formatMinAssignmentGrade;
|
||||
@@ -200,7 +238,6 @@ describe('grades selectors', () => {
|
||||
it('summarizes processed rows', () => {
|
||||
expect(output.resultsSummary).toEqual({
|
||||
text: selectors.getRowsProcessed(rawEntry.data),
|
||||
courseId: rawEntry.unique_id,
|
||||
rowId: rawEntry.id,
|
||||
});
|
||||
});
|
||||
@@ -276,7 +313,7 @@ describe('grades selectors', () => {
|
||||
expect(
|
||||
selectors.bulkImportError({ grades: { bulkManagement: { errorMessages } } }),
|
||||
).toEqual(
|
||||
`Errors while processing: ${errorMessages[0]}, ${errorMessages[1]}`,
|
||||
`Errors while processing: ${errorMessages[0]}; ${errorMessages[1]};`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* eslint-disable import/no-named-as-default-member, import/no-self-import */
|
||||
import { StrictDict } from 'utils';
|
||||
|
||||
import LmsApiService from 'data/services/LmsApiService';
|
||||
import lms from 'data/services/lms';
|
||||
import * as filterConstants from 'data/constants/filters';
|
||||
|
||||
import * as module from '.';
|
||||
@@ -122,13 +121,13 @@ export const getHeadings = (state) => grades.headingMapper(
|
||||
|
||||
/**
|
||||
* gradeExportUrl(state, options)
|
||||
* Returns the output of getGradeExportCsvUrl, applying the current includeCourseRoleMembers
|
||||
* Returns the output of getGradeCsvUrl, applying the current includeCourseRoleMembers
|
||||
* filter.
|
||||
* @param {object} state - redux state
|
||||
* @return {string} - generated grade export url
|
||||
*/
|
||||
export const gradeExportUrl = (state) => (
|
||||
LmsApiService.getGradeExportCsvUrl(app.courseId(state), {
|
||||
lms.urls.gradeCsvUrl({
|
||||
...module.lmsApiServiceArgs(state),
|
||||
excludeCourseRoles: filters.includeCourseRoleMembers(state) ? '' : 'all',
|
||||
})
|
||||
@@ -141,8 +140,7 @@ export const gradeExportUrl = (state) => (
|
||||
* @return {string} - generated intervention export url
|
||||
*/
|
||||
export const interventionExportUrl = (state) => (
|
||||
LmsApiService.getInterventionExportCsvUrl(
|
||||
app.courseId(state),
|
||||
lms.urls.interventionExportCsvUrl(
|
||||
module.lmsApiServiceArgs(state),
|
||||
)
|
||||
);
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
/* eslint-disable import/no-named-as-default-member */
|
||||
/* eslint-disable import/no-named-as-default-member, import/no-named-as-default */
|
||||
import * as filterConstants from '../constants/filters';
|
||||
import selectors from '.';
|
||||
import * as moduleSelectors from '.';
|
||||
import { minGrade, maxGrade } from './grades';
|
||||
|
||||
jest.mock('../services/LmsApiService', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
getGradeExportCsvUrl: jest.fn(
|
||||
(...args) => ({ getGradeExportCsvUrl: { args } }),
|
||||
jest.mock('data/services/lms', () => ({
|
||||
urls: {
|
||||
gradeCsvUrl: jest.fn(
|
||||
(...args) => ({ gradeCsvUrl: { args } }),
|
||||
),
|
||||
getInterventionExportCsvUrl: jest.fn(
|
||||
(...args) => ({ getInterventionExportCsvUrl: { args } }),
|
||||
interventionExportCsvUrl: jest.fn(
|
||||
(...args) => ({ interventionExportCsvUrl: { args } }),
|
||||
),
|
||||
},
|
||||
}));
|
||||
@@ -344,8 +343,8 @@ describe('root selectors', () => {
|
||||
it('calls the API service with the right args, excluding all course roles', () => {
|
||||
selectors.filters.includeCourseRoleMembers.mockReturnValue(undefined);
|
||||
expect(selector(testState)).toEqual({
|
||||
getGradeExportCsvUrl: {
|
||||
args: [testCourseId, { lmsArgs: testState, excludeCourseRoles: 'all' }],
|
||||
gradeCsvUrl: {
|
||||
args: [{ lmsArgs: testState, excludeCourseRoles: 'all' }],
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -354,8 +353,8 @@ describe('root selectors', () => {
|
||||
it('calls the API service with the right args, including course roles', () => {
|
||||
selectors.filters.includeCourseRoleMembers.mockReturnValue(true);
|
||||
expect(selector(testState)).toEqual({
|
||||
getGradeExportCsvUrl: {
|
||||
args: [testCourseId, { lmsArgs: testState, excludeCourseRoles: '' }],
|
||||
gradeCsvUrl: {
|
||||
args: [{ lmsArgs: testState, excludeCourseRoles: '' }],
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -369,8 +368,8 @@ describe('root selectors', () => {
|
||||
expect(
|
||||
moduleSelectors.interventionExportUrl(testState),
|
||||
).toEqual({
|
||||
getInterventionExportCsvUrl: {
|
||||
args: [testCourseId, { lmsArgs: testState }],
|
||||
interventionExportCsvUrl: {
|
||||
args: [{ lmsArgs: testState }],
|
||||
},
|
||||
});
|
||||
moduleSelectors.lmsApiServiceArgs = lmsApiServiceArgs;
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
import { configuration } from '../../config';
|
||||
|
||||
class LmsApiService {
|
||||
static baseUrl = configuration.LMS_BASE_URL;
|
||||
|
||||
static pageSize = 25
|
||||
|
||||
static fetchGradebookData(courseId, searchText, cohort, track, options = {}) {
|
||||
const queryParams = {};
|
||||
queryParams.page_size = LmsApiService.pageSize;
|
||||
if (searchText) {
|
||||
queryParams.user_contains = searchText;
|
||||
}
|
||||
if (cohort) {
|
||||
queryParams.cohort_id = cohort;
|
||||
}
|
||||
if (track) {
|
||||
queryParams.enrollment_mode = track;
|
||||
}
|
||||
if (options.assignmentGradeMax || options.assignmentGradeMin) {
|
||||
if (!options.assignment) {
|
||||
throw new Error('Gradebook LMS API requires assignment to be set to filter by min/max assig. grade');
|
||||
}
|
||||
queryParams.assignment = options.assignment;
|
||||
if (options.assignmentGradeMin) {
|
||||
queryParams.assignment_grade_min = options.assignmentGradeMin;
|
||||
}
|
||||
if (options.assignmentGradeMax) {
|
||||
queryParams.assignment_grade_max = options.assignmentGradeMax;
|
||||
}
|
||||
}
|
||||
if (options.courseGradeMin) {
|
||||
queryParams.course_grade_min = options.courseGradeMin;
|
||||
}
|
||||
if (options.courseGradeMax) {
|
||||
queryParams.course_grade_max = options.courseGradeMax;
|
||||
}
|
||||
if (!options.includeCourseRoleMembers) {
|
||||
queryParams.excluded_course_roles = ['all'];
|
||||
}
|
||||
|
||||
const queryParamString = Object.keys(queryParams)
|
||||
.map(attr => `${attr}=${encodeURIComponent(queryParams[attr])}`)
|
||||
.join('&');
|
||||
|
||||
const gradebookUrl = `${LmsApiService.baseUrl}/api/grades/v1/gradebook/${courseId}/?${queryParamString}`;
|
||||
|
||||
return getAuthenticatedHttpClient().get(gradebookUrl);
|
||||
}
|
||||
|
||||
static updateGradebookData(courseId, updateData) {
|
||||
/*
|
||||
updateData is expected to be a list of objects with the keys 'user_id' (an integer),
|
||||
'usage_id' (a string) and 'grade', which is an object with the keys:
|
||||
'earned_all_override',
|
||||
'possible_all_override',
|
||||
'earned_graded_override',
|
||||
and 'possible_graded_override',
|
||||
each of which should be an integer.
|
||||
Example:
|
||||
[
|
||||
{
|
||||
"user_id": 9,
|
||||
"usage_id": "block-v1:edX+DemoX+Demo_Course+type@sequential+block@basic_questions",
|
||||
"grade": {
|
||||
"earned_all_override": 11,
|
||||
"possible_all_override": 11,
|
||||
"earned_graded_override": 11,
|
||||
"possible_graded_override": 11,
|
||||
"comment": "reason for override"
|
||||
}
|
||||
}
|
||||
]
|
||||
*/
|
||||
const gradebookUrl = `${LmsApiService.baseUrl}/api/grades/v1/gradebook/${courseId}/bulk-update`;
|
||||
return getAuthenticatedHttpClient().post(gradebookUrl, updateData);
|
||||
}
|
||||
|
||||
static fetchTracks(courseId) {
|
||||
const trackUrl = `${LmsApiService.baseUrl}/api/enrollment/v1/course/${courseId}?include_expired=1`;
|
||||
return getAuthenticatedHttpClient().get(trackUrl);
|
||||
}
|
||||
|
||||
static fetchCohorts(courseId) {
|
||||
const cohortsUrl = `${LmsApiService.baseUrl}/courses/${courseId}/cohorts/`;
|
||||
return getAuthenticatedHttpClient().get(cohortsUrl);
|
||||
}
|
||||
|
||||
static fetchAssignmentTypes(courseId) {
|
||||
const assignmentTypesUrl = `${LmsApiService.baseUrl}/api/grades/v1/gradebook/${courseId}/grading-info?graded_only=true`;
|
||||
return getAuthenticatedHttpClient().get(assignmentTypesUrl);
|
||||
}
|
||||
|
||||
static fetchUserRoles(courseId) {
|
||||
const rolesUrl = `${LmsApiService.baseUrl}/api/enrollment/v1/roles/?course_id=${encodeURIComponent(courseId)}`;
|
||||
return getAuthenticatedHttpClient().get(rolesUrl);
|
||||
}
|
||||
|
||||
static getGradeExportCsvUrl(courseId, options = {}) {
|
||||
const queryParams = ['track', 'cohort', 'assignment', 'assignmentType', 'assignmentGradeMax',
|
||||
'assignmentGradeMin', 'courseGradeMin', 'courseGradeMax', 'excludedCourseRoles']
|
||||
.filter(opt => options[opt]
|
||||
&& options[opt] !== 'All')
|
||||
.map(opt => `${opt}=${encodeURIComponent(options[opt])}`)
|
||||
.join('&');
|
||||
return `${LmsApiService.baseUrl}/api/bulk_grades/course/${courseId}/?${queryParams}`;
|
||||
}
|
||||
|
||||
static getInterventionExportCsvUrl(courseId, options = {}) {
|
||||
const queryParams = ['track', 'cohort', 'assignment', 'assignmentType', 'assignmentGradeMax',
|
||||
'assignmentGradeMin', 'courseGradeMin', 'courseGradeMax']
|
||||
.filter(opt => options[opt]
|
||||
&& options[opt] !== 'All')
|
||||
.map(opt => `${opt}=${encodeURIComponent(options[opt])}`)
|
||||
.join('&');
|
||||
return `${LmsApiService.baseUrl}/api/bulk_grades/course/${courseId}/intervention?${queryParams}`;
|
||||
}
|
||||
|
||||
static getGradeImportCsvUrl = LmsApiService.getGradeExportCsvUrl;
|
||||
|
||||
static uploadGradeCsv(courseId, formData) {
|
||||
const fileUploadUrl = LmsApiService.getGradeImportCsvUrl(courseId);
|
||||
return getAuthenticatedHttpClient().post(fileUploadUrl, formData).then((result) => {
|
||||
if (result.status === 200 && !result.data.error_messages.length) {
|
||||
return result.data;
|
||||
}
|
||||
return Promise.reject(result);
|
||||
});
|
||||
}
|
||||
|
||||
static fetchGradeBulkOperationHistory(courseId) {
|
||||
const url = `${LmsApiService.baseUrl}/api/bulk_grades/course/${courseId}/history/`;
|
||||
return getAuthenticatedHttpClient().get(url).then(response => response.data).catch(() => Promise.reject(Error('unhandled response error')));
|
||||
}
|
||||
|
||||
static fetchGradeOverrideHistory(subsectionId, userId) {
|
||||
const historyUrl = `${LmsApiService.baseUrl}/api/grades/v1/subsection/${subsectionId}/?user_id=${userId}&history_record_limit=5`;
|
||||
return getAuthenticatedHttpClient().get(historyUrl);
|
||||
}
|
||||
}
|
||||
|
||||
export default LmsApiService;
|
||||
120
src/data/services/lms/api.js
Normal file
120
src/data/services/lms/api.js
Normal file
@@ -0,0 +1,120 @@
|
||||
import { StrictDict } from 'utils';
|
||||
|
||||
import urls, {
|
||||
gradeCsvUrl,
|
||||
sectionOverrideHistoryUrl,
|
||||
} from './urls';
|
||||
import { pageSize, paramKeys } from './constants';
|
||||
import messages from './messages';
|
||||
|
||||
import * as utils from './utils';
|
||||
|
||||
const { get, post, stringifyUrl } = utils;
|
||||
|
||||
/*********************************************************************************
|
||||
* GET Actions
|
||||
*********************************************************************************/
|
||||
const assignmentTypes = () => get(urls.assignmentTypes);
|
||||
const cohorts = () => get(urls.cohorts);
|
||||
const roles = () => get(urls.roles);
|
||||
const tracks = () => get(urls.tracks);
|
||||
|
||||
/**
|
||||
* fetch.gradebookData(searchText, cohort, track, options)
|
||||
* fetches updated gradebook data based on current filter selections.
|
||||
* Raises an error if assignment grade limits are set, but not assignment.
|
||||
* @param {string} searchText - search text filter
|
||||
* @param {nunber} cohort - selected cohort filter
|
||||
* @param {string} track - selected track filter
|
||||
* @param {object} options - additional optional filter values
|
||||
* @return {Promise} - get response
|
||||
*/
|
||||
const gradebookData = (searchText, cohort, track, options = {}) => {
|
||||
if ((options.assignmentGradeMax || options.assignmentGradeMin) && !options.assignment) {
|
||||
throw new Error(messages.errors.missingAssignment);
|
||||
}
|
||||
const queryParams = {
|
||||
[paramKeys.pageSize]: pageSize,
|
||||
[paramKeys.userContains]: searchText,
|
||||
[paramKeys.cohortId]: cohort,
|
||||
[paramKeys.enrollmentMode]: track,
|
||||
[paramKeys.courseGradeMax]: options.courseGradeMax,
|
||||
[paramKeys.courseGradeMin]: options.courseGradeMin,
|
||||
[paramKeys.excludedCourseRoles]: options.includeCourseRoleMembers ? null : ['all'],
|
||||
[paramKeys.assignment]: options.assignment,
|
||||
[paramKeys.assignmentGradeMax]: options.assignmentGradeMax,
|
||||
[paramKeys.assignmentGradeMin]: options.assignmentGradeMin,
|
||||
};
|
||||
return get(stringifyUrl(urls.gradebook, queryParams));
|
||||
};
|
||||
|
||||
/**
|
||||
* fetch.gradeBulkOperationHistory()
|
||||
* fetches bulk operation history and raises an error if the operation fails
|
||||
* @return {Promise} - get response
|
||||
*/
|
||||
const gradeBulkOperationHistory = () => get(urls.bulkHistory)
|
||||
.then(response => response.data)
|
||||
.catch(() => Promise.reject(Error(messages.errors.unhandledResponse)));
|
||||
|
||||
/**
|
||||
* fetch.gradeOverrideHistory(subsectionId, userId)
|
||||
* fetches grade override history for a given user on a given subsection
|
||||
* @param {string} subsectionId - subsection identifier
|
||||
* @param {string} userId - user identifier
|
||||
* @return {Promise} - get response
|
||||
*/
|
||||
const gradeOverrideHistory = (subsectionId, userId) => (
|
||||
get(sectionOverrideHistoryUrl(subsectionId, userId))
|
||||
);
|
||||
|
||||
/*********************************************************************************
|
||||
* POST Actions
|
||||
*********************************************************************************/
|
||||
/**
|
||||
* updateGradebookData(updateData)
|
||||
* sends an update message with new grades overrides
|
||||
* @param {object[]} updateData
|
||||
* {
|
||||
* user_id: <int>,
|
||||
* usage_id: <string>
|
||||
* grade: {
|
||||
* earned_all_override: <int>
|
||||
* possible_all_override: <int>
|
||||
* earned_graded_override: <int>
|
||||
* possible_graded_override: <int>
|
||||
* }
|
||||
* }
|
||||
* @return {Promise} - post response
|
||||
*/
|
||||
const updateGradebookData = (updateData) => post(urls.bulkUpdate, updateData);
|
||||
|
||||
/**
|
||||
* uploadGradeCsv(formData)
|
||||
* Posts form data to grade csv url. On success, forwards response data.
|
||||
* Reject promise with result on failure.
|
||||
* @param {object} formData - new grade data
|
||||
* @return {Promise} - post response
|
||||
*/
|
||||
const uploadGradeCsv = (formData) => (
|
||||
post(gradeCsvUrl(), formData).then((result) => {
|
||||
if (result.status === 200 && !result.data.error_messages.length) {
|
||||
return result.data;
|
||||
}
|
||||
return Promise.reject(result);
|
||||
})
|
||||
);
|
||||
|
||||
export default StrictDict({
|
||||
fetch: StrictDict({
|
||||
assignmentTypes,
|
||||
cohorts,
|
||||
gradebookData,
|
||||
gradeBulkOperationHistory,
|
||||
gradeOverrideHistory,
|
||||
roles,
|
||||
tracks,
|
||||
}),
|
||||
updateGradebookData,
|
||||
uploadGradeCsv,
|
||||
});
|
||||
234
src/data/services/lms/api.test.js
Normal file
234
src/data/services/lms/api.test.js
Normal file
@@ -0,0 +1,234 @@
|
||||
import api from './api';
|
||||
import { pageSize, paramKeys } from './constants';
|
||||
import messages from './messages';
|
||||
import urls, { gradeCsvUrl, sectionOverrideHistoryUrl } from './urls';
|
||||
import * as utils from './utils';
|
||||
|
||||
jest.mock('./urls', () => ({
|
||||
__esModule: true,
|
||||
default: jest.requireActual('./urls').default,
|
||||
gradeCsvUrl: (...args) => ({ gradeCsvUrl: args }),
|
||||
sectionOverrideHistoryUrl: (...args) => `sectionOverrideHistoryUrl(${args})`,
|
||||
}));
|
||||
|
||||
jest.mock('./utils', () => ({
|
||||
get: jest.fn(),
|
||||
post: jest.fn(),
|
||||
stringifyUrl: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('lms service api', () => {
|
||||
describe('get actions', () => {
|
||||
const mockGet = promiseFn => {
|
||||
jest.spyOn(utils, 'get').mockImplementation(
|
||||
url => new Promise(promiseFn(url)),
|
||||
);
|
||||
};
|
||||
const resolveFn = (url) => (resolve) => resolve({ data: url });
|
||||
const rejectFn = (url) => (resolve, reject) => reject(url);
|
||||
const testSimpleFetch = (method, expectedUrl, description) => {
|
||||
mockGet(resolveFn);
|
||||
test(description, () => (
|
||||
method().then(({ data }) => { expect(data).toEqual(expectedUrl); })
|
||||
));
|
||||
};
|
||||
describe('fetch.assignmentTypes', () => {
|
||||
testSimpleFetch(
|
||||
api.fetch.assignmentTypes,
|
||||
urls.assignmentTypes,
|
||||
'fetches from urls.assignmentTypes',
|
||||
);
|
||||
});
|
||||
describe('fetch.cohorts', () => {
|
||||
testSimpleFetch(
|
||||
api.fetch.cohorts,
|
||||
urls.cohorts,
|
||||
'fetches from urls.cohorts',
|
||||
);
|
||||
});
|
||||
describe('fetch.roles', () => {
|
||||
testSimpleFetch(
|
||||
api.fetch.roles,
|
||||
urls.roles,
|
||||
'fetches from urls.roles',
|
||||
);
|
||||
});
|
||||
describe('fetch.tracks', () => {
|
||||
testSimpleFetch(
|
||||
api.fetch.tracks,
|
||||
urls.tracks,
|
||||
'fetches from urls.tracks',
|
||||
);
|
||||
});
|
||||
describe('fetch.gradebookData', () => {
|
||||
const searchText = 'some user';
|
||||
const cohort = 2;
|
||||
const track = 'masters';
|
||||
const options = {
|
||||
courseGradeMax: 90,
|
||||
courseGradeMin: 10,
|
||||
includeCourseRoleMembers: true,
|
||||
assignment: 'some work',
|
||||
assignmentGradeMax: 95,
|
||||
assignmentGradeMin: 5,
|
||||
};
|
||||
|
||||
it('throws an error if either assignmentGrade limit is set, but no assignment', () => {
|
||||
mockGet(resolveFn);
|
||||
expect(() => {
|
||||
api.fetch.gradebookData(
|
||||
searchText,
|
||||
cohort,
|
||||
track,
|
||||
{ ...options, assignmentGradeMax: null, assignment: null },
|
||||
);
|
||||
}).toThrow(Error(messages.errors.missingAssignment));
|
||||
expect(() => {
|
||||
api.fetch.gradebookData(
|
||||
searchText,
|
||||
cohort,
|
||||
track,
|
||||
{ ...options, assignmentGradeMin: null, assignment: null },
|
||||
);
|
||||
}).toThrow(Error(messages.errors.missingAssignment));
|
||||
});
|
||||
describe('fetches from urls.gradebook with queryParams loaded from options', () => {
|
||||
beforeEach(() => {
|
||||
mockGet(resolveFn);
|
||||
});
|
||||
test('loads only passed values if options is empty', () => (
|
||||
api.fetch.gradebookData(searchText, cohort, track).then(({ data }) => {
|
||||
expect(data).toEqual(utils.stringifyUrl(urls.gradebook, {
|
||||
[paramKeys.pageSize]: pageSize,
|
||||
[paramKeys.userContains]: searchText,
|
||||
[paramKeys.cohortId]: cohort,
|
||||
[paramKeys.enrollmentMode]: track,
|
||||
[paramKeys.courseGradeMax]: undefined,
|
||||
[paramKeys.courseGradeMin]: undefined,
|
||||
[paramKeys.excludedCourseRoles]: undefined,
|
||||
[paramKeys.assignment]: undefined,
|
||||
[paramKeys.assignmentGradeMax]: undefined,
|
||||
[paramKeys.assignmentGradeMin]: undefined,
|
||||
}));
|
||||
})
|
||||
));
|
||||
test('loads ["all"] for excludedCorseRoles if not includeCourseRoles', () => (
|
||||
api.fetch.gradebookData(searchText, cohort, track, options).then(({ data }) => {
|
||||
expect(data).toEqual(utils.stringifyUrl(urls.gradebook, {
|
||||
[paramKeys.pageSize]: pageSize,
|
||||
[paramKeys.userContains]: searchText,
|
||||
[paramKeys.cohortId]: cohort,
|
||||
[paramKeys.enrollmentMode]: track,
|
||||
[paramKeys.courseGradeMax]: options.courseGradeMax,
|
||||
[paramKeys.courseGradeMin]: options.courseGradeMin,
|
||||
[paramKeys.excludedCourseRoles]: ['all'],
|
||||
[paramKeys.assignment]: options.assignment,
|
||||
[paramKeys.assignmentGradeMax]: options.assignmentGradeMax,
|
||||
[paramKeys.assignmentGradeMin]: options.assignmentGradeMin,
|
||||
}));
|
||||
})
|
||||
));
|
||||
test('loads null for excludedCorseRoles if includeCourseRoles', () => (
|
||||
api.fetch.gradebookData(searchText, cohort, track, options).then(({ data }) => {
|
||||
expect(data).toEqual(utils.stringifyUrl(urls.gradebook, {
|
||||
[paramKeys.pageSize]: pageSize,
|
||||
[paramKeys.userContains]: searchText,
|
||||
[paramKeys.cohortId]: cohort,
|
||||
[paramKeys.enrollmentMode]: track,
|
||||
[paramKeys.courseGradeMax]: options.courseGradeMax,
|
||||
[paramKeys.courseGradeMin]: options.courseGradeMin,
|
||||
[paramKeys.excludedCourseRoles]: null,
|
||||
[paramKeys.assignment]: options.assignment,
|
||||
[paramKeys.assignmentGradeMax]: options.assignmentGradeMax,
|
||||
[paramKeys.assignmentGradeMin]: options.assignmentGradeMin,
|
||||
}));
|
||||
})
|
||||
));
|
||||
});
|
||||
});
|
||||
describe('gradeBulkOperationHistory', () => {
|
||||
describe('success', () => {
|
||||
beforeEach(() => {
|
||||
mockGet(resolveFn);
|
||||
});
|
||||
it('fetches from urls.bulkHistory and returns the data', () => (
|
||||
api.fetch.gradeBulkOperationHistory().then(url => {
|
||||
expect(url).toEqual(urls.bulkHistory);
|
||||
})
|
||||
));
|
||||
});
|
||||
describe('failure', () => {
|
||||
beforeEach(() => {
|
||||
mockGet(rejectFn);
|
||||
});
|
||||
it('rejects with unhandledResponse Error', () => (
|
||||
api.fetch.gradeBulkOperationHistory().catch(error => {
|
||||
expect(error).toEqual(Error(messages.errors.unhandledResponse));
|
||||
})
|
||||
));
|
||||
});
|
||||
});
|
||||
describe('gradeOverrideHistory', () => {
|
||||
const subsectionId = 'a subsection';
|
||||
const userId = 'Thomas';
|
||||
beforeEach(() => {
|
||||
mockGet(resolveFn);
|
||||
});
|
||||
test('gets from urls.sectionOverrideHistoryUrl with passed subseciton and user ids', () => (
|
||||
api.fetch.gradeOverrideHistory(subsectionId, userId).then(({ data }) => {
|
||||
expect(data).toEqual(sectionOverrideHistoryUrl(subsectionId, userId));
|
||||
})
|
||||
));
|
||||
});
|
||||
});
|
||||
describe('post actions', () => {
|
||||
const mockPost = promiseFn => {
|
||||
jest.spyOn(utils, 'post').mockImplementation(
|
||||
(url, callback) => new Promise(promiseFn(url, callback)),
|
||||
);
|
||||
};
|
||||
const resolveFn = (url, data) => (resolve) => resolve({ data: { url, data } });
|
||||
describe('updateGradebookData', () => {
|
||||
const updateData = { some: 'update data' };
|
||||
beforeEach(() => {
|
||||
mockPost(resolveFn);
|
||||
});
|
||||
test('posts to urls.bulkUpdate with passed data', () => (
|
||||
api.updateGradebookData(updateData).then(({ data }) => {
|
||||
expect(data).toEqual({ url: urls.bulkUpdate, data: updateData });
|
||||
})
|
||||
));
|
||||
});
|
||||
describe('uploadGradeCsv', () => {
|
||||
describe('200 status with no error_messages', () => {
|
||||
const response = {
|
||||
status: 200,
|
||||
data: {
|
||||
error_messages: [],
|
||||
other: 'data',
|
||||
},
|
||||
};
|
||||
const formData = { some: 'form Data' };
|
||||
beforeEach(() => {
|
||||
mockPost(() => (resolve) => { resolve(response); });
|
||||
});
|
||||
it('posts formData to gradeCsvUrl and returns the data from response', () => (
|
||||
api.uploadGradeCsv(formData).then(result => {
|
||||
expect(result).toEqual(response.data);
|
||||
})
|
||||
));
|
||||
});
|
||||
describe('non-200 status', () => {
|
||||
const formData = { some: 'form Data' };
|
||||
beforeEach(() => {
|
||||
mockPost((url, data) => (resolve) => { resolve({ url, data }); });
|
||||
});
|
||||
it('posts formData to gradeCsvUrl and returns the data from response', () => (
|
||||
api.uploadGradeCsv(formData).catch(result => {
|
||||
expect(result).toEqual({ url: gradeCsvUrl(), data: formData });
|
||||
})
|
||||
));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
17
src/data/services/lms/constants.js
Normal file
17
src/data/services/lms/constants.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import { StrictDict } from 'utils';
|
||||
|
||||
export const pageSize = 25;
|
||||
export const historyRecordLimit = 5;
|
||||
|
||||
export const paramKeys = StrictDict({
|
||||
cohortId: 'cohort_id',
|
||||
pageSize: 'page_size',
|
||||
userContains: 'user_contains',
|
||||
enrollmentMode: 'enrollment_mode',
|
||||
assignment: 'assignment',
|
||||
assignmentGradeMin: 'assignment_grade_min',
|
||||
assignmentGradeMax: 'assignment_grade_max',
|
||||
courseGradeMin: 'course_grade_min',
|
||||
courseGradeMax: 'course_grade_max',
|
||||
excludedCourseRoles: 'excluded_course_roles',
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user