From 9a0911bbd88130a7e61c31c1d66d276169a93f16 Mon Sep 17 00:00:00 2001 From: Joe Boccanfuso Date: Fri, 21 Apr 2023 08:13:41 -0400 Subject: [PATCH 1/2] fix(Browser history): - fixed an NPE when navigating to a different study via the URL - exposed browser history navigation via a command --- extensions/default/src/commandsModule.ts | 14 ++++++++++++++ .../default/src/types/commandModuleTypes.tsx | 6 ++++++ .../TrackedMeasurementsContext.tsx | 4 ++++ platform/ui/package.json | 1 + platform/ui/src/index.js | 1 + platform/ui/src/utils/history.ts | 9 +++++++++ platform/viewer/src/routes/Mode/Mode.tsx | 7 +++++-- 7 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 extensions/default/src/types/commandModuleTypes.tsx create mode 100644 platform/ui/src/utils/history.ts diff --git a/extensions/default/src/commandsModule.ts b/extensions/default/src/commandsModule.ts index 73b54b5dfd..e5f0ff582e 100644 --- a/extensions/default/src/commandsModule.ts +++ b/extensions/default/src/commandsModule.ts @@ -11,6 +11,8 @@ import findViewportsByPosition, { } from './findViewportsByPosition'; import { ContextMenuProps } from './CustomizeableContextMenu/types'; +import { NavigateHistory } from './types/commandModuleTypes'; +import { history } from '@ohif/ui'; const { subscribeToNextViewportGridChange } = utils; @@ -480,6 +482,13 @@ const commandsModule = ({ } }, + /** + * Exposes the browser history navigation used by OHIF. + */ + navigateHistory(historyArgs: NavigateHistory) { + history.navigate(historyArgs.to, historyArgs.options); + }, + openDICOMTagViewer() { const { activeViewportIndex, viewports } = viewportGridService.getState(); const activeViewportSpecificData = viewports[activeViewportIndex]; @@ -540,6 +549,11 @@ const commandsModule = ({ storeContexts: [], options: {}, }, + navigateHistory: { + commandFn: actions.navigateHistory, + storeContexts: [], + options: {}, + }, nextStage: { commandFn: actions.deltaStage, storeContexts: [], diff --git a/extensions/default/src/types/commandModuleTypes.tsx b/extensions/default/src/types/commandModuleTypes.tsx new file mode 100644 index 0000000000..d2cdde1345 --- /dev/null +++ b/extensions/default/src/types/commandModuleTypes.tsx @@ -0,0 +1,6 @@ +export type NavigateHistory = { + to: string; // the URL to navigate to + options?: { + replace?: boolean; // replace or add/push to history? + }; +}; diff --git a/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/TrackedMeasurementsContext.tsx b/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/TrackedMeasurementsContext.tsx index 476e80a405..f73707220d 100644 --- a/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/TrackedMeasurementsContext.tsx +++ b/extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/TrackedMeasurementsContext.tsx @@ -149,6 +149,10 @@ function TrackedMeasurementsContextProvider( activeViewport.displaySetInstanceUIDs[0] ); + if (!displaySet) { + return; + } + // If this is an SR produced by our SR SOPClassHandler, // and it hasn't been loaded yet, do that now so we // can check if it can be rehydrated or not. diff --git a/platform/ui/package.json b/platform/ui/package.json index 68d73cd20c..99b9fb55d0 100644 --- a/platform/ui/package.json +++ b/platform/ui/package.json @@ -42,6 +42,7 @@ "react-error-boundary": "^3.1.3", "react-modal": "3.11.2", "react-outside-click-handler": "^1.3.0", + "react-router-dom": "^6.8.1", "react-select": "3.0.8", "react-with-direction": "^1.3.1", "swiper": "^8.4.2" diff --git a/platform/ui/src/index.js b/platform/ui/src/index.js index 50842160dc..78cbf8d7e2 100644 --- a/platform/ui/src/index.js +++ b/platform/ui/src/index.js @@ -112,3 +112,4 @@ export { getIcon, ICONS, addIcon } from './components/Icon/getIcon'; export { BackgroundColor } from './pages/Colors/BackgroundColor'; export { ModalComponent } from './contextProviders/ModalComponent'; export { Types }; +export { history } from './utils/history'; diff --git a/platform/ui/src/utils/history.ts b/platform/ui/src/utils/history.ts new file mode 100644 index 0000000000..57cdf7d35d --- /dev/null +++ b/platform/ui/src/utils/history.ts @@ -0,0 +1,9 @@ +import { NavigateFunction } from 'react-router'; + +type History = { + navigate: NavigateFunction; +}; + +export const history: History = { + navigate: null, +}; diff --git a/platform/viewer/src/routes/Mode/Mode.tsx b/platform/viewer/src/routes/Mode/Mode.tsx index 7b06bf4459..3b4099a9e5 100644 --- a/platform/viewer/src/routes/Mode/Mode.tsx +++ b/platform/viewer/src/routes/Mode/Mode.tsx @@ -1,9 +1,9 @@ import React, { useEffect, useState, useRef } from 'react'; -import { useParams, useLocation } from 'react-router'; +import { useParams, useLocation, useNavigate } from 'react-router'; import PropTypes from 'prop-types'; // TODO: DicomMetadataStore should be injected? import { DicomMetadataStore, ServicesManager, utils } from '@ohif/core'; -import { DragAndDropProvider, ImageViewerProvider } from '@ohif/ui'; +import { DragAndDropProvider, ImageViewerProvider, history } from '@ohif/ui'; import { useQuery, useSearchParams } from '@hooks'; import ViewportGrid from '@components/ViewportGrid'; import Compose from './Compose'; @@ -105,6 +105,9 @@ export default function ModeRoute({ const locationRef = useRef(null); const isMounted = useRef(false); + // Expose the react router dom navigation. + history.navigate = useNavigate(); + if (location !== locationRef.current) { layoutTemplateData.current = null; locationRef.current = location; From 7b284d089a7599a0a0a550ecc1f51dd5c25c8d38 Mon Sep 17 00:00:00 2001 From: Joe Boccanfuso Date: Mon, 24 Apr 2023 13:25:31 -0400 Subject: [PATCH 2/2] Added documentation for the navigateHistory command. Moved the history object from UI to viewer. --- extensions/default/src/commandsModule.ts | 19 ++++++++++-- platform/docs/docs/platform/modes/routes.md | 31 ++++++++++++++++++++ platform/ui/package.json | 1 - platform/ui/src/index.js | 1 - platform/viewer/src/index.js | 4 +++ platform/viewer/src/routes/Mode/Mode.tsx | 3 +- platform/{ui => viewer}/src/utils/history.ts | 0 7 files changed, 54 insertions(+), 5 deletions(-) rename platform/{ui => viewer}/src/utils/history.ts (100%) diff --git a/extensions/default/src/commandsModule.ts b/extensions/default/src/commandsModule.ts index e5f0ff582e..172f00921c 100644 --- a/extensions/default/src/commandsModule.ts +++ b/extensions/default/src/commandsModule.ts @@ -12,7 +12,7 @@ import findViewportsByPosition, { import { ContextMenuProps } from './CustomizeableContextMenu/types'; import { NavigateHistory } from './types/commandModuleTypes'; -import { history } from '@ohif/ui'; +import { history } from '@ohif/viewer'; const { subscribeToNextViewportGridChange } = utils; @@ -483,7 +483,22 @@ const commandsModule = ({ }, /** - * Exposes the browser history navigation used by OHIF. + * Exposes the browser history navigation used by OHIF. This command can be used to either replace or + * push a new entry into the browser history. For example, the following will replace the current + * browser history entry with the specified relative URL which changes the study displayed to the + * study with study instance UID 1.2.3. Note that as a result of using `options.replace = true`, the + * page prior to invoking this command cannot be returned to via the browser back button. + * + * navigateHistory({ + * to: 'viewer?StudyInstanceUIDs=1.2.3', + * options: { replace: true }, + * }); + * + * @param historyArgs - arguments for the history function; + * the `to` property is the URL; + * the `options.replace` is a boolean indicating if the current browser history entry + * should be replaced or a new entry pushed onto the history (stack); the default value + * for `replace` is false */ navigateHistory(historyArgs: NavigateHistory) { history.navigate(historyArgs.to, historyArgs.options); diff --git a/platform/docs/docs/platform/modes/routes.md b/platform/docs/docs/platform/modes/routes.md index 6e8647309d..36376a131f 100644 --- a/platform/docs/docs/platform/modes/routes.md +++ b/platform/docs/docs/platform/modes/routes.md @@ -313,3 +313,34 @@ function modeFactory() { }; } ``` + +> How can I navigate to (or show) a different study via the browser history/URL? + +There is a command that does this: `navigateHistory`. It takes an object +argument with the `NavigateHistory` type: + +``` +export type NavigateHistory = { + to: string; // the URL to navigate to + options?: { + replace?: boolean; // replace or add/push to history? + }; +}; +``` + +For instance one could bind a hot key to this command to show a specific study +like this... + +``` + { + commandName: 'navigateHistory', + commandOptions: { + to: + '/viewer?StudyInstanceUIDs=1.2.3', + }, + context: 'DEFAULT', + label: 'Nav Study', + keys: ['n'], + isEditable: true, + }, +``` diff --git a/platform/ui/package.json b/platform/ui/package.json index 99b9fb55d0..68d73cd20c 100644 --- a/platform/ui/package.json +++ b/platform/ui/package.json @@ -42,7 +42,6 @@ "react-error-boundary": "^3.1.3", "react-modal": "3.11.2", "react-outside-click-handler": "^1.3.0", - "react-router-dom": "^6.8.1", "react-select": "3.0.8", "react-with-direction": "^1.3.1", "swiper": "^8.4.2" diff --git a/platform/ui/src/index.js b/platform/ui/src/index.js index 78cbf8d7e2..50842160dc 100644 --- a/platform/ui/src/index.js +++ b/platform/ui/src/index.js @@ -112,4 +112,3 @@ export { getIcon, ICONS, addIcon } from './components/Icon/getIcon'; export { BackgroundColor } from './pages/Colors/BackgroundColor'; export { ModalComponent } from './contextProviders/ModalComponent'; export { Types }; -export { history } from './utils/history'; diff --git a/platform/viewer/src/index.js b/platform/viewer/src/index.js index 49f47fa79c..6cec78ad22 100644 --- a/platform/viewer/src/index.js +++ b/platform/viewer/src/index.js @@ -5,6 +5,8 @@ import 'regenerator-runtime/runtime'; import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; +import { history } from './utils/history'; + /** * EXTENSIONS AND MODES * ================= @@ -34,3 +36,5 @@ loadDynamicImports().then(() => { ReactDOM.render(app, document.getElementById('root')); }); }); + +export { history }; diff --git a/platform/viewer/src/routes/Mode/Mode.tsx b/platform/viewer/src/routes/Mode/Mode.tsx index 3b4099a9e5..7e7575bc0c 100644 --- a/platform/viewer/src/routes/Mode/Mode.tsx +++ b/platform/viewer/src/routes/Mode/Mode.tsx @@ -3,11 +3,12 @@ import { useParams, useLocation, useNavigate } from 'react-router'; import PropTypes from 'prop-types'; // TODO: DicomMetadataStore should be injected? import { DicomMetadataStore, ServicesManager, utils } from '@ohif/core'; -import { DragAndDropProvider, ImageViewerProvider, history } from '@ohif/ui'; +import { DragAndDropProvider, ImageViewerProvider } from '@ohif/ui'; import { useQuery, useSearchParams } from '@hooks'; import ViewportGrid from '@components/ViewportGrid'; import Compose from './Compose'; import getStudies from './studiesList'; +import { history } from '../../utils/history'; const { getSplitParam } = utils; diff --git a/platform/ui/src/utils/history.ts b/platform/viewer/src/utils/history.ts similarity index 100% rename from platform/ui/src/utils/history.ts rename to platform/viewer/src/utils/history.ts