feat: Support for OpenID Connect (#2431)
* feat: Add OpenID Connect support, speed up docker rebuilds * fix: Switch Google Cloud API URL to v1 * chore: Remove redux-oidc and use our own components instead
This commit is contained in:
1 parent
5643f8f6d2
commit
e7b32cc51e
50 files changed
+2746
-2109
No files matched your search
@@ -57,7 +57,7 @@ function ExampleContextProvider({ children }) {
|
||||
return (
|
||||
<ExampleContext.Provider value={{ example: 'value' }}>
|
||||
{children}
|
||||
</TrackedMeasurementsContext.Provider>
|
||||
</ExampleContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -63,9 +63,8 @@ All use the `ACTIVE_VIEWPORT::CORNERSTONE` context.
|
||||
|
||||
## Viewport Module
|
||||
|
||||
Our Viewport wraps [cornerstonejs/react-cornerstone-viewport][react-viewport]
|
||||
and is connected the redux store. This module is the most prone to change as we
|
||||
hammer out our Viewport interface.
|
||||
Our Viewport wraps [cornerstonejs/react-cornerstone-viewport][react-viewport].
|
||||
This module is the most prone to change as we hammer out our Viewport interface.
|
||||
|
||||
## Tool Configuration
|
||||
|
||||
@@ -87,10 +86,12 @@ Tools can be configured through extension configuration using the tools key:
|
||||
|
||||
## Annotate Tools Configuration
|
||||
|
||||
*We currently support one property for annotation tools.*
|
||||
_We currently support one property for annotation tools._
|
||||
|
||||
### Hide handles
|
||||
This extension configuration allows you to toggle on/off handle rendering for all annotate tools:
|
||||
|
||||
This extension configuration allows you to toggle on/off handle rendering for
|
||||
all annotate tools:
|
||||
|
||||
```js
|
||||
...
|
||||
@@ -119,3 +120,4 @@ This extension configuration allows you to toggle on/off handle rendering for al
|
||||
[cornerstone-tools]: https://github.com/cornerstonejs/cornerstoneTools
|
||||
[cornerstone]: https://github.com/cornerstonejs/cornerstone
|
||||
<!-- prettier-ignore-end -->
|
||||
```
|
||||
@@ -5,7 +5,7 @@ import csTools from 'cornerstone-tools';
|
||||
import merge from 'lodash.merge';
|
||||
import getTools, { toolsGroupedByType } from './utils/getTools.js';
|
||||
import initCornerstoneTools from './initCornerstoneTools.js';
|
||||
import './initWADOImageLoader.js';
|
||||
import initWADOImageLoader from './initWADOImageLoader.js';
|
||||
import getCornerstoneMeasurementById from './utils/getCornerstoneMeasurementById';
|
||||
import measurementServiceMappingsFactory from './utils/measurementServiceMappings/measurementServiceMappingsFactory';
|
||||
import { setEnabledElement } from './state';
|
||||
@@ -69,6 +69,7 @@ export default function init({
|
||||
MeasurementService,
|
||||
DisplaySetService,
|
||||
ToolBarService,
|
||||
UserAuthenticationService,
|
||||
} = servicesManager.services;
|
||||
const tools = getTools();
|
||||
|
||||
@@ -275,6 +276,8 @@ export default function init({
|
||||
|
||||
cs.metaData.addProvider(metadataProvider.get.bind(metadataProvider), 9999);
|
||||
|
||||
initWADOImageLoader(UserAuthenticationService);
|
||||
|
||||
// ~~
|
||||
const defaultCsToolsConfig = csToolsConfig || {
|
||||
globalToolSyncEnabled: false, // hold on to your pants!
|
||||
|
||||
@@ -2,17 +2,40 @@ import cornerstone from 'cornerstone-core';
|
||||
import cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader';
|
||||
import dicomParser from 'dicom-parser';
|
||||
|
||||
//import { initWebWorkers } from './utils/index.js';
|
||||
let initialized = false;
|
||||
|
||||
cornerstoneWADOImageLoader.external.cornerstone = cornerstone;
|
||||
cornerstoneWADOImageLoader.external.dicomParser = dicomParser;
|
||||
function initWebWorkers() {
|
||||
const config = {
|
||||
maxWebWorkers: Math.max(navigator.hardwareConcurrency - 1, 1),
|
||||
startWebWorkersOnDemand: true,
|
||||
taskConfiguration: {
|
||||
decodeTask: {
|
||||
initializeCodecsOnStartup: false,
|
||||
usePDFJS: false,
|
||||
strict: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
cornerstoneWADOImageLoader.configure({
|
||||
beforeSend: function(xhr) {
|
||||
/*const headers = OHIF.DICOMWeb.getAuthorizationHeader();
|
||||
if (!initialized) {
|
||||
cornerstoneWADOImageLoader.webWorkerManager.initialize(config);
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (headers.Authorization) {
|
||||
xhr.setRequestHeader('Authorization', headers.Authorization);
|
||||
}*/
|
||||
},
|
||||
});
|
||||
export default function initWADOImageLoader(UserAuthenticationService) {
|
||||
cornerstoneWADOImageLoader.external.cornerstone = cornerstone;
|
||||
cornerstoneWADOImageLoader.external.dicomParser = dicomParser;
|
||||
|
||||
cornerstoneWADOImageLoader.configure({
|
||||
beforeSend: function(xhr) {
|
||||
const headers = UserAuthenticationService.getAuthorizationHeader();
|
||||
|
||||
if (headers && headers.Authorization) {
|
||||
xhr.setRequestHeader('Authorization', headers.Authorization);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
initWebWorkers();
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { redux } from '@ohif/core';
|
||||
|
||||
const { setLayout } = redux.actions;
|
||||
|
||||
/**
|
||||
* Update the current layout with a simple Cornerstone one
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
const setCornerstoneLayout = () => {
|
||||
const layout = {
|
||||
numRows: 1,
|
||||
numColumns: 1,
|
||||
viewports: [{ plugin: 'cornerstone' }],
|
||||
};
|
||||
|
||||
const action = setLayout(layout);
|
||||
|
||||
window.store.dispatch(action);
|
||||
};
|
||||
|
||||
export default setCornerstoneLayout;
|
||||
@@ -38,7 +38,7 @@ const EXPLICIT_VR_LITTLE_ENDIAN = '1.2.840.10008.1.2.1';
|
||||
* @param {bool} supportsReject - Whether the server supports reject calls (i.e. DCM4CHEE)
|
||||
* @param {bool} lazyLoadStudy - "enableStudyLazyLoad"; Request series meta async instead of blocking
|
||||
*/
|
||||
function createDicomWebApi(dicomWebConfig) {
|
||||
function createDicomWebApi(dicomWebConfig, UserAuthenticationService) {
|
||||
const {
|
||||
qidoRoot,
|
||||
wadoRoot,
|
||||
@@ -46,15 +46,17 @@ function createDicomWebApi(dicomWebConfig) {
|
||||
supportsFuzzyMatching,
|
||||
supportsWildcard,
|
||||
supportsReject,
|
||||
requestOptions,
|
||||
} = dicomWebConfig;
|
||||
|
||||
const qidoConfig = {
|
||||
url: qidoRoot,
|
||||
// headers: DICOMWeb.getAuthorizationHeader(server),
|
||||
headers: UserAuthenticationService.getAuthorizationHeader(),
|
||||
};
|
||||
|
||||
const wadoConfig = {
|
||||
url: wadoRoot,
|
||||
headers: UserAuthenticationService.getAuthorizationHeader(),
|
||||
};
|
||||
|
||||
// TODO -> Two clients sucks, but its better than 1000.
|
||||
@@ -78,7 +80,12 @@ function createDicomWebApi(dicomWebConfig) {
|
||||
query: {
|
||||
studies: {
|
||||
mapParams: mapParams.bind(),
|
||||
search: async function (origParams) {
|
||||
search: async function(origParams) {
|
||||
const headers = UserAuthenticationService.getAuthorizationHeader();
|
||||
if (headers) {
|
||||
qidoDicomWebClient.headers = headers;
|
||||
}
|
||||
|
||||
const { studyInstanceUid, seriesInstanceUid, ...mappedParams } =
|
||||
mapParams(origParams, {
|
||||
supportsFuzzyMatching,
|
||||
@@ -98,7 +105,12 @@ function createDicomWebApi(dicomWebConfig) {
|
||||
},
|
||||
series: {
|
||||
// mapParams: mapParams.bind(),
|
||||
search: async function (studyInstanceUid) {
|
||||
search: async function(studyInstanceUid) {
|
||||
const headers = UserAuthenticationService.getAuthorizationHeader();
|
||||
if (headers) {
|
||||
qidoDicomWebClient.headers = headers;
|
||||
}
|
||||
|
||||
const results = await seriesInStudy(
|
||||
qidoDicomWebClient,
|
||||
studyInstanceUid
|
||||
@@ -109,14 +121,20 @@ function createDicomWebApi(dicomWebConfig) {
|
||||
// processResults: processResults.bind(),
|
||||
},
|
||||
instances: {
|
||||
search: (studyInstanceUid, queryParameters) =>
|
||||
search: (studyInstanceUid, queryParameters) => {
|
||||
const headers = UserAuthenticationService.getAuthorizationHeader();
|
||||
if (headers) {
|
||||
qidoDicomWebClient.headers = headers;
|
||||
}
|
||||
|
||||
qidoSearch.call(
|
||||
undefined,
|
||||
qidoDicomWebClient,
|
||||
studyInstanceUid,
|
||||
null,
|
||||
queryParameters
|
||||
),
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
retrieve: {
|
||||
@@ -125,6 +143,11 @@ function createDicomWebApi(dicomWebConfig) {
|
||||
// Conduct query, return a promise like others
|
||||
// Await this call and add to DicomMetadataStore after receiving result
|
||||
metadata: (queryParams, callback) => {
|
||||
const headers = UserAuthenticationService.getAuthorizationHeader();
|
||||
if (headers) {
|
||||
wadoDicomWebClient.headers = headers;
|
||||
}
|
||||
|
||||
let { StudyInstanceUIDs } = urlUtil.parse(queryParams, true);
|
||||
|
||||
StudyInstanceUIDs = urlUtil.paramString.parseParam(StudyInstanceUIDs);
|
||||
@@ -164,6 +187,11 @@ function createDicomWebApi(dicomWebConfig) {
|
||||
},
|
||||
store: {
|
||||
dicom: async dataset => {
|
||||
const headers = UserAuthenticationService.getAuthorizationHeader();
|
||||
if (headers) {
|
||||
wadoDicomWebClient.headers = headers;
|
||||
}
|
||||
|
||||
const meta = {
|
||||
FileMetaInformationVersion:
|
||||
dataset._meta.FileMetaInformationVersion.Value,
|
||||
@@ -196,6 +224,11 @@ function createDicomWebApi(dicomWebConfig) {
|
||||
sortFunction,
|
||||
madeInClient = false,
|
||||
} = {}) => {
|
||||
const headers = UserAuthenticationService.getAuthorizationHeader();
|
||||
if (headers) {
|
||||
wadoDicomWebClient.headers = headers;
|
||||
}
|
||||
|
||||
if (!StudyInstanceUID) {
|
||||
throw new Error(
|
||||
'Unable to query for SeriesMetadata without StudyInstanceUID'
|
||||
|
||||
@@ -2,7 +2,9 @@ async function getStudiesForPatientByStudyInstanceUID(
|
||||
dataSource,
|
||||
StudyInstanceUID
|
||||
) {
|
||||
if (StudyInstanceUID === undefined) return;
|
||||
if (StudyInstanceUID === undefined) {
|
||||
return;
|
||||
}
|
||||
// TODO: The `DicomMetadataStore` should short-circuit both of these requests
|
||||
// Data _could_ be here from route query, or if using JSON data source
|
||||
// We could also force this to "await" these values being available in the DICOMStore?
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
const HelloWorldContext = React.createContext({
|
||||
message: 'HelloWorldContextTesting',
|
||||
setMessage: () => { },
|
||||
});
|
||||
|
||||
HelloWorldContext.displayName = 'HelloWorldContext';
|
||||
|
||||
function HelloWorldContextProvider({ children }) {
|
||||
const [message, setMessage] = useState('HelloWorldContextTesting');
|
||||
|
||||
return (
|
||||
<HelloWorldContext.Provider
|
||||
value={{
|
||||
message,
|
||||
setMessage,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</HelloWorldContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
function getContextModule() {
|
||||
return [
|
||||
{
|
||||
name: 'HelloWorldContext',
|
||||
context: HelloWorldContext,
|
||||
provider: HelloWorldContextProvider,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export { HelloWorldContext };
|
||||
|
||||
export default getContextModule;
|
||||
@@ -1,4 +1,3 @@
|
||||
import getContextModule from './getContextModule.js';
|
||||
import getDataSourcesModule from './getDataSourcesModule.js';
|
||||
import getLayoutTemplateModule from './getLayoutTemplateModule.js';
|
||||
import getPanelModule from './getPanelModule.js';
|
||||
@@ -13,7 +12,6 @@ export default {
|
||||
* Only required property. Should be a unique value across all extensions.
|
||||
*/
|
||||
id,
|
||||
getContextModule,
|
||||
getDataSourcesModule,
|
||||
getHangingProtocolModule,
|
||||
getLayoutTemplateModule,
|
||||
|
||||
+3
-1
@@ -2,7 +2,9 @@ async function getStudiesForPatientByStudyInstanceUID(
|
||||
dataSource,
|
||||
StudyInstanceUID
|
||||
) {
|
||||
if (StudyInstanceUID === undefined) return;
|
||||
if (StudyInstanceUID === undefined) {
|
||||
return;
|
||||
}
|
||||
// TODO: The `DicomMetadataStore` should short-circuit both of these requests
|
||||
// Data _could_ be here from route query, or if using JSON data source
|
||||
// We could also force this to "await" these values being available in the DICOMStore?
|
||||
|
||||
Reference in new issue
Block a user