diff --git a/src/AppStore.ts b/src/AppStore.ts index 8ff39c9a1b6..575d1a09dd6 100644 --- a/src/AppStore.ts +++ b/src/AppStore.ts @@ -1,30 +1,31 @@ -import {action, computed, observable} from "mobx"; -import {addServiceErrorHandler, getBrowserWindow, remoteData} from "cbioportal-frontend-commons"; -import {initializeAPIClients} from "./config/config"; +import { action, computed, observable } from 'mobx'; +import { + addServiceErrorHandler, + getBrowserWindow, + remoteData, +} from 'cbioportal-frontend-commons'; +import { initializeAPIClients } from './config/config'; import * as _ from 'lodash'; -import internalClient from "shared/api/cbioportalInternalClientInstance"; -import {sendSentryMessage} from "./shared/lib/tracking"; +import internalClient from 'shared/api/cbioportalInternalClientInstance'; +import { sendSentryMessage } from './shared/lib/tracking'; export type SiteError = { - errorObj:any; - dismissed:boolean; - title?:string; + errorObj: any; + dismissed: boolean; + title?: string; }; export class AppStore { - - constructor(){ - + constructor() { getBrowserWindow().me = this; addServiceErrorHandler((error: any) => { - try{ - sendSentryMessage("ERRORHANDLER:" + error); - } catch (ex) {}; - - if (error.status && /400|500/.test(error.status)) { + try { + sendSentryMessage('ERRORHANDLER:' + error); + } catch (ex) {} - sendSentryMessage("ERROR DIALOG SHOWN:" + error); - this.siteErrors.push({errorObj: error, dismissed:false}); + if (error.status && /400|500/.test(error.status)) { + sendSentryMessage('ERROR DIALOG SHOWN:' + error); + this.siteErrors.push({ errorObj: error, dismissed: false }); } }); } @@ -33,35 +34,35 @@ export class AppStore { @observable siteErrors: SiteError[] = []; - @observable userName:string | undefined; + @observable userName: string | undefined; - @observable authMethod:string | undefined; + @observable authMethod: string | undefined; - @computed get isLoggedIn(){ - return _.isString(this.userName) && this.userName !== "anonymousUser"; + @computed get isLoggedIn() { + return _.isString(this.userName) && this.userName !== 'anonymousUser'; } - @computed get logoutUrl(){ - if (this.authMethod === "saml") { - return "saml/logout"; + @computed get logoutUrl() { + if (this.authMethod === 'saml') { + return 'saml/logout'; } else { - return "j_spring_security_logout"; + return 'j_spring_security_logout'; } } - @computed get undismissedSiteErrors(){ - return _.filter(this.siteErrors.slice(), (err)=>!err.dismissed); + @computed get undismissedSiteErrors() { + return _.filter(this.siteErrors.slice(), err => !err.dismissed); } - @computed get isErrorCondition(){ + @computed get isErrorCondition() { return this.undismissedSiteErrors.length > 0; } @action - public dismissErrors(){ - this.siteErrors = this.siteErrors.map((err)=>{ - err.dismissed = true; - return err; + public dismissErrors() { + this.siteErrors = this.siteErrors.map(err => { + err.dismissed = true; + return err; }); } @@ -75,14 +76,21 @@ export class AppStore { } readonly portalVersion = remoteData({ - invoke:async()=>{ - const portalVersionResult = await internalClient.getInfoUsingGET({}); + invoke: async () => { + const portalVersionResult = await internalClient.getInfoUsingGET( + {} + ); if (portalVersionResult && portalVersionResult.portalVersion) { let version = undefined; // try getting version from branch name assume like release-x.y.z - if (portalVersionResult.gitBranch && portalVersionResult.gitBranch.startsWith("release-")) { - let branchVersion = portalVersionResult.gitBranch.split('-')[1]; + if ( + portalVersionResult.gitBranch && + portalVersionResult.gitBranch.startsWith('release-') + ) { + let branchVersion = portalVersionResult.gitBranch.split( + '-' + )[1]; if (branchVersion.split('.').length == 3) { version = branchVersion; } @@ -95,12 +103,12 @@ export class AppStore { } // add v prefix if missing - if (version !== undefined && !version.startsWith("v")) { + if (version !== undefined && !version.startsWith('v')) { version = `v${version}`; } return Promise.resolve(version); } return undefined; - } + }, }); } diff --git a/src/appBootstrapper.jsx b/src/appBootstrapper.jsx index 8243a8ed4ad..56108ee37ce 100755 --- a/src/appBootstrapper.jsx +++ b/src/appBootstrapper.jsx @@ -2,8 +2,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 { syncHistoryWithStore } from 'mobx-react-router'; +import { createHistory } from 'history'; +import { syncHistoryWithStore } from 'mobx-react-router'; import ExtendedRoutingStore from './shared/lib/ExtendedRouterStore'; import { fetchServerConfig, @@ -11,7 +11,7 @@ import { initializeAppStore, initializeConfiguration, setConfigDefaults, - setServerConfig + setServerConfig, } from './config/config'; import './shared/lib/ajaxQuiet'; @@ -20,15 +20,15 @@ import * as _ from 'lodash'; import $ from 'jquery'; import * as superagent from 'superagent'; import { getHost, buildCBioPortalPageUrl } from './shared/api/urls'; -import AppConfig from "appConfig"; +import AppConfig from 'appConfig'; import browser from 'bowser'; import { setNetworkListener } from './shared/lib/ajaxQuiet'; -import { initializeTracking } from "shared/lib/tracking"; +import { initializeTracking } from 'shared/lib/tracking'; import superagentCache from 'superagent-cache'; -import {getBrowserWindow} from "cbioportal-frontend-commons"; -import {AppStore} from "./AppStore"; -import {handleLongUrls} from "shared/lib/handleLongUrls"; -import "shared/polyfill/canvasToBlob"; +import { getBrowserWindow } from 'cbioportal-frontend-commons'; +import { AppStore } from './AppStore'; +import { handleLongUrls } from 'shared/lib/handleLongUrls'; +import 'shared/polyfill/canvasToBlob'; import mobx from 'mobx'; superagentCache(superagent); @@ -37,39 +37,35 @@ superagentCache(superagent); // it fixes the hash portion of url when cohort patient list is too long handleLongUrls(); - // YOU MUST RUN THESE initialize and then set the public path after initializeConfiguration(); // THIS TELLS WEBPACK BUNDLE LOADER WHERE TO LOAD SPLIT BUNDLES __webpack_public_path__ = AppConfig.frontendUrl; -if (!window.hasOwnProperty("$")) { +if (!window.hasOwnProperty('$')) { window.$ = $; } - - -if (!window.hasOwnProperty("jQuery")) { +if (!window.hasOwnProperty('jQuery')) { window.jQuery = $; } -if (!window.hasOwnProperty("mobx")) { +if (!window.hasOwnProperty('mobx')) { window.mobx = mobx; } // write browser name, version to brody tag if (browser) { - $(document).ready(()=>{ - $("body").addClass(browser.name); + $(document).ready(() => { + $('body').addClass(browser.name); }); } // e2e test specific stuff if (getBrowserWindow().navigator.webdriver) { - - $(document).ready(()=>{ - $("body").addClass("e2etest"); + $(document).ready(() => { + $('body').addClass('e2etest'); window.e2etest = true; }); @@ -82,9 +78,9 @@ window.FRONTEND_COMMIT = COMMIT; // this is special function allowing MSKCC CIS to hide login UI in // portal header -window.postLoadForMskCIS = function(){ +window.postLoadForMskCIS = function() { AppConfig.hide_login = true; -} +}; // make sure lodash doesn't overwrite (or set) global underscore _.noConflict(); @@ -92,7 +88,7 @@ _.noConflict(); const routingStore = new ExtendedRoutingStore(); const history = useRouterHistory(createHistory)({ - basename: AppConfig.basePath || "" + basename: AppConfig.basePath || '', }); const syncedHistory = syncHistoryWithStore(history, routingStore); @@ -100,7 +96,7 @@ const syncedHistory = syncHistoryWithStore(history, routingStore); const stores = { // Key can be whatever you want routing: routingStore, - appStore:new AppStore() + appStore: new AppStore(), }; window.globalStores = stores; @@ -109,21 +105,25 @@ const end = superagent.Request.prototype.end; let redirecting = false; -superagent.Request.prototype.end = function (callback) { +superagent.Request.prototype.end = function(callback) { return end.call(this, (error, response) => { - if (redirecting) { return; } if (response && response.statusCode === 401) { - var storageKey = `redirect${Math.floor(Math.random() * 1000000000000)}` + var storageKey = `redirect${Math.floor( + Math.random() * 1000000000000 + )}`; localStorage.setItem(storageKey, window.location.href); // build URL with a reference to storage key so that /restore route can restore it after login const loginUrl = buildCBioPortalPageUrl({ query: { - "spring-security-redirect":buildCBioPortalPageUrl({ pathname:"restore", query: { key: storageKey} }) - } + 'spring-security-redirect': buildCBioPortalPageUrl({ + pathname: 'restore', + query: { key: storageKey }, + }), + }, }); redirecting = true; @@ -136,22 +136,17 @@ superagent.Request.prototype.end = function (callback) { window.routingStore = routingStore; - let render = () => { - if (!getBrowserWindow().navigator.webdriver) initializeTracking(); - const rootNode = document.getElementById("reactRoot"); + const rootNode = document.getElementById('reactRoot'); ReactDOM.render( - - - - , rootNode); - - + + , + rootNode + ); }; if (__DEBUG__ && module.hot) { @@ -162,15 +157,14 @@ if (__DEBUG__ && module.hot) { } $(document).ready(async () => { - // we show blank page if the window.name is "blank" - if (window.name === "blank") { + if (window.name === 'blank') { return; } // we use rawServerConfig (written by JSP) if it is present // or fetch from config service if not // need to use jsonp, so use jquery - let config = window.rawServerConfig || await fetchServerConfig(); + let config = window.rawServerConfig || (await fetchServerConfig()); setServerConfig(config); @@ -178,7 +172,7 @@ $(document).ready(async () => { initializeAPIClients(); - initializeAppStore(stores.appStore,config); + initializeAppStore(stores.appStore, config); render(); diff --git a/src/appShell/App/Container.tsx b/src/appShell/App/Container.tsx index efa62a753af..a6d0f3fb10f 100644 --- a/src/appShell/App/Container.tsx +++ b/src/appShell/App/Container.tsx @@ -2,19 +2,23 @@ import * as _ from 'lodash'; import * as React from 'react'; import '../../globalStyles/prefixed-global.scss'; -import PortalHeader from "./PortalHeader"; -import {getBrowserWindow, isWebdriver} from "cbioportal-frontend-commons"; -import {observer} from "mobx-react"; +import PortalHeader from './PortalHeader'; +import { getBrowserWindow, isWebdriver } from 'cbioportal-frontend-commons'; +import { observer } from 'mobx-react'; -import LoadingIndicator from "../../shared/components/loadingIndicator/LoadingIndicator"; -import AppConfig from "appConfig"; -import Helmet from "react-helmet"; -import {computed} from "mobx"; +import LoadingIndicator from '../../shared/components/loadingIndicator/LoadingIndicator'; +import AppConfig from 'appConfig'; +import Helmet from 'react-helmet'; +import { computed } from 'mobx'; import { If, Else, Then } from 'react-if'; -import UserMessager from "shared/components/userMessager/UserMessage"; -import {formatErrorLog, formatErrorTitle, formatErrorMessages} from "shared/lib/errorFormatter"; -import {buildCBioPortalPageUrl} from "shared/api/urls"; -import ErrorScreen from "shared/components/errorScreen/ErrorScreen"; +import UserMessager from 'shared/components/userMessager/UserMessage'; +import { + formatErrorLog, + formatErrorTitle, + formatErrorMessages, +} from 'shared/lib/errorFormatter'; +import { buildCBioPortalPageUrl } from 'shared/api/urls'; +import ErrorScreen from 'shared/components/errorScreen/ErrorScreen'; import { ServerConfigHelpers } from 'config/config'; interface IContainerProps { @@ -24,20 +28,20 @@ interface IContainerProps { @observer export default class Container extends React.Component { - - private get routingStore(){ + private get routingStore() { return getBrowserWindow().routingStore; } - private get appStore(){ + private get appStore() { return getBrowserWindow().globalStores.appStore; } renderChildren() { - const childProps = {...this.props}; - const {children} = this.props; - return React.Children.map(children, - c => React.cloneElement(c as React.ReactElement, childProps)); + const childProps = { ...this.props }; + const { children } = this.props; + return React.Children.map(children, c => + React.cloneElement(c as React.ReactElement, childProps) + ); } render() { @@ -45,12 +49,20 @@ export default class Container extends React.Component { return (
As of version 3.0.0, all cBioPortal installations require a session service. Please review these instructions for how to do so. https://docs.cbioportal.org/2.1.2-deploy-without-docker/deploying#run-cbioportal-session-service -

} + title={'No session service configured'} + body={ +

+ As of version 3.0.0, all cBioPortal + installations require a session service. Please + review these instructions for how to do so.{' '} + + https://docs.cbioportal.org/2.1.2-deploy-without-docker/deploying#run-cbioportal-session-service + +

+ } />
- ) + ); } return ( @@ -58,23 +70,39 @@ export default class Container extends React.Component { {AppConfig.serverConfig.skin_title} - +
- +
Return to homepage} - errorLog={formatErrorLog(this.appStore.undismissedSiteErrors)} - errorMessages={formatErrorMessages(this.appStore.undismissedSiteErrors)} + title={ + formatErrorTitle( + this.appStore.undismissedSiteErrors + ) || + 'Oops. There was an error retrieving data.' + } + body={ + + Return to homepage + + } + errorLog={formatErrorLog( + this.appStore.undismissedSiteErrors + )} + errorMessages={formatErrorMessages( + this.appStore.undismissedSiteErrors + )} />
@@ -88,5 +116,3 @@ export default class Container extends React.Component { ); } } - - diff --git a/src/appShell/App/PortalFooter.tsx b/src/appShell/App/PortalFooter.tsx index 6dcd7dfc652..831a78b08bd 100644 --- a/src/appShell/App/PortalFooter.tsx +++ b/src/appShell/App/PortalFooter.tsx @@ -1,105 +1,233 @@ import * as React from 'react'; -import AppConfig from "appConfig"; +import AppConfig from 'appConfig'; 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 {AppStore} from "../../AppStore"; -import {observer} from "mobx-react"; - -@observer export default class PortalFooter extends React.Component<{appStore:AppStore}, {}> { +import { AppStore } from '../../AppStore'; +import { observer } from 'mobx-react'; +@observer +export default class PortalFooter extends React.Component< + { appStore: AppStore }, + {} +> { render() { - var version; - if (this.props.appStore.portalVersion.isComplete && !this.props.appStore.portalVersion.isError && this.props.appStore.portalVersion.result){ - version = this.props.appStore.portalVersion.result; - } - else{ - version = "--" - } - if (AppConfig.serverConfig.skin_footer && !_.isEmpty(AppConfig.serverConfig.skin_footer)) { - return ( - - ); - } else { - return ( -