2019-11-19 20:17:33 +01:00
|
|
|
import React, { Component } from 'react';
|
|
|
|
|
import { OidcProvider } from 'redux-oidc';
|
|
|
|
|
import { I18nextProvider } from 'react-i18next';
|
|
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
|
import { Provider } from 'react-redux';
|
|
|
|
|
import { BrowserRouter as Router } from 'react-router-dom';
|
2019-08-15 09:12:48 +02:00
|
|
|
import { hot } from 'react-hot-loader/root';
|
|
|
|
|
|
2019-12-09 18:47:23 +01:00
|
|
|
import OHIFCornerstoneExtension from '@ohif/extension-cornerstone';
|
|
|
|
|
|
2019-11-19 20:17:33 +01:00
|
|
|
import {
|
|
|
|
|
SnackbarProvider,
|
|
|
|
|
ModalProvider,
|
|
|
|
|
DialogProvider,
|
|
|
|
|
OHIFModal,
|
|
|
|
|
} from '@ohif/ui';
|
2019-08-15 09:12:48 +02:00
|
|
|
|
2019-06-03 21:41:49 +02:00
|
|
|
import {
|
|
|
|
|
CommandsManager,
|
2019-06-12 22:10:57 +02:00
|
|
|
ExtensionManager,
|
2019-11-13 21:02:14 +01:00
|
|
|
ServicesManager,
|
2019-06-03 21:41:49 +02:00
|
|
|
HotkeysManager,
|
2019-12-11 04:28:23 +01:00
|
|
|
UINotificationService,
|
|
|
|
|
UIModalService,
|
|
|
|
|
UIDialogService,
|
2019-06-03 21:41:49 +02:00
|
|
|
utils,
|
2019-12-09 18:47:23 +01:00
|
|
|
redux as reduxOHIF,
|
2019-08-13 21:36:46 +02:00
|
|
|
} from '@ohif/core';
|
2019-11-19 20:17:33 +01:00
|
|
|
|
|
|
|
|
import i18n from '@ohif/i18n';
|
|
|
|
|
|
|
|
|
|
// TODO: This should not be here
|
|
|
|
|
import './config';
|
|
|
|
|
|
|
|
|
|
/** Utils */
|
2019-01-24 10:22:40 +01:00
|
|
|
import {
|
2019-04-29 21:39:09 +02:00
|
|
|
getUserManagerForOpenIdConnectClient,
|
|
|
|
|
initWebWorkers,
|
2019-05-29 14:39:54 +02:00
|
|
|
} from './utils/index.js';
|
2019-05-30 18:57:46 +02:00
|
|
|
|
2019-11-19 20:17:33 +01:00
|
|
|
/** Extensions */
|
2019-07-04 20:09:13 +02:00
|
|
|
import { GenericViewerCommands, MeasurementsPanel } from './appExtensions';
|
2019-11-19 20:17:33 +01:00
|
|
|
|
|
|
|
|
/** Viewer */
|
2019-05-30 18:57:46 +02:00
|
|
|
import OHIFStandaloneViewer from './OHIFStandaloneViewer';
|
2019-11-19 20:17:33 +01:00
|
|
|
|
|
|
|
|
/** Store */
|
2019-06-17 20:48:33 +02:00
|
|
|
import { getActiveContexts } from './store/layout/selectors.js';
|
2019-05-31 17:55:44 +02:00
|
|
|
import store from './store';
|
2019-09-06 20:31:26 +02:00
|
|
|
|
2019-11-19 20:17:33 +01:00
|
|
|
/** Contexts */
|
2019-09-06 20:31:26 +02:00
|
|
|
import WhiteLabellingContext from './context/WhiteLabellingContext';
|
|
|
|
|
import UserManagerContext from './context/UserManagerContext';
|
|
|
|
|
import AppContext from './context/AppContext';
|
2019-12-09 18:47:23 +01:00
|
|
|
const { setUserPreferences } = reduxOHIF.actions;
|
2019-01-24 10:22:40 +01:00
|
|
|
|
2019-11-19 20:17:33 +01:00
|
|
|
/** ~~~~~~~~~~~~~ Application Setup */
|
2019-06-03 21:41:49 +02:00
|
|
|
const commandsManagerConfig = {
|
|
|
|
|
getAppState: () => store.getState(),
|
2019-06-17 20:48:33 +02:00
|
|
|
getActiveContexts: () => getActiveContexts(store.getState()),
|
2019-06-03 21:41:49 +02:00
|
|
|
};
|
|
|
|
|
|
2019-11-19 20:17:33 +01:00
|
|
|
/** Managers */
|
2019-06-06 20:41:31 +02:00
|
|
|
const commandsManager = new CommandsManager(commandsManagerConfig);
|
|
|
|
|
const hotkeysManager = new HotkeysManager(commandsManager);
|
2019-11-13 21:02:14 +01:00
|
|
|
const servicesManager = new ServicesManager();
|
|
|
|
|
const extensionManager = new ExtensionManager({
|
|
|
|
|
commandsManager,
|
|
|
|
|
servicesManager,
|
|
|
|
|
});
|
2019-11-19 20:17:33 +01:00
|
|
|
/** ~~~~~~~~~~~~~ End Application Setup */
|
2019-02-10 22:28:42 +01:00
|
|
|
|
2019-01-24 10:22:40 +01:00
|
|
|
// TODO[react] Use a provider when the whole tree is React
|
2019-05-29 14:39:54 +02:00
|
|
|
window.store = store;
|
2019-01-24 10:22:40 +01:00
|
|
|
|
2019-01-17 17:00:21 +01:00
|
|
|
class App extends Component {
|
2019-01-17 17:39:08 +01:00
|
|
|
static propTypes = {
|
2019-12-09 18:47:23 +01:00
|
|
|
config: PropTypes.oneOfType([
|
|
|
|
|
PropTypes.func,
|
2019-08-13 21:36:46 +02:00
|
|
|
PropTypes.shape({
|
2019-12-09 18:47:23 +01:00
|
|
|
routerBasename: PropTypes.string.isRequired,
|
|
|
|
|
oidc: PropTypes.array,
|
|
|
|
|
whiteLabelling: PropTypes.object,
|
|
|
|
|
extensions: PropTypes.array,
|
|
|
|
|
}),
|
|
|
|
|
]).isRequired,
|
|
|
|
|
defaultExtensions: PropTypes.array,
|
2019-05-29 14:39:54 +02:00
|
|
|
};
|
2019-01-24 10:22:40 +01:00
|
|
|
|
2019-01-30 12:24:34 +01:00
|
|
|
static defaultProps = {
|
2019-12-09 18:47:23 +01:00
|
|
|
config: {
|
|
|
|
|
whiteLabelling: {},
|
|
|
|
|
oidc: [],
|
|
|
|
|
extensions: [],
|
|
|
|
|
},
|
|
|
|
|
defaultExtensions: [],
|
2019-05-29 14:39:54 +02:00
|
|
|
};
|
2019-01-30 12:24:34 +01:00
|
|
|
|
2019-09-06 20:31:26 +02:00
|
|
|
_appConfig;
|
|
|
|
|
_userManager;
|
|
|
|
|
|
2019-01-24 10:22:40 +01:00
|
|
|
constructor(props) {
|
2019-05-29 14:39:54 +02:00
|
|
|
super(props);
|
2019-01-24 10:22:40 +01:00
|
|
|
|
2019-12-09 18:47:23 +01:00
|
|
|
const { config, defaultExtensions } = props;
|
2019-11-13 21:02:14 +01:00
|
|
|
|
2019-12-09 18:47:23 +01:00
|
|
|
const appDefaultConfig = {
|
|
|
|
|
cornerstoneExtensionConfig: {},
|
|
|
|
|
extensions: [],
|
|
|
|
|
routerBasename: '/',
|
|
|
|
|
whiteLabelling: {},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
this._appConfig = {
|
|
|
|
|
...appDefaultConfig,
|
|
|
|
|
...(typeof config === 'function' ? config({ servicesManager }) : config),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const {
|
|
|
|
|
servers,
|
|
|
|
|
hotkeys,
|
|
|
|
|
cornerstoneExtensionConfig,
|
|
|
|
|
extensions,
|
|
|
|
|
oidc,
|
|
|
|
|
} = this._appConfig;
|
2019-09-06 20:31:26 +02:00
|
|
|
|
|
|
|
|
this.initUserManager(oidc);
|
2019-12-16 15:19:40 +01:00
|
|
|
_initServices([UINotificationService, UIModalService, UIDialogService]);
|
2019-12-09 18:47:23 +01:00
|
|
|
_initExtensions(
|
|
|
|
|
[...defaultExtensions, ...extensions],
|
|
|
|
|
cornerstoneExtensionConfig
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Must run after extension commands are registered
|
|
|
|
|
* if there is no hotkeys from localStorage set up from config.
|
|
|
|
|
*/
|
|
|
|
|
_initHotkeys(hotkeys);
|
2019-09-06 20:31:26 +02:00
|
|
|
_initServers(servers);
|
|
|
|
|
initWebWorkers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render() {
|
2019-12-09 18:47:23 +01:00
|
|
|
const { whiteLabelling, routerBasename } = this._appConfig;
|
2019-12-11 04:28:23 +01:00
|
|
|
const {
|
|
|
|
|
UINotificationService,
|
|
|
|
|
UIDialogService,
|
|
|
|
|
UIModalService,
|
|
|
|
|
} = servicesManager.services;
|
|
|
|
|
|
2019-12-09 18:47:23 +01:00
|
|
|
if (this._userManager) {
|
2019-09-06 20:31:26 +02:00
|
|
|
return (
|
2019-12-09 18:47:23 +01:00
|
|
|
<AppContext.Provider value={{ appConfig: this._appConfig }}>
|
2019-09-06 20:31:26 +02:00
|
|
|
<Provider store={store}>
|
|
|
|
|
<I18nextProvider i18n={i18n}>
|
2019-12-09 18:47:23 +01:00
|
|
|
<OidcProvider store={store} userManager={this._userManager}>
|
|
|
|
|
<UserManagerContext.Provider value={this._userManager}>
|
2019-11-04 16:55:05 +01:00
|
|
|
<Router basename={routerBasename}>
|
|
|
|
|
<WhiteLabellingContext.Provider value={whiteLabelling}>
|
2019-11-13 21:02:14 +01:00
|
|
|
<SnackbarProvider service={UINotificationService}>
|
2019-11-19 20:17:33 +01:00
|
|
|
<DialogProvider service={UIDialogService}>
|
|
|
|
|
<ModalProvider
|
|
|
|
|
modal={OHIFModal}
|
|
|
|
|
service={UIModalService}
|
|
|
|
|
>
|
2019-12-16 15:19:40 +01:00
|
|
|
<OHIFStandaloneViewer
|
|
|
|
|
userManager={this._userManager}
|
|
|
|
|
/>
|
2019-11-19 20:17:33 +01:00
|
|
|
</ModalProvider>
|
|
|
|
|
</DialogProvider>
|
2019-10-14 17:39:31 +02:00
|
|
|
</SnackbarProvider>
|
2019-09-06 20:31:26 +02:00
|
|
|
</WhiteLabellingContext.Provider>
|
|
|
|
|
</Router>
|
|
|
|
|
</UserManagerContext.Provider>
|
|
|
|
|
</OidcProvider>
|
|
|
|
|
</I18nextProvider>
|
|
|
|
|
</Provider>
|
|
|
|
|
</AppContext.Provider>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
2019-12-09 18:47:23 +01:00
|
|
|
<AppContext.Provider value={{ appConfig: this._appConfig }}>
|
2019-09-06 20:31:26 +02:00
|
|
|
<Provider store={store}>
|
|
|
|
|
<I18nextProvider i18n={i18n}>
|
2019-11-04 16:55:05 +01:00
|
|
|
<Router basename={routerBasename}>
|
|
|
|
|
<WhiteLabellingContext.Provider value={whiteLabelling}>
|
2019-11-13 21:02:14 +01:00
|
|
|
<SnackbarProvider service={UINotificationService}>
|
2019-11-19 20:17:33 +01:00
|
|
|
<DialogProvider service={UIDialogService}>
|
|
|
|
|
<ModalProvider modal={OHIFModal} service={UIModalService}>
|
2019-12-16 15:19:40 +01:00
|
|
|
<OHIFStandaloneViewer />
|
2019-11-19 20:17:33 +01:00
|
|
|
</ModalProvider>
|
|
|
|
|
</DialogProvider>
|
2019-10-14 17:39:31 +02:00
|
|
|
</SnackbarProvider>
|
2019-09-06 20:31:26 +02:00
|
|
|
</WhiteLabellingContext.Provider>
|
|
|
|
|
</Router>
|
|
|
|
|
</I18nextProvider>
|
|
|
|
|
</Provider>
|
|
|
|
|
</AppContext.Provider>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
initUserManager(oidc) {
|
|
|
|
|
if (oidc && !!oidc.length) {
|
2019-12-09 18:47:23 +01:00
|
|
|
const firstOpenIdClient = this._appConfig.oidc[0];
|
2019-05-04 03:18:13 +02:00
|
|
|
|
2019-07-21 16:43:42 +02:00
|
|
|
const { protocol, host } = window.location;
|
2019-12-09 18:47:23 +01:00
|
|
|
const { routerBasename } = this._appConfig;
|
2019-07-21 16:43:42 +02:00
|
|
|
const baseUri = `${protocol}//${host}${routerBasename}`;
|
|
|
|
|
|
|
|
|
|
const redirect_uri = firstOpenIdClient.redirect_uri || '/callback';
|
2019-08-13 21:36:46 +02:00
|
|
|
const silent_redirect_uri =
|
|
|
|
|
firstOpenIdClient.silent_redirect_uri || '/silent-refresh.html';
|
|
|
|
|
const post_logout_redirect_uri =
|
|
|
|
|
firstOpenIdClient.post_logout_redirect_uri || '/';
|
2019-07-21 16:43:42 +02:00
|
|
|
|
|
|
|
|
const openIdConnectConfiguration = Object.assign({}, firstOpenIdClient, {
|
2019-08-13 21:36:46 +02:00
|
|
|
redirect_uri: _makeAbsoluteIfNecessary(redirect_uri, baseUri),
|
|
|
|
|
silent_redirect_uri: _makeAbsoluteIfNecessary(
|
|
|
|
|
silent_redirect_uri,
|
|
|
|
|
baseUri
|
|
|
|
|
),
|
|
|
|
|
post_logout_redirect_uri: _makeAbsoluteIfNecessary(
|
|
|
|
|
post_logout_redirect_uri,
|
|
|
|
|
baseUri
|
|
|
|
|
),
|
2019-07-21 16:43:42 +02:00
|
|
|
});
|
|
|
|
|
|
2019-09-06 20:31:26 +02:00
|
|
|
this._userManager = getUserManagerForOpenIdConnectClient(
|
2019-05-09 22:07:21 +02:00
|
|
|
store,
|
2019-08-13 21:36:46 +02:00
|
|
|
openIdConnectConfiguration
|
2019-05-29 14:39:54 +02:00
|
|
|
);
|
2019-05-09 22:07:21 +02:00
|
|
|
}
|
2019-01-17 17:00:21 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-13 21:02:14 +01:00
|
|
|
function _initServices(services) {
|
2019-11-15 13:26:34 +01:00
|
|
|
servicesManager.registerServices(services);
|
2019-11-13 21:02:14 +01:00
|
|
|
}
|
|
|
|
|
|
2019-08-13 21:36:46 +02:00
|
|
|
/**
|
|
|
|
|
* @param
|
|
|
|
|
*/
|
2019-12-09 18:47:23 +01:00
|
|
|
function _initExtensions(extensions, cornerstoneExtensionConfig) {
|
|
|
|
|
const requiredExtensions = [
|
2019-08-13 21:36:46 +02:00
|
|
|
GenericViewerCommands,
|
2019-12-09 18:47:23 +01:00
|
|
|
[OHIFCornerstoneExtension, cornerstoneExtensionConfig],
|
|
|
|
|
/* WARNING: MUST BE REGISTERED _AFTER_ OHIFCornerstoneExtension */
|
2019-10-09 16:23:14 +02:00
|
|
|
MeasurementsPanel,
|
2019-08-13 21:36:46 +02:00
|
|
|
];
|
2019-12-09 18:47:23 +01:00
|
|
|
const mergedExtensions = requiredExtensions.concat(extensions);
|
2019-08-13 21:36:46 +02:00
|
|
|
extensionManager.registerExtensions(mergedExtensions);
|
2019-12-09 18:47:23 +01:00
|
|
|
}
|
2019-08-13 21:36:46 +02:00
|
|
|
|
2019-12-09 18:47:23 +01:00
|
|
|
function _initHotkeys(hotkeys) {
|
2019-11-28 06:48:27 +01:00
|
|
|
const { hotkeyDefinitions = {} } = store.getState().preferences || {};
|
|
|
|
|
let updateStore = false;
|
|
|
|
|
let hotkeysToUse = hotkeyDefinitions;
|
|
|
|
|
|
|
|
|
|
if (!Object.keys(hotkeyDefinitions).length) {
|
|
|
|
|
hotkeysToUse = hotkeys;
|
|
|
|
|
updateStore = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hotkeysToUse) {
|
|
|
|
|
hotkeysManager.setHotkeys(hotkeysToUse);
|
2019-12-09 18:47:23 +01:00
|
|
|
|
|
|
|
|
/* Set hotkeys default based on app config. */
|
2019-11-28 06:48:27 +01:00
|
|
|
hotkeysManager.setDefaultHotKeys(hotkeys);
|
|
|
|
|
|
|
|
|
|
if (updateStore) {
|
|
|
|
|
const { hotkeyDefinitions } = hotkeysManager;
|
|
|
|
|
const windowLevelData = {};
|
|
|
|
|
store.dispatch(
|
|
|
|
|
setUserPreferences({ windowLevelData, hotkeyDefinitions })
|
|
|
|
|
);
|
|
|
|
|
}
|
2019-08-13 21:36:46 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function _initServers(servers) {
|
|
|
|
|
if (servers) {
|
|
|
|
|
utils.addServers(servers, store);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function _isAbsoluteUrl(url) {
|
|
|
|
|
return url.includes('http://') || url.includes('https://');
|
|
|
|
|
}
|
2019-06-06 20:41:31 +02:00
|
|
|
|
2019-08-13 21:36:46 +02:00
|
|
|
function _makeAbsoluteIfNecessary(url, base_url) {
|
|
|
|
|
if (_isAbsoluteUrl(url)) {
|
|
|
|
|
return url;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-09 18:47:23 +01:00
|
|
|
/*
|
|
|
|
|
* Make sure base_url and url are not duplicating slashes.
|
|
|
|
|
*/
|
2019-08-13 21:36:46 +02:00
|
|
|
if (base_url[base_url.length - 1] === '/') {
|
|
|
|
|
base_url = base_url.slice(0, base_url.length - 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return base_url + url;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-09 18:47:23 +01:00
|
|
|
/*
|
|
|
|
|
* Only wrap/use hot if in dev.
|
|
|
|
|
*/
|
2019-08-29 14:53:33 +02:00
|
|
|
const ExportedApp = process.env.NODE_ENV === 'development' ? hot(App) : App;
|
|
|
|
|
|
|
|
|
|
export default ExportedApp;
|
2019-11-13 21:02:14 +01:00
|
|
|
export { commandsManager, extensionManager, hotkeysManager, servicesManager };
|