From 1401f3dfc966e969f1e0240be586fc38417d1c70 Mon Sep 17 00:00:00 2001 From: Adam Abeshouse Date: Mon, 9 Nov 2020 19:58:19 -0500 Subject: [PATCH] Upgrade react-router and mobx-react-router Signed-off-by: Adam Abeshouse Former-commit-id: 660da00efb1993a0510f037174356b6f5dbc70ca --- .babelrc | 11 +- package.json | 10 +- src/appBootstrapper.jsx | 14 +- src/appShell/App/Container.tsx | 3 +- src/appShell/App/PortalFooter.tsx | 2 +- src/appShell/App/PortalHeader.tsx | 6 +- .../GroupComparisonLoading.tsx | 2 +- .../groupComparison/GroupComparisonPage.tsx | 2 +- src/pages/patientView/PatientViewPage.tsx | 2 +- src/pages/resultsView/ResultsViewPage.tsx | 2 +- .../mutationMapper/MutationMapperTool.tsx | 2 +- src/pages/studyView/StudyViewPage.tsx | 2 +- src/routes.jsx | 510 +++++++++--------- src/shared/components/StudyLink/StudyLink.tsx | 2 +- .../DataAccessTokensDropdown.tsx | 2 +- .../components/errorScreen/ErrorScreen.tsx | 4 +- .../oncoprint/ResultsViewOncoprint.spec.tsx | 2 +- .../oncoprint/ResultsViewOncoprint.tsx | 4 - src/shared/components/rightbar/RightBar.tsx | 2 +- .../components/testimonials/Testimonials.tsx | 2 +- src/shared/lib/ExtendedRouterStore.spec.ts | 15 +- src/shared/lib/ExtendedRouterStore.ts | 12 +- src/shared/lib/URLWrapper.spec.ts | 48 +- src/shared/lib/URLWrapper.ts | 21 +- src/shared/lib/redirectHelpers.spec.ts | 6 +- src/shared/lib/redirectHelpers.ts | 16 +- src/shared/lib/seekUrlHash.ts | 10 +- webpack.config.js | 3 +- yarn.lock | 157 +++++- 29 files changed, 497 insertions(+), 377 deletions(-) diff --git a/.babelrc b/.babelrc index aba7f2837da..7f5c69e3227 100755 --- a/.babelrc +++ b/.babelrc @@ -2,10 +2,12 @@ "presets": ["@babel/preset-env"], "env": { "development": { - "presets": ["@babel/preset-env"] + "presets": ["@babel/preset-env"], + "plugins": ["@babel/plugin-syntax-dynamic-import"] }, "production": { - "presets": [] + "presets": [], + "plugins": ["@babel/plugin-syntax-dynamic-import"] }, "test": { "presets": [], @@ -15,8 +17,9 @@ "rewire", { "exclude": ["**/*.spec.js"] - } - ], + }, + "@babel/plugin-syntax-dynamic-import" + ] ] } } diff --git a/package.json b/package.json index 5ae4d7664fb..435e3128fb7 100644 --- a/package.json +++ b/package.json @@ -85,6 +85,7 @@ "@types/enzyme": "2.8.0", "@types/expired-storage": "^1.0.0", "@types/google.analytics": "0.0.39", + "@types/history": "^4.7.8", "@types/jquery": "^3.3.31", "@types/js-combinatorics": "0.5.29", "@types/jspdf": "^1.1.31", @@ -94,6 +95,7 @@ "@types/mocha": "2.2.41", "@types/numeral": "0.0.22", "@types/pdfobject": "2.0.5", + "@types/qs": "^6.9.5", "@types/raphael": "2.1.30", "@types/rc-slider": "^8.2.0", "@types/rc-tooltip": "3.7.0", @@ -106,6 +108,7 @@ "@types/react-helmet": "^5.0.7", "@types/react-overlays": "^0.6.9", "@types/react-router": "3.0.2", + "@types/react-router-dom": "^5.1.6", "@types/react-sortable-hoc": "^0.6.5", "@types/react-spinkit": "^1.1.35", "@types/react-table": "^6.8.7", @@ -160,6 +163,7 @@ "fork-ts-checker-webpack-plugin": "^1.2.0", "genome-nexus-ts-api-client": "^1.1.9", "git-revision-webpack-plugin": "^3.0.3", + "history": "4.10.1", "html-webpack-plugin": "3.2.0", "igv": "github:cBioPortal/igv.js#ccaeb7657200c8c1ceb276b53066d47804533418", "imports-loader": "^0.8.0", @@ -187,7 +191,7 @@ "mobx-react": "^4.1.3", "mobx-react-devtools": "^4.2.11", "mobx-react-lite": "^2.0.7", - "mobx-react-router": "^3.1.2", + "mobx-react-router": "4.1.0", "mobx-utils": "^2.0.1", "mobxpromise": "github:cbioportal/mobxpromise#v1.0.2", "node-sass": "^4.9.3", @@ -241,7 +245,8 @@ "react-renderif": "^1.0.2", "react-resize-detector": "^0.5.0", "react-reveal": "^1.2.2", - "react-router": "^3.0.2", + "react-router": "5.2.0", + "react-router-dom": "^5.2.0", "react-select": "^3.0.4", "react-select1": "npm:react-select@1.3.0", "react-sortable-hoc": "^1.9.1", @@ -299,6 +304,7 @@ "word-wrap": "^1.2.3" }, "devDependencies": { + "@babel/plugin-syntax-dynamic-import": "^7.8.3", "argparse": "^1.0.9", "babel-plugin-rewire": "^1.0.0", "chai": "^4.2.0", diff --git a/src/appBootstrapper.jsx b/src/appBootstrapper.jsx index 5e30b45f818..8cbdf491263 100755 --- a/src/appBootstrapper.jsx +++ b/src/appBootstrapper.jsx @@ -1,8 +1,8 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'mobx-react'; -import { Router, useRouterHistory } from 'react-router'; -import { createHistory } from 'history'; +import { Router, Switch } from 'react-router-dom'; +import { createHistory, createBrowserHistory } from 'history'; import { syncHistoryWithStore } from 'mobx-react-router'; import ExtendedRoutingStore from './shared/lib/ExtendedRouterStore'; import { @@ -31,6 +31,7 @@ import { handleLongUrls } from 'shared/lib/handleLongUrls'; import 'shared/polyfill/canvasToBlob'; import mobx from 'mobx'; import { setCurrentURLHeader } from 'shared/lib/extraHeader'; +import Container from 'appShell/App/Container'; superagentCache(superagent); @@ -97,9 +98,10 @@ _.noConflict(); const routingStore = new ExtendedRoutingStore(); -const history = useRouterHistory(createHistory)({ +const history = createBrowserHistory(); +/*useRouterHistory(createHistory)({ basename: AppConfig.basePath || '', -}); +});*/ const syncedHistory = syncHistoryWithStore(history, routingStore); @@ -152,7 +154,9 @@ let render = () => { ReactDOM.render( - + + + , rootNode ); diff --git a/src/appShell/App/Container.tsx b/src/appShell/App/Container.tsx index 37a60c132bc..5773a455646 100644 --- a/src/appShell/App/Container.tsx +++ b/src/appShell/App/Container.tsx @@ -27,6 +27,7 @@ import { GenieAgreement, shouldShowGenieWarning, } from 'appShell/App/usageAgreements/GenieAgreement'; +import makeRoutes from 'routes'; interface IContainerProps { location: Location; @@ -135,7 +136,7 @@ export default class Container extends React.Component {
- {this.props.children} + {makeRoutes(this.routingStore)}
diff --git a/src/appShell/App/PortalFooter.tsx b/src/appShell/App/PortalFooter.tsx index ae204b16bb6..501b31c28ea 100644 --- a/src/appShell/App/PortalFooter.tsx +++ b/src/appShell/App/PortalFooter.tsx @@ -4,7 +4,7 @@ import { If } from 'react-if'; // tslint:disable-next-line:no-import-side-effect import './footer.scss'; import _ from 'lodash'; -import { Link } from 'react-router'; +import { Link } from 'react-router-dom'; import { AppStore } from '../../AppStore'; import { observer } from 'mobx-react'; diff --git a/src/appShell/App/PortalHeader.tsx b/src/appShell/App/PortalHeader.tsx index 7b1e52ea91e..5aa027fe39d 100644 --- a/src/appShell/App/PortalHeader.tsx +++ b/src/appShell/App/PortalHeader.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import * as _ from 'lodash'; -import { Link } from 'react-router'; +import { Link, NavLink } from 'react-router-dom'; import AppConfig from 'appConfig'; import { If, Then, Else } from 'react-if'; import { openSocialAuthWindow } from '../../shared/lib/openSocialAuthWindow'; @@ -110,9 +110,9 @@ export default class PortalHeader extends React.Component< return (
  • {tab.internal ? ( - + {tab.text} - + ) : ( {tab.text} )} diff --git a/src/pages/groupComparison/GroupComparisonLoading.tsx b/src/pages/groupComparison/GroupComparisonLoading.tsx index 9d346d37c0e..b109e00b449 100644 --- a/src/pages/groupComparison/GroupComparisonLoading.tsx +++ b/src/pages/groupComparison/GroupComparisonLoading.tsx @@ -51,7 +51,7 @@ export default class GroupComparisonLoading extends React.Component< } render() { - const query = (window as any).routingStore.location.query as Partial< + const query = (window as any).routingStore.query as Partial< GroupComparisonLoadingParams >; if (this.studyViewWindowClosed) { diff --git a/src/pages/groupComparison/GroupComparisonPage.tsx b/src/pages/groupComparison/GroupComparisonPage.tsx index b9aa14a01f1..17a0e8f7366 100644 --- a/src/pages/groupComparison/GroupComparisonPage.tsx +++ b/src/pages/groupComparison/GroupComparisonPage.tsx @@ -89,7 +89,7 @@ export default class GroupComparisonPage extends React.Component< private getTabHref(tabId: string) { return URL.format({ pathname: tabId, - query: this.props.routing.location.query, + query: this.props.routing.query, hash: this.props.routing.location.hash, }); } diff --git a/src/pages/patientView/PatientViewPage.tsx b/src/pages/patientView/PatientViewPage.tsx index 33417435634..abe045da574 100644 --- a/src/pages/patientView/PatientViewPage.tsx +++ b/src/pages/patientView/PatientViewPage.tsx @@ -169,7 +169,7 @@ export default class PatientViewPage extends React.Component< //TODO: this should be done by a module so that it can be reused on other pages reaction( () => [ - props.routing.location.query, + props.routing.query, props.routing.location.hash, props.routing.location.pathname, ], diff --git a/src/pages/resultsView/ResultsViewPage.tsx b/src/pages/resultsView/ResultsViewPage.tsx index 1bde9e2ef77..10592eaacdc 100644 --- a/src/pages/resultsView/ResultsViewPage.tsx +++ b/src/pages/resultsView/ResultsViewPage.tsx @@ -534,7 +534,7 @@ export default class ResultsViewPage extends React.Component< private getTabHref(tabId: string) { return URL.format({ pathname: tabId, - query: this.props.routing.location.query, + query: this.props.routing.query, hash: this.props.routing.location.hash, }); } diff --git a/src/pages/staticPages/tools/mutationMapper/MutationMapperTool.tsx b/src/pages/staticPages/tools/mutationMapper/MutationMapperTool.tsx index d23d66fa1d0..e95cecd5d05 100644 --- a/src/pages/staticPages/tools/mutationMapper/MutationMapperTool.tsx +++ b/src/pages/staticPages/tools/mutationMapper/MutationMapperTool.tsx @@ -117,7 +117,7 @@ export default class MutationMapperTool extends React.Component< @computed get activeTabId(): string | undefined { // use routing if available, if not fall back to the observable variable return this.props.routing - ? this.props.routing.location.query.standaloneMutationMapperGeneTab + ? this.props.routing.query.standaloneMutationMapperGeneTab : this.standaloneMutationMapperGeneTab; } diff --git a/src/pages/studyView/StudyViewPage.tsx b/src/pages/studyView/StudyViewPage.tsx index 113faac9595..34fad9ba6f3 100644 --- a/src/pages/studyView/StudyViewPage.tsx +++ b/src/pages/studyView/StudyViewPage.tsx @@ -143,7 +143,7 @@ export default class StudyViewPage extends React.Component< return; } - const query = props.routing.location.query; + const query = props.routing.query; const hash = props.routing.location.hash; // clear hash if any props.routing.location.hash = ''; diff --git a/src/routes.jsx b/src/routes.jsx index da4d975203f..a029f07113f 100755 --- a/src/routes.jsx +++ b/src/routes.jsx @@ -1,5 +1,5 @@ -import React from 'react'; -import { Route, Redirect, IndexRoute } from 'react-router'; +import React, { useEffect } from 'react'; +import { Route, Redirect, Switch } from 'react-router-dom'; import { inject } from 'mobx-react'; import Container from 'appShell/App/Container'; import { @@ -25,27 +25,71 @@ import PageNotFound from './shared/components/pageNotFound/PageNotFound'; // which are invoked at run time by the routes // webpack knows to 'split' the code into seperate bundles accordingly // see article http://henleyedition.com/implicit-code-splitting-with-react-router-and-webpack/ -import PatientViewPage from 'bundle-loader?lazy!babel-loader!./pages/patientView/PatientViewPage'; -import ResultsViewPage from 'bundle-loader?lazy!babel-loader!./pages/resultsView/ResultsViewPage'; +const PatientViewPage = SuspenseWrapper( + React.lazy(() => import('./pages/patientView/PatientViewPage')) +); +const ResultsViewPage = SuspenseWrapper( + React.lazy(() => import('./pages/resultsView/ResultsViewPage')) +); import TestimonialsPage from 'pages/staticPages/testimonialsPage/TestimonialsPage'; import GroupComparisonLoading from './pages/groupComparison/GroupComparisonLoading'; -import DatasetPage from 'bundle-loader?lazy!babel-loader!./pages/staticPages/datasetView/DatasetPage'; -import Homepage from 'bundle-loader?lazy!babel-loader!./pages/home/HomePage'; -import StudyViewPage from 'bundle-loader?lazy!babel-loader!./pages/studyView/StudyViewPage'; -import MutationMapperTool from 'bundle-loader?lazy!babel-loader!./pages/staticPages/tools/mutationMapper/MutationMapperTool'; -import OncoprinterTool from 'bundle-loader?lazy!babel-loader!./pages/staticPages/tools/oncoprinter/OncoprinterTool'; -import WebAPIPage from 'bundle-loader?lazy!babel-loader!./pages/staticPages/webAPI/WebAPIPage'; -import RMATLAB from 'bundle-loader?lazy!babel-loader!./pages/staticPages/rmatlab/RMatLAB'; -import Tutorials from 'bundle-loader?lazy!babel-loader!./pages/staticPages/tutorials/Tutorials'; -import Visualize from 'bundle-loader?lazy!babel-loader!./pages/staticPages/visualize/Visualize'; -import AboutUs from 'bundle-loader?lazy!babel-loader!./pages/staticPages/aboutus/AboutUs'; -import InstallationMap from 'bundle-loader?lazy!babel-loader!./pages/staticPages/installations/InstallationMap'; -import Software from 'bundle-loader?lazy!babel-loader!./pages/staticPages/software/Software'; -import News from 'bundle-loader?lazy!babel-loader!./pages/staticPages/news/News'; -import FAQ from 'bundle-loader?lazy!babel-loader!./pages/staticPages/faq/FAQ'; -import OQL from 'bundle-loader?lazy!babel-loader!./pages/staticPages/oql/OQL'; -import GroupComparisonPage from 'bundle-loader?lazy!babel-loader!./pages/groupComparison/GroupComparisonPage'; -import ErrorPage from 'bundle-loader?lazy!babel-loader!./pages/resultsView/ErrorPage'; +const DatasetPage = SuspenseWrapper( + React.lazy(() => import('./pages/staticPages/datasetView/DatasetPage')) +); +const Homepage = SuspenseWrapper( + React.lazy(() => import('./pages/home/HomePage')) +); +const StudyViewPage = SuspenseWrapper( + React.lazy(() => import('./pages/studyView/StudyViewPage')) +); +const MutationMapperTool = SuspenseWrapper( + React.lazy(() => + import('./pages/staticPages/tools/mutationMapper/MutationMapperTool') + ) +); +const OncoprinterTool = SuspenseWrapper( + React.lazy(() => + import('./pages/staticPages/tools/oncoprinter/OncoprinterTool') + ) +); +const WebAPIPage = SuspenseWrapper( + React.lazy(() => import('./pages/staticPages/webAPI/WebAPIPage')) +); +const RMATLAB = SuspenseWrapper( + React.lazy(() => import('./pages/staticPages/rmatlab/RMatLAB')) +); +const Tutorials = SuspenseWrapper( + React.lazy(() => import('./pages/staticPages/tutorials/Tutorials')) +); +const Visualize = SuspenseWrapper( + React.lazy(() => import('./pages/staticPages/visualize/Visualize')) +); +const AboutUs = SuspenseWrapper( + React.lazy(() => import('./pages/staticPages/aboutus/AboutUs')) +); +const InstallationMap = SuspenseWrapper( + React.lazy(() => + import('./pages/staticPages/installations/InstallationMap') + ) +); +const Software = SuspenseWrapper( + React.lazy(() => import('./pages/staticPages/software/Software')) +); +const News = SuspenseWrapper( + React.lazy(() => import('./pages/staticPages/news/News')) +); +const FAQ = SuspenseWrapper( + React.lazy(() => import('./pages/staticPages/faq/FAQ')) +); +const OQL = SuspenseWrapper( + React.lazy(() => import('./pages/staticPages/oql/OQL')) +); +const GroupComparisonPage = SuspenseWrapper( + React.lazy(() => import('./pages/groupComparison/GroupComparisonPage')) +); +const ErrorPage = SuspenseWrapper( + React.lazy(() => import('./pages/resultsView/ErrorPage')) +); import $ from 'jquery'; import { getBrowserWindow } from 'cbioportal-frontend-commons'; @@ -66,6 +110,46 @@ import { CLIN_ATTR_DATA_TYPE } from 'pages/resultsView/plots/PlotsTabUtils'; import { SpecialAttribute } from 'shared/cache/ClinicalDataCache'; import { AlterationTypeConstants } from 'pages/resultsView/ResultsViewPageStore'; +function SuspenseWrapper(Component) { + return props => ( + + + + ); +} + +function LocationValidationWrapper(Component, validator) { + return props => { + if ( + props.location && + !( + validator(props.match.params) || + customTabParamValidator(props.location) + ) + ) { + return ; + } else { + return ; + } + }; +} + +function ScrollToTop(Component) { + return props => { + useEffect(() => { + $(document).scrollTop(0); + }, []); + return ; + }; +} + +function GoToHashLink(Component) { + return props => { + useEffect(handleEnter, []); + return ; + }; +} + /** * Validates that the parameters either do not have * a tab parameter, or have a parameter that matches a @@ -142,8 +226,13 @@ var defaultRoute = window.defaultRoute || '/home'; var restoreRoute = inject('routing')(restoreRouteAfterRedirect); -let getBlankPage = function() { - return
    ; +let getBlankPage = function(callback) { + return props => { + if (callback) { + useEffect(callback, []); + } + return
    ; + }; }; /* when route changes, we want to: @@ -169,252 +258,153 @@ function preloadImportantComponents() { } export const makeRoutes = routing => { + const homepage = Homepage; return ( - - { - $(document).scrollTop(0); - }} - getComponent={lazyLoadComponent( - Homepage, - preloadImportantComponents - )} - /> - { - $(document).scrollTop(0); - }} - component={restoreRoute} - /> - - { - $(document).scrollTop(0); - }} - component={GroupComparisonLoading} - /> - - {/* Redirect legacy survival route directly to survival tab in comparison */} - { - redirectTo( - { comparison_subtab: 'survival' }, - '/results/comparison' - ); - }} - component={getBlankPage()} - /> + + + + + - {/* Redirect legacy expression route directly to plots tab with mrna vs study */} - { - redirectTo( - { - plots_horz_selection: JSON.stringify({ - dataType: CLIN_ATTR_DATA_TYPE, - selectedDataSourceOption: - SpecialAttribute.StudyOfOrigin, - }), + {/* Redirect legacy survival route directly to survival tab in comparison */} + { + redirectTo( + { comparison_subtab: 'survival' }, + '/results/comparison' + ); + })} + /> - plots_vert_selection: JSON.stringify({ - dataType: - AlterationTypeConstants.MRNA_EXPRESSION, - logScale: 'true', - }), - }, - `/results/${ResultsViewTab.PLOTS}` - ); - }} - component={getBlankPage()} - /> + {/* Redirect legacy expression route directly to plots tab with mrna vs study */} + { + redirectTo( + { + plots_horz_selection: JSON.stringify({ + dataType: CLIN_ATTR_DATA_TYPE, + selectedDataSourceOption: + SpecialAttribute.StudyOfOrigin, + }), - {/* Redirect legacy enrichments route directly to mutations tab in comparison */} - { - redirectTo( - { comparison_subtab: 'mutations' }, - '/results/comparison' - ); - }} - component={getBlankPage()} - /> + plots_vert_selection: JSON.stringify({ + dataType: + AlterationTypeConstants.MRNA_EXPRESSION, + logScale: 'true', + }), + }, + `/results/${ResultsViewTab.PLOTS}` + ); + })} + /> - {}} - getComponent={lazyLoadComponent( - ResultsViewPage, - null, - tabParamValidator(ResultsViewTab) - )} - /> - { - $(document).scrollTop(0); - }} - getComponent={lazyLoadComponent( - PatientViewPage, - null, - tabParamValidator(PatientViewPageTabs) - )} - /> - { - $(document).scrollTop(0); - }} - getComponent={lazyLoadComponent( - StudyViewPage, - null, - tabParamValidator(StudyViewPageTabKeyEnum) - )} - /> - { - $(document).scrollTop(0); - }} - getComponent={lazyLoadComponent( - GroupComparisonPage, - null, - comparisonTabParamValidator - )} - /> + {/* Redirect legacy enrichments route directly to mutations tab in comparison */} + { + redirectTo( + { comparison_subtab: 'mutations' }, + '/results/comparison' + ); + })} + /> + + + + - - - - { - $(document).scrollTop(0); - }} - getComponent={lazyLoadComponent(RMATLAB)} - /> - { - $(document).scrollTop(0); - }} - getComponent={lazyLoadComponent(DatasetPage)} - /> - - - { - $(document).scrollTop(0); - }} - getComponent={lazyLoadComponent(Visualize)} - /> - { - $(document).scrollTop(0); - }} - getComponent={lazyLoadComponent(AboutUs)} - /> - { - $(document).scrollTop(0); - }} - getComponent={lazyLoadComponent(Software)} - /> - - - - { - $(document).scrollTop(0); - }} - component={TestimonialsPage} - /> - - - + + + + + + + + + + + + + + + + + - - - + + + - - - - - - - - + + + + + + + + - { - $(document).scrollTop(0); - }} - component={() => } - /> - + ( + + ))} + /> + + ); }; diff --git a/src/shared/components/StudyLink/StudyLink.tsx b/src/shared/components/StudyLink/StudyLink.tsx index 8b846b27281..bebca038088 100644 --- a/src/shared/components/StudyLink/StudyLink.tsx +++ b/src/shared/components/StudyLink/StudyLink.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { CancerStudy } from 'cbioportal-ts-api-client'; -import { Link } from 'react-router'; +import { Link } from 'react-router-dom'; export class StudyLink extends React.Component< { studyId: string; className?: string }, diff --git a/src/shared/components/dataAccessTokens/DataAccessTokensDropdown.tsx b/src/shared/components/dataAccessTokens/DataAccessTokensDropdown.tsx index efd12c1bde3..2a372e309ab 100644 --- a/src/shared/components/dataAccessTokens/DataAccessTokensDropdown.tsx +++ b/src/shared/components/dataAccessTokens/DataAccessTokensDropdown.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import AppConfig from 'appConfig'; -import { Link } from 'react-router'; +import { Link } from 'react-router-dom'; import { AppStore } from '../../../AppStore'; import LoadingIndicator from '../loadingIndicator/LoadingIndicator'; import { observer } from 'mobx-react'; diff --git a/src/shared/components/errorScreen/ErrorScreen.tsx b/src/shared/components/errorScreen/ErrorScreen.tsx index 4fe833cf167..1bf6cf44475 100644 --- a/src/shared/components/errorScreen/ErrorScreen.tsx +++ b/src/shared/components/errorScreen/ErrorScreen.tsx @@ -22,12 +22,12 @@ export default class ErrorScreen extends React.Component< copyToClip: HTMLButtonElement | null; componentDidMount(): void { - new Clipboard(this.copyToClip, { + /*new Clipboard(this.copyToClip, { text: function() { return JSON.stringify(this.errorLog); }.bind(this), container: this.copyToClip, - }); + });*/ } @computed get errorLog() { diff --git a/src/shared/components/oncoprint/ResultsViewOncoprint.spec.tsx b/src/shared/components/oncoprint/ResultsViewOncoprint.spec.tsx index 4c98937eac5..ab86dca7b31 100644 --- a/src/shared/components/oncoprint/ResultsViewOncoprint.spec.tsx +++ b/src/shared/components/oncoprint/ResultsViewOncoprint.spec.tsx @@ -6,7 +6,7 @@ import { getBrowserWindow } from 'cbioportal-frontend-commons'; import ExtendedRouterStore from 'shared/lib/ExtendedRouterStore'; import sinon from 'sinon'; import { SortByUrlParamValue } from 'shared/components/oncoprint/ResultsViewOncoprint'; -import { createMemoryHistory } from 'react-router'; +import { createMemoryHistory } from 'history'; import { syncHistoryWithStore } from 'mobx-react-router'; import ResultsViewURLWrapper from 'pages/resultsView/ResultsViewURLWrapper'; diff --git a/src/shared/components/oncoprint/ResultsViewOncoprint.tsx b/src/shared/components/oncoprint/ResultsViewOncoprint.tsx index cae7b3b005d..15c0aec4cc6 100644 --- a/src/shared/components/oncoprint/ResultsViewOncoprint.tsx +++ b/src/shared/components/oncoprint/ResultsViewOncoprint.tsx @@ -1261,10 +1261,6 @@ export default class ResultsViewOncoprint extends React.Component< // @computed public get oncoprintAnalysisCaseType() { - // return ( - // (this.routing.location.query as CancerStudyQueryUrlParams) - // .show_samples === 'true' - // ) ? OncoprintAnalysisCaseType.SAMPLE : OncoprintAnalysisCaseType.PATIENT; return this.urlWrapper.query.show_samples === 'true' ? OncoprintAnalysisCaseType.SAMPLE : OncoprintAnalysisCaseType.PATIENT; diff --git a/src/shared/components/rightbar/RightBar.tsx b/src/shared/components/rightbar/RightBar.tsx index 734aa7730a4..c443b21562b 100644 --- a/src/shared/components/rightbar/RightBar.tsx +++ b/src/shared/components/rightbar/RightBar.tsx @@ -5,7 +5,7 @@ import { TypeOfCancer as CancerType } from 'cbioportal-ts-api-client'; import Testimonials from '../testimonials/Testimonials'; import AppConfig from 'appConfig'; import { QueryStore } from 'shared/components/query/QueryStore'; -import { Link } from 'react-router'; +import { Link } from 'react-router-dom'; import LoadingIndicator from '../loadingIndicator/LoadingIndicator'; import { buildCBioPortalPageUrl, redirectToStudyView } from '../../api/urls'; import { ResultsViewTab } from '../../../pages/resultsView/ResultsViewPageHelpers'; diff --git a/src/shared/components/testimonials/Testimonials.tsx b/src/shared/components/testimonials/Testimonials.tsx index 296f9101acd..518beff2a68 100644 --- a/src/shared/components/testimonials/Testimonials.tsx +++ b/src/shared/components/testimonials/Testimonials.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { observable, action } from 'mobx'; import { observer } from 'mobx-react'; -import { Link } from 'react-router'; +import { Link } from 'react-router-dom'; import styles from './testimonials.module.scss'; diff --git a/src/shared/lib/ExtendedRouterStore.spec.ts b/src/shared/lib/ExtendedRouterStore.spec.ts index 4f88612a131..e13802a2881 100644 --- a/src/shared/lib/ExtendedRouterStore.spec.ts +++ b/src/shared/lib/ExtendedRouterStore.spec.ts @@ -6,8 +6,7 @@ import * as $ from 'jquery'; import * as sinon from 'sinon'; import * as mobx from 'mobx'; import { syncHistoryWithStore, SynchronizedHistory } from 'mobx-react-router'; -import createMemoryHistory from 'react-router/lib/createMemoryHistory'; -import { MemoryHistory } from 'history'; +import { createBrowserHistory, MemoryHistory } from 'history'; import { SinonStub } from 'sinon'; import { sleep } from './TimeUtils'; import { computed } from 'mobx'; @@ -22,10 +21,10 @@ describe('ExtendedRouterStore', () => { beforeEach(() => { routingStore = new ExtendedRouterStore(); - history = syncHistoryWithStore(createMemoryHistory(), routingStore); + history = syncHistoryWithStore(createBrowserHistory(), routingStore); setServerConfig({ sessionServiceEnabled: true }); routingStore.location.pathname = '/results'; - routingStore.location.query = { param1: 1, param2: 2, param3: 3 }; + routingStore.updateRoute({ param1: '1', param2: '2', param3: '3' }); }); afterEach(() => { @@ -42,7 +41,7 @@ describe('ExtendedRouterStore', () => { ); assert.deepEqual( - routingStore.location.query, + routingStore.query, { param3: 'cleared' }, 'removes param1' ); @@ -61,7 +60,7 @@ describe('ExtendedRouterStore', () => { ); assert.deepEqual( - routingStore.location.query, + routingStore.query, { param1: 'something1', param2: 'something2', @@ -79,7 +78,7 @@ describe('ExtendedRouterStore', () => { ); assert.deepEqual( - routingStore.location.query, + routingStore.query, { param1: 'something1', param2: 'something2' }, 'removes undefined param' ); @@ -93,7 +92,7 @@ describe('ExtendedRouterStore', () => { ); assert.deepEqual( - routingStore.location.query, + routingStore.query, { param1: 'something1' }, 'removes empty string prop' ); diff --git a/src/shared/lib/ExtendedRouterStore.ts b/src/shared/lib/ExtendedRouterStore.ts index 1af42ec8d7e..40b2a68504b 100644 --- a/src/shared/lib/ExtendedRouterStore.ts +++ b/src/shared/lib/ExtendedRouterStore.ts @@ -1,8 +1,9 @@ import { RouterStore } from 'mobx-react-router'; -import { action } from 'mobx'; +import { action, computed } from 'mobx'; import * as _ from 'lodash'; import URL, { QueryParams } from 'url'; import sessionClient from '../api/sessionServiceInstance'; +import { parse } from 'qs'; export function getSessionKey(hash: string) { return `session_${hash}`; @@ -62,7 +63,7 @@ export default class ExtendedRouterStore extends RouterStore { // but if we're clearing, we want to use newParams ONLY and wipe out existing query; let newQuery: any; if (!clear) { - newQuery = _.clone(this.location.query); + newQuery = _.clone(this.query); _.each(newParams, (v, k: string) => { if (v === undefined) { delete newQuery[k]; @@ -92,4 +93,11 @@ export default class ExtendedRouterStore extends RouterStore { }) ); } + + @computed get query() { + return parse(this.location.search, { + depth: 0, + ignoreQueryPrefix: true, + }) as any; + } } diff --git a/src/shared/lib/URLWrapper.spec.ts b/src/shared/lib/URLWrapper.spec.ts index fe28d121565..e670b5adf77 100644 --- a/src/shared/lib/URLWrapper.spec.ts +++ b/src/shared/lib/URLWrapper.spec.ts @@ -5,7 +5,7 @@ import ExtendedRouterStore, { PortalSession, } from 'shared/lib/ExtendedRouterStore'; import sinon from 'sinon'; -import { createMemoryHistory } from 'react-router'; +import { createMemoryHistory } from 'history'; import { syncHistoryWithStore } from 'mobx-react-router'; import memoize from 'memoize-weak-decorator'; import URLWrapper, { needToLoadSession } from 'shared/lib/URLWrapper'; @@ -64,8 +64,10 @@ describe('URLWrapper', () => { beforeEach(() => { routingStore = new ExtendedRouterStore(); - const memoryHistory = createMemoryHistory(); - const history = syncHistoryWithStore(memoryHistory, routingStore); + const history = syncHistoryWithStore( + createMemoryHistory(), + routingStore + ); wrapper = new ResultsViewURLWrapper(routingStore); routingStore.updateRoute({}, '/results'); }); @@ -74,7 +76,7 @@ describe('URLWrapper', () => { const testWrapper = new TestURLWrapper2(routingStore); testWrapper.updateURL({ data: { d1: 'BRCA1 BRCA2', d2: 'hey' } }); assert.equal( - routingStore.location.query.data, + routingStore.query.data, encodeURIComponent( JSON.stringify({ d1: 'BRCA1 BRCA2', d2: 'hey' }) ), @@ -90,7 +92,7 @@ describe('URLWrapper', () => { it('handles doubleURIEncode properties correctly', () => { wrapper.updateURL({ gene_list: 'BRCA1 BRCA2' }); assert.equal( - routingStore.location.query.gene_list, + routingStore.query.gene_list, encodeURIComponent('BRCA1 BRCA2'), 'property is doubly encoded in URL (one layer of encoding is undone by the routingStore query access)' ); @@ -343,7 +345,7 @@ describe('URLWrapper', () => { assert.equal(testWrapper.sessionId, 'pending', 'pending session state'); assert.isUndefined( - routingStore.location.query.data, + routingStore.query.data, 'nested object session params NOT in url' ); @@ -397,7 +399,7 @@ describe('URLWrapper', () => { ); assert.equal( - routingStore.location.query.clinicallist, + routingStore.query.clinicallist, 'one,two,three', 'non session params present in url' ); @@ -412,7 +414,7 @@ describe('URLWrapper', () => { ); assert.isUndefined( - routingStore.location.query.case_ids, + routingStore.query.case_ids, 'session params NOT in url' ); @@ -452,7 +454,7 @@ describe('URLWrapper', () => { ); assert.equal( - routingStore.location.query.case_ids, + routingStore.query.case_ids, '1231', 'update param from url' ); @@ -467,7 +469,7 @@ describe('URLWrapper', () => { }); assert.isUndefined( - routingStore.location.query.case_ids, + routingStore.query.case_ids, 'case_ids no longer in url' ); @@ -482,12 +484,12 @@ describe('URLWrapper', () => { case_ids: '2222', }); - assert.isUndefined(routingStore.location.query.case_ids); + assert.isUndefined(routingStore.query.case_ids); assert.equal(wrapper.query.case_ids, '2222'); setTimeout(() => { assert.equal(wrapper.query.case_ids, '2222'); - assert.isUndefined(routingStore.location.query.case_ids); + assert.isUndefined(routingStore.query.case_ids); done(); }, 50); }, 50); @@ -511,13 +513,13 @@ describe('URLWrapper', () => { assert.isFalse(testWrapper.hasSessionId, 'does not have session id'); assert.equal( - routingStore.location.query.name, + routingStore.query.name, 'CDKN2A MDM2 MDM4 TP53', 'puts session prop in url' ); assert.equal( - routingStore.location.query.data, + routingStore.query.data, JSON.stringify({ d1: 'CDKN2A MDM2 MDM4 TP53', d2: 'def' }), 'puts nested object session prop in url' ); @@ -673,7 +675,7 @@ describe('URLWrapper', () => { 'sets nested object session props on query after session load' ); assert.equal( - routingStore.location.query.session_id, + routingStore.query.session_id, '5dcae586e4b04a9c23e27e5f' ); @@ -916,7 +918,7 @@ describe('URLWrapper', () => { plots_horz_selection: getPlotsSelectionParam(''), }); assert.equal(wrapper.query.case_ids, '12345'); - assert.equal(routingStore.location.query.case_ids, '12345'); + assert.equal(routingStore.query.case_ids, '12345'); assert.deepEqual( toJS(wrapper.query.plots_horz_selection), getPlotsSelectionParam('') @@ -924,9 +926,9 @@ describe('URLWrapper', () => { wrapper.updateURL({ cancer_study_list: 'somelist' }, undefined, true); - assert.isUndefined(routingStore.location.query.case_ids); + assert.isUndefined(routingStore.query.case_ids); - assert.isFalse('case_ids' in routingStore.location.query); + assert.isFalse('case_ids' in routingStore.query); assert.isUndefined( wrapper.query.case_ids, @@ -938,14 +940,16 @@ describe('URLWrapper', () => { 'clears nested object params to undefined' ); - assert.equal(routingStore.location.query.cancer_study_list, 'somelist'); + assert.equal(routingStore.query.cancer_study_list, 'somelist'); }); it('Populates wrapper query according to alias rules ON instantiation (fire immediately on reaction)', () => { routingStore = new ExtendedRouterStore(); - const memoryHistory = createMemoryHistory(); - const history = syncHistoryWithStore(memoryHistory, routingStore); + const history = syncHistoryWithStore( + createMemoryHistory(), + routingStore + ); routingStore.updateRoute({ gene_list: '12345', @@ -994,7 +998,7 @@ describe('URLWrapper', () => { setTimeout(() => { assert.equal(wrapper.sessionId, 'sessionId2'); assert.equal(wrapper.query.gene_list, '54321'); - assert.equal(routingStore.location.query.session_id, 'sessionId2'); + assert.equal(routingStore.query.session_id, 'sessionId2'); done(); }, 1000); }); diff --git a/src/shared/lib/URLWrapper.ts b/src/shared/lib/URLWrapper.ts index b75046f52d1..a7ad6773040 100644 --- a/src/shared/lib/URLWrapper.ts +++ b/src/shared/lib/URLWrapper.ts @@ -73,10 +73,13 @@ export default class URLWrapper< // even if they are not represented in browser url at the moment // they need to be there so that they will observable in the future upon assignment for (const property of this.properties) { - let value: string | undefined | Object = (routing.location - .query as MapValues)[ - property.name - ]; + let value: + | string + | undefined + | Object = (routing.query as MapValues< + QueryParamsType, + string | undefined + >)[property.name]; if (_.isString(value) && property.doubleURIEncode) { // @ts-ignore value = decodeURIComponent(value); @@ -105,10 +108,10 @@ export default class URLWrapper< () => { // this is necessary to establish observation of properties // at least in test context, it doesn't otherwise work - //const queryProps = _.mapValues(routing.location.query); + //const queryProps = _.mapValues(routing.query); //const sessionProps = this._sessionData && this._sessionData.query && _.mapValues(this._sessionData.query); return [ - routing.location.query, + routing.query, this._sessionData && this._sessionData.query, ]; }, @@ -141,7 +144,7 @@ export default class URLWrapper< this.routing.updateRoute(newParams, path, clear, replace); // immediately sync properties from URL and session this.syncAllProperties( - this.routing.location.query, + this.routing.query, this._sessionData && (this._sessionData.query as MapValues< QueryParamsType, @@ -388,9 +391,9 @@ export default class URLWrapper< } @computed public get sessionId() { - return this.routing.location.query.session_id === '' + return this.routing.query.session_id === '' ? undefined - : this.routing.location.query.session_id; + : this.routing.query.session_id; } @observable public _sessionData: PortalSession | undefined; diff --git a/src/shared/lib/redirectHelpers.spec.ts b/src/shared/lib/redirectHelpers.spec.ts index e2f45f1112d..3baca522e64 100644 --- a/src/shared/lib/redirectHelpers.spec.ts +++ b/src/shared/lib/redirectHelpers.spec.ts @@ -11,10 +11,8 @@ describe('restoreRouteAfterRedirect', () => { beforeEach(() => { stores = { routing: { - location: { - query: { - key: 'mooo', - }, + query: { + key: 'mooo', }, push: sinon.stub(), updateRoute: () => {}, diff --git a/src/shared/lib/redirectHelpers.ts b/src/shared/lib/redirectHelpers.ts index 674ebb5dc35..d2da2fba487 100644 --- a/src/shared/lib/redirectHelpers.ts +++ b/src/shared/lib/redirectHelpers.ts @@ -15,7 +15,7 @@ export function restoreRouteAfterRedirect(injected: { }) { const win = getBrowserWindow(); - const key = injected.routing.location.query.key; + const key = injected.routing.query.key; let restoreRoute = win.localStorage.getItem(key); if (restoreRoute) { restoreRoute = restoreRoute.replace(/^#/, ''); @@ -63,7 +63,7 @@ export function handleCaseDO() { const newParams: Partial = {}; - const currentQuery = routingStore.location.query; + const currentQuery = routingStore.query; if (currentQuery.cancer_study_id) { newParams.studyId = currentQuery.cancer_study_id; @@ -150,7 +150,7 @@ async function getCuratedNonRedundantStudyList() { */ export async function handleLinkOut() { const routingStore: ExtendedRouterStore = getBrowserWindow().routingStore; - const currentQuery = routingStore.location.query; + const currentQuery = routingStore.query; const curatedList = await getCuratedNonRedundantStudyList(); @@ -188,10 +188,10 @@ export function handleIndexDO() { // ALL QUERIES NOW HAVE cancer_study_list. if we have a legacy cancer_study_id but not a cancer_study_list, copy it over if ( - !getBrowserWindow().routingStore.location.query.cancer_study_list && - getBrowserWindow().routingStore.location.query.cancer_study_id + !getBrowserWindow().routingStore.query.cancer_study_list && + getBrowserWindow().routingStore.query.cancer_study_id ) { - data.cancer_study_list = getBrowserWindow().routingStore.location.query.cancer_study_id; + data.cancer_study_list = getBrowserWindow().routingStore.query.cancer_study_id; data.cancer_study_id = undefined; } @@ -213,9 +213,7 @@ export function handleIndexDO() { } export function handleEncodedRedirect() { - const encodedURL = getBrowserWindow().routingStore.location.query[ - EncodedURLParam - ]; + const encodedURL = getBrowserWindow().routingStore.query[EncodedURLParam]; const decodedURL = atob(encodedURL); (getBrowserWindow().routingStore as ExtendedRouterStore).replace( decodedURL diff --git a/src/shared/lib/seekUrlHash.ts b/src/shared/lib/seekUrlHash.ts index 71483e0c5fb..5fe9c657908 100644 --- a/src/shared/lib/seekUrlHash.ts +++ b/src/shared/lib/seekUrlHash.ts @@ -23,12 +23,12 @@ export function seekUrlHash(id: string) { let pollInterval = 100; let interval = setInterval(() => { if (getElement(id)) { + // The browser won't scroll to the element if it + // doesn't exist when the page first loads. + // So let's just keep checking if it loads and + // scroll to it when it appears. + getElement(id)?.scrollIntoView(); clearInterval(interval); - // this is a bit of a hack to get browser to - // scroll to element as it would if this problem - // didn't exist - getBrowserWindow().location.hash = ''; - getBrowserWindow().location.hash = id; } // bail if we reach reasonable limit if (counter >= limit) { diff --git a/webpack.config.js b/webpack.config.js index 79f7def4f0d..312bbb1e618 100755 --- a/webpack.config.js +++ b/webpack.config.js @@ -131,8 +131,9 @@ var config = { resolveLoader: { modules: [ - path.resolve(__dirname, 'loaders'), + 'node_modules', path.join(process.cwd(), 'node_modules'), + path.resolve(__dirname, 'loaders'), ], }, diff --git a/yarn.lock b/yarn.lock index e35341a0efb..3d2976cf44a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -306,6 +306,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== +"@babel/helper-plugin-utils@^7.8.0": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" + integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== + "@babel/helper-regex@^7.0.0", "@babel/helper-regex@^7.4.4": version "7.4.4" resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.4.4.tgz#a47e02bc91fb259d2e6727c2a30013e3ac13c4a2" @@ -554,6 +559,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + "@babel/plugin-syntax-json-strings@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz#72bd13f6ffe1d25938129d2a186b11fd62951470" @@ -1273,6 +1285,13 @@ dependencies: regenerator-runtime "^0.12.0" +"@babel/runtime@^7.12.1": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" + integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/runtime@^7.4.2": version "7.4.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.2.tgz#f5ab6897320f16decd855eed70b705908a313fe8" @@ -2741,6 +2760,11 @@ resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.2.tgz#0e670ea254d559241b6eeb3894f8754991e73220" integrity sha512-ui3WwXmjTaY73fOQ3/m3nnajU/Orhi6cEu5rzX+BrAAJxa3eITXZ5ch9suPqtM03OWhAHhPSyBGCN4UKoxO20Q== +"@types/history@^4.7.8": + version "4.7.8" + resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.8.tgz#49348387983075705fe8f4e02fb67f7daaec4934" + integrity sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA== + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff" @@ -2847,6 +2871,11 @@ resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw== +"@types/qs@^6.9.5": + version "6.9.5" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.5.tgz#434711bdd49eb5ee69d90c1d67c354a9a8ecb18b" + integrity sha512-/JHkVHtx/REVG0VVToGRGH2+23hsYLHdyG+GrvoUGlGAd0ErauXDyvHtRI/7H7mzLm+tBCKA7pfcpkQ1lf58iQ== + "@types/raphael@2.1.30": version "2.1.30" resolved "https://registry.yarnpkg.com/@types/raphael/-/raphael-2.1.30.tgz#76cbea4a556ba25eb1c6d7fa5e71ac48e72f81cf" @@ -2930,6 +2959,23 @@ dependencies: "@types/react" "*" +"@types/react-router-dom@^5.1.6": + version "5.1.6" + resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.1.6.tgz#07b14e7ab1893a837c8565634960dc398564b1fb" + integrity sha512-gjrxYqxz37zWEdMVvQtWPFMFj1dRDb4TGOcgyOfSXTrEXdF92L00WE3C471O3TV/RF1oskcStkXsOU0Ete4s/g== + dependencies: + "@types/history" "*" + "@types/react" "*" + "@types/react-router" "*" + +"@types/react-router@*": + version "5.1.8" + resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.8.tgz#4614e5ba7559657438e17766bb95ef6ed6acc3fa" + integrity sha512-HzOyJb+wFmyEhyfp4D4NYrumi+LQgQL/68HvJO+q6XtuHSDvw6Aqov7sCAhjbNq3bUPgPqbdvjXC5HeB2oEAPg== + dependencies: + "@types/history" "*" + "@types/react" "*" + "@types/react-router@3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-3.0.2.tgz#f3f71ae8222e6b5e79499007fd6ed552dfeaae5b" @@ -7182,7 +7228,7 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" -create-react-class@15.x, create-react-class@^15.5.1, create-react-class@^15.5.2, create-react-class@^15.5.3, create-react-class@^15.6.2: +create-react-class@15.x, create-react-class@^15.5.2, create-react-class@^15.5.3, create-react-class@^15.6.2: version "15.6.3" resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.3.tgz#2d73237fb3f970ae6ebe011a9e66f46dbca80036" integrity sha512-M+/3Q6E6DLO6Yx3OwrWjwHBnvfXXYA7W+dFjt/ZDBemHO1DDZhsalX/NUtnTYclN6GfnBDRh4qRHjcDHmlJBJg== @@ -11494,15 +11540,17 @@ hex-to-rgb@^1.0.0: resolved "https://registry.yarnpkg.com/hex-to-rgb/-/hex-to-rgb-1.0.1.tgz#100b9df126b32f2762adf8486be68c65ef8ed2a4" integrity sha1-EAud8SazLydirfhIa+aMZe+O0qQ= -history@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/history/-/history-3.3.0.tgz#fcedcce8f12975371545d735461033579a6dae9c" - integrity sha1-/O3M6PEpdTcVRdc1RhAzV5ptrpw= +history@4.10.1, history@^4.9.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" + integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== dependencies: - invariant "^2.2.1" + "@babel/runtime" "^7.1.2" loose-envify "^1.2.0" - query-string "^4.2.2" - warning "^3.0.0" + resolve-pathname "^3.0.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + value-equal "^1.0.1" hmac-drbg@^1.0.0: version "1.0.1" @@ -11528,6 +11576,13 @@ hoist-non-react-statics@^2.3.1: resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47" integrity sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw== +hoist-non-react-statics@^3.1.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -14941,6 +14996,14 @@ mimic-fn@^2.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mini-create-react-context@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz#072171561bfdc922da08a60c2197a497cc2d1d5e" + integrity sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ== + dependencies: + "@babel/runtime" "^7.12.1" + tiny-warning "^1.0.3" + mini-css-extract-plugin@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.6.0.tgz#a3f13372d6fcde912f3ee4cd039665704801e3b9" @@ -15131,10 +15194,10 @@ mobx-react-lite@^2.0.7: resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-2.0.7.tgz#1bfb3b4272668e288047cf0c7940b14e91cba284" integrity sha512-YKAh2gThC6WooPnVZCoC+rV1bODAKFwkhxikzgH18wpBjkgTkkR9Sb0IesQAH5QrAEH/JQVmy47jcpQkf2Au3Q== -mobx-react-router@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/mobx-react-router/-/mobx-react-router-3.1.2.tgz#83328b108393017148d86fea17f611de2d2aacdc" - integrity sha1-gzKLEIOTAXFI2G/qF/YR3i0qrNw= +mobx-react-router@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/mobx-react-router/-/mobx-react-router-4.1.0.tgz#de014848207d8aa32f6a4e67ed861bd2cb6516e5" + integrity sha512-2knsbDqVorWLngZWbdO8tr7xcZXaLpVFsFlCaGaoyZ+EP9erVGRxnlWGqKyFObs3EH1JPLyTDOJ2LPTxb/lB6Q== mobx-react@^4.1.3: version "4.4.3" @@ -18196,7 +18259,7 @@ quat-slerp@^1.0.0: dependencies: gl-quat "^1.0.0" -query-string@^4.1.0, query-string@^4.2.2: +query-string@^4.1.0: version "4.3.4" resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" integrity sha1-u7aTucqRXCMlFbIosaArYJBD2+s= @@ -18684,6 +18747,11 @@ react-is@^16.6.0, react-is@^16.8.6: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA== +react-is@^16.7.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + react-json-to-table@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/react-json-to-table/-/react-json-to-table-0.1.5.tgz#85aa237b9ee111a0d8f770ed8e9d20bbd4b1dd1a" @@ -18800,18 +18868,34 @@ react-reveal@^1.2.2: dependencies: prop-types "^15.5.10" -react-router@^3.0.2: - version "3.2.1" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-3.2.1.tgz#b9a3279962bdfbe684c8bd0482b81ef288f0f244" - integrity sha512-SXkhC0nr3G0ltzVU07IN8jYl0bB6FsrDIqlLC9dK3SITXqyTJyM7yhXlUqs89w3Nqi5OkXsfRUeHX+P874HQrg== +react-router-dom@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662" + integrity sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA== dependencies: - create-react-class "^15.5.1" - history "^3.0.0" - hoist-non-react-statics "^2.3.1" - invariant "^2.2.1" - loose-envify "^1.2.0" - prop-types "^15.5.6" - warning "^3.0.0" + "@babel/runtime" "^7.1.2" + history "^4.9.0" + loose-envify "^1.3.1" + prop-types "^15.6.2" + react-router "5.2.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + +react-router@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.0.tgz#424e75641ca8747fbf76e5ecca69781aa37ea293" + integrity sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw== + dependencies: + "@babel/runtime" "^7.1.2" + 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" react-scripts-ts@^3.1.0: version "3.1.0" @@ -19376,6 +19460,11 @@ regenerator-runtime@^0.13.2: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447" integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA== +regenerator-runtime@^0.13.4: + version "0.13.7" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" + integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== + regenerator-transform@^0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" @@ -19801,6 +19890,11 @@ resolve-from@^4.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== +resolve-pathname@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" + integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== + resolve-protobuf-schema@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz#9ca9a9e69cf192bbdaf1006ec1973948aa4a3758" @@ -22184,11 +22278,21 @@ tiny-emitter@^2.0.0: resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423" integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== +tiny-invariant@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" + integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== + tiny-sdf@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/tiny-sdf/-/tiny-sdf-1.0.2.tgz#28e76985c44c4e584c4b67d8ecdd9b33a1cac28c" integrity sha1-KOdphcRMTlhMS2fY7N2bM6HKwow= +tiny-warning@^1.0.0, tiny-warning@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" + integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== + tinycolor2@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8" @@ -23269,6 +23373,11 @@ validate.io-string-primitive@^1.0.0: resolved "https://registry.yarnpkg.com/validate.io-string-primitive/-/validate.io-string-primitive-1.0.1.tgz#b8135b9fb1372bde02fdd53ad1d0ccd6de798fee" integrity sha1-uBNbn7E3K94C/dU60dDM1t55j+4= +value-equal@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" + integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== + vary@~1.1.1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"