diff --git a/extensions/default/src/Panels/PanelStudyBrowser.tsx b/extensions/default/src/Panels/PanelStudyBrowser.tsx index 2e4a41999..20af14f4d 100644 --- a/extensions/default/src/Panels/PanelStudyBrowser.tsx +++ b/extensions/default/src/Panels/PanelStudyBrowser.tsx @@ -2,6 +2,7 @@ import React, { useState, useEffect, useRef } from 'react'; import PropTypes from 'prop-types'; import { StudyBrowser, useImageViewer, useViewportGrid } from '@ohif/ui'; import { utils } from '@ohif/core'; +import { useNavigate } from 'react-router-dom'; const { sortStudyInstances, formatDate } = utils; @@ -21,6 +22,8 @@ function PanelStudyBrowser({ displaySetService, uiNotificationService, } = servicesManager.services; + const navigate = useNavigate(); + // Normally you nest the components so the tree isn't so deep, and the data // doesn't have to have such an intense shape. This works well enough for now. // Tabs --> Studies --> DisplaySets --> Thumbnails @@ -69,6 +72,11 @@ function PanelStudyBrowser({ studyInstanceUid: StudyInstanceUID, }); + if (!qidoForStudyUID?.length) { + navigate('/notfoundstudy', '_self'); + throw new Error('Invalid study URL'); + } + let qidoStudiesForPatient = qidoForStudyUID; // try to fetch the prior studies based on the patientID if the diff --git a/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx b/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx index 960bcd573..91228d9c5 100644 --- a/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx +++ b/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx @@ -1,4 +1,5 @@ import React, { useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import PropTypes from 'prop-types'; import { utils } from '@ohif/core'; @@ -30,6 +31,7 @@ function PanelStudyBrowserTracking({ hangingProtocolService, uiNotificationService, } = servicesManager.services; + const navigate = useNavigate(); const { t } = useTranslation('Common'); @@ -90,6 +92,11 @@ function PanelStudyBrowserTracking({ studyInstanceUid: StudyInstanceUID, }); + if (!qidoForStudyUID?.length) { + navigate('/notfoundstudy', '_self'); + throw new Error('Invalid study URL'); + } + let qidoStudiesForPatient = qidoForStudyUID; // try to fetch the prior studies based on the patientID if the diff --git a/platform/app/src/routes/DataSourceWrapper.tsx b/platform/app/src/routes/DataSourceWrapper.tsx index 8536bdc59..c137546d9 100644 --- a/platform/app/src/routes/DataSourceWrapper.tsx +++ b/platform/app/src/routes/DataSourceWrapper.tsx @@ -5,6 +5,7 @@ import { ExtensionManager, MODULE_TYPES } from '@ohif/core'; // import { extensionManager } from '../App.tsx'; import { useParams, useLocation } from 'react-router'; +import { useNavigate } from 'react-router-dom'; import useSearchParams from '../hooks/useSearchParams.ts'; /** @@ -27,6 +28,7 @@ const areLocationsTheSame = (location0, location1) => { * @param {function} props.children - Layout Template React Component */ function DataSourceWrapper(props) { + const navigate = useNavigate(); const { children: LayoutTemplate, ...rest } = props; const params = useParams(); const location = useLocation(); @@ -189,7 +191,7 @@ function DataSourceWrapper(props) { (!isLoading && (newOffset !== previousOffset || isLocationUpdated)); if (isDataInvalid) { - getData(); + getData().catch(() => navigate('/notfoundserver', '_self')); } } catch (ex) { console.warn(ex); diff --git a/platform/app/src/routes/Mode/Mode.tsx b/platform/app/src/routes/Mode/Mode.tsx index 5182478cf..a78b3ce36 100644 --- a/platform/app/src/routes/Mode/Mode.tsx +++ b/platform/app/src/routes/Mode/Mode.tsx @@ -11,6 +11,7 @@ import Compose from './Compose'; import getStudies from './studiesList'; import { history } from '../../utils/history'; import loadModules from '../../pluginImports'; +import isSeriesFilterUsed from '../../utils/isSeriesFilterUsed'; const { getSplitParam } = utils; @@ -30,9 +31,11 @@ function defaultRouteInit( const { displaySetService, hangingProtocolService, + uiNotificationService, } = servicesManager.services; const unsubscriptions = []; + const issuedWarningSeries = []; const { unsubscribe: instanceAddedUnsubscribe, } = DicomMetadataStore.subscribe( @@ -43,6 +46,22 @@ function defaultRouteInit( SeriesInstanceUID ); + // checks if the series filter was used, if it exists + const seriesInstanceUIDs = filters?.seriesInstanceUID; + if ( + seriesInstanceUIDs?.length && + !isSeriesFilterUsed(seriesMetadata.instances, filters) && + !issuedWarningSeries.includes(seriesInstanceUIDs[0]) + ) { + // stores the series instance filter so it shows only once the warning + issuedWarningSeries.push(seriesInstanceUIDs[0]); + uiNotificationService.show({ + title: 'Series filter', + message: `Each of the series in filter: ${seriesInstanceUIDs} are not part of the current study. The entire study is being displayed`, + type: 'error', + duration: 7000, + }); + } displaySetService.makeDisplaySets(seriesMetadata.instances, madeInClient); } ); diff --git a/platform/app/src/routes/index.tsx b/platform/app/src/routes/index.tsx index 0d1101f85..d031d4560 100644 --- a/platform/app/src/routes/index.tsx +++ b/platform/app/src/routes/index.tsx @@ -10,9 +10,56 @@ import Debug from './Debug'; import NotFound from './NotFound'; import buildModeRoutes from './buildModeRoutes'; import PrivateRoute from './PrivateRoute'; +import PropTypes from 'prop-types'; +import { Link } from 'react-router-dom'; + +const NotFoundServer = ({ + message = 'Unable to query for studies at this time. Check your data source configuration or network connection', +}) => { + return ( +