diff --git a/docs/latest/advanced/extensions.md b/docs/latest/advanced/extensions.md
index 681c219d5..dc4284271 100644
--- a/docs/latest/advanced/extensions.md
+++ b/docs/latest/advanced/extensions.md
@@ -8,57 +8,121 @@ toolbar, or as complex as a new viewport capable of rendering volumes in 3D.
- [Overview](#overview)
- [Modules](#modules)
- - [Viewport](#viewport)
- - [Toolbar](#toolbar)
- - [SOP Class Handler](#sopclasshandler)
- - [Panel](#panel)
- [Commands](#commands)
- [Hotkeys](#hotkeys)
+ - [Toolbar](#toolbar)
+ - [Panel](#panel)
+ - [Viewport](#viewport)
+ - [SOP Class Handler](#sopclasshandler)
## Overview
-At a glance, an extension is a class or object that has a `getExtensionId()`
-method, and one or more "module" methods. You can find an abbreviated extension
-below, or
-[view the source](https://github.com/OHIF/Viewers/blob/react/extensions/ohif-cornerstone-extension/src/OHIFCornerstoneExtension.js#L32-L65)
-of our `cornerstone` viewport extension.
+At a glance, an extension is a javascript object that has an `id` property, and
+one or more "module" methods. You can find an abbreviated extension below, or
+[view the source][example-ext-src] of our example extension.
```js
-class myCustomExtension {
+export default {
+ /**
+ * Only required property. Should be a unique value across all extensions.
+ */
+ id: 'example-extension',
- /** Required */
- getExtensionId: () => 'my-extension-id';
+ /**
+ * Registers one or more named commands scoped to a context. Commands are
+ * the primary means for...
+ */
+ getCommandsModule() {
+ return {
+ defaultContext: 'VIEWER'
+ actions: { ... },
+ definitions: { ... }
+ }
+ },
- /** React component that receives props from ConnectLayoutManager
- * If more than one viewport module is registered, SopClassHandler
- * is used to help determine which component is used */
- getViewportModule: () => reactViewportComponent;
+ /**
+ * Allows you to provide toolbar definitions that will be merged with any
+ * existing application toolbar configuration. Used to determine which
+ * buttons should be visible when, their order, what happens when they're
+ * clicked, etc.
+ */
+ getToolbarModule() {
+ return {
+ definitions: [ ... ],
+ defaultContext: 'ACTIVE_VIEWPORT::CORNERSTONE'
+ }
+ }
- /** React component that adds buttons/behavior to the viewer Toolbar */
- getToolbarModule: () => reactToolbarComponent;
+ /**
+ * Not yet implemented
+ */
+ getPanelModule: () => null,
+
+ /**
+ * Registers a ReactComponent that should be used to render data in a
+ * Viewport. The first registered viewport is our "default viewport". If
+ * more than one viewport is registered, we use `SopClassHandlers` to
+ * determine which viewport should be used.
+ */
+ getViewportModule: () => reactViewportComponent,
/** Provides a whitelist of SOPClassUIDs the viewport is capable of rendering.
* Can modify default behavior for methods like `getDisplaySetFromSeries` */
getSopClassHandler: () => {
id: 'some-other-unique-id',
- type: PLUGIN_TYPES.SOP_CLASS_HANDLER,
- sopClassUids: ['string'],
- getDisplaySetFromSeries: (series, study, dicomWebClient, authorizationHeaders) => ...
- };
-
- // Not yet used
- getPanelModule: () => null;
+ sopClassUids: [ ... ],
+ getDisplaySetFromSeries: (series, study, dicomWebClient, authorizationHeaders) => { ... }
+ },
}
```
### Modules
-There are a few different kinds of modules. Each kind of module allows us to
-extend the viewer in a different way, and provides a consistent API for us to do
-so. You can find a full list of the
-[different types of modules `in ohif-core`](https://github.com/OHIF/ohif-core/blob/43c08a29eff3fb646a0e83a03a236ddd84f4a6e8/src/plugins.js#L1-L6).
-Information on each type of module, it's API, and how we determine when/where it
-should be used is included below:
+There are a few different module types. Each module type allows us to extend the
+viewer in a different way, and provides a consistent API for us to do so. You
+can find a full list of the different types of modules
+[`in ohif-core`][module-types]. Information on each type of module, it's API,
+and how we determine when/where it should be used is included below.
+
+> NOTE: Modifying the extensions/modules registered to the OHIF Viewer currently
+> requires us to import and pass extensions to the ExtensionManager in
+> `src/App.js`, then rebuild the application. Long-term, we intend to make it
+> possible to accomplish this without a build step.
+
+#### Commands
+
+The Commands Module allows us to register one or more commands scoped to
+specific contexts. Commands can be run by [hotkeys][#], [toolbar buttons][#],
+and any registered custom react component (like a [viewport][#] or [panel][#]).
+Here is a simple example commands module:
+
+```js
+{
+ getCommandsModule() {
+ return {
+ actions: {
+ speak: ({ viewports, words }) => {
+ console.log(viewports, words);
+ },
+ },
+ definitions: {
+ rotateViewportCW: {
+ commandFn: actions.rotateViewport,
+ storeContexts: ['viewports'],
+ options: { rotation: 90 }
+ },
+ rotateViewportCCW: {
+ commandFn: actions.rotateViewport,
+ storeContexts: ['viewports'],
+ options: { rotation: -90 },
+ context: 'ACTIVE_VIEWER::CORNERSTONE'
+ },
+ },
+ defaultContext: 'VIEWER'
+ }
+ }
+}
+```
#### Viewport
@@ -114,10 +178,6 @@ For a complete example implementation,
> The panel module is not yet in use.
-#### Commands
-
-...
-
#### Hotkeys
...
@@ -159,3 +219,12 @@ top level [`extensions/`](https://github.com/OHIF/Viewers/tree/react/extensions)
directory.
{% include "./_maintained-extensions-table.md" %}
+
+
+
+
+[example-ext-src]: https://github.com/OHIF/Viewers/blob/master/extensions/_ohif-example-extension/src/index.js)
+[module-types]: https://github.com/OHIF/ohif-core/blob/43c08a29eff3fb646a0e83a03a236ddd84f4a6e8/src/plugins.js#L1-L6
+
diff --git a/extensions/_ohif-example-extension/src/index.js b/extensions/_ohif-example-extension/src/index.js
new file mode 100644
index 000000000..2d4e65b30
--- /dev/null
+++ b/extensions/_ohif-example-extension/src/index.js
@@ -0,0 +1,69 @@
+/**
+ *
+ */
+export default {
+ /**
+ * Only required property. Should be a unique value across all extensions.
+ */
+ id: 'example-extension',
+
+ getViewportModule() {},
+ getSopClassHandlerModule() {
+ return sopClassHandlerModule;
+ },
+ getPanelModule() {},
+ getToolbarModule() {},
+ getCommandsModule(/* store */) {
+ return commandsModule;
+ },
+};
+
+/**
+ *
+ */
+const commandsModule = {
+ actions: {
+ // Store Contexts + Options
+ exampleAction: ({ viewports, param1 }) => {
+ console.log(`There are ${viewports.length} viewports`);
+ console.log(`param1's value is: ${param1}`);
+ },
+ },
+ definitions: {
+ exampleActionDef: {
+ commandFn: this.actions.exampleAction,
+ storeContexts: ['viewports'],
+ options: { param1: 'hello world' },
+ },
+ },
+};
+
+/**
+ *
+ */
+const sopClassHandlerModule = {
+ id: 'OHIFDicomHtmlSopClassHandler',
+ sopClassUids: Object.values({
+ BASIC_TEXT_SR: '1.2.840.10008.5.1.4.1.1.88.11',
+ ENHANCED_SR: '1.2.840.10008.5.1.4.1.1.88.22',
+ COMPREHENSIVE_SR: '1.2.840.10008.5.1.4.1.1.88.33',
+ PROCEDURE_LOG_STORAGE: '1.2.840.10008.5.1.4.1.1.88.40',
+ MAMMOGRAPHY_CAD_SR: '1.2.840.10008.5.1.4.1.1.88.50',
+ CHEST_CAD_SR: '1.2.840.10008.5.1.4.1.1.88.65',
+ X_RAY_RADIATION_DOSE_SR: '1.2.840.10008.5.1.4.1.1.88.67',
+ }),
+ getDisplaySetFromSeries(series, study, dicomWebClient, authorizationHeaders) {
+ const instance = series.getFirstInstance();
+
+ return {
+ plugin: 'html',
+ displaySetInstanceUid: 0, //utils.guid(),
+ wadoRoot: study.getData().wadoRoot,
+ wadoUri: instance.getData().wadouri,
+ sopInstanceUid: instance.getSOPInstanceUID(),
+ seriesInstanceUid: series.getSeriesInstanceUID(),
+ studyInstanceUid: study.getStudyInstanceUID(),
+ authorizationHeaders,
+ };
+ },
+};
diff --git a/extensions/ohif-cornerstone-extension/.prettierrc b/extensions/ohif-cornerstone-extension/.prettierrc
index 92cde390a..12348ec6a 100644
--- a/extensions/ohif-cornerstone-extension/.prettierrc
+++ b/extensions/ohif-cornerstone-extension/.prettierrc
@@ -1,3 +1,9 @@
{
- "singleQuote": true
-}
\ No newline at end of file
+ "trailingComma": "es5",
+ "printWidth": 80,
+ "proseWrap": "always",
+ "tabWidth": 2,
+ "semi": true,
+ "singleQuote": true,
+ "endOfLine": "lf"
+}
diff --git a/extensions/ohif-cornerstone-extension/README.md b/extensions/ohif-cornerstone-extension/README.md
index 199da64ca..cc3d8c10c 100644
--- a/extensions/ohif-cornerstone-extension/README.md
+++ b/extensions/ohif-cornerstone-extension/README.md
@@ -1,54 +1,89 @@
# @ohif/extension-cornerstone
-## Commands
+
-This extensions includes the following `Commands` and `Command Definitions`. These can be registered with `@ohif/core`'s `CommandManager`. After registering the commands, they can be bound to `hotkeys` using the `HotkeysManager` and listed in the `UserPreferences` modal.
+This extension adds support for viewing and manipulating 2D medical images via a
+viewport. The underlying implementation wraps the
+`cornerstonejs/react-cornerstone-viewport`, and provides basic commands and
+toolbar buttons for common actions.
-You can read more about [`Commands`](), [`Hotkeys`](), and the [`UserPreferences` Modal]() in their respective locations in the OHIF Viewer's documentation.
+
-| Command Name | Description | Store Contexts |
-| ---------------------------- | ----------- | -------------- |
-| `rotateViewportCW` | | viewports |
-| `rotateViewportCCW` | | viewports |
-| `invertViewport` | | viewports |
-| `flipViewportVertical` | | viewports |
-| `flipViewportHorizontal` | | viewports |
-| `scaleUpViewport` | | viewports |
-| `scaleDownViewport` | | viewports |
-| `fitViewportToWindow` | | viewports |
-| `resetViewport` | | viewports |
-| clearAnnotations | TODO | |
-| next/previous Image | TODO | |
-| first/last Image | TODO | |
-| `nextViewportDisplaySet` | | none |
-| `previousViewportDisplaySet` | | none |
+#### Index
-### TODO:
+Extension Id: `cornerstone`
-_SET TOOL_
+- [Commands Module](#commands-module)
+- [Toolbar Module](#toolbar-module)
+- [Viewport Module](#viewport-module)
-- [] Default Tool
-- [] Set Zoom Tool
-- [] Set WWWC Tool
-- [] Set Pan Tool
-- [] Set Angle Measurement Tool
-- [] Set Stack Scroll Tool
-- [] Set Magnify Tool
-- [] Set Length Tool
-- [] Set Annotate Tool
-- [] Set Pixel Probe Tool
-- [] Set Elliptical ROI Tool
-- [] Set Rectangle ROI Tool
+## Commands Module
-_OTHER_
+This extensions includes the following `Commands` and `Command Definitions`.
+These can be registered with `@ohif/core`'s `CommandManager`. After registering
+the commands, they can be bound to `hotkeys` using the `HotkeysManager` and
+listed in the `UserPreferences` modal.
-- Show/Hide CINE
-- W/L Presets
-- W/L Presets config
+You can read more about [`Commands`][docs-commands], [`Hotkeys`][docs-hotkeys],
+and the [`UserPreferences` Modal][docs-userprefs] in their respective locations
+in the OHIF Viewer's documentation.
+
+| Command Name | Description | Store Contexts |
+| ---------------------------- | --------------------------------------- | -------------- |
+| `rotateViewportCW` | | viewports |
+| `rotateViewportCCW` | | viewports |
+| `invertViewport` | | viewports |
+| `flipViewportVertical` | | viewports |
+| `flipViewportHorizontal` | | viewports |
+| `scaleUpViewport` | | viewports |
+| `scaleDownViewport` | | viewports |
+| `fitViewportToWindow` | | viewports |
+| `resetViewport` | | viewports |
+| clearAnnotations | TODO | |
+| next/previous Image | TODO | |
+| first/last Image | TODO | |
+| `nextViewportDisplaySet` | | |
+| `previousViewportDisplaySet` | | |
+| `setToolActive` | Activates tool for primary button/touch | |
+
+## Toolbar Module
+
+Our toolbar module contains definitions for:
+
+- `StackScroll`
+- `Zoom`
+- `Wwwc`
+- `Pan`
+- `Length`
+- `Angle`
+- `Reset`
+- `Cine`
+
+All use the `ACTIVE_VIEWPORT::CORNERSTONE` context.
+
+## Viewport Module
+
+Our Viewport wraps [cornerstonejs/react-cornerstone-viewport][react-viewport]
+and is connected the redux store. This module is the most prone to change as we
+hammer out our Viewport interface.
+
+## Resources
+
+### Repositories
+
+- [cornerstonejs/react-cornerstone-viewport][react-viewport]
+- [cornerstonejs/cornerstoneTools][cornerstone-tools]
+- [cornerstonejs/cornerstone][cornerstone]
+[docs-commands]: https://www.com
+[docs-hotkeys]: https://www.com
+[docs-userprefs]: htt
+[react-viewport]: https://github.com/cornerstonejs/react-cornerstone-viewport
+[cornerstone-tools]: https://github.com/cornerstonejs/cornerstoneTools
+[cornerstone]: https://github.com/cornerstonejs/cornerstone
diff --git a/extensions/ohif-cornerstone-extension/package.json b/extensions/ohif-cornerstone-extension/package.json
index c784b3546..05199b5a3 100644
--- a/extensions/ohif-cornerstone-extension/package.json
+++ b/extensions/ohif-cornerstone-extension/package.json
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-cornerstone",
- "version": "0.0.36",
+ "version": "0.0.37",
"description": "OHIF extension for Cornerstone",
"author": "OHIF",
"license": "MIT",
@@ -26,7 +26,7 @@
"dcmjs": "^0.3.8",
"dicom-parser": "^1.8.3",
"hammerjs": "^2.0.8",
- "ohif-core": "^0.3.5",
+ "ohif-core": "^0.6.0",
"prop-types": "^15.6.2",
"react": "^15.0.0 || ^16.0.0",
"react-dom": "^15.0.0 || ^16.0.0",
diff --git a/extensions/ohif-cornerstone-extension/src/ConnectedCornerstoneViewport.js b/extensions/ohif-cornerstone-extension/src/ConnectedCornerstoneViewport.js
index 3188723f4..c92f5e3ee 100644
--- a/extensions/ohif-cornerstone-extension/src/ConnectedCornerstoneViewport.js
+++ b/extensions/ohif-cornerstone-extension/src/ConnectedCornerstoneViewport.js
@@ -1,16 +1,11 @@
-import { connect } from 'react-redux';
import CornerstoneViewport from 'react-cornerstone-viewport';
import OHIF from 'ohif-core';
+import { connect } from 'react-redux';
import throttle from 'lodash.throttle';
-const {
- setViewportActive,
- setViewportSpecificData,
- clearViewportSpecificData
-} = OHIF.redux.actions;
+const { setViewportActive, setViewportSpecificData } = OHIF.redux.actions;
const mapStateToProps = (state, ownProps) => {
- const activeButton = state.tools.buttons.find(tool => tool.active === true);
let dataFromStore;
if (state.extensions && state.extensions.cornerstone) {
@@ -26,12 +21,14 @@ const mapStateToProps = (state, ownProps) => {
return {
layout: state.viewports.layout,
isActive,
- activeTool: activeButton && activeButton.command,
+ // TODO: Need a cleaner and more versatile way.
+ // Currently justing using escape hatch + commands
+ // activeTool: activeButton && activeButton.command,
...dataFromStore,
enableStackPrefetch: isActive,
//stack: viewportSpecificData.stack,
cineToolData: viewportSpecificData.cine,
- viewport: viewportSpecificData.viewport
+ viewport: viewportSpecificData.viewport,
};
};
@@ -57,7 +54,9 @@ const mapDispatchToProps = (dispatch, ownProps) => {
const enabledElement = event.detail.element;
dispatch(
setViewportSpecificData(viewportIndex, {
- dom: enabledElement
+ // TODO: Hack to make sure our plugin info is available from the outset
+ plugin: 'cornerstone',
+ dom: enabledElement,
})
);
},
@@ -66,18 +65,18 @@ const mapDispatchToProps = (dispatch, ownProps) => {
const {
onAdded,
onRemoved,
- onModified
+ onModified,
} = OHIF.measurements.MeasurementHandlers;
const actions = {
added: onAdded,
removed: onRemoved,
modified: throttle(event => {
return onModified(event);
- }, 300)
+ }, 300),
};
return actions[action](event);
- }
+ },
};
};
diff --git a/extensions/ohif-cornerstone-extension/src/ConnectedToolbarSection.js b/extensions/ohif-cornerstone-extension/src/ConnectedToolbarSection.js
deleted file mode 100644
index 0f388535f..000000000
--- a/extensions/ohif-cornerstone-extension/src/ConnectedToolbarSection.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import { connect } from 'react-redux';
-import { ToolbarSection } from 'react-viewerbase';
-import OHIF from 'ohif-core'
-
-const { setToolActive } = OHIF.redux.actions;
-
-const mapStateToProps = state => {
- const activeButton = state.tools.buttons.find(tool => tool.active === true);
-
- return {
- buttons: state.tools.buttons,
- activeCommand: activeButton && activeButton.command
- };
-};
-
-const mapDispatchToProps = dispatch => {
- return {
- setToolActive: tool => {
- dispatch(setToolActive(tool.command))
- }
- };
-};
-
-const ConnectedToolbarSection = connect(
- mapStateToProps,
- mapDispatchToProps
-)(ToolbarSection);
-
-export default ConnectedToolbarSection;
diff --git a/extensions/ohif-cornerstone-extension/src/OHIFCornerstoneExtension.js b/extensions/ohif-cornerstone-extension/src/OHIFCornerstoneExtension.js
deleted file mode 100644
index abf239939..000000000
--- a/extensions/ohif-cornerstone-extension/src/OHIFCornerstoneExtension.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import React, { Component } from 'react';
-import OHIFCornerstoneViewport from './OHIFCornerstoneViewport.js';
-import ToolbarModule from './ToolbarModule.js';
-
-/**
- * Pass in 'children' to a React component. The purpose of this is to
- * allow end users of this extension to pass in components which will
- * be rendered on top of the base components.
- *
- * @param WrappedComponent
- * @param children
- * @return {function(*): *}
- */
-function componentWithProps(WrappedComponent, children, customProps) {
- return function(props) {
- const extraProps = {
- customProps
- };
- if (children.viewport) {
- extraProps.children = children.viewport;
- }
-
- const mergedProps = Object.assign({}, props, extraProps);
-
- return ;
- };
-}
-
-// Note: If you are authoring extensions which use stateful libraries (e.g. cornerstone-core, react-redux) as peerDependencies and are also duplicated at the application level, try using 'yalc' to link it to the application, rather than yarn link. This can help fix 'module not found' issues.
-// https://github.com/whitecolor/yalc
-
-export default class OHIFCornerstoneExtension {
- constructor(props) {
- const { children = {}, customProps = {} } = props;
- this.children = children;
- this.customProps = customProps;
- }
-
- /**
- * Extension ID is a unique id, might be used for namespacing extension specific redux actions/reducers (?)
- */
- getExtensionId() {
- return 'cornerstone';
- }
-
- getViewportModule() {
- return componentWithProps(
- OHIFCornerstoneViewport,
- this.children,
- this.customProps
- );
- }
-
- getSopClassHandler() {
- return null;
- }
-
- getPanelModule() {
- return null;
- }
-
- getToolbarModule() {
- return ToolbarModule;
- }
-}
diff --git a/extensions/ohif-cornerstone-extension/src/OHIFCornerstoneViewport.js b/extensions/ohif-cornerstone-extension/src/OHIFCornerstoneViewport.js
index d23129a81..1c1e1d789 100644
--- a/extensions/ohif-cornerstone-extension/src/OHIFCornerstoneViewport.js
+++ b/extensions/ohif-cornerstone-extension/src/OHIFCornerstoneViewport.js
@@ -1,9 +1,11 @@
-import React, { Component } from 'react';
-import PropTypes from 'prop-types';
-import OHIF from 'ohif-core';
-import ConnectedCornerstoneViewport from './ConnectedCornerstoneViewport';
-import cornerstone from 'cornerstone-core';
import './config';
+
+import React, { Component } from 'react';
+
+import ConnectedCornerstoneViewport from './ConnectedCornerstoneViewport';
+import OHIF from 'ohif-core';
+import PropTypes from 'prop-types';
+import cornerstone from 'cornerstone-core';
import handleSegmentationStorage from './handleSegmentationStorage.js';
const { StackManager } = OHIF.utils;
@@ -76,11 +78,11 @@ class OHIFCornerstoneViewport extends Component {
}
if (!studyInstanceUid) {
- throw new Error('StudyInstanceUID not provided.')
+ throw new Error('StudyInstanceUID not provided.');
}
if (!displaySetInstanceUid) {
- throw new Error('StudyInstanceUID not provided.')
+ throw new Error('StudyInstanceUID not provided.');
}
// Create shortcut to displaySet
@@ -123,7 +125,9 @@ class OHIFCornerstoneViewport extends Component {
if (index > -1) {
stack.currentImageIdIndex = index;
} else {
- console.warn('SOPInstanceUID provided was not found in specified DisplaySet');
+ console.warn(
+ 'SOPInstanceUID provided was not found in specified DisplaySet'
+ );
}
}
diff --git a/extensions/ohif-cornerstone-extension/src/ToolbarModule.js b/extensions/ohif-cornerstone-extension/src/ToolbarModule.js
deleted file mode 100644
index ddb5ea30a..000000000
--- a/extensions/ohif-cornerstone-extension/src/ToolbarModule.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import React, { Component } from 'react';
-
-import ConnectedCineDialog from './ConnectedCineDialog';
-import ConnectedToolbarSection from './ConnectedToolbarSection';
-import { ToolbarButton } from 'react-viewerbase';
-
-class ToolbarModule extends Component {
- state = {
- cineDialogOpen: false
- };
-
- onClickCineToolbarButton = () => {
- this.setState({
- cineDialogOpen: !this.state.cineDialogOpen
- });
- };
-
- render() {
- const cineDialogContainerStyle = {
- display: this.state.cineDialogOpen ? 'block' : 'none',
- position: 'absolute',
- top: '82px',
- zIndex: 999
- };
-
- return (
-
- );
- }
-}
-
-export default ToolbarModule;
diff --git a/src/appCommands/cornerstone.js b/extensions/ohif-cornerstone-extension/src/commandsModule.js
similarity index 87%
rename from src/appCommands/cornerstone.js
rename to extensions/ohif-cornerstone-extension/src/commandsModule.js
index 110dda402..d87569456 100644
--- a/src/appCommands/cornerstone.js
+++ b/extensions/ohif-cornerstone-extension/src/commandsModule.js
@@ -1,8 +1,5 @@
import cornerstone from 'cornerstone-core';
-import { redux } from 'ohif-core';
-import store from './../store/';
-
-const { setToolActive } = redux.actions;
+import cornerstoneTools from 'cornerstone-tools';
const actions = {
rotateViewport: ({ viewports, rotation }) => {
@@ -80,12 +77,13 @@ const actions = {
cornerstone.setViewport(enabledElement, viewport);
}
},
- // This has a weird hard dependency on the tools that are available as toolbar
- // buttons. You can see this in `ohif-core/src/redux/reducers/tools.js`
- // the `toolName` needs to equal the button's `command` property.
- // NOTE: It would be nice if `hotkeys` could set this, instead of creating a command per tool
- setCornerstoneToolActive: ({ toolName }) => {
- store.dispatch(setToolActive(toolName));
+ // TODO: this is receiving `evt` from `ToolbarRow`. We could use it to have
+ // better mouseButtonMask sets.
+ setToolActive: ({ toolName }) => {
+ if (!toolName) {
+ console.warn('No toolname provided to setToolActive command');
+ }
+ cornerstoneTools.setToolActive(toolName, { mouseButtonMask: 1 });
},
updateViewportDisplaySet: ({ direction }) => {
// TODO
@@ -130,13 +128,11 @@ const definitions = {
options: {},
},
scaleUpViewport: {
- keys: '',
commandFn: actions.scaleViewport,
storeContexts: ['viewports'],
options: { direction: 1 },
},
scaleDownViewport: {
- keys: '',
commandFn: actions.scaleViewport,
storeContexts: ['viewports'],
options: { direction: -1 },
@@ -166,10 +162,10 @@ const definitions = {
options: { direction: -1 },
},
// TOOLS
- setZoomTool: {
- commandFn: actions.setCornerstoneToolActive,
+ setToolActive: {
+ commandFn: actions.setToolActive,
storeContexts: [],
- options: { toolName: 'Zoom' },
+ options: {},
},
};
@@ -182,4 +178,8 @@ function _getActiveViewportEnabledElement(viewports, activeIndex) {
return activeViewport.dom;
}
-export default definitions;
+export default {
+ actions,
+ definitions,
+ defaultContext: 'ACTIVE_VIEWPORT::CORNERSTONE',
+};
diff --git a/extensions/ohif-cornerstone-extension/src/config.js b/extensions/ohif-cornerstone-extension/src/config.js
index 4127c0901..b8f75e7bf 100644
--- a/extensions/ohif-cornerstone-extension/src/config.js
+++ b/extensions/ohif-cornerstone-extension/src/config.js
@@ -1,7 +1,7 @@
+import Hammer from 'hammerjs';
import cornerstone from 'cornerstone-core';
import cornerstoneMath from 'cornerstone-math';
import cornerstoneTools from 'cornerstone-tools';
-import Hammer from 'hammerjs';
// For debugging
window.cornerstoneTools = cornerstoneTools;
@@ -17,12 +17,9 @@ const fontFamily =
'Roboto, OpenSans, HelveticaNeue-Light, Helvetica Neue Light, Helvetica Neue, Helvetica, Arial, Lucida Grande, sans-serif';
cornerstoneTools.textStyle.setFont(`16px ${fontFamily}`);
-// Set the tool width
+// Tool styles/colors
cornerstoneTools.toolStyle.setToolWidth(2);
-// Set color for inactive tools
cornerstoneTools.toolColors.setToolColor('rgb(255, 255, 0)');
-
-// Set color for active tools
cornerstoneTools.toolColors.setActiveColor('rgb(0, 255, 0)');
cornerstoneTools.store.state.touchProximity = 40;
diff --git a/extensions/ohif-cornerstone-extension/src/handleSegmentationStorage.js b/extensions/ohif-cornerstone-extension/src/handleSegmentationStorage.js
index c6de26091..a65d667d4 100644
--- a/extensions/ohif-cornerstone-extension/src/handleSegmentationStorage.js
+++ b/extensions/ohif-cornerstone-extension/src/handleSegmentationStorage.js
@@ -1,7 +1,8 @@
+import * as dcmjs from 'dcmjs';
+
import OHIF from 'ohif-core';
import cornerstone from 'cornerstone-core';
import cornerstoneTools from 'cornerstone-tools';
-import * as dcmjs from 'dcmjs';
const { StackManager } = OHIF.utils;
@@ -27,28 +28,6 @@ function getDisplaySetsBySeries(studies, studyInstanceUid, seriesInstanceUid) {
});
}
-function getCornerstoneStack(studies, studyInstanceUid, displaySetInstanceUid) {
- const study = studies.find(
- study => study.studyInstanceUid === studyInstanceUid
- );
-
- // Create shortcut to displaySet
- const displaySet = getDisplaySet(
- studies,
- studyInstanceUid,
- displaySetInstanceUid
- );
-
- // Get stack from Stack Manager
- const stack = StackManager.findOrCreateStack(study, displaySet);
-
- // Clone the stack here so we don't mutate it later
- const stackClone = Object.assign({}, stack);
- stackClone.currentImageIdIndex = 0;
-
- return stackClone;
-}
-
function parseSeg(arrayBuffer, imageIds) {
return dcmjs.adapters.Cornerstone.Segmentation.generateToolState(
imageIds,
@@ -77,7 +56,7 @@ function retrieveDicomData(wadoUri) {
// TODO: Authorization header depends on the server. If we ever have multiple servers
// we will need to figure out how / when to pass this information in.
return fetch(wadoUri, {
- headers: OHIF.DICOMWeb.getAuthorizationHeader()
+ headers: OHIF.DICOMWeb.getAuthorizationHeader(),
}).then(response => response.arrayBuffer());
}
@@ -144,7 +123,7 @@ async function handleSegmentationStorage(
return {
studyInstanceUid,
displaySetInstanceUid,
- stack
+ stack,
};
}
diff --git a/extensions/ohif-cornerstone-extension/src/index.js b/extensions/ohif-cornerstone-extension/src/index.js
index 9205d285a..b148fa2e7 100644
--- a/extensions/ohif-cornerstone-extension/src/index.js
+++ b/extensions/ohif-cornerstone-extension/src/index.js
@@ -1,3 +1,23 @@
-import OHIFCornerstoneExtension from './OHIFCornerstoneExtension.js';
+import OHIFCornerstoneViewport from './OHIFCornerstoneViewport.js';
+import commandsModule from './commandsModule.js';
+import toolbarModule from './toolbarModule.js';
-export default OHIFCornerstoneExtension;
+/**
+ *
+ */
+export default {
+ /**
+ * Only required property. Should be a unique value across all extensions.
+ */
+ id: 'cornerstone',
+
+ getViewportModule() {
+ return OHIFCornerstoneViewport;
+ },
+ getToolbarModule() {
+ return toolbarModule;
+ },
+ getCommandsModule() {
+ return commandsModule;
+ },
+};
diff --git a/extensions/ohif-cornerstone-extension/src/toolbarModule.js b/extensions/ohif-cornerstone-extension/src/toolbarModule.js
new file mode 100644
index 000000000..3fd206ade
--- /dev/null
+++ b/extensions/ohif-cornerstone-extension/src/toolbarModule.js
@@ -0,0 +1,106 @@
+// TODO: A way to add Icons that don't already exist?
+// - Register them and add
+// - Include SVG Source/Inline?
+// - By URL, or own component?
+
+// TODO: `ohif-core` toolbar builder?
+
+// What KINDS of toolbar buttons do we have...
+// - One's that dispatch commands
+// - One's that set tool's active
+// - More custom, like CINE
+// - Built in for one's like this, or custom components?
+
+// Visible?
+// Disabled?
+// Based on contexts or misc. criteria?
+// -- ACTIVE_ROUTE::VIEWER
+// -- ACTIVE_VIEWPORT::CORNERSTONE
+// setToolActive commands should receive the button event that triggered
+// so we can do the "bind to this butyon" magic
+
+const TOOLBAR_BUTTON_TYPES = {
+ COMMAND: 'command',
+ SET_TOOL_ACTIVE: 'setToolActive',
+ BUILT_IN: 'builtIn',
+};
+
+const definitions = [
+ {
+ id: 'StackScroll',
+ label: 'Stack Scroll',
+ icon: 'bars',
+ //
+ type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
+ commandName: 'setToolActive',
+ commandOptions: { toolName: 'StackScroll' },
+ },
+ {
+ id: 'Zoom',
+ label: 'Zoom',
+ icon: 'search-plus',
+ //
+ type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
+ commandName: 'setToolActive',
+ commandOptions: { toolName: 'Zoom' },
+ },
+ {
+ id: 'Wwwc',
+ label: 'Levels',
+ icon: 'level',
+ //
+ type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
+ commandName: 'setToolActive',
+ commandOptions: { toolName: 'Wwwc' },
+ },
+ {
+ id: 'Pan',
+ label: 'Pan',
+ icon: 'arrows',
+ //
+ type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
+ commandName: 'setToolActive',
+ commandOptions: { toolName: 'Pan' },
+ },
+ {
+ id: 'Length',
+ label: 'Length',
+ icon: 'measure-temp',
+ //
+ type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
+ commandName: 'setToolActive',
+ commandOptions: { toolName: 'Length' },
+ },
+ {
+ id: 'Angle',
+ label: 'Angle',
+ icon: 'angle-left',
+ //
+ type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
+ commandName: 'setToolActive',
+ commandOptions: { toolName: 'Angle' },
+ },
+ {
+ id: 'Reset',
+ label: 'Reset',
+ icon: 'reset',
+ //
+ type: TOOLBAR_BUTTON_TYPES.COMMAND,
+ commandName: 'resetViewport',
+ },
+ {
+ id: 'Cine',
+ label: 'CINE',
+ icon: 'youtube',
+ //
+ type: TOOLBAR_BUTTON_TYPES.BUILT_IN,
+ options: {
+ behavior: 'CINE',
+ },
+ },
+];
+
+export default {
+ definitions,
+ defaultContext: 'ACTIVE_VIEWPORT::CORNERSTONE',
+};
diff --git a/extensions/ohif-dicom-html-extension/.prettierrc b/extensions/ohif-dicom-html-extension/.prettierrc
index 92cde390a..12348ec6a 100644
--- a/extensions/ohif-dicom-html-extension/.prettierrc
+++ b/extensions/ohif-dicom-html-extension/.prettierrc
@@ -1,3 +1,9 @@
{
- "singleQuote": true
-}
\ No newline at end of file
+ "trailingComma": "es5",
+ "printWidth": 80,
+ "proseWrap": "always",
+ "tabWidth": 2,
+ "semi": true,
+ "singleQuote": true,
+ "endOfLine": "lf"
+}
diff --git a/extensions/ohif-dicom-html-extension/package.json b/extensions/ohif-dicom-html-extension/package.json
index 38681a2c6..723f51b59 100644
--- a/extensions/ohif-dicom-html-extension/package.json
+++ b/extensions/ohif-dicom-html-extension/package.json
@@ -1,6 +1,6 @@
{
- "name": "ohif-dicom-html-extension",
- "version": "0.0.2",
+ "name": "@ohif/extension-dicom-html",
+ "version": "0.0.3",
"description": "OHIF extension for rendering structured reports to HTML",
"author": "OHIF",
"license": "MIT",
@@ -20,11 +20,14 @@
},
"peerDependencies": {
"dcmjs": "^0.3.3",
- "ohif-core": "^0.2.6",
+ "ohif-core": "^0.6.0",
"prop-types": "^15.6.2",
"react": "^15.0.0 || ^16.0.0",
"react-dom": "^15.0.0 || ^16.0.0"
},
+ "dependencies": {
+ "@babel/runtime": "^7.2.0"
+ },
"devDependencies": {
"@babel/core": "^7.2.2",
"@babel/plugin-external-helpers": "^7.2.0",
@@ -80,7 +83,7 @@
"files": [
"dist"
],
- "dependencies": {
- "@babel/runtime": "^7.2.0"
+ "publishConfig": {
+ "access": "public"
}
}
diff --git a/extensions/ohif-dicom-html-extension/src/OHIFDicomHtmlExtension.js b/extensions/ohif-dicom-html-extension/src/OHIFDicomHtmlExtension.js
deleted file mode 100644
index b661aebf2..000000000
--- a/extensions/ohif-dicom-html-extension/src/OHIFDicomHtmlExtension.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import OHIFDicomHtmlViewport from './OHIFDicomHtmlViewport.js';
-import OHIFDicomHtmlSopClassHandler from './OHIFDicomHtmlSopClassHandler.js';
-
-export default class OHIFDicomHtmlExtension {
- /**
- * Extension ID is a unique id, might be used for namespacing extension specific redux actions/reducers (?)
- */
- getExtensionId() {
- return 'html';
- }
-
- getViewportModule() {
- return OHIFDicomHtmlViewport;
- }
-
- getSopClassHandler() {
- return OHIFDicomHtmlSopClassHandler;
- }
-
- getPanelModuleDefinition() {
- return null;
- }
-
- getToolbarModuleDefinition() {
- return null;
- }
-}
diff --git a/extensions/ohif-dicom-html-extension/src/OHIFDicomHtmlSopClassHandler.js b/extensions/ohif-dicom-html-extension/src/OHIFDicomHtmlSopClassHandler.js
index caef91682..7423da779 100644
--- a/extensions/ohif-dicom-html-extension/src/OHIFDicomHtmlSopClassHandler.js
+++ b/extensions/ohif-dicom-html-extension/src/OHIFDicomHtmlSopClassHandler.js
@@ -1,7 +1,4 @@
-import OHIF from 'ohif-core';
-
-const { plugins, utils } = OHIF;
-const { PLUGIN_TYPES } = plugins;
+import { MODULE_TYPES, utils } from 'ohif-core';
// TODO: Should probably use dcmjs for this
const SOP_CLASS_UIDS = {
@@ -20,7 +17,7 @@ const sopClassUids = Object.values(SOP_CLASS_UIDS);
// same SOP Class
const OHIFDicomHtmlSopClassHandler = {
id: 'OHIFDicomHtmlSopClassHandler',
- type: PLUGIN_TYPES.SOP_CLASS_HANDLER,
+ type: MODULE_TYPES.SOP_CLASS_HANDLER,
sopClassUids,
getDisplaySetFromSeries(series, study, dicomWebClient, authorizationHeaders) {
const instance = series.getFirstInstance();
diff --git a/extensions/ohif-dicom-html-extension/src/index.js b/extensions/ohif-dicom-html-extension/src/index.js
index 6a940f7b1..c49488f4c 100644
--- a/extensions/ohif-dicom-html-extension/src/index.js
+++ b/extensions/ohif-dicom-html-extension/src/index.js
@@ -1,3 +1,16 @@
-import OHIFDicomHtmlExtension from './OHIFDicomHtmlExtension.js';
+import OHIFDicomHtmlSopClassHandler from './OHIFDicomHtmlSopClassHandler.js';
+import OHIFDicomHtmlViewport from './OHIFDicomHtmlViewport.js';
-export default OHIFDicomHtmlExtension;
+export default {
+ /**
+ * Only required property. Should be a unique value across all extensions.
+ */
+ id: 'html',
+
+ getViewportModule() {
+ return OHIFDicomHtmlViewport;
+ },
+ getSopClassHandlerModule() {
+ return OHIFDicomHtmlSopClassHandler;
+ }
+};
diff --git a/extensions/ohif-dicom-microscopy-extension/.prettierrc b/extensions/ohif-dicom-microscopy-extension/.prettierrc
index 92cde390a..12348ec6a 100644
--- a/extensions/ohif-dicom-microscopy-extension/.prettierrc
+++ b/extensions/ohif-dicom-microscopy-extension/.prettierrc
@@ -1,3 +1,9 @@
{
- "singleQuote": true
-}
\ No newline at end of file
+ "trailingComma": "es5",
+ "printWidth": 80,
+ "proseWrap": "always",
+ "tabWidth": 2,
+ "semi": true,
+ "singleQuote": true,
+ "endOfLine": "lf"
+}
diff --git a/extensions/ohif-dicom-microscopy-extension/README.md b/extensions/ohif-dicom-microscopy-extension/README.md
new file mode 100644
index 000000000..2254292fa
--- /dev/null
+++ b/extensions/ohif-dicom-microscopy-extension/README.md
@@ -0,0 +1,34 @@
+# @ohif/extension-dicom-microscopy
+
+
+
+
+
+#### Index
+
+Extension Id: `microscopy`
+
+- [SopClassHandler Module](#sopclasshandler-module)
+- [Viewport Module](#viewport-module)
+
+## SopClassHandler Module
+
+..
+
+## Viewport Module
+
+...
+
+## Resources
+
+### Repositories
+
+...
+
+
+
+
+
+
diff --git a/extensions/ohif-dicom-microscopy-extension/package.json b/extensions/ohif-dicom-microscopy-extension/package.json
index 4bd6beb86..dc472ec59 100644
--- a/extensions/ohif-dicom-microscopy-extension/package.json
+++ b/extensions/ohif-dicom-microscopy-extension/package.json
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-dicom-microscopy",
- "version": "0.0.6",
+ "version": "0.0.7",
"description": "OHIF extension for Dicom Microscopy",
"author": "OHIF",
"license": "MIT",
@@ -21,7 +21,7 @@
"peerDependencies": {
"react": "^15.0.0 || ^16.0.0",
"react-dom": "^15.0.0 || ^16.0.0",
- "ohif-core": "^0.4.0"
+ "ohif-core": "^0.6.0"
},
"devDependencies": {
"@babel/core": "^7.2.2",
diff --git a/extensions/ohif-dicom-microscopy-extension/src/DicomMicroscopySopClassHandler.js b/extensions/ohif-dicom-microscopy-extension/src/DicomMicroscopySopClassHandler.js
index cbcab71c1..9196032a3 100644
--- a/extensions/ohif-dicom-microscopy-extension/src/DicomMicroscopySopClassHandler.js
+++ b/extensions/ohif-dicom-microscopy-extension/src/DicomMicroscopySopClassHandler.js
@@ -3,7 +3,7 @@ import OHIF from 'ohif-core';
const { utils } = OHIF;
const SOP_CLASS_UIDS = {
- VL_WHOLE_SLIDE_MICROSCOPY_IMAGE_STORAGE: '1.2.840.10008.5.1.4.1.1.77.1.6'
+ VL_WHOLE_SLIDE_MICROSCOPY_IMAGE_STORAGE: '1.2.840.10008.5.1.4.1.1.77.1.6',
};
const DicomMicroscopySopClassHandler = {
@@ -20,9 +20,9 @@ const DicomMicroscopySopClassHandler = {
dicomWebClient,
sopInstanceUid: instance.getSOPInstanceUID(),
seriesInstanceUid: series.getSeriesInstanceUID(),
- studyInstanceUid: study.getStudyInstanceUID()
+ studyInstanceUid: study.getStudyInstanceUID(),
};
- }
+ },
};
export default DicomMicroscopySopClassHandler;
diff --git a/extensions/ohif-dicom-microscopy-extension/src/DicomMicroscopyViewport.js b/extensions/ohif-dicom-microscopy-extension/src/DicomMicroscopyViewport.js
index ea35325d2..f0cf85264 100644
--- a/extensions/ohif-dicom-microscopy-extension/src/DicomMicroscopyViewport.js
+++ b/extensions/ohif-dicom-microscopy-extension/src/DicomMicroscopyViewport.js
@@ -1,11 +1,12 @@
import React, { Component } from 'react';
+
import { api } from 'dicom-microscopy-viewer';
const microscopyViewer = api.VLWholeSlideMicroscopyImageViewer;
class DicomMicroscopyViewport extends Component {
state = {
- error: null
+ error: null,
};
constructor(props) {
@@ -21,7 +22,7 @@ class DicomMicroscopyViewport extends Component {
const searchInstanceOptions = {
studyInstanceUID: displaySet.studyInstanceUid,
- seriesInstanceUID: displaySet.seriesInstanceUid
+ seriesInstanceUID: displaySet.seriesInstanceUid,
};
dicomWebClient
@@ -33,7 +34,7 @@ class DicomMicroscopyViewport extends Component {
const retrieveInstanceOptions = {
studyInstanceUID: displaySet.studyInstanceUid,
seriesInstanceUID: displaySet.seriesInstanceUid,
- sopInstanceUID
+ sopInstanceUID,
};
const promise = dicomWebClient
@@ -53,7 +54,7 @@ class DicomMicroscopyViewport extends Component {
const viewer = new microscopyViewer({
client: dicomWebClient,
- metadata
+ metadata,
});
viewer.render({ container });
diff --git a/extensions/ohif-dicom-microscopy-extension/src/OHIFDicomMicroscopyExtension.js b/extensions/ohif-dicom-microscopy-extension/src/OHIFDicomMicroscopyExtension.js
deleted file mode 100644
index 089de90fd..000000000
--- a/extensions/ohif-dicom-microscopy-extension/src/OHIFDicomMicroscopyExtension.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import DicomMicroscopyViewport from './DicomMicroscopyViewport.js';
-import DicomMicroscopySopClassHandler from './DicomMicroscopySopClassHandler.js';
-
-export default class OHIFDicomMicroscopyExtension {
- /**
- * Extension ID is a unique id, might be used for namespacing extension specific redux actions/reducers (?)
- */
- getExtensionId() {
- return 'microscopy';
- }
-
- getViewportModule() {
- return DicomMicroscopyViewport;
- }
-
- getSopClassHandler() {
- return DicomMicroscopySopClassHandler;
- }
-
- getPanelModule() {
- return null;
- }
-
- getToolbarModule() {
- return null;
- }
-}
diff --git a/extensions/ohif-dicom-microscopy-extension/src/index.js b/extensions/ohif-dicom-microscopy-extension/src/index.js
index 8bf217ecc..2ec002069 100644
--- a/extensions/ohif-dicom-microscopy-extension/src/index.js
+++ b/extensions/ohif-dicom-microscopy-extension/src/index.js
@@ -1,3 +1,16 @@
-import OHIFDicomMicroscopyExtension from './OHIFDicomMicroscopyExtension.js';
+import DicomMicroscopySopClassHandler from './DicomMicroscopySopClassHandler.js';
+import DicomMicroscopyViewport from './DicomMicroscopyViewport.js';
-export default OHIFDicomMicroscopyExtension;
+export default {
+ /**
+ * Only required property. Should be a unique value across all extensions.
+ */
+ id: 'microscopy',
+
+ getViewportModule() {
+ return DicomMicroscopyViewport;
+ },
+ getSopClassHandlerModule() {
+ return DicomMicroscopySopClassHandler;
+ },
+};
diff --git a/extensions/ohif-dicom-pdf-extension/.prettierrc b/extensions/ohif-dicom-pdf-extension/.prettierrc
index 92cde390a..12348ec6a 100644
--- a/extensions/ohif-dicom-pdf-extension/.prettierrc
+++ b/extensions/ohif-dicom-pdf-extension/.prettierrc
@@ -1,3 +1,9 @@
{
- "singleQuote": true
-}
\ No newline at end of file
+ "trailingComma": "es5",
+ "printWidth": 80,
+ "proseWrap": "always",
+ "tabWidth": 2,
+ "semi": true,
+ "singleQuote": true,
+ "endOfLine": "lf"
+}
diff --git a/extensions/ohif-dicom-pdf-extension/package.json b/extensions/ohif-dicom-pdf-extension/package.json
index afdc3dff1..67b4749b3 100644
--- a/extensions/ohif-dicom-pdf-extension/package.json
+++ b/extensions/ohif-dicom-pdf-extension/package.json
@@ -1,6 +1,6 @@
{
- "name": "ohif-dicom-pdf-extension",
- "version": "0.0.6",
+ "name": "@ohif/extension-dicom-pdf",
+ "version": "0.0.7",
"description": "OHIF extension for Dicom PDF",
"author": "OHIF",
"license": "MIT",
@@ -20,11 +20,16 @@
},
"peerDependencies": {
"dicom-parser": "^1.8.3",
- "ohif-core": "^0.3.4",
+ "ohif-core": "^0.6.0",
"prop-types": "^15.6.2",
"react": "^15.0.0 || ^16.0.0",
"react-dom": "^15.0.0 || ^16.0.0"
},
+ "dependencies": {
+ "@babel/runtime": "^7.2.0",
+ "classnames": "^2.2.6",
+ "lodash.isequal": "^4.5.0"
+ },
"devDependencies": {
"@babel/core": "^7.2.2",
"@babel/plugin-external-helpers": "^7.2.0",
@@ -80,9 +85,7 @@
"files": [
"dist"
],
- "dependencies": {
- "@babel/runtime": "^7.2.0",
- "classnames": "^2.2.6",
- "lodash.isequal": "^4.5.0"
+ "publishConfig": {
+ "access": "public"
}
}
diff --git a/extensions/ohif-dicom-pdf-extension/src/OHIFDicomPDFExtension.js b/extensions/ohif-dicom-pdf-extension/src/OHIFDicomPDFExtension.js
deleted file mode 100644
index e42e981df..000000000
--- a/extensions/ohif-dicom-pdf-extension/src/OHIFDicomPDFExtension.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import OHIFDicomPDFViewport from './OHIFDicomPDFViewport.js';
-import OHIFDicomPDFSopClassHandler from './OHIFDicomPDFSopClassHandler.js';
-
-export default class OHIFDicomPDFExtension {
- /**
- * Extension ID is a unique id, might be used for namespacing extension specific redux actions/reducers (?)
- */
- getExtensionId() {
- return 'pdf';
- }
-
- getViewportModule() {
- return OHIFDicomPDFViewport;
- }
-
- getSopClassHandler() {
- return OHIFDicomPDFSopClassHandler;
- }
-
- getPanelModule() {
- return null;
- }
-
- getToolbarModule() {
- return null;
- }
-}
diff --git a/extensions/ohif-dicom-pdf-extension/src/OHIFDicomPDFSopClassHandler.js b/extensions/ohif-dicom-pdf-extension/src/OHIFDicomPDFSopClassHandler.js
index 4591f3498..0b8e1b7bd 100644
--- a/extensions/ohif-dicom-pdf-extension/src/OHIFDicomPDFSopClassHandler.js
+++ b/extensions/ohif-dicom-pdf-extension/src/OHIFDicomPDFSopClassHandler.js
@@ -1,7 +1,4 @@
-import OHIF from "ohif-core";
-
-const { plugins, utils } = OHIF;
-const { PLUGIN_TYPES } = plugins;
+import { MODULE_TYPES, utils } from 'ohif-core';
// TODO: Should probably use dcmjs for this
const SOP_CLASS_UIDS = {
@@ -10,10 +7,8 @@ const SOP_CLASS_UIDS = {
const OHIFDicomPDFSopClassHandler = {
id: 'OHIFDicomPDFSopClassHandlerPlugin',
- type: PLUGIN_TYPES.SOP_CLASS_HANDLER,
- sopClassUids: [
- SOP_CLASS_UIDS.ENCAPSULATED_PDF
- ],
+ type: MODULE_TYPES.SOP_CLASS_HANDLER,
+ sopClassUids: [SOP_CLASS_UIDS.ENCAPSULATED_PDF],
getDisplaySetFromSeries(series, study, dicomWebClient, authorizationHeaders) {
const instance = series.getFirstInstance();
@@ -28,6 +23,6 @@ const OHIFDicomPDFSopClassHandler = {
authorizationHeaders: authorizationHeaders
};
}
-}
+};
export default OHIFDicomPDFSopClassHandler;
diff --git a/extensions/ohif-dicom-pdf-extension/src/index.js b/extensions/ohif-dicom-pdf-extension/src/index.js
index 74e7fff7b..b74560ec9 100644
--- a/extensions/ohif-dicom-pdf-extension/src/index.js
+++ b/extensions/ohif-dicom-pdf-extension/src/index.js
@@ -1,3 +1,16 @@
-import OHIFDicomPDFExtension from './OHIFDicomPDFExtension.js';
+import OHIFDicomPDFSopClassHandler from './OHIFDicomPDFSopClassHandler.js';
+import OHIFDicomPDFViewport from './OHIFDicomPDFViewport.js';
-export default OHIFDicomPDFExtension;
+export default {
+ /**
+ * Only required property. Should be a unique value across all extensions.
+ */
+ id: 'pdf',
+
+ getViewportModule() {
+ return OHIFDicomPDFViewport;
+ },
+ getSopClassHandlerModule() {
+ return OHIFDicomPDFSopClassHandler;
+ }
+};
diff --git a/extensions/ohif-vtk-extension/.prettierrc b/extensions/ohif-vtk-extension/.prettierrc
index 92cde390a..12348ec6a 100644
--- a/extensions/ohif-vtk-extension/.prettierrc
+++ b/extensions/ohif-vtk-extension/.prettierrc
@@ -1,3 +1,9 @@
{
- "singleQuote": true
-}
\ No newline at end of file
+ "trailingComma": "es5",
+ "printWidth": 80,
+ "proseWrap": "always",
+ "tabWidth": 2,
+ "semi": true,
+ "singleQuote": true,
+ "endOfLine": "lf"
+}
diff --git a/extensions/ohif-vtk-extension/README.md b/extensions/ohif-vtk-extension/README.md
index 1b4c09ef6..e21a3f0bb 100644
--- a/extensions/ohif-vtk-extension/README.md
+++ b/extensions/ohif-vtk-extension/README.md
@@ -1 +1,55 @@
# @ohif/extension-vtk
+
+
+
+
+
+#### Index
+
+Extension Id: `vtk`
+
+- [Commands Module](#commands-module)
+- [Toolbar Module](#toolbar-module)
+- [Viewport Module](#viewport-module)
+
+## Commands Module
+
+| Command Name | Description | Store Contexts |
+| ---------------------- | ----------- | -------------- |
+| `axial` | | viewports |
+| `coronal` | | viewports |
+| `sagittal` | | viewports |
+| `enableRotateTool` | | viewports |
+| `enableCrosshairsTool` | | viewports |
+| `enableLevelTool` | | viewports |
+| `mpr2d` | | viewports |
+
+## Toolbar Module
+
+Our toolbar module contains definitions for:
+
+- `Crosshairs`
+- `WWWC`
+- `Rotate`
+
+All use the `ACTIVE_VIEWPORT::VTK` context.
+
+## Viewport Module
+
+Our Viewport wraps [OHIF/react-vtkjs-viewport][react-viewport] and is connected
+the redux store. This module is the most prone to change as we hammer out our
+Viewport interface.
+
+## Resources
+
+### Repositories
+
+- [OHIF/react-vtkjs-viewport][react-viewport]
+
+
+
+
+[react-viewport]: https://github.com/OHIF/react-vtkjs-viewport
+
diff --git a/extensions/ohif-vtk-extension/package.json b/extensions/ohif-vtk-extension/package.json
index b1728497c..4bf91f6f7 100644
--- a/extensions/ohif-vtk-extension/package.json
+++ b/extensions/ohif-vtk-extension/package.json
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-vtk",
- "version": "0.0.6",
+ "version": "0.0.7",
"description": "OHIF extension for VTK.js",
"author": "OHIF",
"license": "MIT",
@@ -27,7 +27,7 @@
"dicom-parser": "^1.8.3",
"i18next": "^17.0.3",
"i18next-browser-languagedetector": "^3.0.1",
- "ohif-core": "^0.5.9",
+ "ohif-core": "^0.6.0",
"prop-types": "^15.7.2",
"react": "^16.8.6",
"react-dom": "^16.8.6",
@@ -37,6 +37,12 @@
"react-viewerbase": "^0.8.1",
"redux": "^4.0.1"
},
+ "dependencies": {
+ "@babel/runtime": "^7.4.5",
+ "@ohif/i18n": "0.0.4",
+ "react-vtkjs-viewport": "0.0.9",
+ "vtk.js": "^8.9.1"
+ },
"devDependencies": {
"@babel/core": "^7.4.5",
"@babel/plugin-external-helpers": "^7.2.0",
@@ -100,11 +106,5 @@
],
"publishConfig": {
"access": "public"
- },
- "dependencies": {
- "@babel/runtime": "^7.4.5",
- "@ohif/i18n": "0.0.4",
- "react-vtkjs-viewport": "0.0.9",
- "vtk.js": "^8.9.1"
}
}
diff --git a/extensions/ohif-vtk-extension/src/ConnectedToolbarSection.js b/extensions/ohif-vtk-extension/src/ConnectedToolbarSection.js
deleted file mode 100644
index 1717501fd..000000000
--- a/extensions/ohif-vtk-extension/src/ConnectedToolbarSection.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import { connect } from 'react-redux';
-import { ToolbarSection } from 'react-viewerbase';
-import OHIF from 'ohif-core';
-
-const { setToolActive } = OHIF.redux.actions;
-
-const mapStateToProps = state => {
- return {
- buttons: [
- {
- command: 'Crosshairs',
- type: 'tool',
- text: 'Crosshairs',
- icon: 'crosshairs',
- active: true,
- onClick: () => {
- // TODO: Make these use setToolActive instead
- window.commandsManager.runCommand('enableCrosshairsTool', {}, 'vtk');
- }
- },
- {
- command: 'WWWC',
- type: 'tool',
- text: 'WWWC',
- icon: 'level',
- active: true,
- onClick: () => {
- // TODO: Make these use setToolActive instead
- window.commandsManager.runCommand('enableLevelTool', {}, 'vtk');
- }
- },
- {
- command: 'Rotate',
- type: 'tool',
- text: 'Rotate',
- icon: '3d-rotate',
- active: false,
- onClick: () => {
- // TODO: Make these use setToolActive instead
- window.commandsManager.runCommand('enableRotateTool', {}, 'vtk');
- }
- },
- ],
- activeCommand: 'Crosshairs'
- };
-};
-
-const ConnectedToolbarSection = connect(
- mapStateToProps,
- null
-)(ToolbarSection);
-
-export default ConnectedToolbarSection;
diff --git a/extensions/ohif-vtk-extension/src/ConnectedVTKViewport.js b/extensions/ohif-vtk-extension/src/ConnectedVTKViewport.js
index 28689a591..2eb695594 100644
--- a/extensions/ohif-vtk-extension/src/ConnectedVTKViewport.js
+++ b/extensions/ohif-vtk-extension/src/ConnectedVTKViewport.js
@@ -1,15 +1,10 @@
-import { connect } from 'react-redux';
-import { View2D } from 'react-vtkjs-viewport';
import OHIF from 'ohif-core';
+import { View2D } from 'react-vtkjs-viewport';
+import { connect } from 'react-redux';
-const {
- setViewportActive,
- setViewportSpecificData,
- clearViewportSpecificData
-} = OHIF.redux.actions;
+const { setViewportActive, setViewportSpecificData } = OHIF.redux.actions;
const mapStateToProps = (state, ownProps) => {
- const activeButton = state.tools.buttons.find(tool => tool.active === true);
let dataFromStore;
if (state.extensions && state.extensions.vtk) {
@@ -19,9 +14,6 @@ const mapStateToProps = (state, ownProps) => {
// If this is the active viewport, enable prefetching.
const { viewportIndex } = ownProps;
const isActive = viewportIndex === state.viewports.activeViewportIndex;
- const viewportSpecificData =
- state.viewports.viewportSpecificData[viewportIndex] || {};
-
const viewportLayout = state.viewports.layout.viewports[viewportIndex];
const pluginDetails = viewportLayout.vtk || {};
@@ -29,9 +21,10 @@ const mapStateToProps = (state, ownProps) => {
layout: state.viewports.layout,
isActive,
...pluginDetails,
- activeTool: activeButton && activeButton.command,
+ // Hopefully this doesn't break anything under the hood for this one
+ // activeTool: activeButton && activeButton.command,
...dataFromStore,
- enableStackPrefetch: isActive
+ enableStackPrefetch: isActive,
};
};
@@ -45,13 +38,12 @@ const mapDispatchToProps = (dispatch, ownProps) => {
setViewportSpecificData: data => {
dispatch(setViewportSpecificData(viewportIndex, data));
- }
+ },
};
};
const mergeProps = (propsFromState, propsFromDispatch, ownProps) => {
const { afterCreation } = propsFromState;
- const { setViewportSpecificData } = propsFromDispatch;
const props = {
...propsFromState,
@@ -74,7 +66,7 @@ const mergeProps = (propsFromState, propsFromDispatch, ownProps) => {
if (afterCreation && typeof afterCreation === 'function') {
afterCreation(api);
}
- }
+ },
};
return props;
};
diff --git a/extensions/ohif-vtk-extension/src/LoadingIndicator.css b/extensions/ohif-vtk-extension/src/LoadingIndicator.css
index 0883f66cb..e722fdab5 100644
--- a/extensions/ohif-vtk-extension/src/LoadingIndicator.css
+++ b/extensions/ohif-vtk-extension/src/LoadingIndicator.css
@@ -1,5 +1,5 @@
.imageViewerLoadingIndicator {
- color: #91B9CD;
+ color: #91b9cd;
}
.loadingIndicator {
diff --git a/extensions/ohif-vtk-extension/src/LoadingIndicator.js b/extensions/ohif-vtk-extension/src/LoadingIndicator.js
index 7dc5e4614..06bcbf4db 100644
--- a/extensions/ohif-vtk-extension/src/LoadingIndicator.js
+++ b/extensions/ohif-vtk-extension/src/LoadingIndicator.js
@@ -1,17 +1,18 @@
-import React, { PureComponent } from 'react';
-import PropTypes from 'prop-types';
-
import './LoadingIndicator.css';
+import React, { PureComponent } from 'react';
+
+import PropTypes from 'prop-types';
+
class LoadingIndicator extends PureComponent {
static propTypes = {
percentComplete: PropTypes.number.isRequired,
- error: PropTypes.object
+ error: PropTypes.object,
};
static defaultProps = {
percentComplete: 0,
- error: null
+ error: null,
};
render() {
diff --git a/extensions/ohif-vtk-extension/src/OHIFVTKExtension.js b/extensions/ohif-vtk-extension/src/OHIFVTKExtension.js
deleted file mode 100644
index d0eda51a5..000000000
--- a/extensions/ohif-vtk-extension/src/OHIFVTKExtension.js
+++ /dev/null
@@ -1,75 +0,0 @@
-import React, { Component } from 'react';
-import OHIFVTKViewport from './OHIFVTKViewport.js';
-import ToolbarModule from './ToolbarModule.js';
-import { definitions } from './commands';
-
-/**
- * Pass in 'children' to a React component. The purpose of this is to
- * allow end users of this extension to pass in components which will
- * be rendered on top of the base components.
- *
- * @param WrappedComponent
- * @param children
- * @return {function(*): *}
- */
-function withChildren(WrappedComponent, children) {
- return function(props) {
- return ;
- };
-}
-
-// Note: If you are authoring extensions which use stateful libraries (e.g. cornerstone-core, react-redux) as peerDependencies and are also duplicated at the application level, try using 'yalc' to link it to the application, rather than yarn link. This can help fix 'module not found' issues.
-// https://github.com/whitecolor/yalc
-
-export default class OHIFVTKExtension {
- constructor({ children, commandsManager }) {
- this.children = children;
-
- _registerCommands(commandsManager, definitions, this.getExtensionId());
- }
-
- /**
- * Extension ID is a unique id, might be used for namespacing extension specific redux actions/reducers (?)
- */
- getExtensionId() {
- return 'vtk';
- }
-
- getViewportModule() {
- if (this.children && this.children.viewport) {
- return withChildren(OHIFVTKViewport, this.children.viewport);
- }
-
- return OHIFVTKViewport;
- }
-
- getSopClassHandler() {
- return null;
- }
-
- getPanelModule() {
- return null;
- }
-
- getToolbarModule() {
- return ToolbarModule;
- }
-}
-
-/**
- * Register all Viewer commands
- *
- * @private
- */
-function _registerCommands(commandsManager, definitions, commandContext) {
- commandsManager.createContext(commandContext);
- Object.keys(definitions).forEach(commandName => {
- const commandDefinition = definitions[commandName];
-
- commandsManager.registerCommand(
- commandContext,
- commandName,
- commandDefinition
- );
- });
-}
diff --git a/extensions/ohif-vtk-extension/src/OHIFVTKViewport.js b/extensions/ohif-vtk-extension/src/OHIFVTKViewport.js
index ff9eb3b7b..a42ac75b3 100644
--- a/extensions/ohif-vtk-extension/src/OHIFVTKViewport.js
+++ b/extensions/ohif-vtk-extension/src/OHIFVTKViewport.js
@@ -1,17 +1,16 @@
import React, { Component } from 'react';
-import PropTypes from 'prop-types';
-import OHIF from 'ohif-core';
-import cornerstone from 'cornerstone-core';
import { getImageData, loadImageData } from 'react-vtkjs-viewport';
+import ConnectedVTKViewport from './ConnectedVTKViewport';
+import LoadingIndicator from './LoadingIndicator.js';
+import OHIF from 'ohif-core';
+import PropTypes from 'prop-types';
+import cornerstone from 'cornerstone-core';
+import handleSegmentationStorage from './handleSegmentationStorage.js';
+import vtkDataArray from 'vtk.js/Sources/Common/Core/DataArray';
+import vtkImageData from 'vtk.js/Sources/Common/DataModel/ImageData';
import vtkVolume from 'vtk.js/Sources/Rendering/Core/Volume';
import vtkVolumeMapper from 'vtk.js/Sources/Rendering/Core/VolumeMapper';
-import vtkImageData from 'vtk.js/Sources/Common/DataModel/ImageData';
-import vtkDataArray from 'vtk.js/Sources/Common/Core/DataArray';
-
-import ConnectedVTKViewport from './ConnectedVTKViewport';
-import handleSegmentationStorage from './handleSegmentationStorage.js';
-import LoadingIndicator from './LoadingIndicator.js';
const { StackManager } = OHIF.utils;
@@ -25,7 +24,7 @@ cornerstone.metaData.addProvider(
StackManager.setMetadataProvider(metadataProvider);
const SOP_CLASSES = {
- SEGMENTATION_STORAGE: '1.2.840.10008.5.1.4.1.1.66.4'
+ SEGMENTATION_STORAGE: '1.2.840.10008.5.1.4.1.1.66.4',
};
const specialCaseHandlers = {};
@@ -51,7 +50,7 @@ function createLabelMapImageData(backgroundImageData) {
const values = new Uint8Array(backgroundImageData.getNumberOfPoints());
const dataArray = vtkDataArray.newInstance({
numberOfComponents: 1, // labelmap with single component
- values
+ values,
});
labelMapData.getPointData().setScalars(dataArray);
@@ -62,14 +61,14 @@ class OHIFVTKViewport extends Component {
state = {
volumes: null,
paintFilterLabelMapImageData: null,
- paintFilterBackgroundImageData: null
+ paintFilterBackgroundImageData: null,
};
static propTypes = {
studies: PropTypes.object,
displaySet: PropTypes.object,
viewportIndex: PropTypes.number,
- children: PropTypes.node
+ children: PropTypes.node,
};
static id = 'OHIFVTKViewport';
@@ -165,7 +164,7 @@ class OHIFVTKViewport extends Component {
return loadImageData(imageDataObject).then(() => {
return {
data: imageDataObject.vtkImageData,
- labelmap: labelmapDataObject
+ labelmap: labelmapDataObject,
};
});
default:
@@ -173,7 +172,7 @@ class OHIFVTKViewport extends Component {
return loadImageData(imageDataObject).then(() => {
return {
- data: imageDataObject.vtkImageData
+ data: imageDataObject.vtkImageData,
};
});
}
@@ -202,7 +201,7 @@ class OHIFVTKViewport extends Component {
displaySetInstanceUid,
sopClassUids,
sopInstanceUid,
- frameIndex
+ frameIndex,
} = displaySet;
if (sopClassUids.length > 1) {
@@ -231,7 +230,7 @@ class OHIFVTKViewport extends Component {
this.setState({
volumes: [volumeActor],
paintFilterBackgroundImageData: data,
- paintFilterLabelMapImageData: labelmap
+ paintFilterLabelMapImageData: labelmap,
});
}
@@ -261,7 +260,7 @@ class OHIFVTKViewport extends Component {
childrenWithProps = this.props.children.map((child, index) => {
return React.cloneElement(child, {
viewportIndex: this.props.viewportIndex,
- key: index
+ key: index,
});
});
}
diff --git a/extensions/ohif-vtk-extension/src/ToolbarModule.js b/extensions/ohif-vtk-extension/src/ToolbarModule.js
deleted file mode 100644
index 447abcab9..000000000
--- a/extensions/ohif-vtk-extension/src/ToolbarModule.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import React, { Component } from 'react';
-import PropTypes from 'prop-types';
-import ConnectedToolbarSection from './ConnectedToolbarSection';
-
-class ToolbarModule extends Component {
- render() {
- return (
-
-
-
- );
- }
-}
-
-export default ToolbarModule;
diff --git a/extensions/ohif-vtk-extension/src/commands.js b/extensions/ohif-vtk-extension/src/commandsModule.js
similarity index 95%
rename from extensions/ohif-vtk-extension/src/commands.js
rename to extensions/ohif-vtk-extension/src/commandsModule.js
index 19cf396c8..b8cc692c0 100644
--- a/extensions/ohif-vtk-extension/src/commands.js
+++ b/extensions/ohif-vtk-extension/src/commandsModule.js
@@ -1,25 +1,22 @@
import {
- vtkInteractorStyleMPRWindowLevel,
- vtkInteractorStyleMPRSlice,
vtkInteractorStyleMPRCrosshairs,
+ vtkInteractorStyleMPRSlice,
+ vtkInteractorStyleMPRWindowLevel,
vtkSVGCrosshairsWidget,
- vtkSVGWidgetManager
+ vtkSVGWidgetManager,
} from 'react-vtkjs-viewport';
-import setViewportToVTK from './utils/setViewportToVTK.js';
import setMPRLayout from './utils/setMPRLayout.js';
+import setViewportToVTK from './utils/setViewportToVTK.js';
+import vtkCoordinate from 'vtk.js/Sources/Rendering/Core/Coordinate';
import vtkMath from 'vtk.js/Sources/Common/Core/Math';
import vtkMatrixBuilder from 'vtk.js/Sources/Common/Core/MatrixBuilder';
-import vtkCoordinate from 'vtk.js/Sources/Rendering/Core/Coordinate';
-
-// TODO: Should be another way to get this
-const commandsManager = window.commandsManager;
// TODO: Put this somewhere else
let apis = {};
function getCrosshairCallbackForIndex(index) {
- return ({worldPos}) => {
+ return ({ worldPos }) => {
// Set camera focal point to world coordinate for linked views
apis.forEach((api, viewportIndex) => {
if (viewportIndex !== index) {
@@ -52,7 +49,10 @@ function getCrosshairCallbackForIndex(index) {
const displayPosition = wPos.getComputedDisplayValue(renderer);
const { svgWidgetManager } = api;
- api.svgWidgets.crosshairsWidget.setPoint(displayPosition[0], displayPosition[1]);
+ api.svgWidgets.crosshairsWidget.setPoint(
+ displayPosition[0],
+ displayPosition[1]
+ );
svgWidgetManager.render();
});
};
@@ -230,7 +230,7 @@ const actions = {
api.svgWidgetManager = svgWidgetManager;
api.svgWidgets = {
- crosshairsWidget
+ crosshairsWidget,
};
switch (index) {
@@ -255,45 +255,49 @@ const actions = {
renderWindow.render();
});
- }
+ },
};
const definitions = {
axial: {
commandFn: actions.axial,
storeContexts: ['viewports'],
- options: {}
+ options: {},
},
coronal: {
commandFn: actions.coronal,
storeContexts: ['viewports'],
- options: {}
+ options: {},
},
sagittal: {
commandFn: actions.sagittal,
storeContexts: ['viewports'],
- options: {}
+ options: {},
},
enableRotateTool: {
commandFn: actions.enableRotateTool,
storeContexts: ['viewports'],
- options: {}
+ options: {},
},
enableCrosshairsTool: {
commandFn: actions.enableCrosshairsTool,
storeContexts: ['viewports'],
- options: {}
+ options: {},
},
enableLevelTool: {
commandFn: actions.enableLevelTool,
storeContexts: ['viewports'],
- options: {}
+ options: {},
},
mpr2d: {
commandFn: actions.mpr2d,
storeContexts: ['viewports'],
- options: {}
- }
+ options: {},
+ context: 'VIEWER',
+ },
};
-export { definitions };
+export default {
+ definitions,
+ defaultContext: 'ACTIVE_VIEWPORT::VTK',
+};
diff --git a/extensions/ohif-vtk-extension/src/handleSegmentationStorage.js b/extensions/ohif-vtk-extension/src/handleSegmentationStorage.js
index 6941b9712..1988456cd 100644
--- a/extensions/ohif-vtk-extension/src/handleSegmentationStorage.js
+++ b/extensions/ohif-vtk-extension/src/handleSegmentationStorage.js
@@ -1,5 +1,6 @@
-import OHIF from 'ohif-core';
import * as dcmjs from 'dcmjs';
+
+import OHIF from 'ohif-core';
import { api } from 'dicomweb-client';
const { StackManager } = OHIF.utils;
@@ -56,14 +57,14 @@ function retrieveDicomData(
) {
const config = {
url: wadoRoot,
- headers: DICOMWeb.getAuthorizationHeader()
+ headers: DICOMWeb.getAuthorizationHeader(),
};
const dicomWeb = new api.DICOMwebClient(config);
const options = {
studyInstanceUID,
seriesInstanceUID,
- sopInstanceUID
+ sopInstanceUID,
};
return dicomWeb.retrieveInstance(options);
@@ -136,13 +137,13 @@ async function handleSegmentationStorage(
return {
referenceDataObject,
- labelmapDataObject
+ labelmapDataObject,
};
return {
studyInstanceUid,
displaySetInstanceUid,
- stack
+ stack,
};
}
diff --git a/extensions/ohif-vtk-extension/src/index.js b/extensions/ohif-vtk-extension/src/index.js
index 95116b66c..726b13c7c 100644
--- a/extensions/ohif-vtk-extension/src/index.js
+++ b/extensions/ohif-vtk-extension/src/index.js
@@ -1,7 +1,24 @@
+import OHIFVTKViewport from './OHIFVTKViewport.js';
+import commandsModule from './commandsModule.js';
+// This feels weird
import loadLocales from './loadLocales';
+import toolbarModule from './toolbarModule.js';
-import OHIFVTKExtension from './OHIFVTKExtension.js';
+export default {
+ /**
+ * Only required property. Should be a unique value across all extensions.
+ */
+ id: 'vtk',
+
+ getViewportModule() {
+ return OHIFVTKViewport;
+ },
+ getToolbarModule() {
+ return toolbarModule;
+ },
+ getCommandsModule() {
+ return commandsModule;
+ },
+};
loadLocales();
-
-export default OHIFVTKExtension;
diff --git a/extensions/ohif-vtk-extension/src/toolbarModule.js b/extensions/ohif-vtk-extension/src/toolbarModule.js
new file mode 100644
index 000000000..fed4f54db
--- /dev/null
+++ b/extensions/ohif-vtk-extension/src/toolbarModule.js
@@ -0,0 +1,39 @@
+const TOOLBAR_BUTTON_TYPES = {
+ COMMAND: 'command',
+ SET_TOOL_ACTIVE: 'setToolActive',
+};
+
+const definitions = [
+ {
+ id: 'Crosshairs',
+ label: 'Crosshairs',
+ icon: 'crosshairs',
+ //
+ type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
+ commandName: 'enableCrosshairsTool',
+ commandOptions: {},
+ },
+ {
+ id: 'WWWC',
+ label: 'WWWC',
+ icon: 'level',
+ //
+ type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
+ commandName: 'enableLevelTool',
+ commandOptions: {},
+ },
+ {
+ id: 'Rotate',
+ label: 'Rotate',
+ icon: '3d-rotate',
+ //
+ type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
+ commandName: 'enableRotateTool',
+ commandOptions: {},
+ },
+];
+
+export default {
+ definitions,
+ defaultContext: 'ACTIVE_VIEWPORT::VTK',
+};
diff --git a/extensions/ohif-vtk-extension/src/utils/setMPRLayout.js b/extensions/ohif-vtk-extension/src/utils/setMPRLayout.js
index 65570887d..6de1023f4 100644
--- a/extensions/ohif-vtk-extension/src/utils/setMPRLayout.js
+++ b/extensions/ohif-vtk-extension/src/utils/setMPRLayout.js
@@ -11,14 +11,14 @@ export default function setMPRLayout(displaySet) {
for (let i = 0; i < numViewports; i++) {
viewports.push({
height: `${100 / rows}%`,
- width: `${100 / columns}%`
+ width: `${100 / columns}%`,
});
viewportSpecificData[i] = displaySet;
viewportSpecificData[i].plugin = 'vtk';
}
const layout = {
- viewports
+ viewports,
};
const viewportIndices = [0, 1, 2];
@@ -33,7 +33,7 @@ export default function setMPRLayout(displaySet) {
}*/
const data = {
- plugin: 'vtk',
+ // plugin: 'vtk',
vtk: {
mode: 'mpr', // TODO: not used
afterCreation: api => {
@@ -42,8 +42,8 @@ export default function setMPRLayout(displaySet) {
if (apis.every(a => !!a)) {
resolve(apis);
}
- }
- }
+ },
+ },
};
updatedViewports = setSingleLayoutData(
diff --git a/extensions/ohif-vtk-extension/src/utils/setViewportToVTK.js b/extensions/ohif-vtk-extension/src/utils/setViewportToVTK.js
index c018ba909..aa3dfb679 100644
--- a/extensions/ohif-vtk-extension/src/utils/setViewportToVTK.js
+++ b/extensions/ohif-vtk-extension/src/utils/setViewportToVTK.js
@@ -14,13 +14,13 @@ export default function setViewportToVTK(
}*/
const data = {
- plugin: 'vtk',
+ // plugin: 'vtk',
vtk: {
mode: 'mpr', // TODO: not used
afterCreation: api => {
resolve(api);
- }
- }
+ },
+ },
};
const updatedViewports = setSingleLayoutData(
diff --git a/package.json b/package.json
index bfdaa4a08..3b64946e3 100644
--- a/package.json
+++ b/package.json
@@ -67,9 +67,11 @@
},
"dependencies": {
"@babel/runtime": "^7.4.5",
- "@ohif/extension-cornerstone": "0.0.36",
- "@ohif/extension-dicom-microscopy": "0.0.6",
- "@ohif/extension-vtk": "0.0.6",
+ "@ohif/extension-cornerstone": "0.0.37",
+ "@ohif/extension-dicom-html": "0.0.3",
+ "@ohif/extension-dicom-microscopy": "0.0.7",
+ "@ohif/extension-dicom-pdf": "0.0.7",
+ "@ohif/extension-vtk": "0.0.7",
"@ohif/i18n": "0.0.4",
"classnames": "^2.2.6",
"cornerstone-core": "^2.2.8",
@@ -84,9 +86,7 @@
"i18next-browser-languagedetector": "^3.0.1",
"lodash.isequal": "4.5.0",
"moment": "^2.24.0",
- "ohif-core": "0.5.9",
- "ohif-dicom-html-extension": "^0.0.2",
- "ohif-dicom-pdf-extension": "^0.0.6",
+ "ohif-core": "0.6.0",
"oidc-client": "1.7.x",
"prop-types": "^15.7.2",
"react-i18next": "^10.11.0",
@@ -94,9 +94,12 @@
"react-resize-detector": "^4.2.0",
"react-router": "^5.0.1",
"react-router-dom": "^5.0.1",
- "react-viewerbase": "0.9.0",
+ "react-viewerbase": "0.10.0",
"redux": "^4.0.1",
- "redux-oidc": "3.1.x"
+ "redux-logger": "^3.0.6",
+ "redux-oidc": "3.1.x",
+ "redux-thunk": "^2.3.0",
+ "reselect": "^4.0.0"
},
"devDependencies": {
"@babel/core": "^7.4.5",
diff --git a/src/App.js b/src/App.js
index 9d5278768..3a124728f 100644
--- a/src/App.js
+++ b/src/App.js
@@ -2,23 +2,21 @@ import './config';
import {
CommandsManager,
+ ExtensionManager,
HotkeysManager,
- extensions,
- redux,
utils,
} from 'ohif-core';
import React, { Component } from 'react';
import {
- getDefaultToolbarButtons,
getUserManagerForOpenIdConnectClient,
initWebWorkers,
} from './utils/index.js';
-import ConnectedToolContextMenu from './connectedComponents/ConnectedToolContextMenu';
+import { I18nextProvider } from 'react-i18next';
import OHIFCornerstoneExtension from '@ohif/extension-cornerstone';
-import OHIFDicomHtmlExtension from 'ohif-dicom-html-extension';
+import OHIFDicomHtmlExtension from '@ohif/extension-dicom-html';
import OHIFDicomMicroscopyExtension from '@ohif/extension-dicom-microscopy';
-import OHIFDicomPDFExtension from 'ohif-dicom-pdf-extension';
+import OHIFDicomPDFExtension from '@ohif/extension-dicom-pdf';
import OHIFStandaloneViewer from './OHIFStandaloneViewer';
import OHIFVTKExtension from '@ohif/extension-vtk';
import { OidcProvider } from 'redux-oidc';
@@ -27,22 +25,20 @@ import { Provider } from 'react-redux';
import { BrowserRouter as Router } from 'react-router-dom';
import WhiteLabellingContext from './WhiteLabellingContext';
import appCommands from './appCommands';
-import setupTools from './setupTools';
+import { getActiveContexts } from './store/layout/selectors.js';
import i18n from '@ohif/i18n';
-import { I18nextProvider } from 'react-i18next';
+import setupTools from './setupTools';
import store from './store';
// ~~~~ APP SETUP
const commandsManagerConfig = {
getAppState: () => store.getState(),
- getActiveContexts: () => store.getState().ui.activeContexts,
+ getActiveContexts: () => getActiveContexts(store.getState()),
};
const commandsManager = new CommandsManager(commandsManagerConfig);
const hotkeysManager = new HotkeysManager(commandsManager);
-
-// TODO: @dannyrb will fix this
-window.commandsManager = commandsManager;
+const extensionManager = new ExtensionManager({ commandsManager });
// TODO: Should be done in extensions w/ commandsModule
// ~~ ADD COMMANDS
@@ -50,32 +46,21 @@ appCommands.init(commandsManager);
if (window.config.hotkeys) {
hotkeysManager.setHotkeys(window.config.hotkeys, true);
}
-
-// Force active contexts for now. These should be set in Viewer/ActiveViewer
-store.dispatch({
- type: 'ADD_ACTIVE_CONTEXT',
- item: 'VIEWER',
-});
-store.dispatch({
- type: 'ADD_ACTIVE_CONTEXT',
- item: 'VIEWER::CORNERSTONE',
-});
-
// ~~~~ END APP SETUP
setupTools(store);
-const children = {
- viewport: [],
-};
+// const children = {
+// viewport: [],
+// };
/** TODO: extensions should be passed in as prop as soon as we have the extensions as separate packages and then registered by ExtensionsManager */
-extensions.ExtensionManager.registerExtensions(store, [
- new OHIFCornerstoneExtension({ children }),
- new OHIFVTKExtension({ commandsManager }),
- new OHIFDicomPDFExtension(),
- new OHIFDicomHtmlExtension(),
- new OHIFDicomMicroscopyExtension(),
+extensionManager.registerExtensions([
+ OHIFCornerstoneExtension,
+ OHIFVTKExtension,
+ OHIFDicomPDFExtension,
+ OHIFDicomHtmlExtension,
+ OHIFDicomMicroscopyExtension,
]);
// TODO[react] Use a provider when the whole tree is React
@@ -104,12 +89,6 @@ class App extends Component {
constructor(props) {
super(props);
- //
- const defaultButtons = getDefaultToolbarButtons(this.props.routerBasename);
- const buttonsAction = redux.actions.setAvailableButtons(defaultButtons);
-
- store.dispatch(buttonsAction);
-
if (this.props.oidc.length) {
const firstOpenIdClient = this.props.oidc[0];
@@ -162,4 +141,5 @@ class App extends Component {
export default App;
-export { commandsManager, hotkeysManager };
+// Make our managers accessible
+export { commandsManager, extensionManager, hotkeysManager };
diff --git a/src/appCommands/index.js b/src/appCommands/index.js
index 66ab50fa6..40591d5f1 100644
--- a/src/appCommands/index.js
+++ b/src/appCommands/index.js
@@ -1,9 +1,7 @@
-import cornerstoneCommandDefinitions from './cornerstone.js';
import viewerCommandDefinitions from './viewer.js';
const CONTEXTS = {
viewer: 'VIEWER',
- cornerstone: 'VIEWER::CORNERSTONE',
};
/**
@@ -12,7 +10,6 @@ const CONTEXTS = {
*/
function init(commandsManager) {
_registerViewerCommands(commandsManager);
- _registerCornerstoneCommands(commandsManager);
}
/**
@@ -35,26 +32,6 @@ function _registerViewerCommands(commandsManager) {
});
}
-/**
- * Register all Cornerstone commands
- *
- * @private
- */
-function _registerCornerstoneCommands(commandsManager) {
- const commandContext = CONTEXTS.cornerstone;
-
- commandsManager.createContext(commandContext);
- Object.keys(cornerstoneCommandDefinitions).forEach(commandName => {
- const commandDefinition = cornerstoneCommandDefinitions[commandName];
-
- commandsManager.registerCommand(
- commandContext,
- commandName,
- commandDefinition
- );
- });
-}
-
export default {
init,
};
diff --git a/src/components/Header/Header.js b/src/components/Header/Header.js
index 60186a517..f167c1085 100644
--- a/src/components/Header/Header.js
+++ b/src/components/Header/Header.js
@@ -1,15 +1,15 @@
import './Header.css';
+import './Header.css';
import { Link, withRouter } from 'react-router-dom';
import React, { Component } from 'react';
import { Dropdown } from 'react-viewerbase';
-import { withTranslation } from 'react-i18next';
-import './Header.css';
import OHIFLogo from '../OHIFLogo/OHIFLogo.js';
import PropTypes from 'prop-types';
// import { UserPreferencesModal } from 'react-viewerbase';
import { hotkeysManager } from './../../App.js';
+import { withTranslation } from 'react-i18next';
class Header extends Component {
static propTypes = {
@@ -25,8 +25,8 @@ class Header extends Component {
};
// onSave: data => {
- // const contextName = window.store.getState().commandContext.context;
- // const preferences = cloneDeep(window.store.getState().preferences);
+ // const contextName = store.getState().commandContext.context;
+ // const preferences = cloneDeep(store.getState().preferences);
// preferences[contextName] = data;
// dispatch(setUserPreferences(preferences));
// dispatch(setUserPreferencesModalOpen(false));
diff --git a/src/config.js b/src/config.js
index cd1bd8bec..fcfa138ea 100644
--- a/src/config.js
+++ b/src/config.js
@@ -1,7 +1,7 @@
-import dicomParser from 'dicom-parser';
+import OHIF from 'ohif-core';
import cornerstone from 'cornerstone-core';
import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader';
-import OHIF from 'ohif-core';
+import dicomParser from 'dicom-parser';
import version from './version.js';
window.info = {
@@ -10,8 +10,10 @@ window.info = {
};
// For debugging
+//if (process.env.node_env === 'development') {
window.cornerstone = cornerstone;
window.cornerstoneWADOImageLoader = cornerstoneWADOImageLoader;
+//}
cornerstoneWADOImageLoader.external.cornerstone = cornerstone;
cornerstoneWADOImageLoader.external.dicomParser = dicomParser;
diff --git a/extensions/ohif-cornerstone-extension/src/ConnectedCineDialog.js b/src/connectedComponents/ConnectedCineDialog.js
similarity index 95%
rename from extensions/ohif-cornerstone-extension/src/ConnectedCineDialog.js
rename to src/connectedComponents/ConnectedCineDialog.js
index 6247f6bf2..761a79abe 100644
--- a/extensions/ohif-cornerstone-extension/src/ConnectedCineDialog.js
+++ b/src/connectedComponents/ConnectedCineDialog.js
@@ -20,14 +20,14 @@ const mapStateToProps = state => {
const cineData = cine || {
isPlaying: false,
- cineFrameRate: 24
+ cineFrameRate: 24,
};
// New props we're creating?
return {
activeEnabledElement: dom,
activeViewportCineData: cineData,
- activeViewportIndex: state.viewports.activeViewportIndex
+ activeViewportIndex: state.viewports.activeViewportIndex,
};
};
@@ -35,7 +35,7 @@ const mapDispatchToProps = dispatch => {
return {
dispatchSetViewportSpecificData: (viewportIndex, data) => {
dispatch(setViewportSpecificData(viewportIndex, data));
- }
+ },
};
};
@@ -43,7 +43,7 @@ const mergeProps = (propsFromState, propsFromDispatch, ownProps) => {
const {
activeEnabledElement,
activeViewportCineData,
- activeViewportIndex
+ activeViewportIndex,
} = propsFromState;
return {
@@ -54,7 +54,7 @@ const mergeProps = (propsFromState, propsFromDispatch, ownProps) => {
cine.isPlaying = !cine.isPlaying;
propsFromDispatch.dispatchSetViewportSpecificData(activeViewportIndex, {
- cine
+ cine,
});
},
onFrameRateChanged: frameRate => {
@@ -62,7 +62,7 @@ const mergeProps = (propsFromState, propsFromDispatch, ownProps) => {
cine.cineFrameRate = frameRate;
propsFromDispatch.dispatchSetViewportSpecificData(activeViewportIndex, {
- cine
+ cine,
});
},
onClickNextButton: () => {
@@ -89,7 +89,7 @@ const mergeProps = (propsFromState, propsFromDispatch, ownProps) => {
if (!stackData || !stackData.data || !stackData.data.length) return;
const lastIndex = stackData.data[0].imageIds.length - 1;
scrollToIndex(activeEnabledElement, lastIndex);
- }
+ },
};
};
diff --git a/src/connectedComponents/ConnectedLayoutButton.js b/src/connectedComponents/ConnectedLayoutButton.js
index 23f44e70b..4842f5952 100644
--- a/src/connectedComponents/ConnectedLayoutButton.js
+++ b/src/connectedComponents/ConnectedLayoutButton.js
@@ -1,6 +1,6 @@
-import { connect } from 'react-redux';
import { LayoutButton } from 'react-viewerbase';
import OHIF from 'ohif-core';
+import { connect } from 'react-redux';
const { setLayout } = OHIF.redux.actions;
@@ -22,7 +22,6 @@ const mapDispatchToProps = dispatch => {
viewports.push({
height: `${100 / rows}%`,
width: `${100 / columns}%`,
- plugin: 'cornerstone', // Temporary because right now switching back from VTK breaks things
});
}
const layout = {
diff --git a/src/connectedComponents/ConnectedLayoutManager.js b/src/connectedComponents/ConnectedLayoutManager.js
index d18605ac1..564645ac0 100644
--- a/src/connectedComponents/ConnectedLayoutManager.js
+++ b/src/connectedComponents/ConnectedLayoutManager.js
@@ -1,32 +1,29 @@
-import { connect } from 'react-redux';
import { LayoutManager } from 'react-viewerbase';
-import OHIF from 'ohif-core';
+import { MODULE_TYPES } from 'ohif-core';
+import { connect } from 'react-redux';
+import { extensionManager } from './../App.js';
const mapStateToProps = state => {
- const viewportPluginIds = state.plugins.availablePlugins
- .filter(plugin => plugin.type === OHIF.plugins.PLUGIN_TYPES.VIEWPORT)
- .map(plugin => plugin.id);
+ const availableViewportModules = {};
+ const viewportModules = extensionManager.modules[MODULE_TYPES.VIEWPORT];
- const availablePlugins = {};
- viewportPluginIds.forEach(id => {
- const plugin = OHIF.plugins.availablePlugins.find(
- plugin => plugin.id === id
- );
- if (plugin) {
- availablePlugins[id] = plugin.component;
- }
+ viewportModules.forEach(moduleDefinition => {
+ availableViewportModules[moduleDefinition.extensionId] =
+ moduleDefinition.module;
});
- // TODO Use something like state.plugins.defaultPlugin[OHIF.plugins.PLUGIN_TYPES.VIEWPORT]
+ // TODO: Use something like state.plugins.defaultPlugin[MODULE_TYPES.VIEWPORT]
let defaultPlugin;
- if (viewportPluginIds && viewportPluginIds.length) {
- defaultPlugin = viewportPluginIds[0];
+ if (viewportModules.length) {
+ defaultPlugin = viewportModules[0].extensionId;
}
return {
layout: state.viewports.layout,
activeViewportIndex: state.viewports.activeViewportIndex,
- availablePlugins,
+ // TODO: rename `availableViewportModules`
+ availablePlugins: availableViewportModules,
+ // TODO: rename `defaultViewportModule`
defaultPlugin,
};
};
diff --git a/src/connectedComponents/ConnectedPluginSwitch.js b/src/connectedComponents/ConnectedPluginSwitch.js
index 7fd883c7f..965c05350 100644
--- a/src/connectedComponents/ConnectedPluginSwitch.js
+++ b/src/connectedComponents/ConnectedPluginSwitch.js
@@ -1,6 +1,7 @@
-import { connect } from 'react-redux';
-import PluginSwitch from './PluginSwitch.js';
import OHIF from 'ohif-core';
+import PluginSwitch from './PluginSwitch.js';
+import { commandsManager } from './../App.js';
+import { connect } from 'react-redux';
const { setLayout } = OHIF.redux.actions;
@@ -60,7 +61,7 @@ const mergeProps = (propsFromState, propsFromDispatch, ownProps) => {
icon: 'cube',
active: false,
onClick: () => {
- window.commandsManager.runCommand('axial', {}, 'vtk');
+ commandsManager.runCommand('axial');
},
},
{
@@ -68,7 +69,7 @@ const mergeProps = (propsFromState, propsFromDispatch, ownProps) => {
icon: 'cube',
active: false,
onClick: () => {
- window.commandsManager.runCommand('sagittal', {}, 'vtk');
+ commandsManager.runCommand('sagittal');
},
},
{
@@ -76,15 +77,14 @@ const mergeProps = (propsFromState, propsFromDispatch, ownProps) => {
icon: 'cube',
active: false,
onClick: () => {
- window.commandsManager.runCommand('coronal', {}, 'vtk');
+ commandsManager.runCommand('coronal');
},
},*/
{
- text: '2D MPR',
+ label: '2D MPR',
icon: 'cube',
- active: false,
onClick: () => {
- window.commandsManager.runCommand('mpr2d', {}, 'vtk');
+ commandsManager.runCommand('mpr2d');
},
},
];
diff --git a/src/connectedComponents/ConnectedToolbarRow.js b/src/connectedComponents/ConnectedToolbarRow.js
index b887ff9c4..66233bbc9 100644
--- a/src/connectedComponents/ConnectedToolbarRow.js
+++ b/src/connectedComponents/ConnectedToolbarRow.js
@@ -5,23 +5,11 @@ import {
import ToolbarRow from './ToolbarRow';
import { connect } from 'react-redux';
-
-const defaultPlugin = 'cornerstone';
+import { getActiveContexts } from './../store/layout/selectors.js';
const mapStateToProps = state => {
- const { layout, viewportSpecificData, activeViewportIndex } = state.viewports;
- const pluginInLayout =
- layout.viewports[activeViewportIndex] &&
- layout.viewports[activeViewportIndex].plugin;
- const pluginInViewportData =
- viewportSpecificData[activeViewportIndex] &&
- viewportSpecificData[activeViewportIndex].plugin;
- const pluginInActiveViewport =
- pluginInLayout || pluginInViewportData || defaultPlugin;
- // const extensionData = state.extensions[pluginInActiveViewport];
-
return {
- pluginId: pluginInActiveViewport,
+ activeContexts: getActiveContexts(state),
leftSidebarOpen: state.ui.leftSidebarOpen,
rightSidebarOpen: state.ui.rightSidebarOpen,
};
diff --git a/src/connectedComponents/ConnectedToolbarSection.js b/src/connectedComponents/ConnectedToolbarSection.js
deleted file mode 100644
index dc0f73bbc..000000000
--- a/src/connectedComponents/ConnectedToolbarSection.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import { connect } from 'react-redux';
-import { ToolbarSection } from 'react-viewerbase';
-import OHIF from 'ohif-core';
-
-const { setToolActive } = OHIF.redux.actions;
-
-const mapStateToProps = state => {
- const activeButton = state.tools.buttons.find(tool => tool.active === true);
-
- return {
- buttons: state.tools.buttons,
- activeCommand: activeButton && activeButton.command,
- };
-};
-
-const mapDispatchToProps = dispatch => {
- return {
- setToolActive: tool => {
- dispatch(setToolActive(tool.command));
- },
- };
-};
-
-const ConnectedToolbarSection = connect(
- mapStateToProps,
- mapDispatchToProps
-)(ToolbarSection);
-
-export default ConnectedToolbarSection;
diff --git a/src/connectedComponents/ConnectedViewerMain.js b/src/connectedComponents/ConnectedViewerMain.js
index c51e307f9..d0ee196e0 100644
--- a/src/connectedComponents/ConnectedViewerMain.js
+++ b/src/connectedComponents/ConnectedViewerMain.js
@@ -5,8 +5,6 @@ import { connect } from 'react-redux';
const {
setViewportSpecificData,
clearViewportSpecificData,
- // setToolActive,
- // setActiveViewportSpecificData,
} = OHIF.redux.actions;
const mapStateToProps = state => {
@@ -28,12 +26,6 @@ const mapDispatchToProps = dispatch => {
clearViewportSpecificData: () => {
dispatch(clearViewportSpecificData());
},
- // setToolActive: tool => {
- // dispatch(setToolActive(tool));
- // },
- // setActiveViewportSpecificData: viewport => {
- // dispatch(setActiveViewportSpecificData(viewport));
- // },
};
};
diff --git a/src/connectedComponents/ToolbarRow.js b/src/connectedComponents/ToolbarRow.js
index deda8d4c4..43a945c75 100644
--- a/src/connectedComponents/ToolbarRow.js
+++ b/src/connectedComponents/ToolbarRow.js
@@ -1,12 +1,14 @@
import './ToolbarRow.css';
import React, { Component } from 'react';
+import { RoundedButtonGroup, ToolbarButton } from 'react-viewerbase';
+import { commandsManager, extensionManager } from './../App.js';
+import ConnectedCineDialog from './ConnectedCineDialog';
import ConnectedLayoutButton from './ConnectedLayoutButton';
import ConnectedPluginSwitch from './ConnectedPluginSwitch.js';
-import OHIF from 'ohif-core';
+import { MODULE_TYPES } from 'ohif-core';
import PropTypes from 'prop-types';
-import { RoundedButtonGroup } from 'react-viewerbase';
class ToolbarRow extends Component {
static propTypes = {
@@ -14,7 +16,7 @@ class ToolbarRow extends Component {
rightSidebarOpen: PropTypes.bool.isRequired,
setLeftSidebarOpen: PropTypes.func,
setRightSidebarOpen: PropTypes.func,
- pluginId: PropTypes.string,
+ activeContexts: PropTypes.arrayOf(PropTypes.string).isRequired,
};
static defaultProps = {
@@ -22,6 +24,38 @@ class ToolbarRow extends Component {
rightSidebarOpen: false,
};
+ constructor(props) {
+ super(props);
+
+ const toolbarButtonDefinitions = _getVisibleToolbarButtons.call(this);
+ // TODO:
+ // If it's a tool that can be active... Mark it as active?
+ // - Tools that are on/off?
+ // - Tools that can be bound to multiple buttons?
+
+ // Normal ToolbarButtons...
+ // Just how high do we need to hoist this state?
+ // Why ToolbarRow instead of just Toolbar? Do we have any others?
+ this.state = {
+ toolbarButtons: toolbarButtonDefinitions,
+ activeButtons: [],
+ isCineDialogOpen: false,
+ };
+
+ this._handleBuiltIn = _handleBuiltIn.bind(this);
+ }
+
+ componentDidUpdate(prevProps) {
+ const activeContextsChanged =
+ prevProps.activeContexts !== this.props.activeContexts;
+
+ if (activeContextsChanged) {
+ this.setState({
+ toolbarButtons: _getVisibleToolbarButtons.call(this),
+ });
+ }
+ }
+
onLeftSidebarValueChanged = value => {
this.props.setLeftSidebarOpen(!!value);
};
@@ -55,44 +89,111 @@ class ToolbarRow extends Component {
? rightSidebarToggle[0].value
: null;
- const currentPluginId = this.props.pluginId;
+ const buttonComponents = _getButtonComponents.call(
+ this,
+ this.state.toolbarButtons,
+ this.state.activeButtons
+ );
- const { PLUGIN_TYPES, availablePlugins } = OHIF.plugins;
- const plugin = availablePlugins.find(entry => {
- return (
- entry.type === PLUGIN_TYPES.TOOLBAR && entry.id === currentPluginId
- );
- });
-
- let pluginComp;
- if (plugin) {
- const PluginComponent = plugin.component;
-
- pluginComp = ;
- }
+ const cineDialogContainerStyle = {
+ display: this.state.isCineDialogOpen ? 'block' : 'none',
+ position: 'absolute',
+ top: '82px',
+ zIndex: 999,
+ };
return (
-
-
-
+ <>
+
+
+
+
+ {buttonComponents}
+
+
+
+
+
- {pluginComp}
-
-
-
+ >
);
}
}
+/**
+ * Determine which extension buttons should be showing, if they're
+ * active, and what their onClick behavior should be.
+ */
+function _getButtonComponents(toolbarButtons, activeButtons) {
+ return toolbarButtons.map((button, index) => {
+ // TODO: If `button.buttons`, use `ExpandedToolMenu`
+ // I don't believe any extensions currently leverage this
+ return (
+
{
+ if (button.commandName) {
+ const options = Object.assign({ evt }, button.commandOptions);
+ commandsManager.runCommand(button.commandName, options);
+ }
+
+ // TODO: Use Types ENUM
+ // TODO: We can update this to be a `getter` on the extension to query
+ // For the active tools after we apply our updates?
+ if (button.type === 'setToolActive') {
+ this.setState({
+ activeButtons: [button.id],
+ });
+ } else if (button.type === 'builtIn') {
+ this._handleBuiltIn(button.options);
+ }
+ }}
+ isActive={activeButtons.includes(button.id)}
+ />
+ );
+ });
+}
+
+function _getVisibleToolbarButtons() {
+ const toolbarModules = extensionManager.modules[MODULE_TYPES.TOOLBAR];
+ const toolbarButtonDefinitions = [];
+
+ toolbarModules.forEach(extension => {
+ const { definitions, defaultContext } = extension.module;
+ definitions.forEach(definition => {
+ const context = definition.context || defaultContext;
+
+ if (this.props.activeContexts.includes(context)) {
+ toolbarButtonDefinitions.push(definition);
+ }
+ });
+ });
+
+ return toolbarButtonDefinitions;
+}
+
+function _handleBuiltIn({ behavior } = {}) {
+ if (behavior === 'CINE') {
+ this.setState({
+ isCineDialogOpen: !this.state.isCineDialogOpen,
+ });
+ }
+}
+
export default ToolbarRow;
diff --git a/src/connectedComponents/ViewerMain.js b/src/connectedComponents/ViewerMain.js
index f10d8e590..8e412def1 100644
--- a/src/connectedComponents/ViewerMain.js
+++ b/src/connectedComponents/ViewerMain.js
@@ -2,8 +2,7 @@ import './ViewerMain.css';
import { Component } from 'react';
import ConnectedLayoutManager from './ConnectedLayoutManager.js';
-// import { OHIF } from 'ohif-core';
-//
+import ConnectedToolContextMenu from './ConnectedToolContextMenu.js';
import PropTypes from 'prop-types';
import React from 'react';
@@ -20,15 +19,6 @@ class ViewerMain extends Component {
constructor(props) {
super(props);
- // Initialize hotkeys
- // new OHIF.HotkeysUtil('viewer', {
- // setViewportSpecificData: props.setViewportSpecificData,
- // clearViewportSpecificData: props.clearViewportSpecificData,
- // setToolActive: props.setToolActive,
- // setActiveViewportSpecificData: props.setActiveViewportSpecificData,
- // });
- // hotkeys.init();
-
this.state = {
displaySets: [],
};
@@ -139,7 +129,10 @@ class ViewerMain extends Component {
studies={this.props.studies}
viewportData={this.getViewportData()}
setViewportData={this.setViewportData}
- />
+ >
+ {/* Children to add to each viewport that support children */}
+
+
);
}
diff --git a/src/connectedComponents/ViewerRetrieveStudyData.js b/src/connectedComponents/ViewerRetrieveStudyData.js
index bf9f5a08b..8622f4bd4 100644
--- a/src/connectedComponents/ViewerRetrieveStudyData.js
+++ b/src/connectedComponents/ViewerRetrieveStudyData.js
@@ -1,9 +1,13 @@
import React, { Component } from 'react';
-import PropTypes from 'prop-types';
-import OHIF from 'ohif-core';
-import ConnectedViewer from './ConnectedViewer.js';
+import { metadata, studies, utils } from 'ohif-core';
-const { createDisplaySets } = OHIF.utils;
+import ConnectedViewer from './ConnectedViewer.js';
+import PropTypes from 'prop-types';
+import { extensionManager } from './../App.js';
+
+const { OHIFStudyMetadata } = metadata;
+const { retrieveStudiesMetadata } = studies;
+const { studyMetadataManager, updateMetaDataManager } = utils;
class ViewerRetrieveStudyData extends Component {
static propTypes = {
@@ -17,32 +21,55 @@ class ViewerRetrieveStudyData extends Component {
error: null,
};
- componentDidMount() {
+ async componentDidMount() {
// TODO: Avoid using timepoints here
//const params = { studyInstanceUids, seriesInstanceUids, timepointId, timepointsFilter={} };
const { studyInstanceUids, seriesInstanceUids, server } = this.props;
- const promise = OHIF.studies.retrieveStudiesMetadata(
- server,
- studyInstanceUids,
- seriesInstanceUids
- );
- // Render the viewer when the data is ready
- promise
- .then(studies => {
- const updatedStudies = createDisplaySets(studies);
+ try {
+ const studies = await retrieveStudiesMetadata(
+ server,
+ studyInstanceUids,
+ seriesInstanceUids
+ );
- this.setState({
- studies: updatedStudies,
- });
- })
- .catch(error => {
- this.setState({
- error: true,
- });
+ // Render the viewer when the data is ready
+ // TODO: CLEAR THIS SOMEWHERE ELSE
+ studyMetadataManager.purge();
- throw new Error(error);
+ // Map studies to new format, update metadata manager?
+ const updatedStudies = studies.map(study => {
+ const studyMetadata = new OHIFStudyMetadata(
+ study,
+ study.studyInstanceUid
+ );
+ const sopClassHandlerModules =
+ extensionManager.modules['sopClassHandlerModule'];
+
+ study.displaySets =
+ study.displaySets ||
+ studyMetadata.createDisplaySets(sopClassHandlerModules);
+ studyMetadata.setDisplaySets(study.displaySets);
+
+ // Updates WADO-RS metaDataManager
+ updateMetaDataManager(study);
+
+ studyMetadataManager.add(studyMetadata);
+
+ return study;
});
+
+ this.setState({
+ studies: updatedStudies,
+ });
+ } catch (err) {
+ this.setState({
+ error: true,
+ });
+
+ // TODO: Handle gracefully instead of throwing?
+ throw new Error(err);
+ }
}
render() {
diff --git a/src/lib/jumpToRowItem.js b/src/lib/jumpToRowItem.js
index fb05835e1..f9edbfd60 100644
--- a/src/lib/jumpToRowItem.js
+++ b/src/lib/jumpToRowItem.js
@@ -1,4 +1,7 @@
-import { OHIF } from 'ohif-core';
+import { measurements, utils } from 'ohif-core';
+
+const { MeasurementApi } = measurements;
+const { studyMetadataManager } = utils;
// TODO: Move this function to OHIF itself so we can use it on the OHIF measurment table (when it is finished)
@@ -47,9 +50,7 @@ export default function jumpToRowItem(
let measurement = dataAtThisTimepoint;
- const { tool } = OHIF.measurements.MeasurementApi.getToolConfiguration(
- toolType
- );
+ const { tool } = MeasurementApi.getToolConfiguration(toolType);
if (options.childToolKey) {
measurement = dataAtThisTimepoint[options.childToolKey];
} else if (Array.isArray(tool.childTools)) {
@@ -79,7 +80,7 @@ export default function jumpToRowItem(
return;
}
- const study = OHIF.utils.studyMetadataManager.get(data.studyInstanceUid);
+ const study = studyMetadataManager.get(data.studyInstanceUid);
if (!study) {
throw new Error('Study not found.');
}
diff --git a/src/routes/StandaloneRouting.js b/src/routes/StandaloneRouting.js
index 884261d78..622f68625 100644
--- a/src/routes/StandaloneRouting.js
+++ b/src/routes/StandaloneRouting.js
@@ -1,10 +1,14 @@
import React, { Component } from 'react';
-import PropTypes from 'prop-types';
-import qs from 'querystring';
-import Viewer from '../connectedComponents/Viewer';
-import OHIF from 'ohif-core';
+import { log, metadata, studies, utils } from 'ohif-core';
-const { createDisplaySets } = OHIF.utils;
+import PropTypes from 'prop-types';
+import Viewer from '../connectedComponents/Viewer';
+import { extensionManager } from './../App.js';
+import qs from 'querystring';
+
+const { OHIFStudyMetadata } = metadata;
+const { retrieveStudiesMetadata } = studies;
+const { studyMetadataManager, updateMetaDataManager } = utils;
class StandaloneRouting extends Component {
state = {
@@ -31,7 +35,7 @@ class StandaloneRouting extends Component {
// Add event listeners for request failure
oReq.addEventListener('error', error => {
- OHIF.log.warn('An error occurred while retrieving the JSON data');
+ log.warn('An error occurred while retrieving the JSON data');
reject(error);
});
@@ -41,11 +45,11 @@ class StandaloneRouting extends Component {
// Parse the response content
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseText
if (!oReq.responseText) {
- OHIF.log.warn('Response was undefined');
+ log.warn('Response was undefined');
reject(new Error('Response was undefined'));
}
- OHIF.log.info(JSON.stringify(oReq.responseText, null, 2));
+ log.info(JSON.stringify(oReq.responseText, null, 2));
const data = JSON.parse(oReq.responseText);
if (data.servers && query.studyInstanceUids) {
@@ -55,20 +59,18 @@ class StandaloneRouting extends Component {
const studyInstanceUids = query.studyInstanceUids.split(';');
const seriesInstanceUids = [];
- OHIF.studies
- .retrieveStudiesMetadata(
- server,
- studyInstanceUids,
- seriesInstanceUids
- )
- .then(
- studies => {
- resolve(studies);
- },
- error => {
- reject(error);
- }
- );
+ retrieveStudiesMetadata(
+ server,
+ studyInstanceUids,
+ seriesInstanceUids
+ ).then(
+ studies => {
+ resolve(studies);
+ },
+ error => {
+ reject(error);
+ }
+ );
} else {
resolve(data.studies);
}
@@ -77,7 +79,7 @@ class StandaloneRouting extends Component {
// Open the Request to the server for the JSON data
// In this case we have a server-side route called /api/
// which responds to GET requests with the study data
- OHIF.log.info(`Sending Request to: ${url}`);
+ log.info(`Sending Request to: ${url}`);
oReq.open('GET', url);
oReq.setRequestHeader('Accept', 'application/json');
@@ -86,18 +88,39 @@ class StandaloneRouting extends Component {
});
}
- componentDidMount() {
- const query = qs.parse(this.props.location.search);
- StandaloneRouting.parseQueryAndFetchStudies(query).then(
- studies => {
- const updatedStudies = createDisplaySets(studies);
+ async componentDidMount() {
+ try {
+ const query = qs.parse(this.props.location.search);
+ const studies = await StandaloneRouting.parseQueryAndFetchStudies(query);
- this.setState({ studies: updatedStudies });
- },
- error => {
- this.setState({ error });
- }
- );
+ studyMetadataManager.purge();
+
+ // Map studies to new format, update metadata manager?
+ const updatedStudies = studies.map(study => {
+ const studyMetadata = new OHIFStudyMetadata(
+ study,
+ study.studyInstanceUid
+ );
+ const sopClassHandlerModules =
+ extensionManager.modules['sopClassHandlerModule'];
+
+ study.displaySets =
+ study.displaySets ||
+ studyMetadata.createDisplaySets(sopClassHandlerModules);
+ studyMetadata.setDisplaySets(study.displaySets);
+
+ // Updates WADO-RS metaDataManager
+ updateMetaDataManager(study);
+
+ studyMetadataManager.add(studyMetadata);
+
+ return study;
+ });
+
+ this.setState({ studies: updatedStudies });
+ } catch (error) {
+ this.setState({ error });
+ }
}
render() {
diff --git a/src/store/index.js b/src/store/index.js
index 04c81a2d6..baa63385e 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -1,18 +1,28 @@
-import { combineReducers, createStore } from 'redux';
+import { applyMiddleware, combineReducers, createStore } from 'redux';
+// import { createLogger } from 'redux-logger';
import layoutReducers from './layout/reducers.js';
import { reducer as oidcReducer } from 'redux-oidc';
import { redux } from 'ohif-core';
+import thunkMiddleware from 'redux-thunk';
// Combine our ohif-core, ui, and oidc reducers
// Set init data, using values found in localStorage
const { reducers, localStorage } = redux;
+// const loggerMiddleware = createLogger();
reducers.ui = layoutReducers;
reducers.oidc = oidcReducer;
-const combined = combineReducers(reducers);
-const store = createStore(combined, localStorage.loadState());
+const rootReducer = combineReducers(reducers);
+const store = createStore(
+ rootReducer,
+ localStorage.loadState(), // preloadedState
+ applyMiddleware(
+ thunkMiddleware // Lets us dispatch() functions
+ // loggerMiddleware // neat middleware that logs actions
+ )
+);
// When the store's preferences change,
// Update our cached preferences in localStorage
diff --git a/src/store/layout/actions.js b/src/store/layout/actions.js
index 319628c08..2b08800b1 100644
--- a/src/store/layout/actions.js
+++ b/src/store/layout/actions.js
@@ -1,18 +1,3 @@
-export const addActiveContext = state => ({
- type: 'ADD_ACTIVE_CONTEXT',
- state,
-});
-
-export const removeActiveContext = state => ({
- type: 'REMOVE_ACTIVE_CONTEXT',
- state,
-});
-
-export const clearActiveContexts = state => ({
- type: 'CLEAR_ACTIVE_CONTEXTS',
- state,
-});
-
export const setLeftSidebarOpen = state => ({
type: 'SET_LEFT_SIDEBAR_OPEN',
state,
@@ -24,10 +9,6 @@ export const setRightSidebarOpen = state => ({
});
const actions = {
- addActiveContext,
- removeActiveContext,
- clearActiveContexts,
- //
setLeftSidebarOpen,
setRightSidebarOpen,
};
diff --git a/src/store/layout/reducers.js b/src/store/layout/reducers.js
index 6659d72a7..b292074ef 100644
--- a/src/store/layout/reducers.js
+++ b/src/store/layout/reducers.js
@@ -3,27 +3,10 @@ const defaultState = {
rightSidebarOpen: false,
labelling: {},
contextMenu: {},
- activeContexts: [],
};
const ui = (state = defaultState, action) => {
switch (action.type) {
- // ~ ACTIVE CONTEXTS
- // https://redux.js.org/recipes/structuring-reducers/immutable-update-patterns#inserting-and-removing-items-in-arrays
- case 'ADD_ACTIVE_CONTEXT': {
- const shallowCopy = Object.assign({}, state);
- shallowCopy.activeContexts = [...shallowCopy.activeContexts, action.item];
- return shallowCopy;
- }
- case 'REMOVE_ACTIVE_CONTEXT': {
- const shallowCopy = Object.assign({}, state);
- shallowCopy.activeContexts = shallowCopy.activeContexts.filter(
- item => item !== action.item
- );
- return shallowCopy;
- }
- case 'CLEAR_ACTIVE_CONTEXTS':
- return Object.assign({}, state, { activeContexts: [] });
// ~ SIDEBAR
case 'SET_LEFT_SIDEBAR_OPEN':
return Object.assign({}, state, { leftSidebarOpen: action.state });
diff --git a/src/store/layout/selectors.js b/src/store/layout/selectors.js
new file mode 100644
index 000000000..50a8ddb2e
--- /dev/null
+++ b/src/store/layout/selectors.js
@@ -0,0 +1,28 @@
+import { createSelector } from 'reselect';
+
+const getActiveViewportIndex = state => state.viewports.activeViewportIndex;
+const getLayoutViewports = state => state.viewports.layout.viewports;
+const getViewportSpecificData = state => state.viewports.viewportSpecificData;
+
+/**
+ * Think of this as a computed getter for our store. It lets us watch parts of
+ * our redux state, and only update/recalculate when those values change.
+ */
+export const getActiveContexts = createSelector(
+ [getActiveViewportIndex, getLayoutViewports, getViewportSpecificData],
+ (activeViewportIndex, layoutViewports, viewportSpecificData) => {
+ const activeContexts = ['VIEWER'];
+ const activeLayoutViewport = layoutViewports[activeViewportIndex] || {};
+ const activeViewportSpecificData =
+ viewportSpecificData[activeViewportIndex] || {};
+ const activeViewportPluginName =
+ activeLayoutViewport.plugin || activeViewportSpecificData.plugin;
+
+ if (activeViewportPluginName) {
+ const activeViewportExtension = `ACTIVE_VIEWPORT::${activeViewportPluginName.toUpperCase()}`;
+ activeContexts.push(activeViewportExtension);
+ }
+
+ return activeContexts;
+ }
+);
diff --git a/src/utils/getDefaultToolbarButtons.js b/src/utils/getDefaultToolbarButtons.js
deleted file mode 100644
index 408f84c45..000000000
--- a/src/utils/getDefaultToolbarButtons.js
+++ /dev/null
@@ -1,60 +0,0 @@
-export default function() {
- return [
- {
- command: 'StackScroll',
- type: 'tool',
- text: 'Stack Scroll',
- icon: 'bars',
- active: false,
- },
- {
- command: 'Zoom',
- type: 'tool',
- text: 'Zoom',
- icon: 'search-plus',
- active: false,
- },
- {
- command: 'Wwwc',
- type: 'tool',
- text: 'Levels',
- icon: 'level',
- active: true,
- },
- {
- command: 'Pan',
- type: 'tool',
- text: 'Pan',
- icon: 'arrows',
- active: false,
- },
- {
- command: 'Length',
- type: 'tool',
- text: 'Length',
- icon: 'measure-temp',
- active: false,
- },
- /*{
- command: 'Annotate',
- type: 'tool',
- text: 'Annotate',
- icon: `icon-tools-measure-non-target`,
- active: false
- },*/
- {
- command: 'Angle',
- type: 'tool',
- text: 'Angle',
- icon: 'angle-left',
- active: false,
- },
- {
- command: 'reset',
- type: 'command',
- text: 'Reset',
- icon: 'reset',
- active: false,
- },
- ];
-}
diff --git a/src/utils/getDefaultToolbarButtons.test.js b/src/utils/getDefaultToolbarButtons.test.js
deleted file mode 100644
index 8f59f53fa..000000000
--- a/src/utils/getDefaultToolbarButtons.test.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import getDefaultToolbarButtons from './getDefaultToolbarButtons.js';
-
-describe('getDefaultToolbarButtons.js', () => {
- it('returns a non-empty array', () => {
- const buttons = getDefaultToolbarButtons();
-
- expect(buttons.length).toBeGreaterThan(0);
- });
-});
diff --git a/src/utils/index.js b/src/utils/index.js
index 22478739a..efcc1628c 100644
--- a/src/utils/index.js
+++ b/src/utils/index.js
@@ -1,9 +1,4 @@
-import getDefaultToolbarButtons from './getDefaultToolbarButtons.js';
import getUserManagerForOpenIdConnectClient from './getUserManagerForOpenIdConnectClient.js';
import initWebWorkers from './initWebWorkers.js';
-export {
- getDefaultToolbarButtons,
- getUserManagerForOpenIdConnectClient,
- initWebWorkers,
-};
+export { getUserManagerForOpenIdConnectClient, initWebWorkers };
diff --git a/src/utils/index.test.js b/src/utils/index.test.js
index c164ab30e..03f96fe64 100644
--- a/src/utils/index.test.js
+++ b/src/utils/index.test.js
@@ -5,11 +5,7 @@ describe('utils', () => {
const utilExports = Object.keys(utils).sort();
expect(utilExports).toEqual(
- [
- 'getDefaultToolbarButtons',
- 'getUserManagerForOpenIdConnectClient',
- 'initWebWorkers',
- ].sort()
+ ['getUserManagerForOpenIdConnectClient', 'initWebWorkers'].sort()
);
});
});
diff --git a/yarn.lock b/yarn.lock
index b0b92cfd1..ef0f44b3c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1435,29 +1435,45 @@
universal-user-agent "^2.0.0"
url-template "^2.0.8"
-"@ohif/extension-cornerstone@0.0.36":
- version "0.0.36"
- resolved "https://registry.yarnpkg.com/@ohif/extension-cornerstone/-/extension-cornerstone-0.0.36.tgz#a09a01d152bb9f850698b537b02355456425f8d1"
- integrity sha512-FrR9L74vqjNsW2wOSHeDXQo/twJAf/kM0awCn2/zGXN4tNxEaZRq56gfij86CH0OBGl1Wdzb8Zl6xe0JCtsNrA==
+"@ohif/extension-cornerstone@0.0.37":
+ version "0.0.37"
+ resolved "https://registry.yarnpkg.com/@ohif/extension-cornerstone/-/extension-cornerstone-0.0.37.tgz#d9d31409ffbc773dde17767daa02b87f461cf11a"
+ integrity sha512-090WPGXOYIxZjQe0mIM7SipgR3ggUZpbtWpwg7huWC0PQObIM3Juy4L8mtss23OKaKsmrmVxUaFc5NRQhs+Z+w==
dependencies:
"@babel/runtime" "^7.2.0"
classnames "^2.2.6"
lodash.throttle "^4.1.1"
react-cornerstone-viewport "0.1.30"
-"@ohif/extension-dicom-microscopy@0.0.6":
- version "0.0.6"
- resolved "https://registry.yarnpkg.com/@ohif/extension-dicom-microscopy/-/extension-dicom-microscopy-0.0.6.tgz#18e0c128689695a7af505bc3dd7ede97df7f8be2"
- integrity sha512-5On3GdZgeyMse2CKI0sbxJJ269IqlFXZ0Wi+8+D9lsp0Wdt2AOx15ZmmFA9MJ6GGluMHNrrTY2gZBwLyLUZyRw==
+"@ohif/extension-dicom-html@0.0.3":
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/@ohif/extension-dicom-html/-/extension-dicom-html-0.0.3.tgz#1d085f603379599cf07801ec003e3d5050e2d659"
+ integrity sha512-S+Mg9OFHNvllDDza55y4/NmBV1bFJ+NLbpcnsw45QyfgT3KAg8v/8ht1QYM9IcBGqhxMTJs8OqBuJI9sAiTWlw==
+ dependencies:
+ "@babel/runtime" "^7.2.0"
+
+"@ohif/extension-dicom-microscopy@0.0.7":
+ version "0.0.7"
+ resolved "https://registry.yarnpkg.com/@ohif/extension-dicom-microscopy/-/extension-dicom-microscopy-0.0.7.tgz#2ac78c2eef8915e43a81e82ff895c251ced0b441"
+ integrity sha512-QXf7+YE297owIWBMGJJsJwbMk6bfmmu0fBJQhYFwXQYBOToSiabdr21PBxNADf88ZC1kiBcULOcTBRypJtd31g==
dependencies:
"@babel/runtime" "^7.2.0"
classnames "^2.2.6"
dicom-microscopy-viewer "^0.4.3"
-"@ohif/extension-vtk@0.0.6":
- version "0.0.6"
- resolved "https://registry.yarnpkg.com/@ohif/extension-vtk/-/extension-vtk-0.0.6.tgz#a4100963d87f268190ecac7784ff131bd4350b20"
- integrity sha512-IwXIpAQEOSRbPNXW0B6XfBMrp3k3LvdD/uyrOeEjI35hVjABf/9aGwqMk9wiw672AN26w/eZ04uXeKjRBsLzsQ==
+"@ohif/extension-dicom-pdf@0.0.7":
+ version "0.0.7"
+ resolved "https://registry.yarnpkg.com/@ohif/extension-dicom-pdf/-/extension-dicom-pdf-0.0.7.tgz#ba80a77235d43876e25485e1a964f36ebf104b94"
+ integrity sha512-uOevtxH6Vm2p+2xgo+ER3+oV1zfnUqHYoeqrICaKP3PKXGcVanWFE8W/RWiNZ+PS2/LNpSjJyLfuSxwZ3IBUVw==
+ dependencies:
+ "@babel/runtime" "^7.2.0"
+ classnames "^2.2.6"
+ lodash.isequal "^4.5.0"
+
+"@ohif/extension-vtk@0.0.7":
+ version "0.0.7"
+ resolved "https://registry.yarnpkg.com/@ohif/extension-vtk/-/extension-vtk-0.0.7.tgz#5bad8e35cae65957b467a12cc17e027ce80ad40a"
+ integrity sha512-yEdtnk7ImIoM3YrDkXXFo9ClJAXbd3rc9si3GlrOY6ImeWtwTf5LvcHG3QCe1iIfEJ2Q8wkGfERddbSw3joIYQ==
dependencies:
"@babel/runtime" "^7.4.5"
"@ohif/i18n" "0.0.4"
@@ -4503,6 +4519,11 @@ dedent@0.7.0, dedent@^0.7.0:
resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=
+deep-diff@^0.3.5:
+ version "0.3.8"
+ resolved "https://registry.yarnpkg.com/deep-diff/-/deep-diff-0.3.8.tgz#c01de63efb0eec9798801d40c7e0dae25b582c84"
+ integrity sha1-wB3mPvsO7JeYgB1Ax+Da4ltYLIQ=
+
deep-equal@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
@@ -10266,10 +10287,10 @@ octokit-pagination-methods@^1.1.0:
resolved "https://registry.yarnpkg.com/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz#cf472edc9d551055f9ef73f6e42b4dbb4c80bea4"
integrity sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ==
-ohif-core@0.5.9:
- version "0.5.9"
- resolved "https://registry.yarnpkg.com/ohif-core/-/ohif-core-0.5.9.tgz#337835c82571bdc4935210273a6018c3af872adf"
- integrity sha512-TvA/THiTpBnerRbv4FJlfwSMSyb4Tkn40ud14FP6JxLUQgCtLsTsaFhXIFBwZvBR/qVJwIlDluMxj/vqobCwkQ==
+ohif-core@0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/ohif-core/-/ohif-core-0.6.0.tgz#9fea32d8d10da84b9030d2e4f76b30e431e14ac2"
+ integrity sha512-2Z/HTRZ21i7w056MifH1k0y4brhrZSUsmeqbMcPLSh1cztRGnLQBamBZ08SzWvktcNxLDuwJI9zNDkJ8Gw4Idw==
dependencies:
"@babel/runtime" "^7.2.0"
ajv "^6.10.0"
@@ -10280,22 +10301,6 @@ ohif-core@0.5.9:
mousetrap "^1.6.3"
validate.js "^0.12.0"
-ohif-dicom-html-extension@^0.0.2:
- version "0.0.2"
- resolved "https://registry.yarnpkg.com/ohif-dicom-html-extension/-/ohif-dicom-html-extension-0.0.2.tgz#5dd80836ee8f12f6ddf6de2b88c72af96d8c347b"
- integrity sha512-7/YkaKrgnydiypFl39mvWO5vxCoGecudkdyCFedgDnG10UvkDF4nBcgNvoBupwBtGKYhXTfqye6fPWxQO0NWyw==
- dependencies:
- "@babel/runtime" "^7.2.0"
-
-ohif-dicom-pdf-extension@^0.0.6:
- version "0.0.6"
- resolved "https://registry.yarnpkg.com/ohif-dicom-pdf-extension/-/ohif-dicom-pdf-extension-0.0.6.tgz#5c1c1bf955d160dda01c36c4ed899d8e65384d63"
- integrity sha512-MRBDnC78itsos3c8QMKjgaFp8tmXyGIq5qVLREr//osqCYirhWQbCFJv73eYR5+bRCdJfUMMpvnDSChFIhcT6A==
- dependencies:
- "@babel/runtime" "^7.2.0"
- classnames "^2.2.6"
- lodash.isequal "^4.5.0"
-
oidc-client@1.7.x:
version "1.7.1"
resolved "https://registry.yarnpkg.com/oidc-client/-/oidc-client-1.7.1.tgz#8b9d8d50fd7f878968b1cda17712c1747eef9a54"
@@ -12408,10 +12413,10 @@ react-transition-group@^2.0.0, react-transition-group@^2.2.0:
prop-types "^15.6.2"
react-lifecycles-compat "^3.0.4"
-react-viewerbase@0.9.0:
- version "0.9.0"
- resolved "https://registry.yarnpkg.com/react-viewerbase/-/react-viewerbase-0.9.0.tgz#947ab61bf32e1d58836a637403d128247e175d2e"
- integrity sha512-VeOGzno5fg9A0Ttx+O3CQ8KXPr1XbdEOVbA+JiLwcuycX3CmDsqLzODsjeXb8npfXDbQA+n/ZPCyxsB7JDEBlA==
+react-viewerbase@0.10.0:
+ version "0.10.0"
+ resolved "https://registry.yarnpkg.com/react-viewerbase/-/react-viewerbase-0.10.0.tgz#4ac07649325759f8a58fc3be50dea4d1db8f13f8"
+ integrity sha512-pUt+HUGoEkDnVhxcg+gsoRzegEPVpsMPH8cnJINRoaATqbxc0jbt1N+3fTNTbPMMKZYMxC99L5bQ6OQ1QF+3qw==
dependencies:
"@babel/runtime" "7.2.0"
"@ohif/i18n" "^0.0.4"
@@ -12710,6 +12715,13 @@ redeyed@~2.1.0:
dependencies:
esprima "~4.0.0"
+redux-logger@^3.0.6:
+ version "3.0.6"
+ resolved "https://registry.yarnpkg.com/redux-logger/-/redux-logger-3.0.6.tgz#f7555966f3098f3c88604c449cf0baf5778274bf"
+ integrity sha1-91VZZvMJjzyIYExEnPC69XeCdL8=
+ dependencies:
+ deep-diff "^0.3.5"
+
redux-oidc@3.1.x:
version "3.1.2"
resolved "https://registry.yarnpkg.com/redux-oidc/-/redux-oidc-3.1.2.tgz#31a771b0e05a65879626262e1e63ba70a0936ffd"
@@ -12717,6 +12729,11 @@ redux-oidc@3.1.x:
optionalDependencies:
immutable ">=3.6.0"
+redux-thunk@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622"
+ integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==
+
redux@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.1.tgz#436cae6cc40fbe4727689d7c8fae44808f1bfef5"
@@ -13028,6 +13045,11 @@ requires-port@^1.0.0:
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
+reselect@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7"
+ integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==
+
reserved-words@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/reserved-words/-/reserved-words-0.1.2.tgz#00a0940f98cd501aeaaac316411d9adc52b31ab1"