From b6f1169d8803b95fc6b86019e8f07ef993254df8 Mon Sep 17 00:00:00 2001 From: Luke Sikina Date: Thu, 21 Nov 2019 16:27:03 -0500 Subject: [PATCH] Routing Improvements - invalid subpaths (tabs) result in a 404 page - 404 page is more consistent with regular error page This reverts commit 082fc70d --- .../groupComparison/GroupComparisonPage.tsx | 2 +- .../groupComparison/GroupComparisonStore.ts | 4 +- .../groupComparison/GroupComparisonTabs.ts | 9 ++++ .../GroupComparisonURLWrapper.ts | 3 +- .../groupComparison/GroupComparisonUtils.tsx | 11 +---- src/pages/patientView/PatientViewPage.tsx | 23 +++++----- src/pages/patientView/PatientViewPageTabs.ts | 9 ++++ src/pages/resultsView/ErrorPage.tsx | 31 +++++++++++++ src/pages/studyView/StudyViewPage.tsx | 2 +- src/pages/studyView/StudyViewPageStore.ts | 8 +--- src/pages/studyView/StudyViewPageTabs.ts | 6 +++ src/pages/studyView/StudyViewUtils.spec.ts | 4 +- src/pages/studyView/StudyViewUtils.tsx | 6 +-- .../addChartButton/AddChartButton.tsx | 5 +- src/pages/studyView/tabs/CNSegments.tsx | 3 +- src/routes.jsx | 46 +++++++++++++------ .../components/pageNotFound/PageNotFound.tsx | 11 ++++- 17 files changed, 125 insertions(+), 58 deletions(-) create mode 100644 src/pages/groupComparison/GroupComparisonTabs.ts create mode 100644 src/pages/patientView/PatientViewPageTabs.ts create mode 100644 src/pages/resultsView/ErrorPage.tsx create mode 100644 src/pages/studyView/StudyViewPageTabs.ts diff --git a/src/pages/groupComparison/GroupComparisonPage.tsx b/src/pages/groupComparison/GroupComparisonPage.tsx index 85218e0c8a2..968e395133c 100644 --- a/src/pages/groupComparison/GroupComparisonPage.tsx +++ b/src/pages/groupComparison/GroupComparisonPage.tsx @@ -13,7 +13,7 @@ import {MakeMobxView} from "../../shared/components/MobxView"; import LoadingIndicator from "../../shared/components/loadingIndicator/LoadingIndicator"; import ErrorMessage from "../../shared/components/ErrorMessage"; import GroupSelector from "./groupSelector/GroupSelector"; -import {getTabId, GroupComparisonTab} from "./GroupComparisonUtils"; +import { GroupComparisonTab } from "./GroupComparisonTabs" import styles from "./styles.module.scss"; import {StudyLink} from "shared/components/StudyLink/StudyLink"; import {action, computed, IReactionDisposer, observable, reaction} from "mobx"; diff --git a/src/pages/groupComparison/GroupComparisonStore.ts b/src/pages/groupComparison/GroupComparisonStore.ts index 467a55a08aa..7050b85e0a0 100644 --- a/src/pages/groupComparison/GroupComparisonStore.ts +++ b/src/pages/groupComparison/GroupComparisonStore.ts @@ -8,12 +8,12 @@ import { getOverlapComputations, getSampleIdentifiers, getStudyIds, - GroupComparisonTab, IOverlapComputations, isGroupEmpty, partitionCasesByGroupMembership, - getNumSamples + getNumSamples, } from "./GroupComparisonUtils"; +import { GroupComparisonTab } from "./GroupComparisonTabs" import {remoteData} from "../../public-lib/api/remoteData"; import { CancerStudy, diff --git a/src/pages/groupComparison/GroupComparisonTabs.ts b/src/pages/groupComparison/GroupComparisonTabs.ts new file mode 100644 index 00000000000..b4301baf0fc --- /dev/null +++ b/src/pages/groupComparison/GroupComparisonTabs.ts @@ -0,0 +1,9 @@ +export enum GroupComparisonTab { + OVERLAP = "overlap", + MUTATIONS = "mutations", + CNA = "cna", + MRNA = "mrna", + PROTEIN = "protein", + SURVIVAL = "survival", + CLINICAL = "clinical" +} \ No newline at end of file diff --git a/src/pages/groupComparison/GroupComparisonURLWrapper.ts b/src/pages/groupComparison/GroupComparisonURLWrapper.ts index 2a376104dc0..fac0b9bbf62 100644 --- a/src/pages/groupComparison/GroupComparisonURLWrapper.ts +++ b/src/pages/groupComparison/GroupComparisonURLWrapper.ts @@ -1,7 +1,8 @@ import URLWrapper from "../../shared/lib/URLWrapper"; import ExtendedRouterStore from "../../shared/lib/ExtendedRouterStore"; import {computed} from "mobx"; -import {getTabId, GroupComparisonTab} from "./GroupComparisonUtils"; +import {getTabId} from "./GroupComparisonUtils"; +import { GroupComparisonTab } from "./GroupComparisonTabs" import autobind from "autobind-decorator"; import {OverlapStrategy} from "./GroupComparisonStore"; diff --git a/src/pages/groupComparison/GroupComparisonUtils.tsx b/src/pages/groupComparison/GroupComparisonUtils.tsx index 33115fa8246..89838e58b0a 100644 --- a/src/pages/groupComparison/GroupComparisonUtils.tsx +++ b/src/pages/groupComparison/GroupComparisonUtils.tsx @@ -20,16 +20,7 @@ import OverlapExclusionIndicator from "./OverlapExclusionIndicator"; import Loader from "../../shared/components/loadingIndicator/LoadingIndicator"; import ErrorMessage from "../../shared/components/ErrorMessage"; import {stringListToIndexSet} from "public-lib/lib/StringUtils"; - -export enum GroupComparisonTab { - OVERLAP = "overlap", - MUTATIONS = "mutations", - CNA = "cna", - MRNA = "mrna", - PROTEIN = "protein", - SURVIVAL = "survival", - CLINICAL = "clinical" -} +import { GroupComparisonTab } from "./GroupComparisonTabs" type Omit = Pick>; diff --git a/src/pages/patientView/PatientViewPage.tsx b/src/pages/patientView/PatientViewPage.tsx index 3b30257a53f..7c33458693b 100644 --- a/src/pages/patientView/PatientViewPage.tsx +++ b/src/pages/patientView/PatientViewPage.tsx @@ -59,6 +59,7 @@ import { PagePath } from "shared/enums/PagePaths"; import { GeneFilterOption } from "./mutation/GeneFilterMenu"; import { checkNonProfiledGenesExist } from "./PatientViewPageUtils"; import PatientViewGenePanelModal from "./PatientViewGenePanelModal/PatientViewGenePanelModal"; +import { PatientViewPageTabs } from "./PatientViewPageTabs"; export interface IPatientViewPageProps { params: any; // react route @@ -269,7 +270,7 @@ export default class PatientViewPage extends React.Component - {this.genePanelModal.isOpen && - this.urlWrapper.setTab(id)} className="mainTabs" > - + @@ -599,7 +600,7 @@ export default class PatientViewPage extends React.Component - +
-
@@ -634,7 +635,7 @@ export default class PatientViewPage extends React.Component -
@@ -643,7 +644,7 @@ export default class PatientViewPage extends React.Component {(this.patientViewPageStore.studyId === "mskimpact" && this.wholeSlideViewerUrl.result) && ( -
@@ -654,7 +655,7 @@ export default class PatientViewPage extends React.Component + */} + {/**/} {/*
*/} {/**/} {/**/} diff --git a/src/pages/patientView/PatientViewPageTabs.ts b/src/pages/patientView/PatientViewPageTabs.ts new file mode 100644 index 00000000000..5b806d42f9f --- /dev/null +++ b/src/pages/patientView/PatientViewPageTabs.ts @@ -0,0 +1,9 @@ +export enum PatientViewPageTabs { + Summary = "summary", + ClinicalData = "clinicalData", + PathologyReport = "pathologyReport", + TissueImage = "tissueImage", + MSKTissueImage = "MSKTissueImage", + TrialMatchTab = "trialMatchTab", + MutationalSignatures = "mutationalSignatures", +} \ No newline at end of file diff --git a/src/pages/resultsView/ErrorPage.tsx b/src/pages/resultsView/ErrorPage.tsx new file mode 100644 index 00000000000..dc1867df6cd --- /dev/null +++ b/src/pages/resultsView/ErrorPage.tsx @@ -0,0 +1,31 @@ +import * as React from 'react'; +import { inject } from 'mobx-react'; +import { AppStore } from 'AppStore'; +import PortalHeader from 'appShell/App/PortalHeader'; +import PortalFooter from 'appShell/App/PortalFooter'; +import UserMessager from 'shared/components/userMessager/UserMessage'; +import ErrorScreen from 'shared/components/errorScreen/ErrorScreen'; +import { formatErrorTitle } from 'shared/lib/errorFormatter'; +import { buildCBioPortalPageUrl } from 'shared/api/urls'; + +@inject("appStore") +export default class ErrorPage extends React.Component<{appStore?: AppStore}, {}> { + render () { + return ( +
+
+ +
+ +
+
+
+ Return to homepage} + /> +
+
+ ) + } +} \ No newline at end of file diff --git a/src/pages/studyView/StudyViewPage.tsx b/src/pages/studyView/StudyViewPage.tsx index d3e618e8a90..f64d81504d7 100644 --- a/src/pages/studyView/StudyViewPage.tsx +++ b/src/pages/studyView/StudyViewPage.tsx @@ -7,9 +7,9 @@ import { CustomChart, StudyViewPageStore, StudyViewPageTabDescriptions, - StudyViewPageTabKeyEnum, StudyViewURLQuery, } from "pages/studyView/StudyViewPageStore"; +import { StudyViewPageTabKeyEnum } from "pages/studyView/StudyViewPageTabs"; import LoadingIndicator from "shared/components/loadingIndicator/LoadingIndicator"; import { ClinicalDataTab } from "./tabs/ClinicalDataTab"; import getBrowserWindow from "../../public-lib/lib/getBrowserWindow"; diff --git a/src/pages/studyView/StudyViewPageStore.ts b/src/pages/studyView/StudyViewPageStore.ts index f374058b914..fcd9347924d 100644 --- a/src/pages/studyView/StudyViewPageStore.ts +++ b/src/pages/studyView/StudyViewPageStore.ts @@ -134,6 +134,7 @@ import { } from "pages/studyView/TableUtils"; import { GeneTableRow } from './table/GeneTable'; import { getSelectedGroups, getGroupParameters } from '../groupComparison/comparisonGroupManager/ComparisonGroupManagerUtils'; +import { StudyViewPageTabKeyEnum } from "pages/studyView/StudyViewPageTabs"; export type ChartUserSetting = { id: string, @@ -157,13 +158,6 @@ export type StudyPageSettings = { origin:string[] } -export enum StudyViewPageTabKeyEnum { - SUMMARY = 'summary', - CLINICAL_DATA = 'clinicalData', - HEATMAPS = 'heatmaps', - CN_SEGMENTS = 'cnSegments' -} - export type StudyViewPageTabKey = StudyViewPageTabKeyEnum.CLINICAL_DATA | StudyViewPageTabKeyEnum.SUMMARY | StudyViewPageTabKeyEnum.HEATMAPS | StudyViewPageTabKeyEnum.CN_SEGMENTS; diff --git a/src/pages/studyView/StudyViewPageTabs.ts b/src/pages/studyView/StudyViewPageTabs.ts new file mode 100644 index 00000000000..3f9ce5448f2 --- /dev/null +++ b/src/pages/studyView/StudyViewPageTabs.ts @@ -0,0 +1,6 @@ +export enum StudyViewPageTabKeyEnum { + SUMMARY = 'summary', + CLINICAL_DATA = 'clinicalData', + HEATMAPS = 'heatmaps', + CN_SEGMENTS = 'cnSegments', +} diff --git a/src/pages/studyView/StudyViewUtils.spec.ts b/src/pages/studyView/StudyViewUtils.spec.ts index f9bf51a48d9..bd3d40cca1e 100644 --- a/src/pages/studyView/StudyViewUtils.spec.ts +++ b/src/pages/studyView/StudyViewUtils.spec.ts @@ -61,9 +61,7 @@ import { StudyViewFilter } from 'shared/api/generated/CBioPortalAPIInternal'; import {CancerStudy, ClinicalAttribute, Gene} from 'shared/api/generated/CBioPortalAPI'; -import { - StudyViewPageTabKeyEnum -} from "./StudyViewPageStore"; +import { StudyViewPageTabKeyEnum } from "pages/studyView/StudyViewPageTabs"; import { UniqueKey } from "./StudyViewUtils"; diff --git a/src/pages/studyView/StudyViewUtils.tsx b/src/pages/studyView/StudyViewUtils.tsx index 54eca7a5fd7..56d761c5901 100644 --- a/src/pages/studyView/StudyViewUtils.tsx +++ b/src/pages/studyView/StudyViewUtils.tsx @@ -14,9 +14,9 @@ import * as React from "react"; import {buildCBioPortalPageUrl} from "../../shared/api/urls"; import {IStudyViewScatterPlotData} from "./charts/scatterPlot/StudyViewScatterPlot"; import {BarDatum} from "./charts/barChart/BarChart"; -import { - StudyViewPageTabKeyEnum, ChartUserSetting, CustomChart -} from "./StudyViewPageStore"; +import { ChartUserSetting, CustomChart } from "./StudyViewPageStore"; +import { StudyViewPageTabKeyEnum } from "pages/studyView/StudyViewPageTabs"; + import {Layout} from 'react-grid-layout'; import internalClient from "shared/api/cbioportalInternalClientInstance"; import {VirtualStudy} from "shared/model/VirtualStudy"; diff --git a/src/pages/studyView/addChartButton/AddChartButton.tsx b/src/pages/studyView/addChartButton/AddChartButton.tsx index a35098d40fd..4fdfcf89198 100644 --- a/src/pages/studyView/addChartButton/AddChartButton.tsx +++ b/src/pages/studyView/addChartButton/AddChartButton.tsx @@ -5,9 +5,10 @@ import {ChildButton, MainButton, Menu} from 'react-mfb'; import 'react-mfb/mfb.css'; import { CustomChart, - StudyViewPageStore, StudyViewPageTabKey, - StudyViewPageTabKeyEnum + StudyViewPageStore, + StudyViewPageTabKey, } from "../StudyViewPageStore"; +import { StudyViewPageTabKeyEnum } from "pages/studyView/StudyViewPageTabs"; import autobind from 'autobind-decorator'; import * as _ from 'lodash'; import AddChartByType from "./addChartByType/AddChartByType"; diff --git a/src/pages/studyView/tabs/CNSegments.tsx b/src/pages/studyView/tabs/CNSegments.tsx index 66d00deed6b..6fb3052129b 100644 --- a/src/pages/studyView/tabs/CNSegments.tsx +++ b/src/pages/studyView/tabs/CNSegments.tsx @@ -12,7 +12,8 @@ import LoadingIndicator from "shared/components/loadingIndicator/LoadingIndicato import CNSegmentsDownloader from "shared/components/cnSegments/CNSegmentsDownloader"; import WindowStore from "shared/components/window/WindowStore"; -import {StudyViewPageStore, StudyViewPageTabKeyEnum} from "../StudyViewPageStore"; +import { StudyViewPageTabKeyEnum } from "pages/studyView/StudyViewPageTabs"; +import {StudyViewPageStore} from "../StudyViewPageStore"; @observer export default class CNSegments extends React.Component<{ store: StudyViewPageStore }, {}> { diff --git a/src/routes.jsx b/src/routes.jsx index 2c48d0516f2..afea54c736f 100755 --- a/src/routes.jsx +++ b/src/routes.jsx @@ -14,6 +14,8 @@ import PageNotFound from './shared/components/pageNotFound/PageNotFound'; /* HOW TO ADD A NEW ROUTE * 1. Import the "page" component using the bundle-loader directives as seen in imports below * 2. Add a Route element with getComponent set to the result the lazyLoadComponent function passed your new component + * If your route includes tabs, include `null, tabParamValidator(YourPageTabEnum) in the lazyLoadComponent call. + * This ensures that invalid sub routes 404 correctly */ // import page components here @@ -39,27 +41,40 @@ 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'; -import AppConfig from 'appConfig'; -import { getBasePath } from 'shared/api/urls'; import $ from 'jquery'; -import ExtendedRouterStore from 'shared/lib/ExtendedRouterStore'; import getBrowserWindow from 'public-lib/lib/getBrowserWindow'; import { seekUrlHash } from 'shared/lib/seekUrlHash'; -import queryString from 'query-string'; import { PagePath } from 'shared/enums/PagePaths'; +import { ResultsViewTab } from 'pages/resultsView/ResultsViewPageHelpers' +import { StudyViewPageTabKeyEnum } from 'pages/studyView/StudyViewPageTabs' +import { PatientViewPageTabs } from 'pages/patientView/PatientViewPageTabs' +import { GroupComparisonTab } from 'pages/groupComparison/GroupComparisonTabs' + +/** + * Validates that the parameters either do not have + * a tab parameter, or have a parameter that matches a + * value in `tabEnum` + * @param tabEnum a TypeScript string enum + */ +function tabParamValidator(tabEnum) { + return function(params) { + return !params.tab || Object.values(tabEnum).indexOf(params.tab) > -1; + } +} // accepts bundle-loader's deferred loader function and defers execution of route's render // until chunk is loaded -function lazyLoadComponent(loader, loadingCallback) { +function lazyLoadComponent(loader, loadingCallback, validator = (_) => {return true;}) { return (location, cb) => { + if (location && !validator(location.params)) { + loader = ErrorPage; + } loader(module => { - if (cb) cb(null, module.default); - if (loadingCallback) loadingCallback(); - // if (typeof window.onReactAppReady === 'function') { - // window.onReactAppReady(); - // } + if (cb) { cb(null, module.default); } + if (loadingCallback) { loadingCallback(); } }); }; } @@ -123,28 +138,29 @@ export const makeRoutes = routing => { /> {}} + getComponent={lazyLoadComponent(ResultsViewPage, null, tabParamValidator(ResultsViewTab))} /> { $(document).scrollTop(0); }} - getComponent={lazyLoadComponent(PatientViewPage)} + getComponent={lazyLoadComponent(PatientViewPage, null, tabParamValidator(PatientViewPageTabs))} /> { $(document).scrollTop(0); }} - getComponent={lazyLoadComponent(StudyViewPage)} + getComponent={lazyLoadComponent(StudyViewPage, null, tabParamValidator(StudyViewPageTabKeyEnum))} /> { $(document).scrollTop(0); }} - getComponent={lazyLoadComponent(GroupComparisonPage)} + getComponent={lazyLoadComponent(GroupComparisonPage, null, tabParamValidator(GroupComparisonTab))} /> ( -

Sorry, this page doesn't exist.

+
+
+ Return to homepage} + /> +
+
); export default PageNotFound; \ No newline at end of file