fix(state synchronization): SEG and RT viewports should keep their before hydration voi (#3560)
This commit is contained in:
parent
4f037ae55e
commit
8adf663248
@ -36,12 +36,14 @@ const extension: Types.Extensions.Extension = {
|
|||||||
getViewportModule({
|
getViewportModule({
|
||||||
servicesManager,
|
servicesManager,
|
||||||
extensionManager,
|
extensionManager,
|
||||||
|
commandsManager,
|
||||||
}: Types.Extensions.ExtensionParams) {
|
}: Types.Extensions.ExtensionParams) {
|
||||||
const ExtendedOHIFCornerstoneRTViewport = props => {
|
const ExtendedOHIFCornerstoneRTViewport = props => {
|
||||||
return (
|
return (
|
||||||
<OHIFCornerstoneRTViewport
|
<OHIFCornerstoneRTViewport
|
||||||
servicesManager={servicesManager}
|
servicesManager={servicesManager}
|
||||||
extensionManager={extensionManager}
|
extensionManager={extensionManager}
|
||||||
|
commandsManager={commandsManager}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -12,6 +12,7 @@ function promptHydrateRT({
|
|||||||
rtDisplaySet,
|
rtDisplaySet,
|
||||||
viewportIndex,
|
viewportIndex,
|
||||||
toolGroupId = 'default',
|
toolGroupId = 'default',
|
||||||
|
preHydrateCallbacks,
|
||||||
}) {
|
}) {
|
||||||
const { uiViewportDialogService } = servicesManager.services;
|
const { uiViewportDialogService } = servicesManager.services;
|
||||||
|
|
||||||
@ -22,6 +23,10 @@ function promptHydrateRT({
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (promptResult === RESPONSE.HYDRATE_SEG) {
|
if (promptResult === RESPONSE.HYDRATE_SEG) {
|
||||||
|
preHydrateCallbacks?.forEach(callback => {
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
|
||||||
const isHydrated = await hydrateRTDisplaySet({
|
const isHydrated = await hydrateRTDisplaySet({
|
||||||
rtDisplaySet,
|
rtDisplaySet,
|
||||||
viewportIndex,
|
viewportIndex,
|
||||||
|
|||||||
@ -25,6 +25,7 @@ function OHIFCornerstoneRTViewport(props) {
|
|||||||
viewportLabel,
|
viewportLabel,
|
||||||
servicesManager,
|
servicesManager,
|
||||||
extensionManager,
|
extensionManager,
|
||||||
|
commandsManager,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -91,6 +92,14 @@ function OHIFCornerstoneRTViewport(props) {
|
|||||||
setElement(null);
|
setElement(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const storePresentationState = useCallback(() => {
|
||||||
|
viewportGrid?.viewports.forEach(({ viewportIndex }) => {
|
||||||
|
commandsManager.runCommand('storePresentation', {
|
||||||
|
viewportIndex,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, [viewportGrid]);
|
||||||
|
|
||||||
const getCornerstoneViewport = useCallback(() => {
|
const getCornerstoneViewport = useCallback(() => {
|
||||||
const { component: Component } = extensionManager.getModuleEntry(
|
const { component: Component } = extensionManager.getModuleEntry(
|
||||||
'@ohif/extension-cornerstone.viewportModule.cornerstone'
|
'@ohif/extension-cornerstone.viewportModule.cornerstone'
|
||||||
@ -155,6 +164,7 @@ function OHIFCornerstoneRTViewport(props) {
|
|||||||
servicesManager,
|
servicesManager,
|
||||||
viewportIndex,
|
viewportIndex,
|
||||||
rtDisplaySet,
|
rtDisplaySet,
|
||||||
|
preHydrateCallbacks: [storePresentationState],
|
||||||
}).then(isHydrated => {
|
}).then(isHydrated => {
|
||||||
if (isHydrated) {
|
if (isHydrated) {
|
||||||
setIsHydrated(true);
|
setIsHydrated(true);
|
||||||
@ -303,6 +313,13 @@ function OHIFCornerstoneRTViewport(props) {
|
|||||||
} = referencedDisplaySetRef.current.metadata;
|
} = referencedDisplaySetRef.current.metadata;
|
||||||
|
|
||||||
const onStatusClick = async () => {
|
const onStatusClick = async () => {
|
||||||
|
// Before hydrating a RT and make it added to all viewports in the grid
|
||||||
|
// that share the same frameOfReferenceUID, we need to store the viewport grid
|
||||||
|
// presentation state, so that we can restore it after hydrating the RT. This is
|
||||||
|
// required if the user has changed the viewport (other viewport than RT viewport)
|
||||||
|
// presentation state (w/l and invert) and then opens the RT. If we don't store
|
||||||
|
// the presentation state, the viewport will be reset to the default presentation
|
||||||
|
storePresentationState();
|
||||||
const isHydrated = await _hydrateRTDisplaySet({
|
const isHydrated = await _hydrateRTDisplaySet({
|
||||||
rtDisplaySet,
|
rtDisplaySet,
|
||||||
viewportIndex,
|
viewportIndex,
|
||||||
|
|||||||
@ -69,6 +69,7 @@ const extension = {
|
|||||||
<OHIFCornerstoneSEGViewport
|
<OHIFCornerstoneSEGViewport
|
||||||
servicesManager={servicesManager}
|
servicesManager={servicesManager}
|
||||||
extensionManager={extensionManager}
|
extensionManager={extensionManager}
|
||||||
|
commandsManager={commandsManager}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -88,4 +89,4 @@ const extension = {
|
|||||||
getHangingProtocolModule,
|
getHangingProtocolModule,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default extension;
|
export default extension;
|
||||||
|
|||||||
@ -7,7 +7,12 @@ const RESPONSE = {
|
|||||||
HYDRATE_SEG: 5,
|
HYDRATE_SEG: 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
function promptHydrateSEG({ servicesManager, segDisplaySet, viewportIndex }) {
|
function promptHydrateSEG({
|
||||||
|
servicesManager,
|
||||||
|
segDisplaySet,
|
||||||
|
viewportIndex,
|
||||||
|
preHydrateCallbacks,
|
||||||
|
}) {
|
||||||
const { uiViewportDialogService } = servicesManager.services;
|
const { uiViewportDialogService } = servicesManager.services;
|
||||||
|
|
||||||
return new Promise(async function(resolve, reject) {
|
return new Promise(async function(resolve, reject) {
|
||||||
@ -17,6 +22,10 @@ function promptHydrateSEG({ servicesManager, segDisplaySet, viewportIndex }) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (promptResult === RESPONSE.HYDRATE_SEG) {
|
if (promptResult === RESPONSE.HYDRATE_SEG) {
|
||||||
|
preHydrateCallbacks?.forEach(callback => {
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
|
||||||
const isHydrated = await hydrateSEGDisplaySet({
|
const isHydrated = await hydrateSEGDisplaySet({
|
||||||
segDisplaySet,
|
segDisplaySet,
|
||||||
viewportIndex,
|
viewportIndex,
|
||||||
|
|||||||
@ -24,6 +24,7 @@ function OHIFCornerstoneSEGViewport(props) {
|
|||||||
viewportLabel,
|
viewportLabel,
|
||||||
servicesManager,
|
servicesManager,
|
||||||
extensionManager,
|
extensionManager,
|
||||||
|
commandsManager,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const { t } = useTranslation('SEGViewport');
|
const { t } = useTranslation('SEGViewport');
|
||||||
@ -48,7 +49,6 @@ function OHIFCornerstoneSEGViewport(props) {
|
|||||||
const [viewportGrid, viewportGridService] = useViewportGrid();
|
const [viewportGrid, viewportGridService] = useViewportGrid();
|
||||||
|
|
||||||
// States
|
// States
|
||||||
const [isToolGroupCreated, setToolGroupCreated] = useState(false);
|
|
||||||
const [selectedSegment, setSelectedSegment] = useState(1);
|
const [selectedSegment, setSelectedSegment] = useState(1);
|
||||||
|
|
||||||
// Hydration means that the SEG is opened and segments are loaded into the
|
// Hydration means that the SEG is opened and segments are loaded into the
|
||||||
@ -93,6 +93,14 @@ function OHIFCornerstoneSEGViewport(props) {
|
|||||||
setElement(null);
|
setElement(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const storePresentationState = useCallback(() => {
|
||||||
|
viewportGrid?.viewports.forEach(({ viewportIndex }) => {
|
||||||
|
commandsManager.runCommand('storePresentation', {
|
||||||
|
viewportIndex,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, [viewportGrid]);
|
||||||
|
|
||||||
const getCornerstoneViewport = useCallback(() => {
|
const getCornerstoneViewport = useCallback(() => {
|
||||||
const { component: Component } = extensionManager.getModuleEntry(
|
const { component: Component } = extensionManager.getModuleEntry(
|
||||||
'@ohif/extension-cornerstone.viewportModule.cornerstone'
|
'@ohif/extension-cornerstone.viewportModule.cornerstone'
|
||||||
@ -159,6 +167,7 @@ function OHIFCornerstoneSEGViewport(props) {
|
|||||||
servicesManager,
|
servicesManager,
|
||||||
viewportIndex,
|
viewportIndex,
|
||||||
segDisplaySet,
|
segDisplaySet,
|
||||||
|
preHydrateCallbacks: [storePresentationState],
|
||||||
}).then(isHydrated => {
|
}).then(isHydrated => {
|
||||||
if (isHydrated) {
|
if (isHydrated) {
|
||||||
setIsHydrated(true);
|
setIsHydrated(true);
|
||||||
@ -248,8 +257,6 @@ function OHIFCornerstoneSEGViewport(props) {
|
|||||||
toolGroupId
|
toolGroupId
|
||||||
);
|
);
|
||||||
|
|
||||||
setToolGroupCreated(true);
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
// remove the segmentation representations if seg displayset changed
|
// remove the segmentation representations if seg displayset changed
|
||||||
segmentationService.removeSegmentationRepresentationFromToolGroup(
|
segmentationService.removeSegmentationRepresentationFromToolGroup(
|
||||||
@ -309,6 +316,13 @@ function OHIFCornerstoneSEGViewport(props) {
|
|||||||
} = referencedDisplaySetRef.current.metadata;
|
} = referencedDisplaySetRef.current.metadata;
|
||||||
|
|
||||||
const onStatusClick = async () => {
|
const onStatusClick = async () => {
|
||||||
|
// Before hydrating a SEG and make it added to all viewports in the grid
|
||||||
|
// that share the same frameOfReferenceUID, we need to store the viewport grid
|
||||||
|
// presentation state, so that we can restore it after hydrating the SEG. This is
|
||||||
|
// required if the user has changed the viewport (other viewport than SEG viewport)
|
||||||
|
// presentation state (w/l and invert) and then opens the SEG. If we don't store
|
||||||
|
// the presentation state, the viewport will be reset to the default presentation
|
||||||
|
storePresentationState();
|
||||||
const isHydrated = await hydrateSEGDisplaySet({
|
const isHydrated = await hydrateSEGDisplaySet({
|
||||||
segDisplaySet,
|
segDisplaySet,
|
||||||
viewportIndex,
|
viewportIndex,
|
||||||
|
|||||||
@ -112,6 +112,7 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
|||||||
viewportOptions,
|
viewportOptions,
|
||||||
displaySetOptions,
|
displaySetOptions,
|
||||||
servicesManager,
|
servicesManager,
|
||||||
|
commandsManager,
|
||||||
onElementEnabled,
|
onElementEnabled,
|
||||||
onElementDisabled,
|
onElementDisabled,
|
||||||
isJumpToMeasurementDisabled,
|
isJumpToMeasurementDisabled,
|
||||||
@ -152,33 +153,6 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
|||||||
}
|
}
|
||||||
}, [elementRef]);
|
}, [elementRef]);
|
||||||
|
|
||||||
const storePresentation = () => {
|
|
||||||
const currentPresentation = cornerstoneViewportService.getPresentation(
|
|
||||||
viewportIndex
|
|
||||||
);
|
|
||||||
if (!currentPresentation || !currentPresentation.presentationIds) return;
|
|
||||||
const {
|
|
||||||
lutPresentationStore,
|
|
||||||
positionPresentationStore,
|
|
||||||
} = stateSyncService.getState();
|
|
||||||
const { presentationIds } = currentPresentation;
|
|
||||||
const { lutPresentationId, positionPresentationId } = presentationIds || {};
|
|
||||||
const storeState = {};
|
|
||||||
if (lutPresentationId) {
|
|
||||||
storeState.lutPresentationStore = {
|
|
||||||
...lutPresentationStore,
|
|
||||||
[lutPresentationId]: currentPresentation,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (positionPresentationId) {
|
|
||||||
storeState.positionPresentationStore = {
|
|
||||||
...positionPresentationStore,
|
|
||||||
[positionPresentationId]: currentPresentation,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
stateSyncService.store(storeState);
|
|
||||||
};
|
|
||||||
|
|
||||||
const cleanUpServices = useCallback(() => {
|
const cleanUpServices = useCallback(() => {
|
||||||
const viewportInfo = cornerstoneViewportService.getViewportInfoByIndex(
|
const viewportInfo = cornerstoneViewportService.getViewportInfoByIndex(
|
||||||
viewportIndex
|
viewportIndex
|
||||||
@ -256,7 +230,9 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
|||||||
setImageScrollBarHeight();
|
setImageScrollBarHeight();
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
storePresentation();
|
commandsManager.runCommand('storePresentation', {
|
||||||
|
viewportIndex,
|
||||||
|
});
|
||||||
|
|
||||||
cleanUpServices();
|
cleanUpServices();
|
||||||
|
|
||||||
@ -407,8 +383,6 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
|||||||
};
|
};
|
||||||
}, [displaySets, elementRef, viewportIndex]);
|
}, [displaySets, elementRef, viewportIndex]);
|
||||||
|
|
||||||
console.debug('OHIFCornerstoneViewport rendering');
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<div className="viewport-wrapper">
|
<div className="viewport-wrapper">
|
||||||
|
|||||||
@ -28,6 +28,7 @@ function commandsModule({
|
|||||||
toolGroupService,
|
toolGroupService,
|
||||||
cineService,
|
cineService,
|
||||||
toolbarService,
|
toolbarService,
|
||||||
|
stateSyncService,
|
||||||
uiDialogService,
|
uiDialogService,
|
||||||
cornerstoneViewportService,
|
cornerstoneViewportService,
|
||||||
uiNotificationService,
|
uiNotificationService,
|
||||||
@ -616,6 +617,35 @@ function commandsModule({
|
|||||||
);
|
);
|
||||||
toolGroup.setToolEnabled(ReferenceLinesTool.toolName);
|
toolGroup.setToolEnabled(ReferenceLinesTool.toolName);
|
||||||
},
|
},
|
||||||
|
storePresentation: ({ viewportIndex }) => {
|
||||||
|
const presentation = cornerstoneViewportService.getPresentation(
|
||||||
|
viewportIndex
|
||||||
|
);
|
||||||
|
if (!presentation || !presentation.presentationIds) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const {
|
||||||
|
lutPresentationStore,
|
||||||
|
positionPresentationStore,
|
||||||
|
} = stateSyncService.getState();
|
||||||
|
const { presentationIds } = presentation;
|
||||||
|
const { lutPresentationId, positionPresentationId } =
|
||||||
|
presentationIds || {};
|
||||||
|
const storeState = {};
|
||||||
|
if (lutPresentationId) {
|
||||||
|
storeState.lutPresentationStore = {
|
||||||
|
...lutPresentationStore,
|
||||||
|
[lutPresentationId]: presentation,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (positionPresentationId) {
|
||||||
|
storeState.positionPresentationStore = {
|
||||||
|
...positionPresentationStore,
|
||||||
|
[positionPresentationId]: presentation,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
stateSyncService.store(storeState);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const definitions = {
|
const definitions = {
|
||||||
@ -740,6 +770,11 @@ function commandsModule({
|
|||||||
toggleReferenceLines: {
|
toggleReferenceLines: {
|
||||||
commandFn: actions.toggleReferenceLines,
|
commandFn: actions.toggleReferenceLines,
|
||||||
},
|
},
|
||||||
|
storePresentation: {
|
||||||
|
commandFn: actions.storePresentation,
|
||||||
|
storeContexts: [],
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -10,8 +10,14 @@ const DEFAULT = 'default';
|
|||||||
// dragged and dropped the view in twice. For example, it allows displaying
|
// dragged and dropped the view in twice. For example, it allows displaying
|
||||||
// bone, brain and soft tissue views of a single display set, and to still
|
// bone, brain and soft tissue views of a single display set, and to still
|
||||||
// remember the specific changes to each viewport.
|
// remember the specific changes to each viewport.
|
||||||
const addUniqueIndex = (arr, key, viewports) => {
|
const addUniqueIndex = (arr, key, viewports, isUpdatingSameViewport) => {
|
||||||
arr.push(0);
|
arr.push(0);
|
||||||
|
|
||||||
|
// If we are updating the viewport, we should not increment the index
|
||||||
|
if (isUpdatingSameViewport) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// The 128 is just a value that is larger than how many viewports we
|
// The 128 is just a value that is larger than how many viewports we
|
||||||
// display at once, used as an upper bound on how many unique presentation
|
// display at once, used as an upper bound on how many unique presentation
|
||||||
// ID's might exist for a single display set at once.
|
// ID's might exist for a single display set at once.
|
||||||
@ -109,8 +115,30 @@ const getPresentationIds = (viewport, viewports): PresentationIds => {
|
|||||||
lutPresentationArr.push(uid);
|
lutPresentationArr.push(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
addUniqueIndex(positionPresentationArr, 'positionPresentationId', viewports);
|
// only add unique index if the viewport is getting inserted and not updated
|
||||||
addUniqueIndex(lutPresentationArr, 'lutPresentationId', viewports);
|
const isUpdatingSameViewport = viewports.some(v => {
|
||||||
|
return (
|
||||||
|
v.displaySetInstanceUIDs.toString() ===
|
||||||
|
viewport.displaySetInstanceUIDs.toString() &&
|
||||||
|
v.viewportIndex === viewport.viewportIndex
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// if it is updating the viewport we should not increment the index since
|
||||||
|
// it might be a layer on the fusion or a SEG layer that is added on
|
||||||
|
// top of the original display set
|
||||||
|
addUniqueIndex(
|
||||||
|
positionPresentationArr,
|
||||||
|
'positionPresentationId',
|
||||||
|
viewports,
|
||||||
|
isUpdatingSameViewport
|
||||||
|
);
|
||||||
|
addUniqueIndex(
|
||||||
|
lutPresentationArr,
|
||||||
|
'lutPresentationId',
|
||||||
|
viewports,
|
||||||
|
isUpdatingSameViewport
|
||||||
|
);
|
||||||
|
|
||||||
const lutPresentationId = lutPresentationArr.join(JOIN_STR);
|
const lutPresentationId = lutPresentationArr.join(JOIN_STR);
|
||||||
const positionPresentationId = positionPresentationArr.join(JOIN_STR);
|
const positionPresentationId = positionPresentationArr.join(JOIN_STR);
|
||||||
|
|||||||
@ -10,10 +10,11 @@ After following the steps outlined in
|
|||||||
OHIF Viewer has data for several studies and their images. You didn't add this
|
OHIF Viewer has data for several studies and their images. You didn't add this
|
||||||
data, so where is it coming from?
|
data, so where is it coming from?
|
||||||
|
|
||||||
By default, the viewer is configured to connect to a remote server hosted by the
|
By default, the viewer is configured to connect to a Amazon S3 bucket that is hosting
|
||||||
nice folks over at [dcmjs.org][dcmjs-org]. While convenient for getting started,
|
a Static WADO server (see [Static WADO DICOMWeb](https://github.com/RadicalImaging/static-dicomweb)).
|
||||||
the time may come when you want to develop using your own data either locally or
|
By default we use `default.js` for the configuration file. You can change this by setting the `APP_CONFIG` environment variable
|
||||||
remotely.
|
and select other options such as `config/local_orthanc.js` or `config/google.js`.
|
||||||
|
|
||||||
|
|
||||||
## Configuration Files
|
## Configuration Files
|
||||||
|
|
||||||
@ -172,6 +173,7 @@ if auth headers are used, a preflight request is required.
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
- `showLoadingIndicator`: (default to true), if set to false, the loading indicator will not be shown when navigating between studies.
|
- `showLoadingIndicator`: (default to true), if set to false, the loading indicator will not be shown when navigating between studies.
|
||||||
|
- `supportsWildcard`: (default to false), if set to true, the datasource will support wildcard matching for patient name and patient id.
|
||||||
- `dangerouslyUseDynamicConfig`: Dynamic config allows user to pass `configUrl` query string. This allows to load config without recompiling application. If the `configUrl` query string is passed, the worklist and modes will load from the referenced json rather than the default .env config. If there is no `configUrl` path provided, the default behaviour is used and there should not be any deviation from current user experience.<br/>
|
- `dangerouslyUseDynamicConfig`: Dynamic config allows user to pass `configUrl` query string. This allows to load config without recompiling application. If the `configUrl` query string is passed, the worklist and modes will load from the referenced json rather than the default .env config. If there is no `configUrl` path provided, the default behaviour is used and there should not be any deviation from current user experience.<br/>
|
||||||
Points to consider while using `dangerouslyUseDynamicConfig`:<br/>
|
Points to consider while using `dangerouslyUseDynamicConfig`:<br/>
|
||||||
- User have to enable this feature by setting `dangerouslyUseDynamicConfig.enabled:true`. By default it is `false`.
|
- User have to enable this feature by setting `dangerouslyUseDynamicConfig.enabled:true`. By default it is `false`.
|
||||||
|
|||||||
@ -89,6 +89,16 @@ Since the platform/viewer (@ohif/viewer) is already at v4.12.51, we opted to ren
|
|||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
|
:::tip
|
||||||
|
There are various configurations available to customize the viewer. Each configuration is represented by a custom-tailored object that should be used with the viewer to work effectively with a specific server. Here are some examples of configuration files found in the platform/app/public/config directory. Some server-specific configurations that you should be aware are: `supportsWildcard`, `bulkDataURI`, `omitQuotationForMultipartRequest`, `staticWado` (Read more about them [here](./configuration/configurationFiles.md)).
|
||||||
|
|
||||||
|
- default.js: This is our default configuration designed for our main server, which uses a Static WADO datasource hosted on Amazon S3.
|
||||||
|
- local_orthanc.js: Use this configuration when working with our local Orthanc server.
|
||||||
|
- local_dcm4chee.js: This configuration is intended for our local dcm4chee server.
|
||||||
|
- netlify.js: This configuration is the same as default.js and is used for deployment on Netlify.
|
||||||
|
- google.js: Use this configuration to run the viewer against the Google Health API.
|
||||||
|
:::
|
||||||
|
|
||||||
OHIF v3 has a new configuration structure. The main difference is that the `servers` is renamed to `dataSources` and the configuration is now asynchronous. Datasources are more abstract and
|
OHIF v3 has a new configuration structure. The main difference is that the `servers` is renamed to `dataSources` and the configuration is now asynchronous. Datasources are more abstract and
|
||||||
far more capable than servers. Read more about dataSources [here](./platform/extensions/modules/data-source.md).
|
far more capable than servers. Read more about dataSources [here](./platform/extensions/modules/data-source.md).
|
||||||
|
|
||||||
@ -98,6 +108,7 @@ far more capable than servers. Read more about dataSources [here](./platform/ext
|
|||||||
- The maxConcurrentMetadataRequests property has been removed in favor of `maxNumRequests`
|
- The maxConcurrentMetadataRequests property has been removed in favor of `maxNumRequests`
|
||||||
- The hotkeys array has been updated with different command names and options, and some keys have been removed.
|
- The hotkeys array has been updated with different command names and options, and some keys have been removed.
|
||||||
- New properties have been added, including `maxNumberOfWebWorkers`, `omitQuotationForMultipartRequest`, `showWarningMessageForCrossOrigin`, `showCPUFallbackMessage`, `showLoadingIndicator`, `strictZSpacingForVolumeViewport`.
|
- New properties have been added, including `maxNumberOfWebWorkers`, `omitQuotationForMultipartRequest`, `showWarningMessageForCrossOrigin`, `showCPUFallbackMessage`, `showLoadingIndicator`, `strictZSpacingForVolumeViewport`.
|
||||||
|
- you should see if `supportsWildcard` is supported in your server, some servers don't support it and you need to make it false.
|
||||||
|
|
||||||
## Modes
|
## Modes
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import Icon from '../Icon';
|
|||||||
|
|
||||||
const ContextMenu = ({ items, ...props }) => {
|
const ContextMenu = ({ items, ...props }) => {
|
||||||
if (!items) {
|
if (!items) {
|
||||||
console.warn('No items for context menu');
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user