feat: 🎸 Allow routes to load Google Cloud DICOM Stores in the Study List (#1069)

This commit is contained in:
ladeirarodolfo 2019-10-25 09:49:48 -03:00 committed by Erik Ziegler
parent 3bbeb1c521
commit 21b586b08f
9 changed files with 194 additions and 45 deletions

View File

@ -6,7 +6,7 @@ const PARAM_PATTERN_IDENTIFIER = ':';
function toLowerCaseFirstLetter(word) { function toLowerCaseFirstLetter(word) {
return word[0].toLowerCase() + word.slice(1); return word[0].toLowerCase() + word.slice(1);
} }
const getFilters = (location = {}) => { const getQueryFilters = (location = {}) => {
const { search } = location; const { search } = location;
if (!search) { if (!search) {
@ -55,13 +55,19 @@ const replaceParam = (path = '', paramKey, paramValue) => {
return path; return path;
}; };
const isValidPath = path => {
const paramPatternPiece = `/${PARAM_PATTERN_IDENTIFIER}`;
return path.indexOf(paramPatternPiece) < 0;
};
const queryString = { const queryString = {
getQueryFilters: getFilters, getQueryFilters,
}; };
const paramString = { const paramString = {
parseParam: parseParam, isValidPath,
replaceParam: replaceParam, parseParam,
replaceParam,
}; };
export { parse, queryString, paramString }; export { parse, queryString, paramString };

View File

@ -7,10 +7,6 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
**Note:** Version bump only for package @ohif/viewer **Note:** Version bump only for package @ohif/viewer
## [1.11.4](https://github.com/OHIF/Viewers/compare/@ohif/viewer@1.11.3...@ohif/viewer@1.11.4) (2019-10-23) ## [1.11.4](https://github.com/OHIF/Viewers/compare/@ohif/viewer@1.11.3...@ohif/viewer@1.11.4) (2019-10-23)
@ -18,10 +14,6 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
* Revert "Revert "fix: MPR initialization"" ([#1065](https://github.com/OHIF/Viewers/issues/1065)) ([c680720](https://github.com/OHIF/Viewers/commit/c680720ce5ead58fdb399e3a356edac18093f5c0)), closes [#1062](https://github.com/OHIF/Viewers/issues/1062) [#1064](https://github.com/OHIF/Viewers/issues/1064) * Revert "Revert "fix: MPR initialization"" ([#1065](https://github.com/OHIF/Viewers/issues/1065)) ([c680720](https://github.com/OHIF/Viewers/commit/c680720ce5ead58fdb399e3a356edac18093f5c0)), closes [#1062](https://github.com/OHIF/Viewers/issues/1062) [#1064](https://github.com/OHIF/Viewers/issues/1064)
## [1.11.3](https://github.com/OHIF/Viewers/compare/@ohif/viewer@1.11.2...@ohif/viewer@1.11.3) (2019-10-23) ## [1.11.3](https://github.com/OHIF/Viewers/compare/@ohif/viewer@1.11.2...@ohif/viewer@1.11.3) (2019-10-23)

View File

@ -0,0 +1,9 @@
import React, { useEffect, useRef } from 'react';
export default function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}

View File

@ -1,8 +1,10 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import GoogleCloudApi from '../googleCloud/api/GoogleCloudApi'; import GoogleCloudApi from '../googleCloud/api/GoogleCloudApi';
import usePrevious from './usePrevious';
import * as GoogleCloudUtilServers from '../googleCloud/utils/getServers'; import * as GoogleCloudUtilServers from '../googleCloud/utils/getServers';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import isEqual from 'lodash.isequal';
// Contexts // Contexts
import AppContext from '../context/AppContext'; import AppContext from '../context/AppContext';
@ -32,28 +34,68 @@ const getServers = (appConfig, project, location, dataset, dicomStore) => {
wadoRoot: pathUrl, wadoRoot: pathUrl,
}; };
servers = GoogleCloudUtilServers.getServers(data, dicomStore); servers = GoogleCloudUtilServers.getServers(data, dicomStore);
if (!isValidServer(servers[0], appConfig)) {
return;
}
} }
return servers; return servers;
}; };
const updateServer = ( const isValidServer = (server, appConfig) => {
if (appConfig.enableGoogleCloudAdapter) {
return GoogleCloudUtilServers.isValidServer(server);
}
return !!server;
};
const setServers = (dispatch, servers) => {
const action = {
type: 'SET_SERVERS',
servers,
};
dispatch(action);
};
const useServerFromUrl = (
servers = [],
previousServers,
activeServer,
urlBasedServers,
appConfig, appConfig,
dispatch,
project, project,
location, location,
dataset, dataset,
dicomStore dicomStore
) => { ) => {
const servers = getServers(appConfig, project, location, dataset, dicomStore); // update state from url available only when gcloud on
if (!appConfig.enableGoogleCloudAdapter) {
if (servers && servers.length) { return false;
const action = {
type: 'SET_SERVERS',
servers,
};
dispatch(action);
} }
const serverHasChanged = previousServers !== servers && previousServers;
// do not update from url. use state instead.
if (serverHasChanged) {
return false;
}
// if no valid urlbased servers
if (!urlBasedServers || !urlBasedServers.length) {
return false;
} else if (!servers.length || !activeServer) {
// no current valid server
return true;
}
const newServer = urlBasedServers[0];
let exists = servers.some(
GoogleCloudUtilServers.isEqualServer.bind(undefined, newServer)
);
return !exists;
}; };
export default function useServer({ export default function useServer({
@ -64,14 +106,29 @@ export default function useServer({
} = {}) { } = {}) {
// Hooks // Hooks
const servers = useSelector(state => state && state.servers); const servers = useSelector(state => state && state.servers);
const previousServers = usePrevious(servers);
const dispatch = useDispatch(); const dispatch = useDispatch();
const { appConfig = {} } = useContext(AppContext); const { appConfig = {} } = useContext(AppContext);
const server = getActiveServer(servers); const activeServer = getActiveServer(servers);
const urlBasedServers =
getServers(appConfig, project, location, dataset, dicomStore) || [];
const shouldUpdateServer = useServerFromUrl(
servers.servers,
previousServers,
activeServer,
urlBasedServers,
appConfig,
project,
location,
dataset,
dicomStore
);
if (!server) { if (shouldUpdateServer) {
updateServer(appConfig, dispatch, project, location, dataset, dicomStore); setServers(dispatch, urlBasedServers);
} else { } else if (isValidServer(activeServer, appConfig)) {
return server; return activeServer;
} }
} }

View File

@ -29,6 +29,10 @@ class GoogleCloudApi {
); );
} }
getUrlPath(project, location, dataset, dicomStore) {
`/projects/${project}/locations/${location}/datasets/${dataset}/dicomStores/${dicomStore}`;
}
async doRequest(urlStr, config = {}, params = {}) { async doRequest(urlStr, config = {}, params = {}) {
const url = new URL(urlStr); const url = new URL(urlStr);
let data = null; let data = null;

View File

@ -29,4 +29,31 @@ const getServers = (data, name) => {
]; ];
}; };
export { getServers }; const isValidServer = server => {
return (
server &&
!!server.dataset &&
!!server.dicomStore &&
!!server.location &&
!!server.project
);
};
const isEqualServer = (server = {}, toCompare = {}) => {
const serverLength = Object.keys(server).length;
const toCompareLength = Object.keys(toCompare).length;
if (!serverLength || !toCompareLength) {
return false;
}
return (
server.dataset === toCompare.dataset &&
server.dataset === toCompare.dataset &&
server.dicomStore === toCompare.dicomStore &&
server.location === toCompare.location &&
server.project === toCompare.project
);
};
export { getServers, isValidServer, isEqualServer };

View File

@ -65,6 +65,19 @@ const ROUTES_DEF = {
return !!appConfig.enableGoogleCloudAdapter; return !!appConfig.enableGoogleCloudAdapter;
}, },
}, },
list: {
path:
'/projects/:project/locations/:location/datasets/:dataset/dicomStores/:dicomStore',
component: StudyListRouting,
condition: appConfig => {
const showList =
appConfig.showStudyList !== undefined
? appConfig.showStudyList
: true;
return showList && !!appConfig.enableGoogleCloudAdapter;
},
},
}, },
}; };
@ -92,23 +105,33 @@ const getRoutes = appConfig => {
return routes; return routes;
}; };
const parsePath = (path, server, params) => {
let _path = path;
const _paramsCopy = Object.assign({}, server, params);
for (let key in _paramsCopy) {
_path = UrlUtil.paramString.replaceParam(_path, key, _paramsCopy[key]);
}
return _path;
};
const parseViewerPath = (appConfig = {}, server = {}, params) => { const parseViewerPath = (appConfig = {}, server = {}, params) => {
let viewerPath = ROUTES_DEF.default.viewer.path; let viewerPath = ROUTES_DEF.default.viewer.path;
if (appConfig.enableGoogleCloudAdapter) { if (appConfig.enableGoogleCloudAdapter) {
viewerPath = ROUTES_DEF.gcloud.viewer.path; viewerPath = ROUTES_DEF.gcloud.viewer.path;
} }
const _paramsCopy = Object.assign({}, server, params); return parsePath(viewerPath, server, params);
for (let key in _paramsCopy) {
viewerPath = UrlUtil.paramString.replaceParam(
viewerPath,
key,
_paramsCopy[key]
);
}
return viewerPath;
}; };
export { getRoutes, parseViewerPath, reload }; const parseStudyListPath = (appConfig = {}, server = {}, params) => {
let studyListPath = ROUTES_DEF.default.list.path;
if (appConfig.enableGoogleCloudAdapter) {
studyListPath = ROUTES_DEF.gcloud.list.path || studyListPath;
}
return parsePath(studyListPath, server, params);
};
export { getRoutes, parseViewerPath, parseStudyListPath, reload };

View File

@ -2,17 +2,26 @@ import React, { useContext } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import ConnectedStudyList from './ConnectedStudyList'; import ConnectedStudyList from './ConnectedStudyList';
import useServer from '../customHooks/useServer';
import OHIF from '@ohif/core'; import OHIF from '@ohif/core';
const { urlUtil: UrlUtil } = OHIF.utils; const { urlUtil: UrlUtil } = OHIF.utils;
// Contexts // Contexts
import AppContext from '../context/AppContext'; import AppContext from '../context/AppContext';
function StudyListRouting({ location }) { function StudyListRouting({ match: routeMatch, location: routeLocation }) {
const {
project,
location,
dataset,
dicomStore,
studyInstanceUids,
seriesInstanceUids,
} = routeMatch.params;
const server = useServer({ project, location, dataset, dicomStore });
const { appConfig = {} } = useContext(AppContext); const { appConfig = {} } = useContext(AppContext);
const filters = UrlUtil.queryString.getQueryFilters(location); const filters = UrlUtil.queryString.getQueryFilters(routeLocation);
let studyListFunctionsEnabled = false; let studyListFunctionsEnabled = false;
if (appConfig.studyListFunctionsEnabled) { if (appConfig.studyListFunctionsEnabled) {

View File

@ -13,6 +13,7 @@ import ConnectedDicomFilesUploader from '../googleCloud/ConnectedDicomFilesUploa
import ConnectedDicomStorePicker from '../googleCloud/ConnectedDicomStorePicker'; import ConnectedDicomStorePicker from '../googleCloud/ConnectedDicomStorePicker';
import filesToStudies from '../lib/filesToStudies.js'; import filesToStudies from '../lib/filesToStudies.js';
const { urlUtil: UrlUtil } = OHIF.utils;
// Contexts // Contexts
import UserManagerContext from '../context/UserManagerContext'; import UserManagerContext from '../context/UserManagerContext';
import WhiteLabellingContext from '../context/WhiteLabellingContext'; import WhiteLabellingContext from '../context/WhiteLabellingContext';
@ -202,9 +203,27 @@ class StudyListWithData extends Component {
const viewerPath = RoutesUtil.parseViewerPath(appConfig, server, { const viewerPath = RoutesUtil.parseViewerPath(appConfig, server, {
studyInstanceUids: studyInstanceUID, studyInstanceUids: studyInstanceUID,
}); });
this.props.history.push(viewerPath);
if (UrlUtil.paramString.isValidPath(viewerPath)) {
this.props.history.push(viewerPath);
}
}; };
updateURL(modalOpened) {
if (!modalOpened) {
const { appConfig = {} } = this.context;
const { server } = this.props;
const listPath = RoutesUtil.parseStudyListPath(appConfig, server);
if (UrlUtil.paramString.isValidPath(listPath)) {
const { location = {} } = this.props.history;
if (location.pathname !== listPath) {
this.props.history.replace(listPath);
}
}
}
}
onSearch = searchData => { onSearch = searchData => {
this.searchForStudies(searchData); this.searchForStudies(searchData);
}; };
@ -235,9 +254,12 @@ class StudyListWithData extends Component {
let healthCareApiWindows = null; let healthCareApiWindows = null;
if (appConfig.enableGoogleCloudAdapter) { if (appConfig.enableGoogleCloudAdapter) {
const modalOpened = this.state.modalComponentId === 'DicomStorePicker';
this.updateURL(modalOpened);
healthCareApiWindows = ( healthCareApiWindows = (
<ConnectedDicomStorePicker <ConnectedDicomStorePicker
isOpen={this.state.modalComponentId === 'DicomStorePicker'} isOpen={modalOpened}
onClose={this.closeModals} onClose={this.closeModals}
/> />
); );