diff --git a/platform/core/src/redux/reducers/servers.js b/platform/core/src/redux/reducers/servers.js index b834f4fb0..6b11b2310 100644 --- a/platform/core/src/redux/reducers/servers.js +++ b/platform/core/src/redux/reducers/servers.js @@ -11,6 +11,16 @@ const servers = (state = defaultState, action) => { servers.forEach(s => (s.active = true)); return { ...state, servers }; + case 'ACTIVATE_SERVER': { + const newServer = { ...action.server, active: true }; + const newServers = state.servers; + newServers.forEach(s => (s.active = false)); + return { + ...state, + servers: uniqBy([...newServers, newServer], 'wadoRoot'), + }; + } + case 'SET_SERVERS': return { ...state, servers: action.servers }; diff --git a/platform/viewer/src/connectedComponents/ConnectedStandaloneRouting.js b/platform/viewer/src/connectedComponents/ConnectedStandaloneRouting.js new file mode 100644 index 000000000..26d553a93 --- /dev/null +++ b/platform/viewer/src/connectedComponents/ConnectedStandaloneRouting.js @@ -0,0 +1,21 @@ +import { connect } from 'react-redux'; +import StandaloneRouting from '../routes/StandaloneRouting'; + +const mapDispatchToProps = dispatch => { + return { + activateServer: server => { + const action = { + type: 'ACTIVATE_SERVER', + server, + }; + dispatch(action); + }, + }; +}; + +const ConnectedStandaloneRouting = connect( + null, + mapDispatchToProps +)(StandaloneRouting); + +export default ConnectedStandaloneRouting; diff --git a/platform/viewer/src/connectedComponents/ConnectedViewerRetrieveStudyData.js b/platform/viewer/src/connectedComponents/ConnectedViewerRetrieveStudyData.js index f3a7e5ee2..d7ffc6ea2 100644 --- a/platform/viewer/src/connectedComponents/ConnectedViewerRetrieveStudyData.js +++ b/platform/viewer/src/connectedComponents/ConnectedViewerRetrieveStudyData.js @@ -2,23 +2,21 @@ import { connect } from 'react-redux'; import ViewerRetrieveStudyData from './ViewerRetrieveStudyData.js'; import OHIF from "@ohif/core"; -const { - clearViewportSpecificData -} = OHIF.redux.actions; +const { clearViewportSpecificData } = OHIF.redux.actions; const isActive = a => a.active === true; -const mapStateToProps = state => { +const mapStateToProps = (state, ownProps) => { const activeServer = state.servers.servers.find(isActive); return { - server: activeServer, + server: ownProps.server || activeServer, }; }; const mapDispatchToProps = dispatch => { return { clearViewportSpecificData: () => { dispatch(clearViewportSpecificData()); - } + }, }; }; diff --git a/platform/viewer/src/routes/NotFound.js b/platform/viewer/src/routes/NotFound.js index 2844b35da..41f5e01f1 100644 --- a/platform/viewer/src/routes/NotFound.js +++ b/platform/viewer/src/routes/NotFound.js @@ -2,14 +2,16 @@ import React from 'react'; import './NotFound.css'; import { Link } from 'react-router-dom'; -export default function NotFound() { +export default function NotFound({ message = 'Sorry, this page does not exist.', showGoBackButton = true }) { return (
-

Sorry, this page does not exist.

-
- Go back to the Study List -
+

{message}

+ {showGoBackButton && ( +
+ Go back to the Study List +
+ )}
); diff --git a/platform/viewer/src/routes/StandaloneRouting.js b/platform/viewer/src/routes/StandaloneRouting.js index a061f818d..44fa8a7a9 100644 --- a/platform/viewer/src/routes/StandaloneRouting.js +++ b/platform/viewer/src/routes/StandaloneRouting.js @@ -1,29 +1,33 @@ import React, { Component } from 'react'; -import { log, metadata, studies, utils } from '@ohif/core'; - +import { log, metadata, utils } from '@ohif/core'; import PropTypes from 'prop-types'; -import ConnectedViewer from '../connectedComponents/ConnectedViewer'; -import { extensionManager } from './../App.js'; import qs from 'querystring'; -const { OHIFStudyMetadata } = metadata; -const { retrieveStudiesMetadata } = studies; +import { extensionManager } from './../App.js'; +import ConnectedViewer from '../connectedComponents/ConnectedViewer'; +import ConnectedViewerRetrieveStudyData from '../connectedComponents/ConnectedViewerRetrieveStudyData'; +import NotFound from '../routes/NotFound'; + const { studyMetadataManager, updateMetaDataManager } = utils; +const { OHIFStudyMetadata } = metadata; class StandaloneRouting extends Component { state = { studies: null, + server: null, + studyInstanceUids: null, + seriesInstanceUids: null, error: null, + loading: true, }; - studyInstanceUids = []; - static propTypes = { location: PropTypes.object, store: PropTypes.object, + setServers: PropTypes.func, }; - static parseQueryAndFetchStudies(query) { + parseQueryAndRetrieveDICOMWebData(query) { return new Promise((resolve, reject) => { const url = query.url; @@ -43,7 +47,11 @@ class StandaloneRouting extends Component { // When the JSON has been returned, parse it into a JavaScript Object // and render the OHIF Viewer with this data - oReq.addEventListener('load', () => { + oReq.addEventListener('load', event => { + if (event.target.status === 404) { + reject(new Error('No JSON data found')); + } + // Parse the response content // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseText if (!oReq.responseText) { @@ -54,27 +62,24 @@ class StandaloneRouting extends Component { log.info(JSON.stringify(oReq.responseText, null, 2)); const data = JSON.parse(oReq.responseText); - if (data.servers && query.studyInstanceUids) { + if (data.servers) { + if (!query.studyInstanceUids) { + log.warn('No study instance uids specified'); + reject(new Error('No study instance uids specified')); + } + const server = data.servers.dicomWeb[0]; server.type = 'dicomWeb'; - const studyInstanceUids = query.studyInstanceUids.split(';'); - const seriesInstanceUids = []; + log.warn('Activating server', server); + this.props.activateServer(server); - retrieveStudiesMetadata( - server, - studyInstanceUids, - seriesInstanceUids - ).then( - studies => { - resolve(studies); - }, - error => { - reject(error); - } - ); + const studyInstanceUids = query.studyInstanceUids.split(';'); + const seriesInstanceUids = query.seriesInstanceUids ? query.seriesInstanceUids.split(';') : []; + + resolve({ server, studyInstanceUids, seriesInstanceUids }); } else { - resolve(data.studies); + resolve({ studies: data.studies, studyInstanceUids: [] }); } }); @@ -96,56 +101,80 @@ class StandaloneRouting extends Component { // Remove ? prefix which is included for some reason search = search.slice(1, search.length); - const query = qs.parse(search); - const studies = await StandaloneRouting.parseQueryAndFetchStudies(query); - studyMetadataManager.purge(); + let { + server, + studies, + studyInstanceUids, + seriesInstanceUids, + } = await this.parseQueryAndRetrieveDICOMWebData(query); - // Map studies to new format, update metadata manager? - const uniqueStudyUids = new Set(); - const updatedStudies = studies.map(study => { - const studyMetadata = new OHIFStudyMetadata( - study, - study.studyInstanceUid - ); - const sopClassHandlerModules = - extensionManager.modules['sopClassHandlerModule']; + if (studies) { + const { + studies: updatedStudies, + studyInstanceUids: updatedStudiesInstanceUids, + } = _mapStudiesToNewFormat(studies); + studies = updatedStudies; + studyInstanceUids = updatedStudiesInstanceUids; + } - study.displaySets = - study.displaySets || - studyMetadata.createDisplaySets(sopClassHandlerModules); - studyMetadata.setDisplaySets(study.displaySets); - - // Updates WADO-RS metaDataManager - updateMetaDataManager(study); - - studyMetadataManager.add(studyMetadata); - uniqueStudyUids.add(study.studyInstanceUid); - - return study; + this.setState({ + studies, + server, + studyInstanceUids, + seriesInstanceUids, + loading: false, }); - - this.studyInstanceUids = Array.from(uniqueStudyUids); - this.setState({ studies: updatedStudies }); } catch (error) { - this.setState({ error }); + this.setState({ error: error.message, loading: false }); } } render() { - if (this.state.error) { - return
Error: {JSON.stringify(this.state.error)}
; - } else if (!this.state.studies) { - return
Loading...
; + const message = this.state.error ? `Error: ${JSON.stringify(this.state.error)}` : 'Loading...'; + if (this.state.error || this.state.loading) { + return ; } - return ( - - ); + + return this.state.studies ? ( + + ) : ( + + ); } } +const _mapStudiesToNewFormat = studies => { + studyMetadataManager.purge(); + + /* Map studies to new format, update metadata manager? */ + const uniqueStudyUids = new Set(); + const updatedStudies = studies.map(study => { + const studyMetadata = new OHIFStudyMetadata(study, study.studyInstanceUid); + + const sopClassHandlerModules = extensionManager.modules['sopClassHandlerModule']; + study.displaySets = study.displaySets || + studyMetadata.createDisplaySets(sopClassHandlerModules); + studyMetadata.setDisplaySets(study.displaySets); + + /* Updates WADO-RS metaDataManager */ + updateMetaDataManager(study); + + studyMetadataManager.add(studyMetadata); + uniqueStudyUids.add(study.studyInstanceUid); + + return study; + }); + + return { + studies: updatedStudies, + studyInstanceUids: Array.from(uniqueStudyUids), + }; +}; + export default StandaloneRouting; diff --git a/platform/viewer/src/routes/routesUtil.js b/platform/viewer/src/routes/routesUtil.js index 552eda18a..b0c39a598 100644 --- a/platform/viewer/src/routes/routesUtil.js +++ b/platform/viewer/src/routes/routesUtil.js @@ -19,7 +19,7 @@ const StudyListRouting = asyncComponent(() => ) ); const StandaloneRouting = asyncComponent(() => - import(/* webpackChunkName: "StandaloneRouting" */ './StandaloneRouting.js') + import(/* webpackChunkName: "ConnectedStandaloneRouting" */ '../connectedComponents/ConnectedStandaloneRouting.js') ); const ViewerLocalFileData = asyncComponent(() => import(