[React] Integrating UserPreferences + Hotkeys (#332)

* User Preferences - basic integration

* wip user prefs

* Creating ConnectedHeader

* Removing old UserPreferences

* Reverting studylistwithdata

* Initial hotkeys handler migration

* Setting keys after save

* Getting hotkeys from redux

* Adding windowslevel preset listeners

* Refactoring - moving hotkeys setup to ohif-core-hotkeysUtil

* Using hotkeysUtil method on userPreferences save

* Using context in the user preferences

* Adding redux store into localstorage

* Hotkeys - Fixing onResetToDefaults

* Mmoving from OHIFViewer-react to ohif-viewer
This commit is contained in:
Thiago Maltempi 2019-01-31 05:55:05 -02:00 committed by Erik Ziegler
parent fbcc4fcf40
commit 8a3056b9f0
26 changed files with 24557 additions and 448 deletions

23768
OHIFViewer-react/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -27,6 +27,8 @@ class App extends Component {
static propTypes = {
history: PropTypes.object.isRequired,
user: PropTypes.object,
userManager: PropTypes.object,
location: PropTypes.object,
}
componentDidMount() {
@ -44,26 +46,26 @@ class App extends Component {
const userNotLoggedIn = userManager && (!user || user.expired);
if (userNotLoggedIn) {
const pathname = this.props.location.pathname;
const pathname = this.props.location.pathname;
if (pathname !== '/callback') {
sessionStorage.setItem('ohif-redirect-to', pathname);
}
if (pathname !== '/callback') {
sessionStorage.setItem('ohif-redirect-to', pathname);
}
return (
<Switch>
<Route exact path="/silent-refresh.html" onEnter={reload} />
<Route exact path="/logout-redirect.html" onEnter={reload} />
<Route path="/callback" render={
() => <CallbackPage userManager={userManager}/>
}/>
<Route component={() => {
userManager.signinRedirect();
return (
<Switch>
<Route exact path="/silent-refresh.html" onEnter={reload} />
<Route exact path="/logout-redirect.html" onEnter={reload} />
<Route path="/callback" render={
() => <CallbackPage userManager={userManager} />
} />
<Route component={() => {
userManager.signinRedirect();
return null;
}}/>
</Switch>
)
return null;
}} />
</Switch>
)
}
return (
@ -97,6 +99,13 @@ class App extends Component {
path="/IHEInvokeImageDisplay"
component={IHEInvokeImageDisplay}
/>
<Route path="/silent-refresh.html" onEnter={reload} />
<Route path="/logout-redirect.html" onEnter={reload} />
<Route exact path='/login' component={() => {
userManager.signinRedirect();
}}
/>
<Route path="/callback" component={CallbackPage} />
<Route render={() =>
<div> Sorry, this page does not exist. </div>}
/>

View File

@ -0,0 +1,24 @@
import { connect } from 'react-redux';
import Header from './Header.js';
import { setUserPreferencesModalOpen } from '../../redux/actions.js';
const mapStateToProps = state => {
return {
isOpen: state.ui.userPreferencesModalOpen,
};
};
const mapDispatchToProps = dispatch => {
return {
openUserPreferencesModal: () => {
dispatch(setUserPreferencesModalOpen(true))
}
};
};
const ConnectedHeader = connect(
mapStateToProps,
mapDispatchToProps
)(Header);
export default ConnectedHeader;

View File

@ -1,22 +1,50 @@
import React from 'react';
import React, { Component } from "react";
import PropTypes from 'prop-types';
import { Link, withRouter } from 'react-router-dom';
import { Dropdown } from "react-viewerbase";
import './Header.css';
import list from './HeaderMenuList.json';
//import Icons from "../../images/icons.svg";
import ConnectedUserPreferencesModal from "../../connectedComponents/ConnectedUserPreferencesModal";
const Icons = '/icons.svg';
function Header({ home, location }) {
const { state } = location
class Header extends Component {
return (
<div className={`entry-header ${home ? 'header-big' : ''}`}>
static propTypes = {
home: PropTypes.bool.isRequired,
location: PropTypes.object,
openUserPreferencesModal: PropTypes.func,
};
static defaultProps = {
home: true
};
constructor(props) {
super(props);
this.state = {
userPreferencesOpen: false,
};
this.options = [
{
title: 'Preferences ',
icon: 'fa fa-user',
onClick: this.props.openUserPreferencesModal,
},
{
title: 'About',
icon: 'fa fa-info',
link: 'http://ohif.org',
}
];
}
render() {
return (<div className={`entry-header ${this.props.home ? 'header-big' : ''}`}>
<div className='header-left-box'>
{
state && state.studyLink &&
<Link to={state.studyLink} className="header-btn header-viewerLink">
this.props.location && this.props.location.studyLink &&
<Link to={this.props.location.studyLink} className="header-btn header-viewerLink">
Back to Viewer
</Link>
}
@ -28,10 +56,10 @@ function Header({ home, location }) {
<div className="header-logo-text">Open Health Imaging Foundation</div>
</a>
{!home &&
{!this.props.home &&
<Link className='header-btn header-studyListLinkSection' to={{
pathname: "/",
state: { studyLink: location.pathname }
state: { studyLink: this.props.location.pathname }
}}>Study list</Link>
}
</div>
@ -39,26 +67,19 @@ function Header({ home, location }) {
<div className="header-menu">
<span className="research-use">
INVESTIGATIONAL USE ONLY
INVESTIGATIONAL USE ONLY
</span>
<Dropdown
title='Options'
list={list}
list={this.options}
align='right'
/>
<ConnectedUserPreferencesModal />
</div>
</div>
)
);
}
}
Header.propTypes = {
home: PropTypes.bool.isRequired,
location: PropTypes.object.isRequired
};
Header.defaultProps = {
home: true
};
export default withRouter(Header)

View File

@ -0,0 +1,15 @@
import UserPreferences from "../UserPreferences/UserPreferences";
export default [
{
"title": "Preferences",
"icon": "fa fa-user",
"onClick": UserPreferences,
"state": { "modal": true }
},
{
"title": "About",
"icon": "fa fa-info",
"link": "http://ohif.org"
}
];

View File

@ -1,12 +0,0 @@
[
{
"title": "Preferences",
"icon": "fa fa-user",
"link": "http://www.google.com"
},
{
"title": "About",
"icon": "fa fa-info",
"link": "http://ohif.org"
}
]

View File

@ -0,0 +1,44 @@
import { connect } from 'react-redux';
import { UserPreferencesModal } from 'react-viewerbase';
import OHIF from 'ohif-core';
import { setUserPreferencesModalOpen } from '../redux/actions.js';
import cloneDeep from 'lodash.clonedeep';
const { setUserPreferences } = OHIF.redux.actions;
const mapStateToProps = state => {
const contextName = window.store.getState().commandContext.context;
return {
isOpen: state.ui.userPreferencesModalOpen,
windowLevelData: state.preferences[contextName] ? state.preferences[contextName].windowLevelData : {},
hotKeysData: state.preferences[contextName] ? state.preferences[contextName].hotKeysData : {},
};
};
const mapDispatchToProps = dispatch => {
return {
onCancel: () => {
dispatch(setUserPreferencesModalOpen(false));
},
onSave: data => {
const contextName = window.store.getState().commandContext.context;
const preferences = cloneDeep(window.store.getState().preferences)
preferences[contextName] = data;
dispatch(setUserPreferences(preferences));
dispatch(setUserPreferencesModalOpen(false));
OHIF.hotkeysUtil.setHotkeys(data.hotKeysData);
},
onResetToDefaults: () => {
dispatch(setUserPreferences());
dispatch(setUserPreferencesModalOpen(false));
OHIF.hotkeysUtil.setHotkeys();
},
};
};
const ConnectedUserPreferencesModal = connect(
mapStateToProps,
mapDispatchToProps
)(UserPreferencesModal);
export default ConnectedUserPreferencesModal;

View File

@ -2,12 +2,12 @@ import React, { Component } from "react";
import PropTypes from "prop-types";
//import { CineDialog } from 'react-viewerbase';
import Header from '../components/Header'
import ConnectedFlexboxLayout from './ConnectedFlexboxLayout.js';
import ConnectedToolbarRow from './ConnectedToolbarRow';
import ConnectedStudyLoadingMonitor from './ConnectedStudyLoadingMonitor.js';
import StudyPrefetcher from '../components/StudyPrefetcher.js';
import './Viewer.css';
import ConnectedHeader from "../components/Header/ConnectedHeader";
/**
* Inits OHIF Hanging Protocol's onReady.
@ -52,7 +52,7 @@ class Viewer extends Component {
render() {
return (<>
<Header home={false}/>
<ConnectedHeader home={false} />
<div className='viewerDialogs'>
</div>
<div id="viewer" className='Viewer'>

View File

@ -14,6 +14,11 @@ class ViewerMain extends Component {
studies: PropTypes.array.isRequired
};
constructor(props) {
super(props);
OHIF.hotkeysUtil.setup('viewer');
}
getDisplaySets(studies) {
const displaySets = [];
studies.forEach((study) => {
@ -51,7 +56,7 @@ class ViewerMain extends Component {
});
}
setViewportData = ({viewportIndex, item}) => {
setViewportData = ({ viewportIndex, item }) => {
// TODO: Replace this with mapDispatchToProps call
// if we decide to put viewport info into redux

View File

@ -8,6 +8,7 @@ import OHIF from 'ohif-core';
import './config';
import ui from './redux/ui.js';
import App from './App.js';
import { loadState, saveState } from './redux/localStorageState.js';
import OHIFCornerstoneViewportPlugin from "./connectedComponents/OHIFCornerstoneViewportPlugin/OHIFCornerstoneViewportPlugin.js";
//import ConnectedExampleViewportPlugin from './components/ConnectedExampleViewportPlugin.js';
@ -15,13 +16,20 @@ import OHIFCornerstoneViewportPlugin from "./connectedComponents/OHIFCornerstone
import OHIFDicomPDFViewportPlugin from './connectedComponents/OHIFDicomPDFViewportPlugin/OHIFDicomPDFViewportPlugin.js';
import OHIFDicomPDFSopClassHandlerPlugin from './connectedComponents/OHIFDicomPDFViewportPlugin/OHIFDicomPDFSopClassHandlerPlugin.js';
const reducers = OHIF.redux.reducers;
let reducers = OHIF.redux.reducers;
reducers.ui = ui;
reducers.oidc = oidcReducer;
const Icons = '/icons.svg';
const combined = combineReducers(reducers)
const store = createStore(combined);
const combined = combineReducers(reducers);
const store = createStore(combined, loadState());
// Subscribing store to save state of persistable data
store.subscribe(() => {
saveState({
preferences: store.getState().preferences,
});
});
// Note: Run your build like this:
// REACT_APP_CONFIG=$(cat ../config-react/ccc.json) yarn start
@ -61,69 +69,69 @@ if (config && config.servers) {
}
const defaultButtons = [
{
command: 'StackScroll',
type: 'tool',
text: 'Stack Scroll',
svgUrl: `${Icons}#icon-tools-stack-scroll`,
active: false
},
{
command: 'Zoom',
type: 'tool',
text: 'Zoom',
svgUrl: `${Icons}#icon-tools-zoom`,
active: false
},
{
command: 'Wwwc',
type: 'tool',
text: 'Levels',
svgUrl: `${Icons}#icon-tools-levels`,
active: true
},
{
command: 'Pan',
type: 'tool',
text: 'Pan',
svgUrl: `${Icons}#icon-tools-pan`,
active: false
},
{
command: 'Length',
type: 'tool',
text: 'Length',
svgUrl: `${Icons}#icon-tools-measure-temp`,
active: false
},
/*{
command: 'Annotate',
type: 'tool',
text: 'Annotate',
svgUrl: `${Icons}#icon-tools-measure-non-target`,
active: false
},*/
{
command: 'Angle',
type: 'tool',
text: 'Angle',
iconClasses: 'fa fa-angle-left',
active: false
},
{
command: 'Bidirectional',
type: 'tool',
text: 'Bidirectional',
svgUrl: `${Icons}#icon-tools-measure-target`,
active: false
},
{
command: 'reset',
type: 'command',
text: 'Reset',
svgUrl: `${Icons}#icon-tools-reset`,
active: false
},
{
command: 'StackScroll',
type: 'tool',
text: 'Stack Scroll',
svgUrl: `${Icons}#icon-tools-stack-scroll`,
active: false
},
{
command: 'Zoom',
type: 'tool',
text: 'Zoom',
svgUrl: `${Icons}#icon-tools-zoom`,
active: false
},
{
command: 'Wwwc',
type: 'tool',
text: 'Levels',
svgUrl: `${Icons}#icon-tools-levels`,
active: true
},
{
command: 'Pan',
type: 'tool',
text: 'Pan',
svgUrl: `${Icons}#icon-tools-pan`,
active: false
},
{
command: 'Length',
type: 'tool',
text: 'Length',
svgUrl: `${Icons}#icon-tools-measure-temp`,
active: false
},
/*{
command: 'Annotate',
type: 'tool',
text: 'Annotate',
svgUrl: `${Icons}#icon-tools-measure-non-target`,
active: false
},*/
{
command: 'Angle',
type: 'tool',
text: 'Angle',
iconClasses: 'fa fa-angle-left',
active: false
},
{
command: 'Bidirectional',
type: 'tool',
text: 'Bidirectional',
svgUrl: `${Icons}#icon-tools-measure-target`,
active: false
},
{
command: 'reset',
type: 'command',
text: 'Reset',
svgUrl: `${Icons}#icon-tools-reset`,
active: false
},
];
const buttonsAction = OHIF.redux.actions.setAvailableButtons(defaultButtons);
@ -159,6 +167,36 @@ const pdfPluginAction = OHIF.redux.actions.addPlugin({
component: OHIFDicomPDFViewportPlugin
});
const servers = {
dicomWeb: [
{
"name": "DCM4CHEE",
//"wadoUriRoot": "http://localhost:8080/dcm4chee-arc/aets/DCM4CHEE/wado",
//"qidoRoot": "http://localhost:8080/dcm4chee-arc/aets/DCM4CHEE/rs",
//"wadoRoot": "http://localhost:8080/dcm4chee-arc/aets/DCM4CHEE/rs",
"wadoUriRoot": "https://dcm4che.ohif.club/dcm4chee-arc/aets/DCM4CHEE/wado",
"qidoRoot": "https://dcm4che.ohif.club/dcm4chee-arc/aets/DCM4CHEE/rs",
"wadoRoot": "https://dcm4che.ohif.club/dcm4chee-arc/aets/DCM4CHEE/rs",
// "wadoUriRoot": "https://cancer.crowds-cure.org/dcm4chee-arc/aets/DCM4CHEE/wado",
// "qidoRoot": "https://cancer.crowds-cure.org/dcm4chee-arc/aets/DCM4CHEE/rs",
// "wadoRoot": "https://cancer.crowds-cure.org/dcm4chee-arc/aets/DCM4CHEE/rs",
"qidoSupportsIncludeField": true,
"imageRendering": "wadors",
"thumbnailRendering": "wadors",
"requestOptions": {
"requestFromBrowser": true,
"logRequests": true,
"logResponses": false,
"logTiming": true,
//"auth": "admin:admin"
//"auth": "cloud:healthcare"
}
}
]
};
OHIF.utils.addServers(servers, store);
const pdfPluginActionSopClass = OHIF.redux.actions.addPlugin({
id: 'pdf_sopClassHandler',
type: PLUGIN_TYPES.SOP_CLASS_HANDLER,
@ -177,7 +215,7 @@ if (userManager) {
<Provider store={store}>
<OidcProvider store={store} userManager={userManager}>
<BrowserRouter>
<App userManager={userManager}/>
<App userManager={userManager} />
</BrowserRouter>
</OidcProvider>
</Provider>,
@ -186,9 +224,9 @@ if (userManager) {
} else {
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<App/>
</BrowserRouter>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
document.getElementById('root')
);

View File

@ -8,9 +8,15 @@ export const setRightSidebarOpen = state => ({
state
});
export const setUserPreferencesModalOpen = state => ({
type: 'SET_USER_PREFERENCES_MODAL_OPEN',
state
});
const actions = {
setLeftSidebarOpen,
setRightSidebarOpen
setRightSidebarOpen,
setUserPreferencesModalOpen
};
export default actions;

View File

@ -0,0 +1,21 @@
export const loadState = () => {
try {
const serializedState = window.localStorage.getItem('state');
if (!serializedState) {
return undefined;
}
return JSON.parse(serializedState)
} catch (e) {
return undefined;
}
}
export const saveState = (state) => {
try {
const serializedState = JSON.stringify(state);
localStorage.setItem('state', serializedState);
} catch (e) {
console.warn(e);
}
}

View File

@ -1,6 +1,7 @@
const defaultState = {
leftSidebarOpen: true,
rightSidebarOpen: false,
userPreferencesModalOpen: false
}
const ui = (state = defaultState, action) => {
@ -9,6 +10,8 @@ const ui = (state = defaultState, action) => {
return Object.assign({}, state, { leftSidebarOpen: action.state });
case 'SET_RIGHT_SIDEBAR_OPEN':
return Object.assign({}, state, { rightSidebarOpen: action.state });
case 'SET_USER_PREFERENCES_MODAL_OPEN':
return Object.assign({}, state, { userPreferencesModalOpen: action.state });
default:
return state;
}

View File

@ -2,8 +2,8 @@ import React, { Component } from "react";
import PropTypes from "prop-types";
import OHIF from 'ohif-core';
import { withRouter } from 'react-router-dom';
import { StudyList } from "react-viewerbase";
import Header from "../components/Header";
import { StudyList } from 'react-viewerbase';
import ConnectedHeader from "../components/Header/ConnectedHeader";
class StudyListWithData extends Component {
state = {
@ -96,7 +96,7 @@ class StudyListWithData extends Component {
const studyCount = this.state.studies ? this.state.studies.length : 0;
return (<>
<Header home={true} user={this.props.user}/>
<ConnectedHeader home={true} user={this.props.user} />
<StudyList studies={this.state.studies}
studyCount={studyCount}
studyListFunctionsEnabled={false}

View File

@ -50,11 +50,11 @@
source-map "^0.5.0"
"@babel/generator@^7.1.6", "@babel/generator@^7.2.2":
version "7.2.2"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.2.2.tgz#18c816c70962640eab42fe8cae5f3947a5c65ccc"
integrity sha512-I4o675J/iS8k+P38dvJ3IBGqObLXyQLTxtrR4u9cSUJOURvafeEWb/pFMOTwtNrmq73mJzyF6ueTbO1BtN0Zeg==
version "7.3.0"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.0.tgz#f663838cd7b542366de3aa608a657b8ccb2a99eb"
integrity sha512-dZTwMvTgWfhmibq4V9X+LMf6Bgl7zAodRn9PvcPdhlzFMbvUutx74dbEv7Atz3ToeEpevYEJtAwfxq/bDCzHWg==
dependencies:
"@babel/types" "^7.2.2"
"@babel/types" "^7.3.0"
jsesc "^2.5.1"
lodash "^4.17.10"
source-map "^0.5.0"
@ -75,12 +75,12 @@
"@babel/helper-explode-assignable-expression" "^7.1.0"
"@babel/types" "^7.0.0"
"@babel/helper-builder-react-jsx@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.0.0.tgz#fa154cb53eb918cf2a9a7ce928e29eb649c5acdb"
integrity sha512-ebJ2JM6NAKW0fQEqN8hOLxK84RbRz9OkUhGS/Xd5u56ejMfVbayJ4+LykERZCOUM6faa6Fp3SZNX3fcT16MKHw==
"@babel/helper-builder-react-jsx@^7.3.0":
version "7.3.0"
resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.3.0.tgz#a1ac95a5d2b3e88ae5e54846bf462eeb81b318a4"
integrity sha512-MjA9KgwCuPEkQd9ncSXvSyJ5y+j2sICHyrI0M3L+6fnS4wMSNDc1ARXsbTfbb2cXHn17VisSnU/sHFTCxVxSMw==
dependencies:
"@babel/types" "^7.0.0"
"@babel/types" "^7.3.0"
esutils "^2.0.0"
"@babel/helper-call-delegate@^7.1.0":
@ -92,10 +92,10 @@
"@babel/traverse" "^7.1.0"
"@babel/types" "^7.0.0"
"@babel/helper-create-class-features-plugin@^7.2.3":
version "7.2.3"
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.2.3.tgz#f6e719abb90cb7f4a69591e35fd5eb89047c4a7c"
integrity sha512-xO/3Gn+2C7/eOUeb0VRnSP1+yvWHNxlpAot1eMhtoKDCN7POsyQP5excuT5UsV5daHxMWBeIIOeI5cmB8vMRgQ==
"@babel/helper-create-class-features-plugin@^7.3.0":
version "7.3.0"
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.3.0.tgz#2b01a81b3adc2b1287f9ee193688ef8dc71e718f"
integrity sha512-DUsQNS2CGLZZ7I3W3fvh0YpPDd6BuWJlDl+qmZZpABZHza2ErE3LxtEzLJFHFC1ZwtlAXvHhbFYbtM5o5B0WBw==
dependencies:
"@babel/helper-function-name" "^7.1.0"
"@babel/helper-member-expression-to-functions" "^7.0.0"
@ -235,13 +235,13 @@
"@babel/types" "^7.2.0"
"@babel/helpers@^7.1.5", "@babel/helpers@^7.2.0":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.2.0.tgz#8335f3140f3144270dc63c4732a4f8b0a50b7a21"
integrity sha512-Fr07N+ea0dMcMN8nFpuK6dUIT7/ivt9yKQdEEnjVS83tG2pHwPi03gYmk/tyuwONnZ+sY+GFFPlWGgCtW1hF9A==
version "7.3.1"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.3.1.tgz#949eec9ea4b45d3210feb7dc1c22db664c9e44b9"
integrity sha512-Q82R3jKsVpUV99mgX50gOPCWwco9Ec5Iln/8Vyu4osNIOQgSrd9RFrQeUvmvddFNoLwMyOUWU+5ckioEKpDoGA==
dependencies:
"@babel/template" "^7.1.2"
"@babel/traverse" "^7.1.5"
"@babel/types" "^7.2.0"
"@babel/types" "^7.3.0"
"@babel/highlight@^7.0.0":
version "7.0.0"
@ -253,9 +253,9 @@
js-tokens "^4.0.0"
"@babel/parser@^7.0.0", "@babel/parser@^7.1.6", "@babel/parser@^7.2.2", "@babel/parser@^7.2.3":
version "7.2.3"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.2.3.tgz#32f5df65744b70888d17872ec106b02434ba1489"
integrity sha512-0LyEcVlfCoFmci8mXx8A5oIkpkOgyo8dRHtxBnK9RRBwxO2+JZPNsqtVEZQ7mJFPxnXF9lfmU24mHOPI0qnlkA==
version "7.3.1"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.1.tgz#8f4ffd45f779e6132780835ffa7a215fa0b2d181"
integrity sha512-ATz6yX/L8LEnC3dtLQnIx4ydcPxhLcoy9Vl6re00zb2w5lG6itY6Vhnr1KFRPq/FHNsgl/gh2mjNN20f9iJTTA==
"@babel/plugin-proposal-async-generator-functions@^7.1.0", "@babel/plugin-proposal-async-generator-functions@^7.2.0":
version "7.2.0"
@ -279,11 +279,11 @@
"@babel/plugin-syntax-class-properties" "^7.0.0"
"@babel/plugin-proposal-class-properties@^7.2.3":
version "7.2.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.2.3.tgz#c9e1294363b346cff333007a92080f3203698461"
integrity sha512-FVuQngLoN2iDrpW7LmhPZ2sO4DJxf35FOcwidwB9Ru9tMvI5URthnkVHuG14IStV+TzkMTyLMoOUlSTtrdVwqw==
version "7.3.0"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.3.0.tgz#272636bc0fa19a0bc46e601ec78136a173ea36cd"
integrity sha512-wNHxLkEKTQ2ay0tnsam2z7fGZUi+05ziDJflEt3AZTP3oXLKHJp9HqhfroB/vdMvt3sda9fAbq7FsG8QPDrZBg==
dependencies:
"@babel/helper-create-class-features-plugin" "^7.2.3"
"@babel/helper-create-class-features-plugin" "^7.3.0"
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-proposal-decorators@7.1.6":
@ -312,10 +312,10 @@
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-syntax-object-rest-spread" "^7.0.0"
"@babel/plugin-proposal-object-rest-spread@^7.0.0", "@babel/plugin-proposal-object-rest-spread@^7.2.0":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.2.0.tgz#88f5fec3e7ad019014c97f7ee3c992f0adbf7fb8"
integrity sha512-1L5mWLSvR76XYUQJXkd/EEQgjq8HHRP6lQuZTTg0VA4tTGPpGemmCdAfQIz1rzEuWAm+ecP8PyyEm30jC1eQCg==
"@babel/plugin-proposal-object-rest-spread@^7.0.0", "@babel/plugin-proposal-object-rest-spread@^7.3.1":
version "7.3.1"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.1.tgz#f69fb6a1ea6a4e1c503994a91d9cf76f3c4b36e8"
integrity sha512-Nmmv1+3LqxJu/V5jU9vJmxR/KIRWFk2qLHmbB56yRRRFhlaSuOVXscX3gUmhaKgUhzA3otOHVubbIEVYsZ0eZg==
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-syntax-object-rest-spread" "^7.2.0"
@ -574,6 +574,13 @@
"@babel/helper-module-transforms" "^7.1.0"
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-transform-named-capturing-groups-regex@^7.3.0":
version "7.3.0"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.3.0.tgz#140b52985b2d6ef0cb092ef3b29502b990f9cd50"
integrity sha512-NxIoNVhk9ZxS+9lSoAQ/LM0V2UEvARLttEHUrRDGKFaAxOYQcrkN/nLRE+BbbicCAvZPl7wMP0X60HsHE5DtQw==
dependencies:
regexp-tree "^0.1.0"
"@babel/plugin-transform-new-target@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0.tgz#ae8fbd89517fa7892d20e6564e641e8770c3aa4a"
@ -645,11 +652,11 @@
"@babel/plugin-syntax-jsx" "^7.2.0"
"@babel/plugin-transform-react-jsx@^7.0.0":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.2.0.tgz#ca36b6561c4d3b45524f8efb6f0fbc9a0d1d622f"
integrity sha512-h/fZRel5wAfCqcKgq3OhbmYaReo7KkoJBpt8XnvpS7wqaNMqtw5xhxutzcm35iMUWucfAdT/nvGTsWln0JTg2Q==
version "7.3.0"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.3.0.tgz#f2cab99026631c767e2745a5368b331cfe8f5290"
integrity sha512-a/+aRb7R06WcKvQLOu4/TpjKOdvVEKRLWFpKcNuHhiREPgGRB4TQJxq07+EZLS8LFVYpfq1a5lDUnuMdcCpBKg==
dependencies:
"@babel/helper-builder-react-jsx" "^7.0.0"
"@babel/helper-builder-react-jsx" "^7.3.0"
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-syntax-jsx" "^7.2.0"
@ -780,18 +787,19 @@
semver "^5.3.0"
"@babel/preset-env@^7.0.0":
version "7.2.3"
resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.2.3.tgz#948c8df4d4609c99c7e0130169f052ea6a7a8933"
integrity sha512-AuHzW7a9rbv5WXmvGaPX7wADxFkZIqKlbBh1dmZUQp4iwiPpkE/Qnrji6SC4UQCQzvWY/cpHET29eUhXS9cLPw==
version "7.3.1"
resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.3.1.tgz#389e8ca6b17ae67aaf9a2111665030be923515db"
integrity sha512-FHKrD6Dxf30e8xgHQO0zJZpUPfVZg+Xwgz5/RdSWCbza9QLNk4Qbp40ctRoqDxml3O8RMzB1DU55SXeDG6PqHQ==
dependencies:
"@babel/helper-module-imports" "^7.0.0"
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-proposal-async-generator-functions" "^7.2.0"
"@babel/plugin-proposal-json-strings" "^7.2.0"
"@babel/plugin-proposal-object-rest-spread" "^7.2.0"
"@babel/plugin-proposal-object-rest-spread" "^7.3.1"
"@babel/plugin-proposal-optional-catch-binding" "^7.2.0"
"@babel/plugin-proposal-unicode-property-regex" "^7.2.0"
"@babel/plugin-syntax-async-generators" "^7.2.0"
"@babel/plugin-syntax-json-strings" "^7.2.0"
"@babel/plugin-syntax-object-rest-spread" "^7.2.0"
"@babel/plugin-syntax-optional-catch-binding" "^7.2.0"
"@babel/plugin-transform-arrow-functions" "^7.2.0"
@ -811,6 +819,7 @@
"@babel/plugin-transform-modules-commonjs" "^7.2.0"
"@babel/plugin-transform-modules-systemjs" "^7.2.0"
"@babel/plugin-transform-modules-umd" "^7.2.0"
"@babel/plugin-transform-named-capturing-groups-regex" "^7.3.0"
"@babel/plugin-transform-new-target" "^7.0.0"
"@babel/plugin-transform-object-super" "^7.2.0"
"@babel/plugin-transform-parameters" "^7.2.0"
@ -860,9 +869,9 @@
regenerator-runtime "^0.12.0"
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.2.0":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.2.0.tgz#b03e42eeddf5898e00646e4c840fa07ba8dcad7f"
integrity sha512-oouEibCbHMVdZSDlJBO6bZmID/zA/G/Qx3H1d3rSNPTD+L8UNKvCat7aKWSJ74zYbm5zWGh0GQN0hKj8zYFTCg==
version "7.3.1"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.3.1.tgz#574b03e8e8a9898eaf4a872a92ea20b7846f6f2a"
integrity sha512-7jGW8ppV0ant637pIqAcFfQDDH1orEPGJb8aXfUozuCU3QqX7rX4DA8iwrbPrR1hcH0FTTHz47yQnk+bl5xHQA==
dependencies:
regenerator-runtime "^0.12.0"
@ -890,10 +899,10 @@
globals "^11.1.0"
lodash "^4.17.10"
"@babel/types@^7.0.0", "@babel/types@^7.1.6", "@babel/types@^7.2.0", "@babel/types@^7.2.2":
version "7.2.2"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.2.2.tgz#44e10fc24e33af524488b716cdaee5360ea8ed1e"
integrity sha512-fKCuD6UFUMkR541eDWL+2ih/xFZBXPOg/7EQFeTluMDebfqR4jrpaCjLhkWlQS4hT6nRa2PMEgXKbRB5/H2fpg==
"@babel/types@^7.0.0", "@babel/types@^7.1.6", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0":
version "7.3.0"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.3.0.tgz#61dc0b336a93badc02bf5f69c4cd8e1353f2ffc0"
integrity sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==
dependencies:
esutils "^2.0.2"
lodash "^4.17.10"
@ -1499,15 +1508,15 @@ atob@^2.1.1:
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
autoprefixer@^9.3.1:
version "9.4.5"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.4.5.tgz#a13ccb001e4bc8837f71c3354005b42f02cc03d7"
integrity sha512-M602C0ZxzFpJKqD4V6eq2j+K5CkzlhekCrcQupJmAOrPEZjWJyj/wSeo6qRSNoN6M3/9mtLPQqTTrABfReytQg==
version "9.4.6"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.4.6.tgz#0ace275e33b37de16b09a5547dbfe73a98c1d446"
integrity sha512-Yp51mevbOEdxDUy5WjiKtpQaecqYq9OqZSL04rSoCiry7Tc5I9FEyo3bfxiTJc1DfHeKwSFCUYbBAiOQ2VGfiw==
dependencies:
browserslist "^4.4.0"
caniuse-lite "^1.0.30000928"
browserslist "^4.4.1"
caniuse-lite "^1.0.30000929"
normalize-range "^0.1.2"
num2fraction "^1.2.2"
postcss "^7.0.11"
postcss "^7.0.13"
postcss-value-parser "^3.3.1"
aws-sign2@~0.7.0:
@ -2051,13 +2060,13 @@ browserslist@4.1.1:
electron-to-chromium "^1.3.62"
node-releases "^1.0.0-alpha.11"
browserslist@^4.0.0, browserslist@^4.1.0, browserslist@^4.3.4, browserslist@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.4.0.tgz#7050d1412cbfc5274aba609ed5e50359ca1a5fdf"
integrity sha512-tQkHS8VVxWbrjnNDXgt7/+SuPJ7qDvD0Y2e6bLtoQluR2SPvlmPUcfcU75L1KAalhqULlIFJlJ6BDfnYyJxJsw==
browserslist@^4.0.0, browserslist@^4.1.0, browserslist@^4.3.4, browserslist@^4.4.1:
version "4.4.1"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.4.1.tgz#42e828954b6b29a7a53e352277be429478a69062"
integrity sha512-pEBxEXg7JwaakBXjATYw/D1YZh4QUSCX/Mnd/wnqSRPPSi1U39iDhDoKGoBUcraKdxDlrYqJxSI5nNvD+dWP2A==
dependencies:
caniuse-lite "^1.0.30000928"
electron-to-chromium "^1.3.100"
caniuse-lite "^1.0.30000929"
electron-to-chromium "^1.3.103"
node-releases "^1.1.3"
bser@^2.0.0:
@ -2244,10 +2253,10 @@ caniuse-api@^3.0.0:
lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000884, caniuse-lite@^1.0.30000905, caniuse-lite@^1.0.30000928:
version "1.0.30000929"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000929.tgz#7b391b781a9c3097ecc39ea053301aea8ea16317"
integrity sha512-n2w1gPQSsYyorSVYqPMqbSaz1w7o9ZC8VhOEGI9T5MfGDzp7sbopQxG6GaQmYsaq13Xfx/mkxJUWC1Dz3oZfzw==
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000884, caniuse-lite@^1.0.30000905, caniuse-lite@^1.0.30000929:
version "1.0.30000932"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000932.tgz#d01763e9ce77810962ca7391ff827b5949ce4272"
integrity sha512-4bghJFItvzz8m0T3lLZbacmEY9X1Z2AtIzTr7s7byqZIOumASfr4ynDx7rtm0J85nDmx8vsgR6vnaSoeU8Oh0A==
capture-exit@^1.2.0:
version "1.2.0"
@ -2761,9 +2770,9 @@ core-js@^1.0.0:
integrity sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=
core-js@^2.4.0, core-js@^2.5.0, core-js@^2.5.7:
version "2.6.2"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.2.tgz#267988d7268323b349e20b4588211655f0e83944"
integrity sha512-NdBPF/RVwPW6jr0NCILuyN9RiqLo2b1mddWHkUL+VnvcB7dzlnBJ1bXYntjpTGOgkZiiLWj2JxmOr7eGE3qK6g==
version "2.6.3"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.3.tgz#4b70938bdffdaf64931e66e2db158f0892289c49"
integrity sha512-l00tmFFZOBHtYhN4Cz7k32VM7vTn3rE2ANjQDxdEN6zmXZ/xq1jQuutnmHvMG1ZJ7xd72+TA5YpUK8wz3rWsfQ==
core-js@~2.3.0:
version "2.3.0"
@ -3358,9 +3367,9 @@ diffie-hellman@^5.0.0:
randombytes "^2.0.0"
dir-glob@^2.0.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.1.tgz#ce8413234ffe8452b76b7741c32f116cf2a7b1a7"
integrity sha512-UN6X6XwRjllabfRhBdkVSo63uurJ8nSvMGrwl94EYVz6g+exhTV+yVSYk5VC/xl3MBFBTtC0J20uFKce4Brrng==
version "2.2.2"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4"
integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==
dependencies:
path-type "^3.0.0"
@ -3543,10 +3552,10 @@ ee-first@1.1.1:
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
electron-to-chromium@^1.3.100, electron-to-chromium@^1.3.62:
version "1.3.103"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.103.tgz#a695777efdbc419cad6cbb0e58458251302cd52f"
integrity sha512-tObPqGmY9X8MUM8i3MEimYmbnLLf05/QV5gPlkR8MQ3Uj8G8B2govE1U4cQcBYtv3ymck9Y8cIOu4waoiykMZQ==
electron-to-chromium@^1.3.103, electron-to-chromium@^1.3.62:
version "1.3.108"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.108.tgz#2e79a6fcaa4b3e7c75abf871505bda8e268c910e"
integrity sha512-/QI4hMpAh48a1Sea6PALGv+kuVne9A2EWGd8HrWHMdYhIzGtbhVVHh6heL5fAzGaDnZuPyrlWJRl8WPm4RyiQQ==
elliptic@^6.0.0:
version "6.4.1"
@ -3710,12 +3719,12 @@ eslint-loader@2.1.1:
rimraf "^2.6.1"
eslint-module-utils@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz#b270362cd88b1a48ad308976ce7fa54e98411746"
integrity sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=
version "2.3.0"
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.3.0.tgz#546178dab5e046c8b562bbb50705e2456d7bda49"
integrity sha512-lmDJgeOOjk8hObTysjqH7wyMi+nsHwwvfBykwfhjR1LNdd7C2uFJBvx4OpWYpXOw4df1yE1cDEVd1yLHitk34w==
dependencies:
debug "^2.6.8"
pkg-dir "^1.0.0"
pkg-dir "^2.0.0"
eslint-plugin-flowtype@2.50.1:
version "2.50.1"
@ -4490,9 +4499,9 @@ fsevents@1.2.4:
node-pre-gyp "^0.10.0"
fsevents@^1.2.2, fsevents@^1.2.3:
version "1.2.6"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.6.tgz#d3a1864a71876a2eb9b244e3bd8f606eb09568c0"
integrity sha512-BalK54tfK0pMC0jQFb2oHn1nz7JNQD/2ex5pBnCHgBi2xG7VV0cAOGy2RS2VbCqUXx5/6obMrMcQTJ8yjcGzbg==
version "1.2.7"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.7.tgz#4851b664a3783e52003b3c66eb0eee1074933aa4"
integrity sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==
dependencies:
nan "^2.9.2"
node-pre-gyp "^0.10.0"
@ -4953,11 +4962,11 @@ hoist-non-react-statics@^2.3.1, hoist-non-react-statics@^2.5.0:
integrity sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==
hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.2.1.tgz#c09c0555c84b38a7ede6912b61efddafd6e75e1e"
integrity sha512-TFsu3TV3YLY+zFTZDrN8L2DTFanObwmBLpWvJs1qfUuEQ5bTAdFcwfx2T/bsCXfM9QHSLvjfP+nihEl0yvozxw==
version "3.3.0"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b"
integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==
dependencies:
react-is "^16.3.2"
react-is "^16.7.0"
home-or-tmp@^2.0.0:
version "2.0.0"
@ -6265,9 +6274,9 @@ jsbn@~0.1.0:
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
jsdom@>=11.0.0:
version "13.1.0"
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-13.1.0.tgz#fa7356f0cc8111d0f1077cb7800d06f22f1d66c7"
integrity sha512-C2Kp0qNuopw0smXFaHeayvharqF3kkcNqlcIlSX71+3XrsOFwkEPLt/9f5JksMmaul2JZYIQuY+WTpqHpQQcLg==
version "13.2.0"
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-13.2.0.tgz#b1a0dbdadc255435262be8ea3723d2dba0d7eb3a"
integrity sha512-cG1NtMWO9hWpqRNRR3dSvEQa8bFI6iLlqU2x4kwX51FQjp0qus8T9aBaAO6iGp3DeBrhdwuKxckknohkmfvsFw==
dependencies:
abab "^2.0.0"
acorn "^6.0.4"
@ -6284,7 +6293,7 @@ jsdom@>=11.0.0:
pn "^1.1.0"
request "^2.88.0"
request-promise-native "^1.0.5"
saxes "^3.1.4"
saxes "^3.1.5"
symbol-tree "^3.2.2"
tough-cookie "^2.5.0"
w3c-hr-time "^1.0.1"
@ -7194,9 +7203,9 @@ mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdi
minimist "0.0.8"
moment@^2.22.2, moment@^2.23.0:
version "2.23.0"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.23.0.tgz#759ea491ac97d54bac5ad776996e2a58cc1bc225"
integrity sha512-3IE39bHVqFbWWaPOMHZF98Q9c3LDKGTmypMiTM2QygGXXElkFWIH7GxfmlwmY2vwa+wmNsoYZmG2iusf1ZjJoA==
version "2.24.0"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
move-concurrently@^1.0.1:
version "1.0.1"
@ -7814,10 +7823,10 @@ obuf@^1.0.0, obuf@^1.1.2:
resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==
ohif-core@^0.1.7:
version "0.1.7"
resolved "https://registry.yarnpkg.com/ohif-core/-/ohif-core-0.1.7.tgz#81f49f142d40338a3839f06c849aace675847002"
integrity sha512-VXnpaw4VjKBR1P9tSB2ZGLpXYXwdbmL0oZ7P+bbKKOh2Q+8An4E9lTiKpUlUoxaf/HiTZIUQ/2Cjp7qJe88FDg==
ohif-core@^0.1.7, ohif-core@^0.1.8:
version "0.1.8"
resolved "https://registry.yarnpkg.com/ohif-core/-/ohif-core-0.1.8.tgz#af0ff273e9ad3096d5d98187191a336e08e72f93"
integrity sha512-e5fIKDHOfVaYkrkKFjyqhad/vP7D2ynn2q77mNFMAX49Lo5y/WgXiXytJTeaXNJzksnzTQquOxA93XAh8viuWg==
dependencies:
"@babel/runtime" "^7.2.0"
dicomweb-client "^0.4.1"
@ -8136,9 +8145,9 @@ param-case@2.1.x:
no-case "^2.2.0"
parse-asn1@^5.0.0:
version "5.1.2"
resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.2.tgz#13efbaaac8da669a9751a6b50a7cfccfdef756ae"
integrity sha512-zVAb35DsNvwINEA7EEK+78YoNDGRpYEAGoIl3bSHyI9OU4IIrrrU5DC4xaCLZ42gvOfQg1+wS778WbJW+mCMCQ==
version "5.1.3"
resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.3.tgz#1600c6cc0727365d68b97f3aa78939e735a75204"
integrity sha512-VrPoetlz7B/FqjBLD2f5wBVZvsZVLnRUrxVLfRYhGXCODa/NWE4p3Wp+6+aV3ZPL3KM7/OZmxDIwwijD7yuucg==
dependencies:
asn1.js "^4.0.0"
browserify-aes "^1.0.0"
@ -8992,10 +9001,10 @@ postcss@^6.0.1, postcss@^6.0.23:
source-map "^0.6.1"
supports-color "^5.4.0"
postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.11, postcss@^7.0.2, postcss@^7.0.5:
version "7.0.13"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.13.tgz#42bf716413e8f1c786ab71dc6e722b3671b16708"
integrity sha512-h8SY6kQTd1wISHWjz+E6cswdhMuyBZRb16pSTv3W4zYZ3/YbyWeJdNUeOXB5IdZqE1U76OUEjjjqsC3z2f3hVg==
postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.13, postcss@^7.0.2, postcss@^7.0.5:
version "7.0.14"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.14.tgz#4527ed6b1ca0d82c53ce5ec1a2041c2346bbd6e5"
integrity sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==
dependencies:
chalk "^2.4.2"
source-map "^0.6.1"
@ -9017,9 +9026,9 @@ preserve@^0.2.0:
integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=
prettier@^1.14.2:
version "1.15.3"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.15.3.tgz#1feaac5bdd181237b54dbe65d874e02a1472786a"
integrity sha512-gAU9AGAPMaKb3NNSUUuhhFAS7SCO4ALTN4nRIn6PJ075Qd28Yn2Ig2ahEJWdJwJmlEBTUfC7mMUSFy8MwsOCfg==
version "1.16.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.1.tgz#534c2c9d7853f8845e5e078384e71973bd74089f"
integrity sha512-XXUITwIkGb3CPJ2hforHah/zTINRyie5006Jd2HKy2qz7snEJXl0KLfsJZW/wst9g6R2rFvqba3VpNYdu1hDcA==
pretty-bytes@^4.0.2:
version "4.0.2"
@ -9416,7 +9425,7 @@ react-error-overlay@^5.1.2:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-5.1.2.tgz#888957b884d4b25b083a82ad550f7aad96585394"
integrity sha512-7kEBKwU9R8fKnZJBRa5RSIfay4KJwnYvKB6gODGicUmDSAhQJ7Tdnll5S0RLtYrzRfMVXlqYw61rzrSpP4ThLQ==
react-is@^16.3.2, react-is@^16.6.3:
react-is@^16.3.2, react-is@^16.6.3, react-is@^16.7.0:
version "16.7.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.7.0.tgz#c1bd21c64f1f1364c6f70695ec02d69392f41bfa"
integrity sha512-Z0VRQdF4NPDoI0tsXVMLkJLiwEBa+RP66g0xDHxgxysxSoCUccSten4RTF/UFvZF1dZvZ9Zu1sx+MDXwcOR34g==
@ -9540,10 +9549,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.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/react-viewerbase/-/react-viewerbase-0.2.1.tgz#1c7f1927e47ea5efd80ebe457eba7c95f485726d"
integrity sha512-nDT1fIZ0HHgNf+GicvkuF9ZqSvkFjW8BHTMUnKkjW6rPPKUQ+zdAGQn4PyU1TH+rtfj67sqO6t1p0ekXX1nNgQ==
react-viewerbase@^0.2.1, react-viewerbase@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/react-viewerbase/-/react-viewerbase-0.2.2.tgz#b77d341c0dbb4efd4a63b1ae696ffd32668cb0e0"
integrity sha512-92x9Miraln+n3vtDLByT/2OUh6m4LdayZPrWIWy6Jw400H96x3JmuTFAC/ebYaQLllbns6AKVI0u6EXWjtQocg==
dependencies:
"@babel/runtime" "^7.2.0"
classnames "^2.2.6"
@ -9834,6 +9843,15 @@ regex-not@^1.0.0, regex-not@^1.0.2:
extend-shallow "^3.0.2"
safe-regex "^1.1.0"
regexp-tree@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.0.tgz#a56ad7746097888ea16457479029ec9345b96ab0"
integrity sha512-rHQv+tzu+0l3KS/ERabas1yK49ahNVxuH40WcPg53CzP5p8TgmmyBgHELLyJcvjhTD0e5ahSY6C76LbEVtr7cg==
dependencies:
cli-table3 "^0.5.0"
colors "^1.1.2"
yargs "^10.0.3"
regexpp@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f"
@ -10059,20 +10077,13 @@ resolve@1.8.1:
dependencies:
path-parse "^1.0.5"
resolve@^1.1.6:
resolve@^1.1.6, resolve@^1.3.2, resolve@^1.5.0, resolve@^1.6.0, resolve@^1.8.1:
version "1.10.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba"
integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==
dependencies:
path-parse "^1.0.6"
resolve@^1.3.2, resolve@^1.5.0, resolve@^1.6.0, resolve@^1.8.1:
version "1.9.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.9.0.tgz#a14c6fdfa8f92a7df1d996cb7105fa744658ea06"
integrity sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ==
dependencies:
path-parse "^1.0.6"
restore-cursor@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
@ -10207,7 +10218,7 @@ sax@^1.2.4, sax@~1.2.4:
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
saxes@^3.1.4:
saxes@^3.1.5:
version "3.1.6"
resolved "https://registry.yarnpkg.com/saxes/-/saxes-3.1.6.tgz#2d948a47b54918516c5a64096f08865deb5bd8cd"
integrity sha512-LAYs+lChg1v5uKNzPtsgTxSS5hLo8aIhSMCJt1WMpefAxm3D1RTpMwSpb6ebdL31cubiLTnhokVktBW+cv9Y9w==
@ -10707,9 +10718,9 @@ sprintf-js@~1.0.2:
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
sshpk@^1.7.0:
version "1.16.0"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.0.tgz#1d4963a2fbffe58050aa9084ca20be81741c07de"
integrity sha512-Zhev35/y7hRMcID/upReIvRse+I9SVhyVre/KTJSJQWMz3C3+G+HpO7m1wK/yckEtujKZ7dS4hkVxAnmHaIGVQ==
version "1.16.1"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
dependencies:
asn1 "~0.2.3"
assert-plus "^1.0.0"
@ -10769,9 +10780,9 @@ stealthy-require@^1.1.0:
integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=
stream-browserify@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
integrity sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=
version "2.0.2"
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b"
integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==
dependencies:
inherits "~2.0.1"
readable-stream "^2.0.2"
@ -12023,7 +12034,7 @@ wrappy@1, wrappy@~1.0.2:
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
write-file-atomic@^2.0.0, write-file-atomic@^2.3.0:
write-file-atomic@^2.0.0, write-file-atomic@^2.1.0, write-file-atomic@^2.3.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.2.tgz#a7181706dfba17855d221140a9c06e15fcdd87b9"
integrity sha512-s0b6vB3xIVRLWywa6X9TOMA7k9zio0TMOsl9ZnDkliA/cfJlpHXAscj0gbHVJiTdIuAYpIyqS5GW91fqm6gG5g==
@ -12032,15 +12043,6 @@ write-file-atomic@^2.0.0, write-file-atomic@^2.3.0:
imurmurhash "^0.1.4"
signal-exit "^3.0.2"
write-file-atomic@^2.1.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab"
integrity sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==
dependencies:
graceful-fs "^4.1.11"
imurmurhash "^0.1.4"
signal-exit "^3.0.2"
write@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757"
@ -12056,9 +12058,9 @@ ws@^5.2.0:
async-limiter "~1.0.0"
ws@^6.1.2:
version "6.1.2"
resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.2.tgz#3cc7462e98792f0ac679424148903ded3b9c3ad8"
integrity sha512-rfUqzvz0WxmSXtJpPMX2EeASXabOrSMk1ruMOV3JBTBjo4ac2lDjGGsbQSyxj8Odhw5fBib8ZKEjDNvgouNKYw==
version "6.1.3"
resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.3.tgz#d2d2e5f0e3c700ef2de89080ebc0ac6e1bf3a72d"
integrity sha512-tbSxiT+qJI223AP4iLfQbkbxkwdFcneYinM2+x46Gx2wgvbaOMO36czfdfVUBRTHvzAMRhDd98sA5d/BuWbQdg==
dependencies:
async-limiter "~1.0.0"
@ -12114,6 +12116,13 @@ yargs-parser@^10.1.0:
dependencies:
camelcase "^4.1.0"
yargs-parser@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950"
integrity sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==
dependencies:
camelcase "^4.1.0"
yargs-parser@^9.0.2:
version "9.0.2"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077"
@ -12139,6 +12148,24 @@ yargs@12.0.2:
y18n "^3.2.1 || ^4.0.0"
yargs-parser "^10.1.0"
yargs@^10.0.3:
version "10.1.2"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.1.2.tgz#454d074c2b16a51a43e2fb7807e4f9de69ccb5c5"
integrity sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig==
dependencies:
cliui "^4.0.0"
decamelize "^1.1.1"
find-up "^2.1.0"
get-caller-file "^1.0.1"
os-locale "^2.0.0"
require-directory "^2.1.1"
require-main-filename "^1.0.1"
set-blocking "^2.0.0"
string-width "^2.0.0"
which-module "^2.0.0"
y18n "^3.2.1"
yargs-parser "^8.1.0"
yargs@^11.0.0:
version "11.1.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77"

View File

@ -13,7 +13,7 @@ import OHIFDicomPDFViewportPlugin from './connectedComponents/OHIFDicomPDFViewpo
import OHIFDicomPDFSopClassHandlerPlugin from './connectedComponents/OHIFDicomPDFViewportPlugin/OHIFDicomPDFSopClassHandlerPlugin.js';
import DicomMicroscopySopClassHandlerPlugin from './connectedComponents/DicomMicroscopyPlugin/DicomMicroscopySopClassHandlerPlugin.js';
import DicomMicroscopyViewport from './connectedComponents/DicomMicroscopyPlugin/DicomMicroscopyViewport.js';
import { loadState, saveState } from './redux/localStorageState.js';
import {
loadUser,
OidcProvider,
@ -26,13 +26,18 @@ import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader';
const Icons = '/icons.svg';
const reducers = OHIF.redux.reducers;
let reducers = OHIF.redux.reducers;
reducers.ui = ui;
reducers.oidc = oidcReducer;
const combined = combineReducers(reducers);
const store = createStore(combined, loadState());
const store = createStore(combined);
store.subscribe(() => {
saveState({
preferences: store.getState().preferences
});
});
const defaultButtons = [
{
@ -206,7 +211,9 @@ class App extends Component {
static propTypes = {
servers: PropTypes.object,
oidc: PropTypes.array,
routerBasename: PropTypes.string
routerBasename: PropTypes.string,
userManager: PropTypes.object,
location: PropTypes.object
};
static defaultProps = {

View File

@ -1,61 +1,84 @@
import React from 'react';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Link, withRouter } from 'react-router-dom';
import { Dropdown } from 'react-viewerbase';
import './Header.css';
import list from './HeaderMenuList.json';
import OHIFLogo from '../OHIFLogo/OHIFLogo.js';
import ConnectedUserPreferencesModal from '../../connectedComponents/ConnectedUserPreferencesModal.js';
//import Icons from "../../images/icons.svg";
//const Icons = '/icons.svg';
function Header({ home, location, children }) {
const { state } = location;
class Header extends Component {
static propTypes = {
home: PropTypes.bool.isRequired,
location: PropTypes.object.isRequired,
openUserPreferencesModal: PropTypes.func,
children: PropTypes.node
};
if (!children) {
children = OHIFLogo();
static defaultProps = {
home: true,
children: OHIFLogo()
};
constructor(props) {
super(props);
this.state = {
userPreferencesOpen: false
};
this.options = [
{
title: 'Preferences ',
icon: 'fa fa-user',
onClick: this.props.openUserPreferencesModal
},
{
title: 'About',
icon: 'fa fa-info',
link: 'http://ohif.org'
}
];
}
return (
<div className={`entry-header ${home ? 'header-big' : ''}`}>
<div className="header-left-box">
{state && state.studyLink && (
<Link to={state.studyLink} className="header-btn header-viewerLink">
Back to Viewer
</Link>
)}
render() {
return (
<div className={`entry-header ${this.props.home ? 'header-big' : ''}`}>
<div className="header-left-box">
{this.props.location && this.props.location.studyLink && (
<Link
to={this.props.location.studyLink}
className="header-btn header-viewerLink"
>
Back to Viewer
</Link>
)}
{children}
{this.props.children}
{!home && (
<Link
className="header-btn header-studyListLinkSection"
to={{
pathname: '/',
state: { studyLink: location.pathname }
}}
>
Study list
</Link>
)}
{!this.props.home && (
<Link
className="header-btn header-studyListLinkSection"
to={{
pathname: '/',
state: { studyLink: this.props.location.pathname }
}}
>
Study list
</Link>
)}
</div>
<div className="header-menu">
<span className="research-use">INVESTIGATIONAL USE ONLY</span>
<Dropdown title="Options" list={this.options} align="right" />
<ConnectedUserPreferencesModal />
</div>
</div>
<div className="header-menu">
<span className="research-use">INVESTIGATIONAL USE ONLY</span>
<Dropdown title="Options" list={list} align="right" />
</div>
</div>
);
);
}
}
Header.propTypes = {
home: PropTypes.bool.isRequired,
location: PropTypes.object.isRequired,
children: PropTypes.node
};
Header.defaultProps = {
home: true
};
export default withRouter(Header);

View File

@ -1,12 +0,0 @@
[
{
"title": "Preferences",
"icon": "fa fa-user",
"link": "http://www.google.com"
},
{
"title": "About",
"icon": "fa fa-info",
"link": "http://ohif.org"
}
]

View File

@ -0,0 +1,24 @@
import { connect } from 'react-redux';
import Header from '../components/Header/Header.js';
import { setUserPreferencesModalOpen } from '../redux/actions.js';
const mapStateToProps = state => {
return {
isOpen: state.ui.userPreferencesModalOpen
};
};
const mapDispatchToProps = dispatch => {
return {
openUserPreferencesModal: () => {
dispatch(setUserPreferencesModalOpen(true));
}
};
};
const ConnectedHeader = connect(
mapStateToProps,
mapDispatchToProps
)(Header);
export default ConnectedHeader;

View File

@ -0,0 +1,48 @@
import { connect } from 'react-redux';
import { UserPreferencesModal } from 'react-viewerbase';
import OHIF from 'ohif-core';
import { setUserPreferencesModalOpen } from '../redux/actions.js';
import cloneDeep from 'lodash.clonedeep';
const { setUserPreferences } = OHIF.redux.actions;
const mapStateToProps = state => {
const contextName = window.store.getState().commandContext.context;
return {
isOpen: state.ui.userPreferencesModalOpen,
windowLevelData: state.preferences[contextName]
? state.preferences[contextName].windowLevelData
: {},
hotKeysData: state.preferences[contextName]
? state.preferences[contextName].hotKeysData
: {}
};
};
const mapDispatchToProps = dispatch => {
return {
onCancel: () => {
dispatch(setUserPreferencesModalOpen(false));
},
onSave: data => {
const contextName = window.store.getState().commandContext.context;
const preferences = cloneDeep(window.store.getState().preferences);
preferences[contextName] = data;
dispatch(setUserPreferences(preferences));
dispatch(setUserPreferencesModalOpen(false));
OHIF.hotkeysUtil.setHotkeys(data.hotKeysData);
},
onResetToDefaults: () => {
dispatch(setUserPreferences());
dispatch(setUserPreferencesModalOpen(false));
OHIF.hotkeysUtil.setHotkeys();
}
};
};
const ConnectedUserPreferencesModal = connect(
mapStateToProps,
mapDispatchToProps
)(UserPreferencesModal);
export default ConnectedUserPreferencesModal;

View File

@ -4,13 +4,12 @@ import PropTypes from 'prop-types';
//import { CineDialog } from 'react-viewerbase';
import WhiteLabellingContext from '../WhiteLabellingContext.js';
import Header from '../components/Header';
import ConnectedHeader from './ConnectedHeader.js';
import ConnectedFlexboxLayout from './ConnectedFlexboxLayout.js';
import ConnectedToolbarRow from './ConnectedToolbarRow';
import ConnectedToolbarRow from './ConnectedToolbarRow.js';
import ConnectedStudyLoadingMonitor from './ConnectedStudyLoadingMonitor.js';
import StudyPrefetcher from '../components/StudyPrefetcher.js';
import './Viewer.css';
/**
* Inits OHIF Hanging Protocol's onReady.
* It waits for OHIF Hanging Protocol to be ready to instantiate the ProtocolEngine
@ -57,7 +56,9 @@ class Viewer extends Component {
<>
<WhiteLabellingContext.Consumer>
{whiteLabelling => (
<Header home={false}>{whiteLabelling.logoComponent}</Header>
<ConnectedHeader home={false}>
{whiteLabelling.logoComponent}
</ConnectedHeader>
)}
</WhiteLabellingContext.Consumer>
<div id="viewer" className="Viewer">

View File

@ -7,16 +7,21 @@ import './ViewerMain.css';
class ViewerMain extends Component {
state = {
viewportData: [],
viewportData: []
};
static propTypes = {
studies: PropTypes.array.isRequired
};
constructor(props) {
super(props);
OHIF.hotkeysUtil.setup('viewer');
}
getDisplaySets(studies) {
const displaySets = [];
studies.forEach((study) => {
studies.forEach(study => {
study.displaySets.forEach(dSet => {
displaySets.push(dSet);
});
@ -51,7 +56,7 @@ class ViewerMain extends Component {
});
}
setViewportData = ({viewportIndex, item}) => {
setViewportData = ({ viewportIndex, item }) => {
// TODO: Replace this with mapDispatchToProps call
// if we decide to put viewport info into redux
@ -59,14 +64,18 @@ class ViewerMain extends Component {
// would not trigger a re-render. We have to create a copy.
const updatedViewportData = this.state.viewportData.slice(0);
const displaySet = this.findDisplaySet(this.props.studies, item.studyInstanceUid, item.displaySetInstanceUid);
const displaySet = this.findDisplaySet(
this.props.studies,
item.studyInstanceUid,
item.displaySetInstanceUid
);
updatedViewportData[viewportIndex] = Object.assign({}, displaySet);
this.setState({
viewportData: updatedViewportData
});
}
};
render() {
return (

View File

@ -1,16 +1,22 @@
export const setLeftSidebarOpen = state => ({
type: 'SET_LEFT_SIDEBAR_OPEN',
state
type: 'SET_LEFT_SIDEBAR_OPEN',
state
});
export const setRightSidebarOpen = state => ({
type: 'SET_RIGHT_SIDEBAR_OPEN',
state
type: 'SET_RIGHT_SIDEBAR_OPEN',
state
});
export const setUserPreferencesModalOpen = state => ({
type: 'SET_USER_PREFERENCES_MODAL_OPEN',
state
});
const actions = {
setLeftSidebarOpen,
setRightSidebarOpen
setLeftSidebarOpen,
setRightSidebarOpen,
setUserPreferencesModalOpen
};
export default actions;

View File

@ -0,0 +1,19 @@
export const loadState = () => {
try {
const serializedState = window.localStorage.getItem('state');
if (!serializedState) {
return undefined;
}
return JSON.parse(serializedState);
} catch (e) {
return undefined;
}
};
export const saveState = state => {
try {
const serializedState = JSON.stringify(state);
localStorage.setItem('state', serializedState);
} catch (e) {}
};

View File

@ -1,17 +1,22 @@
const defaultState = {
leftSidebarOpen: true,
rightSidebarOpen: false,
}
leftSidebarOpen: true,
rightSidebarOpen: false,
userPreferencesModalOpen: false
};
const ui = (state = defaultState, action) => {
switch (action.type) {
case 'SET_LEFT_SIDEBAR_OPEN':
return Object.assign({}, state, { leftSidebarOpen: action.state });
case 'SET_RIGHT_SIDEBAR_OPEN':
return Object.assign({}, state, { rightSidebarOpen: action.state });
default:
return state;
}
switch (action.type) {
case 'SET_LEFT_SIDEBAR_OPEN':
return Object.assign({}, state, { leftSidebarOpen: action.state });
case 'SET_RIGHT_SIDEBAR_OPEN':
return Object.assign({}, state, { rightSidebarOpen: action.state });
case 'SET_USER_PREFERENCES_MODAL_OPEN':
return Object.assign({}, state, {
userPreferencesModalOpen: action.state
});
default:
return state;
}
};
export default ui;

View File

@ -1,113 +1,123 @@
import React, { Component } from "react";
import PropTypes from "prop-types";
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import OHIF from 'ohif-core';
import { withRouter } from 'react-router-dom';
import { StudyList } from "react-viewerbase";
import Header from "../components/Header";
import { StudyList } from 'react-viewerbase';
import Header from '../components/Header';
import ConnectedHeader from '../connectedComponents/ConnectedHeader.js';
class StudyListWithData extends Component {
state = {
searchData: {},
studies: null,
error: null
state = {
searchData: {},
studies: null,
error: null
};
static propTypes = {
patientId: PropTypes.string,
server: PropTypes.object,
user: PropTypes.object,
history: PropTypes.object
};
static rowsPerPage = 25;
static defaultSort = { field: 'patientName', order: 'desc' };
componentDidMount() {
// TODO: Avoid using timepoints here
//const params = { studyInstanceUids, seriesInstanceUids, timepointId, timepointsFilter={} };
this.searchForStudies();
}
searchForStudies = (
searchData = {
currentPage: 0,
rowsPerPage: StudyListWithData.rowsPerPage
}
) => {
const { server } = this.props;
const filter = {
patientId: searchData.patientId,
patientName: searchData.patientName,
accessionNumber: searchData.accessionNumber,
studyDescription: searchData.studyDescription,
modalitiesInStudy: searchData.modalitiesInStudy,
limit:
searchData.currentPage * searchData.rowsPerPage +
searchData.rowsPerPage,
offset: searchData.currentPage * searchData.rowsPerPage
};
static propTypes = {
patientId: PropTypes.string,
server: PropTypes.object,
user: PropTypes.object,
history: PropTypes.object
};
// TODO: add sorting
const promise = OHIF.studies.searchStudies(server, filter);
static rowsPerPage = 25;
static defaultSort = { field: 'patientName', order: 'desc' };
componentDidMount() {
// TODO: Avoid using timepoints here
//const params = { studyInstanceUids, seriesInstanceUids, timepointId, timepointsFilter={} };
this.searchForStudies();
}
searchForStudies = (searchData = {
currentPage: 0,
rowsPerPage: StudyListWithData.rowsPerPage
}) => {
const { server } = this.props;
const filter = {
patientId: searchData.patientId,
patientName: searchData.patientName,
accessionNumber: searchData.accessionNumber,
studyDescription: searchData.studyDescription,
modalitiesInStudy: searchData.modalitiesInStudy,
limit: searchData.currentPage * searchData.rowsPerPage + searchData.rowsPerPage,
offset: searchData.currentPage * searchData.rowsPerPage
};
// TODO: add sorting
const promise = OHIF.studies.searchStudies(server, filter)
// Render the viewer when the data is ready
promise.then(studies => {
if (!studies) {
studies = [];
}
// TODO: Fix casing of this property!
const fixedStudies = studies.map(study => {
const fixedStudy = study;
fixedStudy.studyInstanceUID = study.studyInstanceUid;
return fixedStudy;
})
this.setState({
studies: fixedStudies,
});
}).catch(error => {
this.setState({
error: true,
});
throw new Error(error);
});
}
onImport = () => {
//console.log('onImport');
}
onSelectItem = (studyInstanceUID) => {
this.props.history.push(`/viewer/${studyInstanceUID}`);
}
onSearch = (searchData) => {
// TODO: Update search filters
this.searchForStudies(searchData);
}
render() {
if (this.state.error) {
return (<div>Error: {JSON.stringify(this.state.error)}</div>);
} else if (this.state.studies === null) {
return (<div>Loading...</div>);
// Render the viewer when the data is ready
promise
.then(studies => {
if (!studies) {
studies = [];
}
const studyCount = this.state.studies ? this.state.studies.length : 0;
// TODO: Fix casing of this property!
const fixedStudies = studies.map(study => {
const fixedStudy = study;
fixedStudy.studyInstanceUID = study.studyInstanceUid;
return (<>
<Header home={true} user={this.props.user}/>
<StudyList studies={this.state.studies}
studyCount={studyCount}
studyListFunctionsEnabled={false}
onImport={this.onImport}
onSelectItem={this.onSelectItem}
pageSize={this.rowsPerPage}
defaultSort={StudyListWithData.defaultSort}
onSearch={this.onSearch} />
</>
);
return fixedStudy;
});
this.setState({
studies: fixedStudies
});
})
.catch(error => {
this.setState({
error: true
});
throw new Error(error);
});
};
onImport = () => {
//console.log('onImport');
};
onSelectItem = studyInstanceUID => {
this.props.history.push(`/viewer/${studyInstanceUID}`);
};
onSearch = searchData => {
// TODO: Update search filters
this.searchForStudies(searchData);
};
render() {
if (this.state.error) {
return <div>Error: {JSON.stringify(this.state.error)}</div>;
} else if (this.state.studies === null) {
return <div>Loading...</div>;
}
const studyCount = this.state.studies ? this.state.studies.length : 0;
return (
<>
<ConnectedHeader home={true} user={this.props.user} />
<StudyList
studies={this.state.studies}
studyCount={studyCount}
studyListFunctionsEnabled={false}
onImport={this.onImport}
onSelectItem={this.onSelectItem}
pageSize={this.rowsPerPage}
defaultSort={StudyListWithData.defaultSort}
onSearch={this.onSearch}
/>
</>
);
}
}
export default withRouter(StudyListWithData);