feat(errorHandling): Create fallback page for Server, Study and Series (#3592)
This commit is contained in:
parent
9c51f17c60
commit
19408c987f
@ -2,6 +2,7 @@ import React, { useState, useEffect, useRef } from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { StudyBrowser, useImageViewer, useViewportGrid } from '@ohif/ui';
|
import { StudyBrowser, useImageViewer, useViewportGrid } from '@ohif/ui';
|
||||||
import { utils } from '@ohif/core';
|
import { utils } from '@ohif/core';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
const { sortStudyInstances, formatDate } = utils;
|
const { sortStudyInstances, formatDate } = utils;
|
||||||
|
|
||||||
@ -21,6 +22,8 @@ function PanelStudyBrowser({
|
|||||||
displaySetService,
|
displaySetService,
|
||||||
uiNotificationService,
|
uiNotificationService,
|
||||||
} = servicesManager.services;
|
} = servicesManager.services;
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
// Normally you nest the components so the tree isn't so deep, and the data
|
// 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.
|
// doesn't have to have such an intense shape. This works well enough for now.
|
||||||
// Tabs --> Studies --> DisplaySets --> Thumbnails
|
// Tabs --> Studies --> DisplaySets --> Thumbnails
|
||||||
@ -69,6 +72,11 @@ function PanelStudyBrowser({
|
|||||||
studyInstanceUid: StudyInstanceUID,
|
studyInstanceUid: StudyInstanceUID,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!qidoForStudyUID?.length) {
|
||||||
|
navigate('/notfoundstudy', '_self');
|
||||||
|
throw new Error('Invalid study URL');
|
||||||
|
}
|
||||||
|
|
||||||
let qidoStudiesForPatient = qidoForStudyUID;
|
let qidoStudiesForPatient = qidoForStudyUID;
|
||||||
|
|
||||||
// try to fetch the prior studies based on the patientID if the
|
// try to fetch the prior studies based on the patientID if the
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { utils } from '@ohif/core';
|
import { utils } from '@ohif/core';
|
||||||
@ -30,6 +31,7 @@ function PanelStudyBrowserTracking({
|
|||||||
hangingProtocolService,
|
hangingProtocolService,
|
||||||
uiNotificationService,
|
uiNotificationService,
|
||||||
} = servicesManager.services;
|
} = servicesManager.services;
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const { t } = useTranslation('Common');
|
const { t } = useTranslation('Common');
|
||||||
|
|
||||||
@ -90,6 +92,11 @@ function PanelStudyBrowserTracking({
|
|||||||
studyInstanceUid: StudyInstanceUID,
|
studyInstanceUid: StudyInstanceUID,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!qidoForStudyUID?.length) {
|
||||||
|
navigate('/notfoundstudy', '_self');
|
||||||
|
throw new Error('Invalid study URL');
|
||||||
|
}
|
||||||
|
|
||||||
let qidoStudiesForPatient = qidoForStudyUID;
|
let qidoStudiesForPatient = qidoForStudyUID;
|
||||||
|
|
||||||
// try to fetch the prior studies based on the patientID if the
|
// try to fetch the prior studies based on the patientID if the
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { ExtensionManager, MODULE_TYPES } from '@ohif/core';
|
|||||||
//
|
//
|
||||||
import { extensionManager } from '../App.tsx';
|
import { extensionManager } from '../App.tsx';
|
||||||
import { useParams, useLocation } from 'react-router';
|
import { useParams, useLocation } from 'react-router';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
import useSearchParams from '../hooks/useSearchParams.ts';
|
import useSearchParams from '../hooks/useSearchParams.ts';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,6 +28,7 @@ const areLocationsTheSame = (location0, location1) => {
|
|||||||
* @param {function} props.children - Layout Template React Component
|
* @param {function} props.children - Layout Template React Component
|
||||||
*/
|
*/
|
||||||
function DataSourceWrapper(props) {
|
function DataSourceWrapper(props) {
|
||||||
|
const navigate = useNavigate();
|
||||||
const { children: LayoutTemplate, ...rest } = props;
|
const { children: LayoutTemplate, ...rest } = props;
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
@ -189,7 +191,7 @@ function DataSourceWrapper(props) {
|
|||||||
(!isLoading && (newOffset !== previousOffset || isLocationUpdated));
|
(!isLoading && (newOffset !== previousOffset || isLocationUpdated));
|
||||||
|
|
||||||
if (isDataInvalid) {
|
if (isDataInvalid) {
|
||||||
getData();
|
getData().catch(() => navigate('/notfoundserver', '_self'));
|
||||||
}
|
}
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
console.warn(ex);
|
console.warn(ex);
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import Compose from './Compose';
|
|||||||
import getStudies from './studiesList';
|
import getStudies from './studiesList';
|
||||||
import { history } from '../../utils/history';
|
import { history } from '../../utils/history';
|
||||||
import loadModules from '../../pluginImports';
|
import loadModules from '../../pluginImports';
|
||||||
|
import isSeriesFilterUsed from '../../utils/isSeriesFilterUsed';
|
||||||
|
|
||||||
const { getSplitParam } = utils;
|
const { getSplitParam } = utils;
|
||||||
|
|
||||||
@ -30,9 +31,11 @@ function defaultRouteInit(
|
|||||||
const {
|
const {
|
||||||
displaySetService,
|
displaySetService,
|
||||||
hangingProtocolService,
|
hangingProtocolService,
|
||||||
|
uiNotificationService,
|
||||||
} = servicesManager.services;
|
} = servicesManager.services;
|
||||||
|
|
||||||
const unsubscriptions = [];
|
const unsubscriptions = [];
|
||||||
|
const issuedWarningSeries = [];
|
||||||
const {
|
const {
|
||||||
unsubscribe: instanceAddedUnsubscribe,
|
unsubscribe: instanceAddedUnsubscribe,
|
||||||
} = DicomMetadataStore.subscribe(
|
} = DicomMetadataStore.subscribe(
|
||||||
@ -43,6 +46,22 @@ function defaultRouteInit(
|
|||||||
SeriesInstanceUID
|
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);
|
displaySetService.makeDisplaySets(seriesMetadata.instances, madeInClient);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@ -10,9 +10,56 @@ import Debug from './Debug';
|
|||||||
import NotFound from './NotFound';
|
import NotFound from './NotFound';
|
||||||
import buildModeRoutes from './buildModeRoutes';
|
import buildModeRoutes from './buildModeRoutes';
|
||||||
import PrivateRoute from './PrivateRoute';
|
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 (
|
||||||
|
<div className="absolute w-full h-full flex justify-center items-center text-white">
|
||||||
|
<div>
|
||||||
|
<h4>{message}</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
NotFoundServer.propTypes = {
|
||||||
|
message: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
const NotFoundStudy = () => {
|
||||||
|
return (
|
||||||
|
<div className="absolute w-full h-full flex justify-center items-center text-white">
|
||||||
|
<div>
|
||||||
|
<h4>
|
||||||
|
One or more of the requested studies are not available at this time.
|
||||||
|
Return to the{' '}
|
||||||
|
<Link className="text-primary-light" to={'/'}>
|
||||||
|
study list
|
||||||
|
</Link>{' '}
|
||||||
|
to select a different study to view.
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
NotFoundStudy.propTypes = {
|
||||||
|
message: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: Include "routes" debug route if dev build
|
// TODO: Include "routes" debug route if dev build
|
||||||
const bakedInRoutes = [
|
const bakedInRoutes = [
|
||||||
|
{
|
||||||
|
path: '/notfoundserver',
|
||||||
|
children: NotFoundServer,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/notfoundstudy',
|
||||||
|
children: NotFoundStudy,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/debug',
|
path: '/debug',
|
||||||
children: Debug,
|
children: Debug,
|
||||||
|
|||||||
16
platform/app/src/utils/isSeriesFilterUsed.ts
Normal file
16
platform/app/src/utils/isSeriesFilterUsed.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* This function is used to check if the filter is used. Its intend is to
|
||||||
|
* warn the user in case of link with a SeriesInstanceUID was called
|
||||||
|
* @param instances
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function isSeriesFilterUsed(instances, filters) {
|
||||||
|
const seriesInstanceUIDs = filters?.seriesInstanceUID;
|
||||||
|
if (!seriesInstanceUIDs) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!instances.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return seriesInstanceUIDs.includes(instances[0].SeriesInstanceUID);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user