merge from ract and adding docker-compose PACs configuration files

This commit is contained in:
biharck committed 2019-04-30 10:32:53 -03:00
commit e39e3dd5d5
67 files changed
+1009 -801

No files matched your search

+81 -143
View File
@@ -1,42 +1,39 @@
import React, { Component } from 'react';
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import { createStore, combineReducers } from 'redux';
import PropTypes from 'prop-types';
import OHIF from 'ohif-core';
import './config';
import ui from './redux/ui.js';
import OHIFStandaloneViewer from './OHIFStandaloneViewer';
import WhiteLabellingContext from './WhiteLabellingContext';
import OHIFCornerstoneExtension from 'ohif-cornerstone-extension';
import OHIFVTKExtension from 'ohif-vtk-extension';
import OHIFDicomPDFExtension from 'ohif-dicom-pdf-extension';
import OHIFDicomHtmlExtension from 'ohif-dicom-html-extension';
import OHIFDicomMicroscopyExtension from 'ohif-dicom-microscopy-extension';
import React, { Component } from 'react'
import { BrowserRouter as Router } from 'react-router-dom'
import { Provider } from 'react-redux'
import { createStore, combineReducers } from 'redux'
import PropTypes from 'prop-types'
import OHIF from 'ohif-core'
import './config'
import ui from './redux/ui.js'
import OHIFStandaloneViewer from './OHIFStandaloneViewer'
import WhiteLabellingContext from './WhiteLabellingContext'
import OHIFCornerstoneExtension from 'ohif-cornerstone-extension'
import OHIFVTKExtension from 'ohif-vtk-extension'
import OHIFDicomPDFExtension from 'ohif-dicom-pdf-extension'
import OHIFDicomHtmlExtension from 'ohif-dicom-html-extension'
import OHIFDicomMicroscopyExtension from 'ohif-dicom-microscopy-extension'
import { OidcProvider, reducer as oidcReducer } from 'redux-oidc'
import {
loadUser,
OidcProvider,
createUserManager,
reducer as oidcReducer
} from 'redux-oidc';
import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader';
getUserManagerForOpenIdConnectClient,
initWebWorkers,
} from './utils/index.js'
const { ExtensionManager } = OHIF.extensions;
const Icons = 'icons.svg'
const { ExtensionManager } = OHIF.extensions
const { reducers, localStorage } = OHIF.redux
const Icons = 'icons.svg';
reducers.ui = ui
reducers.oidc = oidcReducer
const { reducers, localStorage } = OHIF.redux;
reducers.ui = ui;
reducers.oidc = oidcReducer;
const combined = combineReducers(reducers);
const store = createStore(combined, localStorage.loadState());
const combined = combineReducers(reducers)
const store = createStore(combined, localStorage.loadState())
store.subscribe(() => {
localStorage.saveState({
preferences: store.getState().preferences
});
});
preferences: store.getState().preferences,
})
})
const defaultButtons = [
{
@@ -44,35 +41,35 @@ const defaultButtons = [
type: 'tool',
text: 'Stack Scroll',
svgUrl: `${Icons}#icon-tools-stack-scroll`,
active: false
active: false,
},
{
command: 'Zoom',
type: 'tool',
text: 'Zoom',
svgUrl: `${Icons}#icon-tools-zoom`,
active: false
active: false,
},
{
command: 'Wwwc',
type: 'tool',
text: 'Levels',
svgUrl: `${Icons}#icon-tools-levels`,
active: true
active: true,
},
{
command: 'Pan',
type: 'tool',
text: 'Pan',
svgUrl: `${Icons}#icon-tools-pan`,
active: false
active: false,
},
{
command: 'Length',
type: 'tool',
text: 'Length',
svgUrl: `${Icons}#icon-tools-measure-temp`,
active: false
active: false,
},
/*{
command: 'Annotate',
@@ -86,41 +83,41 @@ const defaultButtons = [
type: 'tool',
text: 'Angle',
iconClasses: 'fa fa-angle-left',
active: false
active: false,
},
{
command: 'Bidirectional',
type: 'tool',
text: 'Bidirectional',
svgUrl: `${Icons}#icon-tools-measure-target`,
active: false
active: false,
},
{
command: 'Brush',
type: 'tool',
text: 'Brush',
iconClasses: 'fa fa-circle',
active: false
active: false,
},
{
command: 'FreehandMouse',
type: 'tool',
text: 'Freehand',
iconClasses: 'fa fa-star',
active: false
active: false,
},
{
command: 'reset',
type: 'command',
text: 'Reset',
svgUrl: `${Icons}#icon-tools-reset`,
active: false
}
];
active: false,
},
]
const buttonsAction = OHIF.redux.actions.setAvailableButtons(defaultButtons);
const buttonsAction = OHIF.redux.actions.setAvailableButtons(defaultButtons)
store.dispatch(buttonsAction);
store.dispatch(buttonsAction)
const availableTools = [
{ name: 'Pan', mouseButtonMasks: [1, 4] },
@@ -135,14 +132,14 @@ const availableTools = [
{ name: 'PanMultiTouch' },
{ name: 'ZoomTouchPinch' },
{ name: 'StackScrollMouseWheel' },
{ name: 'StackScrollMultiTouch' }
];
{ name: 'StackScrollMultiTouch' },
]
const toolAction = OHIF.redux.actions.setExtensionData('cornerstone', {
availableTools
});
availableTools,
})
store.dispatch(toolAction);
store.dispatch(toolAction)
/** TODO: extensions should be passed in as prop as soon as we have the extensions as separate packages and then registered by ExtensionsManager */
const extensions = [
@@ -150,137 +147,78 @@ const extensions = [
new OHIFVTKExtension(),
new OHIFDicomPDFExtension(),
new OHIFDicomHtmlExtension(),
new OHIFDicomMicroscopyExtension()
];
ExtensionManager.registerExtensions(store, extensions);
new OHIFDicomMicroscopyExtension(),
]
ExtensionManager.registerExtensions(store, extensions)
// TODO[react] Use a provider when the whole tree is React
window.store = store;
window.store = store
function handleServers(servers) {
if (servers) {
OHIF.utils.addServers(servers, store);
}
}
function handleOIDC(oidc) {
if (!oidc) {
return;
}
const oidcClient = oidc[0];
const settings = {
authority: oidcClient.authServerUrl,
client_id: oidcClient.clientId,
redirect_uri: oidcClient.authRedirectUri,
silent_redirect_uri: '/silent-refresh.html',
post_logout_redirect_uri: oidcClient.postLogoutRedirectUri,
response_type: oidcClient.responseType,
scope: 'email profile openid', // Note: Request must have scope 'openid' to be considered an OpenID Connect request
automaticSilentRenew: true,
revokeAccessTokenOnSignout: true,
filterProtocolClaims: true,
loadUserInfo: true,
extraQueryParams: oidcClient.extraQueryParams
};
const userManager = createUserManager(settings);
loadUser(store, userManager);
return userManager;
}
function handleWebWorkerInit(basename) {
const config = {
maxWebWorkers: Math.max(navigator.hardwareConcurrency - 1, 1),
startWebWorkersOnDemand: true,
webWorkerPath: basename + '/cornerstoneWADOImageLoaderWebWorker.min.js',
taskConfiguration: {
decodeTask: {
loadCodecsOnStartup: true,
initializeCodecsOnStartup: false,
codecsPath: basename + '/cornerstoneWADOImageLoaderCodecs.min.js',
usePDFJS: false,
strict: false
}
}
};
cornerstoneWADOImageLoader.webWorkerManager.initialize(config);
}
/**
* Set or update the HTML Base tag present on the document
* to point to the provided ROOT Url.
*
* @param rootUrl
*/
function updateBaseTag(rootUrl) {
const bases = document.getElementsByTagName('base');
let baseHref = rootUrl;
baseHref += baseHref.endsWith('/') ? '' : '/';
if (bases.length > 1) {
throw new Error('For some reason there is more than one base tag present.');
} else if (bases.length === 1) {
bases[0].href = baseHref;
} else {
document.write(`<base href='${baseHref}'/>`);
OHIF.utils.addServers(servers, store)
}
}
class App extends Component {
static propTypes = {
routerBasename: PropTypes.string,
relativeWebWorkerScriptsPath: PropTypes.string,
//
servers: PropTypes.object,
oidc: PropTypes.array,
routerBasename: PropTypes.string,
rootUrl: PropTypes.string,
userManager: PropTypes.object,
location: PropTypes.object
};
location: PropTypes.object,
whiteLabelling: PropTypes.object,
}
static defaultProps = {
whiteLabelling: {}
};
routerBasename: '/',
relativeWebWorkerScriptsPath: '',
whiteLabelling: {},
}
constructor(props) {
super(props);
super(props)
this.userManager = handleOIDC(this.props.oidc);
handleServers(this.props.servers);
handleWebWorkerInit(this.props.rootUrl);
updateBaseTag(this.props.rootUrl);
this.userManager = getUserManagerForOpenIdConnectClient(
store,
this.props.oidc
)
handleServers(this.props.servers)
initWebWorkers(
this.props.routerBasename,
this.props.relativeWebWorkerScriptsPath
)
}
render() {
const userManager = this.userManager;
const userManager = this.userManager
if (userManager) {
return (
<Provider store={store}>
<OidcProvider store={store} userManager={userManager}>
<BrowserRouter basename={this.props.routerBasename}>
<Router basename={this.props.routerBasename}>
<WhiteLabellingContext.Provider value={this.props.whiteLabelling}>
<OHIFStandaloneViewer userManager={userManager} />
</WhiteLabellingContext.Provider>
</BrowserRouter>
</Router>
</OidcProvider>
</Provider>
);
)
}
return (
<Provider store={store}>
<BrowserRouter basename={this.props.routerBasename}>
<Router basename={this.props.routerBasename}>
<WhiteLabellingContext.Provider value={this.props.whiteLabelling}>
<OHIFStandaloneViewer />
</WhiteLabellingContext.Provider>
</BrowserRouter>
</Router>
</Provider>
);
)
}
}
export default App;
export default App
+48 -37
View File
@@ -1,48 +1,63 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router';
import { Route, Switch } from 'react-router-dom';
import { connect } from 'react-redux';
import { ViewerbaseDragDropContext } from 'react-viewerbase';
import ViewerRouting from './routes/ViewerRouting.js';
import React, { Component } from 'react'
import PropTypes from 'prop-types'
// import asyncComponent from './components/AsyncComponent.js'
import IHEInvokeImageDisplay from './routes/IHEInvokeImageDisplay.js'
import ViewerRouting from './routes/ViewerRouting.js'
import StudyListRouting from './studylist/StudyListRouting.js'
import StandaloneRouting from './routes/StandaloneRouting.js';
import IHEInvokeImageDisplay from './routes/IHEInvokeImageDisplay.js';
import CallbackPage from './CallbackPage.js';
import StandaloneRouting from './routes/StandaloneRouting.js'
import CallbackPage from './CallbackPage.js'
import { withRouter } from 'react-router'
import { Route, Switch } from 'react-router-dom'
import { connect } from 'react-redux'
import { ViewerbaseDragDropContext } from 'react-viewerbase'
import './OHIFStandaloneViewer.css';
import './variables.css';
import './theme-tide.css';
import './OHIFStandaloneViewer.css'
import './variables.css'
import './theme-tide.css'
const reload = () => window.location.reload();
// Dynamic Import Routes (CodeSplitting)
// const IHEInvokeImageDisplay = asyncComponent(() =>
// import('./routes/IHEInvokeImageDisplay.js')
// )
// const ViewerRouting = asyncComponent(() => import('./routes/ViewerRouting.js'))
// const StudyListRouting = asyncComponent(() =>
// import('./studylist/StudyListRouting.js')
// )
// const StandaloneRouting = asyncComponent(() =>
// import('./routes/StandaloneRouting.js')
// )
// const CallbackPage = asyncComponent(() => import('./CallbackPage.js'))
//
const reload = () => window.location.reload()
class OHIFStandaloneViewer extends Component {
static propTypes = {
history: PropTypes.object.isRequired,
user: PropTypes.object
};
user: PropTypes.object,
}
componentDidMount() {
this.unlisten = this.props.history.listen((location, action) => {
if (this.props.setContext) {
this.props.setContext(window.location.pathname);
this.props.setContext(window.location.pathname)
}
});
})
}
componentWillUnmount() {
this.unlisten();
this.unlisten()
}
render() {
const { user, userManager } = this.props;
const { user, userManager } = this.props
const userNotLoggedIn = userManager && (!user || user.expired);
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);
sessionStorage.setItem('ohif-redirect-to', pathname)
}
return (
@@ -55,24 +70,20 @@ class OHIFStandaloneViewer extends Component {
/>
<Route
component={() => {
userManager.signinRedirect();
userManager.signinRedirect()
return null;
return null
}}
/>
</Switch>
);
)
}
return (
<Switch>
<Route exact path="/silent-refresh.html" onEnter={reload} />
<Route exact path="/logout-redirect.html" onEnter={reload} />
<Route
exact
path="/studylist"
component={StudyListRouting}
/>
<Route exact path="/studylist" component={StudyListRouting} />
<Route exact path="/" component={StudyListRouting} />
<Route exact path="/viewer" component={StandaloneRouting} />
<Route path="/viewer/:studyInstanceUids" component={ViewerRouting} />
@@ -86,21 +97,21 @@ class OHIFStandaloneViewer extends Component {
/>
<Route render={() => <div> Sorry, this page does not exist. </div>} />
</Switch>
);
)
}
}
const mapStateToProps = state => {
return {
user: state.oidc.user
};
};
user: state.oidc.user,
}
}
const ConnectedOHIFStandaloneViewer = connect(
mapStateToProps,
null
)(OHIFStandaloneViewer);
)(OHIFStandaloneViewer)
export default ViewerbaseDragDropContext(
withRouter(ConnectedOHIFStandaloneViewer)
);
)
@@ -0,0 +1,5 @@
export default {
webWorkerManager: {
initialize: jest.fn(),
},
}
+4
View File
@@ -0,0 +1,4 @@
const createUserManager = () => jest.fn().mockReturnValue({})
const loadUser = () => jest.fn()
export { createUserManager, loadUser }
+37
View File
@@ -0,0 +1,37 @@
/**
* We use this component to leverage "Code Splitting"
*
* Link: https://serverless-stack.com/chapters/code-splitting-in-create-react-app.html
*/
import React, { Component } from 'react'
export default function asyncComponent(importComponent) {
class AsyncComponent extends Component {
constructor(props) {
super(props)
this.state = {
component: null,
}
}
async componentDidMount() {
// Add dynamically loaded component to state
const { default: component } = await importComponent()
this.setState({
component: component,
})
}
render() {
const C = this.state.component
// Render the loaded component, or null
return C ? <C {...this.props} /> : null
}
}
return AsyncComponent
}
+19 -20
View File
@@ -1,38 +1,37 @@
import dicomParser from 'dicom-parser';
import cornerstone from 'cornerstone-core';
import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader';
import OHIF from 'ohif-core';
import version from './version.js';
import { homepage } from '../package.json';
import dicomParser from 'dicom-parser'
import cornerstone from 'cornerstone-core'
import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader'
import OHIF from 'ohif-core'
import version from './version.js'
window.info = {
version,
homepage
};
homepage: `${process.env.PUBLIC_URL}`,
}
// For debugging
window.cornerstone = cornerstone;
window.cornerstoneWADOImageLoader = cornerstoneWADOImageLoader;
window.cornerstone = cornerstone
window.cornerstoneWADOImageLoader = cornerstoneWADOImageLoader
cornerstoneWADOImageLoader.external.cornerstone = cornerstone;
cornerstoneWADOImageLoader.external.dicomParser = dicomParser;
cornerstoneWADOImageLoader.external.cornerstone = cornerstone
cornerstoneWADOImageLoader.external.dicomParser = dicomParser
OHIF.user.getAccessToken = () => {
// TODO: Get the Redux store from somewhere else
const state = window.store.getState();
const state = window.store.getState()
if (!state.oidc || !state.oidc.user) {
return;
return
}
return state.oidc.user.access_token;
};
return state.oidc.user.access_token
}
cornerstoneWADOImageLoader.configure({
beforeSend: function(xhr) {
const headers = OHIF.DICOMWeb.getAuthorizationHeader();
const headers = OHIF.DICOMWeb.getAuthorizationHeader()
if (headers.Authorization) {
xhr.setRequestHeader('Authorization', headers.Authorization);
xhr.setRequestHeader('Authorization', headers.Authorization)
}
}
});
},
})
+14 -49
View File
@@ -1,19 +1,22 @@
/**
* Entry point index.js for development
* Entry point for development and production PWA builds.
* Packaged (NPM) builds go through `index_publish.js`
*/
import App from './App.js'
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App.js';
import React from 'react';
import ReactDOM from 'react-dom';
export { App }
export { App };
window.config = window.config || {}
const applicationDefaults = {
routerBasename: '/',
relativeWebWorkerScriptsPath: '',
}
const applicationProps = Object.assign({}, applicationDefaults, window.config)
const app = React.createElement(App, applicationProps, null)
var rootUrl = 'http://localhost:5000';
var routerBasename = '/';
var props = {
routerBasename: routerBasename,
rootUrl: rootUrl
};
ReactDOM.render(app, document.getElementById('root'))
/*
Example config with OIDC
@@ -87,24 +90,6 @@ props.oidc = [
}
]; */
/* Example config without OIDC */
props.servers = {
dicomWeb: [
{
name: 'DCM4CHEE',
wadoUriRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado',
qidoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
wadoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
qidoSupportsIncludeField: true,
imageRendering: 'wadors',
thumbnailRendering: 'wadors',
requestOptions: {
requestFromBrowser: true
}
}
]
};
/*props.servers = {
"dicomWeb": [
{
@@ -169,23 +154,3 @@ White labelling example
props.whiteLabelling = {
logoComponent: RadicalImagingLogo()
};*/
// Note: Run your build like this:
// REACT_APP_CONFIG=$(cat ../config-react/ccc.json) yarn start
//
// If you change the JSON config, you need to re-run the command!
const configString = process.env && process.env && process.env.REACT_APP_CONFIG;
if (configString) {
if (configString.servers) {
props.servers = configString.servers;
}
if (configString.oidc) {
props.oidc = configString.oidc;
}
}
var app = React.createElement(App, props, null);
ReactDOM.render(app, document.getElementById('root'));
-17
View File
@@ -1,17 +0,0 @@
import IHEInvokeImageDisplay from './IHEInvokeImageDisplay.js';
import StandaloneRouting from './StandaloneRouting.js';
import ViewerRouting from './ViewerRouting.js';
export {
IHEInvokeImageDisplay,
ViewerRouting,
StandaloneRouting
};
const routes = {
IHEInvokeImageDisplay,
ViewerRouting,
StandaloneRouting
};
export default routes;
@@ -0,0 +1,52 @@
// https://github.com/maxmantz/redux-oidc/blob/master/docs/API.md
import { loadUser, createUserManager } from 'redux-oidc'
/**
* Creates a userManager from oidcSettings;
* loads the user into the provided redux store
*
* @param {*} store
* @param {Object} oidcSettings
* @param {string} oidcSettings.authServerUrl,
* @param {string} oidcSettings.clientId,
* @param {string} oidcSettings.authRedirectUri,
* @param {string} oidcSettings.postLogoutRedirectUri,
* @param {string} oidcSettings.responseType,
* @param {string} oidcSettings.extraQueryParams,
*/
export default function(store, oidcSettings) {
if (!store || !oidcSettings) {
return
}
const {
authServerUrl,
clientId,
authRedirectUri,
postLogoutRedirectUri,
responseType,
extraQueryParams,
} = oidcSettings
const settings = {
authority: authServerUrl,
client_id: clientId,
redirect_uri: authRedirectUri,
silent_redirect_uri: '/silent-refresh.html',
post_logout_redirect_uri: postLogoutRedirectUri,
response_type: responseType,
// Note: Request must have scope 'openid' to be considered an OpenID Connect request
scope: 'email profile openid',
automaticSilentRenew: true,
revokeAccessTokenOnSignout: true,
filterProtocolClaims: true,
loadUserInfo: true,
extraQueryParams: extraQueryParams,
}
const userManager = createUserManager(settings)
loadUser(store, userManager)
return userManager
}
@@ -0,0 +1,23 @@
import getUserManagerForOpenIdConnectClient from './getUserManagerForOpenIdConnectClient.js'
describe('getUserManagerForOpenIdConnectClient', () => {
it('returns undefined if store is not provided', () => {
const expectedReturnVal = undefined
const returnVal = getUserManagerForOpenIdConnectClient(undefined, {})
expect(returnVal).toEqual(expectedReturnVal)
})
it('returns undefined if oidcSettings are not provided', () => {
const expectedReturnVal = undefined
const returnVal = getUserManagerForOpenIdConnectClient({}, undefined)
expect(returnVal).toEqual(expectedReturnVal)
})
it('does not return undefined when store and oidcSettings are defined', () => {
const returnVal = getUserManagerForOpenIdConnectClient({}, {})
expect(returnVal).not.toBe(undefined)
})
})
+4
View File
@@ -0,0 +1,4 @@
import getUserManagerForOpenIdConnectClient from './getUserManagerForOpenIdConnectClient.js'
import initWebWorkers from './initWebWorkers.js'
export { getUserManagerForOpenIdConnectClient, initWebWorkers }
+26
View File
@@ -0,0 +1,26 @@
import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader'
/**
*
* @param {String} baseDirectory
* @param {String} webWorkScriptsPath
*/
export default function(baseDirectory, webWorkScriptsPath) {
const scriptsPath = `${baseDirectory}/${webWorkScriptsPath}`
const config = {
maxWebWorkers: Math.max(navigator.hardwareConcurrency - 1, 1),
startWebWorkersOnDemand: true,
webWorkerPath: `${scriptsPath}/cornerstoneWADOImageLoaderWebWorker.min.js`,
taskConfiguration: {
decodeTask: {
loadCodecsOnStartup: true,
initializeCodecsOnStartup: false,
codecsPath: `${scriptsPath}/cornerstoneWADOImageLoaderCodecs.min.js`,
usePDFJS: false,
strict: false,
},
},
}
cornerstoneWADOImageLoader.webWorkerManager.initialize(config)
}
+15
View File
@@ -0,0 +1,15 @@
import initWebWorkers from './initWebWorkers.js'
import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader'
describe('initWebWorkers', () => {
it("initializes cornerstoneWADOImageLoader's web workers", () => {
const basePath = '/'
const relativeWebWorkerScriptsPath = ''
initWebWorkers(basePath, relativeWebWorkerScriptsPath)
expect(
cornerstoneWADOImageLoader.webWorkerManager.initialize
).toHaveBeenCalled()
})
})