diff --git a/jsconfig.json b/jsconfig.json
index a40157ac93..4a810717ee 100644
--- a/jsconfig.json
+++ b/jsconfig.json
@@ -1,4 +1,7 @@
{
+ "compilerOptions": {
+ "experimentalDecorators": true
+ },
"typeAcquisition": {
"include": [
"jest"
diff --git a/package-lock.json b/package-lock.json
index 16414403e9..d2b1cda734 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3511,6 +3511,11 @@
"resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz",
"integrity": "sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg=="
},
+ "@remix-run/router": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.1.tgz",
+ "integrity": "sha512-eBV5rvW4dRFOU1eajN7FmYxjAIVz/mRHgUE9En9mBn6m3mulK3WTR5C3iQhL9MZ14rWAq+xOlEaCkDiW0/heOg=="
+ },
"@saithodev/semantic-release-backmerge": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@saithodev/semantic-release-backmerge/-/semantic-release-backmerge-2.1.2.tgz",
@@ -4504,7 +4509,7 @@
"ansicolors": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz",
- "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=",
+ "integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==",
"dev": true
},
"anymatch": {
@@ -4535,7 +4540,7 @@
"argv-formatter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/argv-formatter/-/argv-formatter-1.0.0.tgz",
- "integrity": "sha1-oMoMvCmltz6Dbuvhy/bF4OTrgvk=",
+ "integrity": "sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw==",
"dev": true
},
"array-flatten": {
@@ -4546,7 +4551,7 @@
"array-ify": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz",
- "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=",
+ "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==",
"dev": true
},
"array-includes": {
@@ -5154,7 +5159,7 @@
"cardinal": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz",
- "integrity": "sha1-fMEFXYItISlU0HsIXeolHMe8VQU=",
+ "integrity": "sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==",
"dev": true,
"requires": {
"ansicolors": "~0.3.2",
@@ -6401,7 +6406,7 @@
"duplexer2": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
- "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=",
+ "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==",
"dev": true,
"requires": {
"readable-stream": "^2.0.2"
@@ -7722,7 +7727,7 @@
"from2": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
- "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=",
+ "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==",
"dev": true,
"requires": {
"inherits": "^2.0.1",
@@ -7883,7 +7888,7 @@
"git-log-parser": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.0.tgz",
- "integrity": "sha1-LmpMGxP8AAKCB7p5WnrDFme5/Uo=",
+ "integrity": "sha512-rnCVNfkTL8tdNryFuaY0fYiBWEBcgF748O6ZI61rslBvr2o7U65c2/6npCRqH40vuAhtgtDiqLTJjBVdrejCzA==",
"dev": true,
"requires": {
"argv-formatter": "~1.0.0",
@@ -7912,7 +7917,7 @@
"split2": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/split2/-/split2-1.0.0.tgz",
- "integrity": "sha1-UuLiIdiMdfmnP5BVbiY/+WdysxQ=",
+ "integrity": "sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg==",
"dev": true,
"requires": {
"through2": "~2.0.0"
@@ -8163,19 +8168,6 @@
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
"dev": true
},
- "history": {
- "version": "4.10.1",
- "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
- "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==",
- "requires": {
- "@babel/runtime": "^7.1.2",
- "loose-envify": "^1.2.0",
- "resolve-pathname": "^3.0.0",
- "tiny-invariant": "^1.0.2",
- "tiny-warning": "^1.0.0",
- "value-equal": "^1.0.1"
- }
- },
"hoist-non-react-statics": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
@@ -8794,7 +8786,7 @@
"is-text-path": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz",
- "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=",
+ "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==",
"dev": true,
"requires": {
"text-extensions": "^1.0.0"
@@ -10698,7 +10690,7 @@
"jsonparse": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
- "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=",
+ "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==",
"dev": true
},
"jsprim": {
@@ -10795,7 +10787,7 @@
"load-json-file": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
- "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
+ "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
@@ -10807,7 +10799,7 @@
"parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
- "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
+ "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
"dev": true,
"requires": {
"error-ex": "^1.3.1",
@@ -10867,7 +10859,7 @@
"lodash.capitalize": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz",
- "integrity": "sha1-+CbJtOKoUR2E46yinbBeGk87cqk=",
+ "integrity": "sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==",
"dev": true
},
"lodash.curry": {
@@ -10884,7 +10876,7 @@
"lodash.escaperegexp": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz",
- "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=",
+ "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==",
"dev": true
},
"lodash.flow": {
@@ -10905,25 +10897,25 @@
"lodash.ismatch": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz",
- "integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=",
+ "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==",
"dev": true
},
"lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
- "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=",
+ "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
"dev": true
},
"lodash.isstring": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
- "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=",
+ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
"dev": true
},
"lodash.uniqby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz",
- "integrity": "sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI=",
+ "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==",
"dev": true
},
"log-symbols": {
@@ -11261,15 +11253,6 @@
"integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
"dev": true
},
- "mini-create-react-context": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz",
- "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==",
- "requires": {
- "@babel/runtime": "^7.12.1",
- "tiny-warning": "^1.0.3"
- }
- },
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
@@ -11389,7 +11372,7 @@
"nerf-dart": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/nerf-dart/-/nerf-dart-1.0.0.tgz",
- "integrity": "sha1-5tq3/r9a2Bbqgc9cYpxaDr3nLBo=",
+ "integrity": "sha512-EZSPZB70jiVsivaBLYDCyntd5eH8NTSMOn3rB+HxwdmKThGELLdYv8qVIMWvZEFy9w8ZZpW9h9OB32l1rGtj7g==",
"dev": true
},
"nice-try": {
@@ -14501,12 +14484,6 @@
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
- "path-to-regexp": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.2.0.tgz",
- "integrity": "sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==",
- "dev": true
- },
"path-type": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
@@ -14551,7 +14528,7 @@
"pkg-conf": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz",
- "integrity": "sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg=",
+ "integrity": "sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==",
"dev": true,
"requires": {
"find-up": "^2.0.0",
@@ -14561,7 +14538,7 @@
"find-up": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
- "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
+ "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==",
"dev": true,
"requires": {
"locate-path": "^2.0.0"
@@ -14570,7 +14547,7 @@
"locate-path": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
- "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
+ "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==",
"dev": true,
"requires": {
"p-locate": "^2.0.0",
@@ -14589,7 +14566,7 @@
"p-locate": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
- "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
+ "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==",
"dev": true,
"requires": {
"p-limit": "^1.1.0"
@@ -14598,13 +14575,13 @@
"p-try": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
- "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
+ "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==",
"dev": true
},
"path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
- "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+ "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
"dev": true
}
}
@@ -14976,7 +14953,7 @@
"q": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
- "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
+ "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==",
"dev": true
},
"qrcode": {
@@ -15373,49 +15350,20 @@
}
},
"react-router": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.1.tgz",
- "integrity": "sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ==",
- "requires": {
- "@babel/runtime": "^7.12.13",
- "history": "^4.9.0",
- "hoist-non-react-statics": "^3.1.0",
- "loose-envify": "^1.3.1",
- "mini-create-react-context": "^0.4.0",
- "path-to-regexp": "^1.7.0",
- "prop-types": "^15.6.2",
- "react-is": "^16.6.0",
- "tiny-invariant": "^1.0.2",
- "tiny-warning": "^1.0.0"
- },
- "dependencies": {
- "isarray": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
- "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
- },
- "path-to-regexp": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
- "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
- "requires": {
- "isarray": "0.0.1"
- }
- }
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.1.tgz",
+ "integrity": "sha512-OJASKp5AykDWFewgWUim1vlLr7yfD4vO/h+bSgcP/ix8Md+LMHuAjovA74MQfsfhQJGGN1nHRhwS5qQQbbBt3A==",
+ "requires": {
+ "@remix-run/router": "1.0.1"
}
},
"react-router-dom": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.0.tgz",
- "integrity": "sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ==",
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.4.1.tgz",
+ "integrity": "sha512-MY7NJCrGNVJtGp8ODMOBHu20UaIkmwD2V3YsAOUQoCXFk7Ppdwf55RdcGyrSj+ycSL9Uiwrb3gTLYSnzcRoXww==",
"requires": {
- "@babel/runtime": "^7.12.13",
- "history": "^4.9.0",
- "loose-envify": "^1.3.1",
- "prop-types": "^15.6.2",
- "react-router": "5.2.1",
- "tiny-invariant": "^1.0.2",
- "tiny-warning": "^1.0.0"
+ "@remix-run/router": "1.0.1",
+ "react-router": "6.4.1"
}
},
"react-side-effect": {
@@ -15595,7 +15543,7 @@
"redeyed": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz",
- "integrity": "sha1-iYS1gV2ZyyIEacme7v/jiRPmzAs=",
+ "integrity": "sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==",
"dev": true,
"requires": {
"esprima": "~4.0.0"
@@ -15834,11 +15782,6 @@
"integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
"dev": true
},
- "resolve-pathname": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz",
- "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng=="
- },
"resolve.exports": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz",
@@ -16370,7 +16313,7 @@
"figures": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
- "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+ "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==",
"dev": true,
"requires": {
"escape-string-regexp": "^1.0.5"
@@ -16434,7 +16377,7 @@
"spawn-error-forwarder": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz",
- "integrity": "sha1-Gv2Uc46ZmwNG17n8NzvlXgdXcCk=",
+ "integrity": "sha512-gRjMgK5uFjbCvdibeGJuy3I5OYz6VLoVdsOJdA6wV0WlfQVLFueoqMxwwYD9RODdgb6oUIvlRlsyFSiQkMKu0g==",
"dev": true
},
"spdx-correct": {
@@ -16541,7 +16484,7 @@
"stream-combiner2": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz",
- "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=",
+ "integrity": "sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==",
"dev": true,
"requires": {
"duplexer2": "~0.1.0",
@@ -16699,7 +16642,7 @@
"strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
- "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+ "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
"dev": true
},
"strip-final-newline": {
@@ -17037,11 +16980,6 @@
"readable-stream": "3"
}
},
- "tiny-invariant": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz",
- "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw=="
- },
"tiny-warning": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
@@ -17104,7 +17042,7 @@
"traverse": {
"version": "0.6.6",
"resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz",
- "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=",
+ "integrity": "sha512-kdf4JKs8lbARxWdp7RKdNzoJBhGUcIalSYibuGyHJbmk40pOysQ0+QPvlkCOICOivDWU2IJo2rkrxyTK2AH4fw==",
"dev": true
},
"trim-newlines": {
@@ -17443,11 +17381,6 @@
"spdx-expression-parse": "^3.0.0"
}
},
- "value-equal": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz",
- "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw=="
- },
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@@ -17798,7 +17731,7 @@
"wordwrap": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
- "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
+ "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
"dev": true
},
"wrap-ansi": {
diff --git a/package.json b/package.json
index 5925b8026f..5bf02a9928 100644
--- a/package.json
+++ b/package.json
@@ -47,7 +47,6 @@
"express": "4.18.1",
"graphiql": "2.0.7",
"graphql": "16.6.0",
- "history": "4.10.1",
"immutable": "4.1.0",
"immutable-devtools": "0.1.5",
"inquirer": "8.2.4",
@@ -68,8 +67,7 @@
"react-helmet": "6.1.0",
"react-json-view": "1.21.3",
"react-popper-tooltip": "4.4.2",
- "react-router": "5.2.1",
- "react-router-dom": "5.3.0",
+ "react-router-dom": "6.4.1",
"regenerator-runtime": "0.13.9",
"semver": "7.3.7",
"typescript": "4.8.2"
@@ -103,7 +101,6 @@
"madge": "5.0.1",
"marked": "4.0.10",
"null-loader": "4.0.1",
- "path-to-regexp": "3.2.0",
"puppeteer": "18.0.5",
"react-test-renderer": "16.13.1",
"request": "2.88.2",
diff --git a/src/components/Autocomplete/Autocomplete.react.js b/src/components/Autocomplete/Autocomplete.react.js
index 937a526702..be6d4e953f 100644
--- a/src/components/Autocomplete/Autocomplete.react.js
+++ b/src/components/Autocomplete/Autocomplete.react.js
@@ -6,7 +6,7 @@
* the root directory of this source tree.
*/
import Position from 'lib/Position';
-import PropTypes from 'prop-types'
+import PropTypes from 'lib/PropTypes'
import React, { Component } from 'react';
import styles from 'components/Autocomplete/Autocomplete.scss';
import SuggestionsList from 'components/SuggestionsList/SuggestionsList.react';
diff --git a/src/components/Chip/Chip.react.js b/src/components/Chip/Chip.react.js
index 678063337e..c737699cf9 100644
--- a/src/components/Chip/Chip.react.js
+++ b/src/components/Chip/Chip.react.js
@@ -7,7 +7,7 @@
*/
import React from 'react';
import styles from 'components/Chip/Chip.scss';
-import PropTypes from 'prop-types'
+import PropTypes from 'lib/PropTypes'
import Icon from 'components/Icon/Icon.react'
let Chip = ({ value, onClose }) => (
diff --git a/src/components/FourOhFour/FourOhFour.react.js b/src/components/FourOhFour/FourOhFour.react.js
index 53aba06e1a..2e53789d92 100644
--- a/src/components/FourOhFour/FourOhFour.react.js
+++ b/src/components/FourOhFour/FourOhFour.react.js
@@ -5,13 +5,14 @@
* This source code is licensed under the license found in the LICENSE file in
* the root directory of this source tree.
*/
-import history from 'dashboard/history';
import React from 'react';
import styles from 'components/FourOhFour/FourOhFour.scss';
+import { withRouter } from 'lib/withRouter';
const EMOJI_COUNT = 30;
-export default class FourOhFour extends React.Component {
+@withRouter
+class FourOhFour extends React.Component {
constructor() {
super();
@@ -51,10 +52,12 @@ export default class FourOhFour extends React.Component {
Oh no, we can't find that page!
-
+
);
}
}
+
+export default FourOhFour;
diff --git a/src/components/Sidebar/AppsMenu.react.js b/src/components/Sidebar/AppsMenu.react.js
index 62e906f3cd..cbee4edd80 100644
--- a/src/components/Sidebar/AppsMenu.react.js
+++ b/src/components/Sidebar/AppsMenu.react.js
@@ -23,7 +23,7 @@ const AppsMenu = ({ apps, current, height, onSelect, onPinClick }) => (
return null;
}
return (
-
+
{app.name}
diff --git a/src/components/Toolbar/Toolbar.react.js b/src/components/Toolbar/Toolbar.react.js
index b73378ff86..505c37021e 100644
--- a/src/components/Toolbar/Toolbar.react.js
+++ b/src/components/Toolbar/Toolbar.react.js
@@ -9,17 +9,17 @@ import PropTypes from 'lib/PropTypes';
import React from 'react';
import Icon from 'components/Icon/Icon.react';
import styles from 'components/Toolbar/Toolbar.scss';
-import history from 'dashboard/history';
-
-const goBack = () => history.goBack();
+import { useNavigate, useNavigationType, NavigationType } from 'react-router-dom';
let Toolbar = (props) => {
+ const action = useNavigationType();
+ const navigate = useNavigate();
let backButton;
- if ((props.relation || (props.filters && props.filters.size)) && history.action !== 'POP') {
+ if ((props.relation || (props.filters && props.filters.size)) && action !== NavigationType.Pop) {
backButton = (
navigate(-1)}
>
{
let name = [query.source];
@@ -38,8 +39,8 @@ let buildFriendlyName = (query) => {
return name.join(' ');
};
-export default
@subscribeTo('AnalyticsQuery', 'customQueries')
+@withRouter
class Explorer extends DashboardView {
constructor() {
super();
@@ -547,3 +548,5 @@ class Explorer extends DashboardView {
);
}
}
+
+export default Explorer;
diff --git a/src/dashboard/AppData.react.js b/src/dashboard/AppData.react.js
index ff113bde60..de33aa0703 100644
--- a/src/dashboard/AppData.react.js
+++ b/src/dashboard/AppData.react.js
@@ -8,30 +8,33 @@
import React from 'react';
import AppSelector from 'dashboard/AppSelector.react';
import AppsManager from 'lib/AppsManager';
-import history from 'dashboard/history';
import { CurrentApp } from 'context/currentApp';
+import { Outlet, useNavigate , useParams} from 'react-router-dom';
-class AppData extends React.Component {
- render() {
- if (this.props.params.appId === '_') {
- return ;
- }
- //Find by name to catch edge cases around escaping apostrophes in URLs
- let current = AppsManager.findAppBySlugOrName(this.props.params.appId);
- if (current) {
- current.setParseKeys();
- } else {
- history.replace('/apps');
- return ;
- }
- return (
-
-
- {this.props.children}
-
-
- );
+
+function AppData() {
+ const navigate = useNavigate();
+ const params = useParams();
+
+ if (params.appId === '_') {
+ return ;
+ }
+
+ // Find by name to catch edge cases around escaping apostrophes in URLs
+ let current = AppsManager.findAppBySlugOrName(params.appId);
+
+ if (current) {
+ current.setParseKeys();
+ } else {
+ navigate('/apps', { replace: true });
+ return ;
}
+
+ return (
+
+
+
+ );
}
export default AppData;
diff --git a/src/dashboard/AppSelector.react.js b/src/dashboard/AppSelector.react.js
index 722cfdb6f8..aba0f84ca7 100644
--- a/src/dashboard/AppSelector.react.js
+++ b/src/dashboard/AppSelector.react.js
@@ -8,13 +8,14 @@
import AppsManager from 'lib/AppsManager';
import Dropdown from 'components/Dropdown/Dropdown.react';
import Field from 'components/Field/Field.react';
-import history from 'dashboard/history';
import Label from 'components/Label/Label.react';
import Modal from 'components/Modal/Modal.react';
import Option from 'components/Dropdown/Option.react';
import React from 'react';
+import { withRouter } from 'lib/withRouter';
-export default class AppSelector extends React.Component {
+@withRouter
+class AppSelector extends React.Component {
constructor(props) {
super(props);
let apps = AppsManager.apps();
@@ -25,12 +26,12 @@ export default class AppSelector extends React.Component {
}
handleConfirm() {
- let newPath = location.pathname.replace(/\/_(\/|$)/, '/' + this.state.slug + '/');
- history.push(newPath);
+ let newPath = this.location.pathname.replace(/\/_(\/|$)/, '/' + this.state.slug + '/');
+ this.props.navigate(newPath);
}
handleCancel() {
- history.push('/apps');
+ this.props.navigate('/apps');
}
render() {
@@ -58,3 +59,5 @@ export default class AppSelector extends React.Component {
);
}
}
+
+export default AppSelector;
diff --git a/src/dashboard/Apps/AppsIndex.react.js b/src/dashboard/Apps/AppsIndex.react.js
index eca859d94b..4b1d5efbd5 100644
--- a/src/dashboard/Apps/AppsIndex.react.js
+++ b/src/dashboard/Apps/AppsIndex.react.js
@@ -7,7 +7,6 @@
*/
import AppsManager from 'lib/AppsManager';
import FlowFooter from 'components/FlowFooter/FlowFooter.react';
-import history from 'dashboard/history';
import html from 'lib/htmlString';
import Icon from 'components/Icon/Icon.react';
import joinWithFinal from 'lib/joinWithFinal';
@@ -17,6 +16,8 @@ import React from 'react';
import styles from 'dashboard/Apps/AppsIndex.scss';
import baseStyles from 'stylesheets/base.scss';
import AppBadge from 'components/AppBadge/AppBadge.react';
+import { withRouter } from 'lib/withRouter';
+import { useNavigate } from 'react-router-dom';
function dash(value, content) {
if (value === undefined) {
@@ -64,7 +65,8 @@ let AppCard = ({
app,
icon,
}) => {
- let canBrowse = app.serverInfo.error ? null : () => history.push(html`/apps/${app.slug}/browser`);
+ const navigate = useNavigate();
+ let canBrowse = app.serverInfo.error ? null : () => navigate(html`/apps/${app.slug}/browser`);
let versionMessage = app.serverInfo.error ?
Server not reachable: {app.serverInfo.error.toString()}
:
@@ -88,7 +90,8 @@ let AppCard = ({
}
-export default class AppsIndex extends React.Component {
+@withRouter
+class AppsIndex extends React.Component {
constructor() {
super();
this.state = { search: '' };
@@ -99,7 +102,7 @@ export default class AppsIndex extends React.Component {
componentWillMount() {
if (AppsManager.apps().length === 1) {
const [app] = AppsManager.apps();
- history.push(`/apps/${app.slug}/browser`);
+ this.props.navigate(`/apps/${app.slug}/browser`);
return;
}
document.body.addEventListener('keydown', this.focusField);
@@ -169,3 +172,5 @@ export default class AppsIndex extends React.Component {
);
}
}
+
+export default AppsIndex;
diff --git a/src/dashboard/Dashboard.js b/src/dashboard/Dashboard.js
index ebde1004f4..3a639cdb79 100644
--- a/src/dashboard/Dashboard.js
+++ b/src/dashboard/Dashboard.js
@@ -19,7 +19,6 @@ import Explorer from './Analytics/Explorer/Explorer.react';
import FourOhFour from 'components/FourOhFour/FourOhFour.react';
import GeneralSettings from './Settings/GeneralSettings.react';
import GraphQLConsole from './Data/ApiConsole/GraphQLConsole.react';
-import history from 'dashboard/history';
import HostingSettings from './Settings/HostingSettings.react';
import Icon from 'components/Icon/Icon.react';
import JobEdit from 'dashboard/Data/Jobs/JobEdit.react';
@@ -49,11 +48,7 @@ import { AsyncStatus } from 'lib/Constants';
import baseStyles from 'stylesheets/base.scss';
import { get } from 'lib/AJAX';
import { setBasePath } from 'lib/AJAX';
-import {
- Router,
- Switch,
-} from 'react-router';
-import { Route, Redirect } from 'react-router-dom';
+import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import { Helmet } from 'react-helmet';
import Playground from './Data/Playground/Playground.react';
@@ -202,146 +197,121 @@ export default class Dashboard extends React.Component {
);
- const SettingsRoute = ({ match }) => (
-
-
-
-
-
-
-
-
-
+ const SettingsRoute = (
+
}>
+
} />
+
} />
+
} />
+
} />
+
} />
+
} />
+
)
- const JobsRoute = (props) => (
-
- (
-
-
-
- )} />
- (
-
-
-
- )} />
- (
-
-
-
- )} />
-
-
+ const JobsRoute = (
+
}>
+
} />
+
} />
+
} />
+
} />
+
)
- const AnalyticsRoute = ({ match }) => (
-
-
-
-
-
-
-
-
- );
+ const AnalyticsRoute = (
+
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+
+ )
- const BrowserRoute = (props) => {
- if (ShowSchemaOverview) {
- return
- }
- return
- }
+ const BrowserRoute = ShowSchemaOverview ? SchemaOverview : Browser;
- const ApiConsoleRoute = (props) => (
-
- (
-
-
-
- )} />
- (
-
-
-
- )} />
- (
-
-
-
- )} />
-
-
+ const ApiConsoleRoute = (
+
}>
+
} />
+
} />
+
} />
+
} />
+
)
- const AppRoute = ({ match }) => (
-
-
-
-
-
-
-
-
-
+ const AppRoute = (
+ }>
+ } />
+
+ } />
+
+ } />
+ } />
+ } />
+
+ } />
+ } />
+ } />
-
+
+ {JobsRoute}
+
- (
-
- )} />
-
+ } />
+ } />
-
-
-
+ } />
+
+ {ApiConsoleRoute}
+
-
-
+ } />
- (
-
- )} />
-
-
- (
-
- )} />
+ } />
+ } />
- {/* Unused routes... */}
-
-
-
-
-
-
+
} />
+
} />
+
} />
+
} />
+
+ {/* Unused routes... */}
+
+ {AnalyticsRoute}
+
+
+
+ {SettingsRoute}
+
+
)
- const Index = () => (
-
-
-
-
-
-
-
+ const Index = (
+
+ } />
+
+ {AppRoute}
+
+
)
+
return (
-
-
-
- Parse Dashboard
-
-
-
-
-
-
-
-
-
-
+
+
+ Parse Dashboard
+
+
+
+ {Index}
+
+ } />
+ } />
+ } />
+ } />
+
+
);
}
}
diff --git a/src/dashboard/Data/ApiConsole/ApiConsole.react.js b/src/dashboard/Data/ApiConsole/ApiConsole.react.js
index 46ab64cef9..513e26c683 100644
--- a/src/dashboard/Data/ApiConsole/ApiConsole.react.js
+++ b/src/dashboard/Data/ApiConsole/ApiConsole.react.js
@@ -8,8 +8,11 @@
import React from 'react';
import CategoryList from 'components/CategoryList/CategoryList.react';
import DashboardView from 'dashboard/DashboardView.react';
+import { Outlet } from 'react-router-dom';
+import { withRouter } from 'lib/withRouter';
-export default class ApiConsole extends DashboardView {
+@withRouter
+class ApiConsole extends DashboardView {
constructor() {
super();
this.section = 'Core';
@@ -17,8 +20,8 @@ export default class ApiConsole extends DashboardView {
}
renderSidebar() {
- const { path } = this.props.match;
- const current = path.substr(path.lastIndexOf('/') + 1, path.length - 1);
+ const { pathname } = this.props.location;
+ const current = pathname.substr(pathname.lastIndexOf('/') + 1, pathname.length - 1);
return (
;
}
}
+
+export default ApiConsole;
diff --git a/src/dashboard/Data/Browser/Browser.react.js b/src/dashboard/Data/Browser/Browser.react.js
index 23702a7419..9cfecb36ba 100644
--- a/src/dashboard/Data/Browser/Browser.react.js
+++ b/src/dashboard/Data/Browser/Browser.react.js
@@ -21,7 +21,6 @@ import AttachSelectedRowsDialog from 'dashboard/Data/Browser/AttachSel
import CloneSelectedRowsDialog from 'dashboard/Data/Browser/CloneSelectedRowsDialog.react';
import EditRowDialog from 'dashboard/Data/Browser/EditRowDialog.react';
import ExportSelectedRowsDialog from 'dashboard/Data/Browser/ExportSelectedRowsDialog.react';
-import history from 'dashboard/history';
import { List, Map } from 'immutable';
import Notification from 'dashboard/Data/Browser/Notification.react';
import Parse from 'parse';
@@ -37,12 +36,13 @@ import subscribeTo from 'lib/subscribeTo';
import * as ColumnPreferences from 'lib/ColumnPreferences';
import { Helmet } from 'react-helmet';
import generatePath from 'lib/generatePath';
+import { withRouter } from 'lib/withRouter';
// The initial and max amount of rows fetched by lazy loading
const MAX_ROWS_FETCHED = 200;
-export default
@subscribeTo('Schema', 'schema')
+@withRouter
class Browser extends DashboardView {
constructor() {
super();
@@ -147,6 +147,7 @@ class Browser extends DashboardView {
this.saveEditCloneRow = this.saveEditCloneRow.bind(this);
this.abortEditCloneRow = this.abortEditCloneRow.bind(this);
this.cancelPendingEditRows = this.cancelPendingEditRows.bind(this);
+ this.redirectToFirstClass = this.redirectToFirstClass.bind(this);
this.dataBrowserRef = React.createRef();
window.addEventListener('popstate', () => {
@@ -246,7 +247,7 @@ class Browser extends DashboardView {
}
return a.toUpperCase() < b.toUpperCase() ? -1 : 1;
});
- history.replace(generatePath(context || this.context, 'browser/' + classes[0]));
+ this.props.navigate(generatePath(context || this.context, 'browser/' + classes[0]), { replace: true });
}
}
@@ -299,7 +300,7 @@ class Browser extends DashboardView {
createClass(className) {
this.props.schema.dispatch(ActionTypes.CREATE_CLASS, { className }).then(() => {
this.state.counts[className] = 0;
- history.push(generatePath(this.context, 'browser/' + className));
+ this.props.navigate(generatePath(this.context, 'browser/' + className));
}).finally(() => {
this.setState({ showCreateClassDialog: false });
});
@@ -309,7 +310,7 @@ class Browser extends DashboardView {
this.props.schema.dispatch(ActionTypes.DROP_CLASS, { className }).then(() => {
this.setState({showDropClassDialog: false });
delete this.state.counts[className];
- history.push(generatePath(this.context, 'browser'));
+ this.props.navigate(generatePath(this.context, 'browser'));
}, (error) => {
let msg = typeof error === 'string' ? error : error.message;
if (msg) {
@@ -802,7 +803,7 @@ class Browser extends DashboardView {
const _filters = JSON.stringify(filters.toJSON());
const url = `browser/${source}${(filters.size === 0 ? '' : `?filters=${(encodeURIComponent(_filters))}`)}`;
// filters param change is making the fetch call
- history.push(generatePath(this.context, url));
+ this.props.navigate(generatePath(this.context, url));
}
}
@@ -837,7 +838,7 @@ class Browser extends DashboardView {
filterQueryString = encodeURIComponent(JSON.stringify(filters.toJSON()));
}
const url = `${this.getRelationURL()}${filterQueryString ? `?filters=${filterQueryString}` : ''}`;
- history.push(url);
+ this.props.navigate(url);
});
this.fetchRelation(relation, filters);
}
@@ -848,7 +849,7 @@ class Browser extends DashboardView {
constraint: 'eq',
compareTo: id
}]);
- history.push(generatePath(this.context, `browser/${className}?filters=${encodeURIComponent(filters)}`));
+ this.props.navigate(generatePath(this.context, `browser/${className}?filters=${encodeURIComponent(filters)}`));
}
handlePointerCmdClick({ className, id, field = 'objectId' }) {
@@ -1784,3 +1785,5 @@ class Browser extends DashboardView {
);
}
}
+
+export default Browser;
diff --git a/src/dashboard/Data/Browser/CreateClassDialog.react.js b/src/dashboard/Data/Browser/CreateClassDialog.react.js
index e54f345157..9c2747bccf 100644
--- a/src/dashboard/Data/Browser/CreateClassDialog.react.js
+++ b/src/dashboard/Data/Browser/CreateClassDialog.react.js
@@ -13,13 +13,14 @@ import Option from 'components/Dropdown/Option.react';
import React from 'react';
import { SpecialClasses } from 'lib/Constants';
import TextInput from 'components/TextInput/TextInput.react';
-import history from 'dashboard/history';
+import { withRouter } from 'lib/withRouter';
function validClassName(name) {
return !!name.match(/^[a-zA-Z][_a-zA-Z0-9]*$/);
}
-export default class CreateClassDialog extends React.Component {
+@withRouter
+class CreateClassDialog extends React.Component {
constructor() {
super();
this.state = {
@@ -76,7 +77,7 @@ export default class CreateClassDialog extends React.Component {
let type = this.state.type;
let className = type === 'Custom' ? this.state.name : type;
await this.props.onConfirm(className);
- history.push(`/apps/${this.props.currentAppSlug}/browser/${className}`);
+ this.props.navigate(`/apps/${this.props.currentAppSlug}/browser/${className}`);
this.props.onAddColumn();
}}
onConfirm={() => {
@@ -101,3 +102,5 @@ export default class CreateClassDialog extends React.Component {
);
}
}
+
+export default CreateClassDialog;
diff --git a/src/dashboard/Data/CloudCode/CloudCode.react.js b/src/dashboard/Data/CloudCode/CloudCode.react.js
index e75324db7f..8af0698389 100644
--- a/src/dashboard/Data/CloudCode/CloudCode.react.js
+++ b/src/dashboard/Data/CloudCode/CloudCode.react.js
@@ -9,17 +9,18 @@ import CodeSnippet from 'components/CodeSnippet/CodeSnippet.react';
import DashboardView from 'dashboard/DashboardView.react';
import EmptyState from 'components/EmptyState/EmptyState.react';
import FileTree from 'components/FileTree/FileTree.react';
-import history from 'dashboard/history';
import React from 'react';
import styles from 'dashboard/Data/CloudCode/CloudCode.scss';
import Toolbar from 'components/Toolbar/Toolbar.react';
import generatePath from 'lib/generatePath';
+import { withRouter } from 'lib/withRouter';
function getPath(params) {
return params.splat;
}
-export default class CloudCode extends DashboardView {
+@withRouter
+class CloudCode extends DashboardView {
constructor() {
super();
this.section = 'Core';
@@ -53,7 +54,7 @@ export default class CloudCode extends DashboardView {
if (!fileName || release.files[fileName] === undefined) {
// Means we're still in /cloud_code/. Let's redirect to /cloud_code/main.js
- history.replace(generatePath(this.context, 'cloud_code/main.js'))
+ this.props.navigate(generatePath(this.context, 'cloud_code/main.js'), { replace: true });
} else {
// Means we can load /cloud_code/
app.getSource(fileName).then(
@@ -129,3 +130,5 @@ export default class CloudCode extends DashboardView {
);
}
}
+
+export default CloudCode;
diff --git a/src/dashboard/Data/Jobs/JobEdit.react.js b/src/dashboard/Data/Jobs/JobEdit.react.js
index 1c7008156c..6e1111ffe4 100644
--- a/src/dashboard/Data/Jobs/JobEdit.react.js
+++ b/src/dashboard/Data/Jobs/JobEdit.react.js
@@ -6,14 +6,15 @@
* the root directory of this source tree.
*/
import { ActionTypes } from 'lib/stores/JobsStore';
-import history from 'dashboard/history';
import JobsForm from 'dashboard/Data/Jobs/JobsForm.react';
import React from 'react';
import subscribeTo from 'lib/subscribeTo';
import generatePath from 'lib/generatePath';
import { CurrentApp } from 'context/currentApp';
+import { withRouter } from 'lib/withRouter';
@subscribeTo('Jobs', 'jobs')
+@withRouter
class JobEdit extends React.Component {
static contextType = CurrentApp;
@@ -51,7 +52,7 @@ class JobEdit extends React.Component {
let promise = this.props.params.jobId ?
this.props.jobs.dispatch(ActionTypes.EDIT, { jobId: this.props.params.jobId, updates: schedule }) :
this.props.jobs.dispatch(ActionTypes.CREATE, { schedule });
- promise.then(() => {history.push(generatePath(this.context, 'jobs/scheduled'))});
+ promise.then(() => {this.props.navigate(generatePath(this.context, 'jobs/scheduled'))});
return promise;
}
diff --git a/src/dashboard/Data/Jobs/Jobs.react.js b/src/dashboard/Data/Jobs/Jobs.react.js
index 5d1521f9fd..d163847db8 100644
--- a/src/dashboard/Data/Jobs/Jobs.react.js
+++ b/src/dashboard/Data/Jobs/Jobs.react.js
@@ -10,7 +10,6 @@ import Button from 'components/Button/Button.react';
import * as DateUtils from 'lib/DateUtils';
import CategoryList from 'components/CategoryList/CategoryList.react';
import EmptyState from 'components/EmptyState/EmptyState.react';
-import history from 'dashboard/history';
import Icon from 'components/Icon/Icon.react';
import JobScheduleReminder from 'dashboard/Data/Jobs/JobScheduleReminder.react';
import Modal from 'components/Modal/Modal.react';
@@ -26,6 +25,7 @@ import TableHeader from 'components/Table/TableHeader.react';
import TableView from 'dashboard/TableView.react';
import Toolbar from 'components/Toolbar/Toolbar.react';
import generatePath from 'lib/generatePath';
+import { withRouter } from 'lib/withRouter';
let subsections = {
all: 'All Jobs',
@@ -61,8 +61,8 @@ function scheduleString(data) {
}
// TODO: create scrollable view component that handles lazy fetch container on scroll
-export default
@subscribeTo('Jobs', 'jobs')
+@withRouter
class Jobs extends TableView {
constructor() {
super();
@@ -92,11 +92,11 @@ class Jobs extends TableView {
}
navigateToNew() {
- history.push(generatePath(this.context, 'jobs/new'));
+ this.props.navigate(generatePath(this.context, 'jobs/new'));
}
navigateToJob(jobId) {
- history.push(generatePath(this.context, `jobs/edit/${jobId}`))
+ this.props.navigate(generatePath(this.context, `jobs/edit/${jobId}`))
}
loadData() {
@@ -300,3 +300,5 @@ class Jobs extends TableView {
return null;
}
}
+
+export default Jobs;
diff --git a/src/dashboard/Data/Jobs/JobsData.react.js b/src/dashboard/Data/Jobs/JobsData.react.js
index 574ba5453c..441dd7c25b 100644
--- a/src/dashboard/Data/Jobs/JobsData.react.js
+++ b/src/dashboard/Data/Jobs/JobsData.react.js
@@ -7,6 +7,7 @@
*/
import React from 'react';
import { CurrentApp } from 'context/currentApp';
+import { Outlet } from 'react-router-dom';
export default class JobsData extends React.Component {
static contextType = CurrentApp;
@@ -58,15 +59,14 @@ export default class JobsData extends React.Component {
}
render() {
- let child = React.Children.only(this.props.children);
- return React.cloneElement(
- child,
- {
- ...child.props,
- availableJobs: this.state.jobs,
- jobsInUse: this.state.inUse,
- release: this.state.release
- }
+ return (
+
);
}
}
diff --git a/src/dashboard/Data/Logs/Logs.react.js b/src/dashboard/Data/Logs/Logs.react.js
index 2e2a5c5027..27ce8eb8f6 100644
--- a/src/dashboard/Data/Logs/Logs.react.js
+++ b/src/dashboard/Data/Logs/Logs.react.js
@@ -15,13 +15,15 @@ import ReleaseInfo from 'components/ReleaseInfo/ReleaseInfo';
import Toolbar from 'components/Toolbar/Toolbar.react';
import styles from 'dashboard/Data/Logs/Logs.scss';
+import { withRouter } from 'lib/withRouter';
let subsections = {
info: 'Info',
error: 'Error'
};
-export default class Logs extends DashboardView {
+@withRouter
+class Logs extends DashboardView {
constructor() {
super();
this.section = 'Core';
@@ -120,3 +122,5 @@ export default class Logs extends DashboardView {
);
}
}
+
+export default Logs;
diff --git a/src/dashboard/Push/PushAudiencesIndex.react.js b/src/dashboard/Push/PushAudiencesIndex.react.js
index 9168f0ea69..1120719f29 100644
--- a/src/dashboard/Push/PushAudiencesIndex.react.js
+++ b/src/dashboard/Push/PushAudiencesIndex.react.js
@@ -12,7 +12,6 @@ import Button from 'components/Button/Button.react';
import DashboardView from 'dashboard/DashboardView.react';
import EmptyState from 'components/EmptyState/EmptyState.react';
import FormModal from 'components/FormModal/FormModal.react';
-import history from 'dashboard/history';
import LoaderContainer from 'components/LoaderContainer/LoaderContainer.react';
import Modal from 'components/Modal/Modal.react';
import PushAudienceDialog from 'components/PushAudienceDialog/PushAudienceDialog.react';
@@ -27,12 +26,13 @@ import Toolbar from 'components/Toolbar/Toolbar.react';
import { formatAudienceSchema } from 'lib/PushUtils';
import { List } from 'immutable';
import generatePath from 'lib/generatePath';
+import { withRouter } from 'lib/withRouter';
const XHR_KEY = 'PushAudiencesIndex';
-export default
@subscribeTo('Schema', 'schema')
@subscribeTo('PushAudiences', 'pushaudiences')
+@withRouter
class PushAudiencesIndex extends DashboardView {
constructor() {
super();
@@ -111,7 +111,7 @@ class PushAudiencesIndex extends DashboardView {
}
handleSendPush(objectId) {
- history.push(generatePath(this.context, `push/new?audienceId=${objectId}`));
+ this.props.navigate(generatePath(this.context, `push/new?audienceId=${objectId}`));
}
renderRow(audience) {
@@ -276,3 +276,5 @@ class PushAudiencesIndex extends DashboardView {
);
}
}
+
+export default PushAudiencesIndex;
diff --git a/src/dashboard/Push/PushDetails.react.js b/src/dashboard/Push/PushDetails.react.js
index cc022301b7..3ab30046bc 100644
--- a/src/dashboard/Push/PushDetails.react.js
+++ b/src/dashboard/Push/PushDetails.react.js
@@ -15,7 +15,6 @@ import Field from 'components/Field/Field.react';
import Fieldset from 'components/Fieldset/Fieldset.react';
import FieldStyles from 'components/Field/Field.scss';
import FlowView from 'components/FlowView/FlowView.react';
-import history from 'dashboard/history';
import Label from 'components/Label/Label.react';
import LoaderContainer from 'components/LoaderContainer/LoaderContainer.react';
import Parse from 'parse';
@@ -33,6 +32,7 @@ import { Directions } from 'lib/Constants';
import { Link } from 'react-router-dom';
import { tableInfoBuilder } from 'lib/PushUtils';
import generatePath from 'lib/generatePath';
+import { withRouter } from 'lib/withRouter';
const EXP_STATS_URL = 'http://docs.parseplatform.org/ios/guide/#push-experiments';
@@ -200,8 +200,8 @@ const COLOR_MAP = {
const DROPDOWN_KEY_GROUP_A = 'Group A';
const DROPDOWN_KEY_GROUP_B = 'Group B';
-export default
@subscribeTo('Schema', 'schema')
+@withRouter
class PushDetails extends DashboardView {
constructor() {
super();
@@ -472,7 +472,7 @@ class PushDetails extends DashboardView {
prevLaunchGroup = (
- This push is the Launch Group for a previous experiment.
+ This push is the Launch Group for a previous experiment.
);
@@ -586,7 +586,7 @@ class PushDetails extends DashboardView {
if (error) {
promise.reject({ error });
} else {
- history.push(generatePath(this.context, 'push/activity'));
+ this.props.navigate(generatePath(this.context, 'push/activity'));
}
}, (error) => {
promise.reject({ error });
@@ -744,3 +744,5 @@ class PushDetails extends DashboardView {
);
}
}
+
+export default PushDetails;
diff --git a/src/dashboard/Push/PushIndex.react.js b/src/dashboard/Push/PushIndex.react.js
index 5e025fb0b6..79f39d55ff 100644
--- a/src/dashboard/Push/PushIndex.react.js
+++ b/src/dashboard/Push/PushIndex.react.js
@@ -11,7 +11,6 @@ import Button from 'components/Button/Button.react';
import CategoryList from 'components/CategoryList/CategoryList.react';
import DashboardView from 'dashboard/DashboardView.react';
import EmptyState from 'components/EmptyState/EmptyState.react';
-import history from 'dashboard/history';
import LoaderContainer from 'components/LoaderContainer/LoaderContainer.react';
import LoaderDots from 'components/LoaderDots/LoaderDots.react';
import React from 'react';
@@ -22,6 +21,7 @@ import stylesTable from 'dashboard/TableView.scss';
import TableHeader from 'components/Table/TableHeader.react';
import Toolbar from 'components/Toolbar/Toolbar.react';
import generatePath from 'lib/generatePath';
+import { withRouter } from 'lib/withRouter';
const PUSH_TYPE_ALL = 'all';
const PUSH_TYPE_CAMPAIGN = 'campaign';
@@ -227,7 +227,8 @@ let getPushTime = (pushTime, updatedAt) => {
return result;
}
-export default class PushIndex extends DashboardView {
+@withRouter
+class PushIndex extends DashboardView {
constructor() {
super();
this.section = 'Push';
@@ -294,11 +295,11 @@ export default class PushIndex extends DashboardView {
}
navigateToNew() {
- history.push(generatePath(this.context, 'push/new'));
+ this.props.navigate(generatePath(this.context, 'push/new'));
}
navigateToDetails(objectId) {
- history.push(generatePath(this.context, `push/${objectId}`));
+ this.props.navigate(generatePath(this.context, `push/${objectId}`));
}
handleShowMore(page) {
@@ -447,3 +448,5 @@ export default class PushIndex extends DashboardView {
);
}
}
+
+export default PushIndex;
diff --git a/src/dashboard/Push/PushNew.react.js b/src/dashboard/Push/PushNew.react.js
index 3c964a161c..48b056f5dd 100644
--- a/src/dashboard/Push/PushNew.react.js
+++ b/src/dashboard/Push/PushNew.react.js
@@ -17,7 +17,6 @@ import Field from 'components/Field/Field.react';
import Fieldset from 'components/Fieldset/Fieldset.react';
import FieldStyles from 'components/Field/Field.scss';
import FlowView from 'components/FlowView/FlowView.react';
-import history from 'dashboard/history';
import joinWithFinal from 'lib/joinWithFinal';
import Label from 'components/Label/Label.react';
import Option from 'components/Dropdown/Option.react';
@@ -37,6 +36,7 @@ import Toolbar from 'components/Toolbar/Toolbar.react';
import { Directions } from 'lib/Constants';
import { extractExpiration, extractPushTime } from 'lib/extractTime';
import generatePath from 'lib/generatePath';
+import { withRouter } from 'lib/withRouter';
const PARSE_SERVER_SUPPORTS_AB_TESTING = false;
@@ -121,9 +121,9 @@ let LocalizedMessageField = ({
const XHR_KEY = 'PushNew';
-export default
@subscribeTo('Schema', 'schema')
@subscribeTo('PushAudiences', 'pushaudiences')
+@withRouter
class PushNew extends DashboardView {
constructor() {
super();
@@ -230,7 +230,7 @@ class PushNew extends DashboardView {
//TODO: global success message banner for passing successful creation - store should also be cleared
const PARSE_SERVER_SUPPORTS_PUSH_INDEX = false;
if (PARSE_SERVER_SUPPORTS_PUSH_INDEX) {
- history.push(generatePath(this.context, 'push/activity'));
+ this.props.navigate(generatePath(this.context, 'push/activity'));
} else {
return;
}
@@ -895,3 +895,5 @@ class PushNew extends DashboardView {
}}/>;
}
}
+
+export default PushNew;
diff --git a/src/dashboard/Settings/GeneralSettings.react.js b/src/dashboard/Settings/GeneralSettings.react.js
index 8cff83780a..9a9981ab54 100644
--- a/src/dashboard/Settings/GeneralSettings.react.js
+++ b/src/dashboard/Settings/GeneralSettings.react.js
@@ -18,7 +18,6 @@ import FormButton from 'components/FormButton/FormButton.
import FormModal from 'components/FormModal/FormModal.react';
import FormNote from 'components/FormNote/FormNote.react';
import getSiteDomain from 'lib/getSiteDomain';
-import history from 'dashboard/history';
import joinWithFinal from 'lib/joinWithFinal';
import KeyField from 'components/KeyField/KeyField.react';
import Label from 'components/Label/Label.react';
@@ -37,7 +36,8 @@ import Toolbar from 'components/Toolbar/Toolbar.react'
import unique from 'lib/unique';
import validateAndSubmitConnectionString from 'lib/validateAndSubmitConnectionString';
import styles from 'dashboard/Settings/GeneralSettings.scss';
-import { Link } from 'react-router-dom';
+import { Link, useNavigate } from 'react-router-dom';
+import { withRouter } from 'lib/withRouter';
const DEFAULT_SETTINGS_LABEL_WIDTH = 62;
@@ -204,6 +204,7 @@ let ManageAppFields = ({
transferAppMessage,
deleteApp,
}) => {
+ const navigate = useNavigate();
let migrateAppField = null;
if (!mongoURL && !hasInProgressMigration) {
migrateAppField = }
input={ history.push(`/apps/${appSlug}/migration`)}
+ onClick={() => navigate(`/apps/${appSlug}/migration`)}
value='View progress' />} />
} else {
migrateAppField = [
- {cloneAppMessage} Check out the progress on your apps page!
+ {cloneAppMessage} Check out the progress on your apps page!
: null}
{!isCollaborator ? );
}
-export default class GeneralSettings extends DashboardView {
+@withRouter
+class GeneralSettings extends DashboardView {
constructor() {
super();
this.section = 'App Settings';
@@ -424,7 +426,7 @@ export default class GeneralSettings extends DashboardView {
return promise;
}}
onClose={closeModalWithConnectionString}
- onSuccess={() => history.push(`/apps/${this.context.slug}/migration`)}
+ onSuccess={() => this.props.navigate(`/apps/${this.context.slug}/migration`)}
clearFields={() => this.setState({
migrationMongoURL: '',
migrationWarnings: [],
@@ -535,7 +537,7 @@ export default class GeneralSettings extends DashboardView {
inProgressText={'Deleting\u2026'}
enabled={this.state.password.length > 0}
onSubmit={() => AppsManager.deleteApp(this.context.slug, this.state.password)}
- onSuccess={() => history.push('/apps')}
+ onSuccess={() => this.props.navigate('/apps')}
onClose={() => this.setState({showDeleteAppModal: false})}
clearFields={() => this.setState({password: ''})}>
{passwordField}
@@ -797,3 +799,5 @@ let generalFieldsOptions = {
friendlyName: 'other URL',
},
};
+
+export default GeneralSettings;
diff --git a/src/dashboard/Settings/SettingsData.react.js b/src/dashboard/Settings/SettingsData.react.js
index 4b2a37e931..161ea0614b 100644
--- a/src/dashboard/Settings/SettingsData.react.js
+++ b/src/dashboard/Settings/SettingsData.react.js
@@ -7,6 +7,7 @@
*/
import React from 'react';
import { CurrentApp } from 'context/currentApp';
+import { Outlet } from 'react-router-dom';
export default class SettingsData extends React.Component {
static contextType = CurrentApp;
@@ -43,14 +44,13 @@ export default class SettingsData extends React.Component {
}
render() {
- let child = React.Children.only(this.props.children);
- return React.cloneElement(
- child,
- {
- ...child.props,
- initialFields: this.state.fields,
- saveChanges: this.saveChanges.bind(this)
- }
+ return (
+
);
}
}
diff --git a/src/dashboard/history.js b/src/dashboard/history.js
deleted file mode 100644
index 35dd81d965..0000000000
--- a/src/dashboard/history.js
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Copyright (c) 2016-present, Parse, LLC
- * All rights reserved.
- *
- * This source code is licensed under the license found in the LICENSE file in
- * the root directory of this source tree.
- */
-
-import { createBrowserHistory } from 'history';
-
-const path = window.PARSE_DASHBOARD_PATH || '/';
-export default createBrowserHistory({ basename: path });
diff --git a/src/lib/withRouter.js b/src/lib/withRouter.js
new file mode 100644
index 0000000000..707c1a6e6e
--- /dev/null
+++ b/src/lib/withRouter.js
@@ -0,0 +1,18 @@
+import React from 'react';
+import { useParams, useNavigate, useOutletContext, useLocation } from 'react-router-dom';
+
+export function withRouter(Component) {
+ function render(props) {
+ const params = useParams();
+ const navigate = useNavigate();
+ const outletContext = useOutletContext();
+ const location = useLocation();
+
+ return ;
+ }
+
+ const name = Component.displayName || Component.name;
+ render.displayName = `withRouter(${name})`;
+
+ return render;
+}
diff --git a/src/parse-interface-guide/PIG.react.js b/src/parse-interface-guide/PIG.react.js
index 15a009dc8a..800ef521b1 100644
--- a/src/parse-interface-guide/PIG.react.js
+++ b/src/parse-interface-guide/PIG.react.js
@@ -6,20 +6,22 @@
* the root directory of this source tree.
*/
import * as ComponentsMap from 'parse-interface-guide/ComponentsMap';
-import { Link } from 'react-router-dom';
+import { NavLink } from 'react-router-dom';
import Icon from 'components/Icon/Icon.react';
import PropsTable from 'parse-interface-guide/PropsTable.react';
import React from 'react';
import styles from 'parse-interface-guide/PIG.scss';
import beautify from 'js-beautify';
import CodeSnippet from 'components/CodeSnippet/CodeSnippet.react';
+import { withRouter } from 'lib/withRouter';
let PIGRow = ({ title, children }) => ;
-export default class PIG extends React.Component {
+@withRouter
+class PIG extends React.Component {
constructor() {
super();
@@ -46,7 +48,7 @@ export default class PIG extends React.Component {
}}/>
{components.map((name) => {
return name.toLowerCase().indexOf(this.state.query.toLowerCase()) !== -1
- ? {name}
+ ? isActive ? styles.active : undefined} key={name} to={`/${name}`}>{name}
: null;
})}
@@ -54,7 +56,7 @@ export default class PIG extends React.Component {
}
renderContent() {
- let componentInfo = ComponentsMap[this.props.params.component];
+ let componentInfo = ComponentsMap[this.props.params['*']];
if (!componentInfo) {
componentInfo = ComponentsMap[Object.keys(ComponentsMap)[0]];
}
@@ -89,3 +91,5 @@ export default class PIG extends React.Component {
);
}
}
+
+export default PIG;
diff --git a/src/parse-interface-guide/routes.js b/src/parse-interface-guide/routes.js
index c270bb8f64..d6cc233d0a 100644
--- a/src/parse-interface-guide/routes.js
+++ b/src/parse-interface-guide/routes.js
@@ -7,18 +7,14 @@
*/
import PIG from 'parse-interface-guide/PIG.react';
import React from 'react';
-import { Router, Route } from 'react-router';
-import { createBrowserHistory } from 'history';
-const history = createBrowserHistory({});
+import { BrowserRouter, Routes, Route } from 'react-router-dom';
const routes = (
-
-
-
+
+
+ } />
+
+
);
export default routes