Merge branch 'feat/v2-main' into feat/v2-main-docusaurus-netlify-monorepo

This commit is contained in:
Erik Ziegler 2021-07-20 15:55:21 +02:00 committed by GitHub
commit 7a9f113b91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 173 additions and 56 deletions

View File

@ -266,6 +266,10 @@ function createDicomWebApi(dicomWebConfig, UserAuthenticationService) {
study.isLoaded = true; study.isLoaded = true;
} }
// Google Cloud Healthcare doesn't return StudyInstanceUID, so we need to add
// it manually here
seriesSummaryMetadata.forEach(aSeries => { aSeries.StudyInstanceUID = StudyInstanceUID })
DicomMetadataStore.addSeriesMetadata(seriesSummaryMetadata, madeInClient); DicomMetadataStore.addSeriesMetadata(seriesSummaryMetadata, madeInClient);
const numberOfSeries = seriesPromises.length; const numberOfSeries = seriesPromises.length;

View File

@ -175,7 +175,8 @@ function PanelStudyBrowser({
setExpandedStudyInstanceUIDs(updatedExpandedStudyInstanceUIDs); setExpandedStudyInstanceUIDs(updatedExpandedStudyInstanceUIDs);
if (!shouldCollapseStudy) { if (!shouldCollapseStudy) {
requestDisplaySetCreationForStudy(DisplaySetService, StudyInstanceUID); const madeInClient = true
requestDisplaySetCreationForStudy(DisplaySetService, StudyInstanceUID, madeInClient);
} }
} }

View File

@ -1,7 +1,8 @@
function requestDisplaySetCreationForStudy( function requestDisplaySetCreationForStudy(
dataSource, dataSource,
DisplaySetService, DisplaySetService,
StudyInstanceUID StudyInstanceUID,
madeInClient,
) { ) {
// TODO: is this already short-circuited by the map of Retrieve promises? // TODO: is this already short-circuited by the map of Retrieve promises?
if ( if (
@ -12,7 +13,7 @@ function requestDisplaySetCreationForStudy(
return; return;
} }
dataSource.retrieveSeriesMetadata({ StudyInstanceUID }); dataSource.retrieveSeriesMetadata({ StudyInstanceUID, madeInClient });
} }
export default requestDisplaySetCreationForStudy; export default requestDisplaySetCreationForStudy;

View File

@ -377,7 +377,7 @@ function OHIFCornerstoneSRViewport({
evt.preventDefault(); evt.preventDefault();
}} }}
onPillClick={() => { onPillClick={() => {
sendTrackedMeasurementsEvent('PROMPT_HYDRATE_SR', { sendTrackedMeasurementsEvent('RESTORE_PROMPT_HYDRATE_SR', {
displaySetInstanceUID: displaySet.displaySetInstanceUID, displaySetInstanceUID: displaySet.displaySetInstanceUID,
viewportIndex, viewportIndex,
}); });

View File

@ -164,6 +164,7 @@ function TrackedMeasurementsContextProvider(
console.log('sending event...', trackedMeasurements); console.log('sending event...', trackedMeasurements);
sendTrackedMeasurementsEvent('PROMPT_HYDRATE_SR', { sendTrackedMeasurementsEvent('PROMPT_HYDRATE_SR', {
displaySetInstanceUID: displaySet.displaySetInstanceUID, displaySetInstanceUID: displaySet.displaySetInstanceUID,
SeriesInstanceUID: displaySet.SeriesInstanceUID,
viewportIndex: activeViewportIndex, viewportIndex: activeViewportIndex,
}); });
} }

View File

@ -22,6 +22,7 @@ const machineConfiguration = {
prevTrackedSeries: [], prevTrackedSeries: [],
prevIgnoredSeries: [], prevIgnoredSeries: [],
// //
ignoredSRSeriesForHydration: [],
isDirty: false, isDirty: false,
}, },
states: { states: {
@ -39,7 +40,11 @@ const machineConfiguration = {
actions: ['setTrackedStudyAndMultipleSeries', 'setIsDirtyToClean'], actions: ['setTrackedStudyAndMultipleSeries', 'setIsDirtyToClean'],
}, },
], ],
PROMPT_HYDRATE_SR: 'promptHydrateStructuredReport', PROMPT_HYDRATE_SR: {
target: 'promptHydrateStructuredReport',
cond: 'hasNotIgnoredSRSeriesForHydration',
},
RESTORE_PROMPT_HYDRATE_SR: 'promptHydrateStructuredReport'
}, },
}, },
promptBeginTracking: { promptBeginTracking: {
@ -218,6 +223,8 @@ const machineConfiguration = {
}, },
{ {
target: 'idle', target: 'idle',
actions: ['ignoreHydrationForSRSeries'],
cond: 'shouldIgnoreHydrationForSR'
}, },
], ],
onError: { onError: {
@ -300,6 +307,9 @@ const defaultOptions = {
prevIgnoredSeries: [...ctx.ignoredSeries], prevIgnoredSeries: [...ctx.ignoredSeries],
ignoredSeries: [...ctx.ignoredSeries, evt.data.SeriesInstanceUID], ignoredSeries: [...ctx.ignoredSeries, evt.data.SeriesInstanceUID],
})), })),
ignoreHydrationForSRSeries: assign((ctx, evt) => ({
ignoredSRSeriesForHydration: [...ctx.ignoredSRSeriesForHydration, evt.data.srSeriesInstanceUID],
})),
addTrackedSeries: assign((ctx, evt) => ({ addTrackedSeries: assign((ctx, evt) => ({
prevTrackedSeries: [...ctx.trackedSeries], prevTrackedSeries: [...ctx.trackedSeries],
trackedSeries: [...ctx.trackedSeries, evt.data.SeriesInstanceUID], trackedSeries: [...ctx.trackedSeries, evt.data.SeriesInstanceUID],
@ -348,6 +358,8 @@ const defaultOptions = {
evt.data && evt.data.userResponse === RESPONSE.NO_NOT_FOR_SERIES, evt.data && evt.data.userResponse === RESPONSE.NO_NOT_FOR_SERIES,
shouldPromptSaveReport: (ctx, evt) => shouldPromptSaveReport: (ctx, evt) =>
evt.data && evt.data.userResponse === RESPONSE.CREATE_REPORT, evt.data && evt.data.userResponse === RESPONSE.CREATE_REPORT,
shouldIgnoreHydrationForSR: (ctx, evt) =>
evt.data && evt.data.userResponse === RESPONSE.CANCEL,
shouldSaveAndContinueWithSameReport: (ctx, evt) => shouldSaveAndContinueWithSameReport: (ctx, evt) =>
evt.data && evt.data &&
evt.data.userResponse === RESPONSE.CREATE_REPORT && evt.data.userResponse === RESPONSE.CREATE_REPORT &&
@ -363,6 +375,9 @@ const defaultOptions = {
hasRemainingTrackedSeries: (ctx, evt) => hasRemainingTrackedSeries: (ctx, evt) =>
ctx.trackedSeries.length > 1 || ctx.trackedSeries.length > 1 ||
!ctx.trackedSeries.includes(evt.SeriesInstanceUID), !ctx.trackedSeries.includes(evt.SeriesInstanceUID),
hasNotIgnoredSRSeriesForHydration: (ctx, evt) => {
return !ctx.ignoredSRSeriesForHydration.includes(evt.SeriesInstanceUID)
},
isNewStudy: (ctx, evt) => isNewStudy: (ctx, evt) =>
!ctx.ignoredSeries.includes(evt.SeriesInstanceUID) && !ctx.ignoredSeries.includes(evt.SeriesInstanceUID) &&
ctx.trackedStudy !== evt.StudyInstanceUID, ctx.trackedStudy !== evt.StudyInstanceUID,

View File

@ -11,8 +11,9 @@ const RESPONSE = {
}; };
function promptUser({ servicesManager, extensionManager }, ctx, evt) { function promptUser({ servicesManager, extensionManager }, ctx, evt) {
const { UIViewportDialogService } = servicesManager.services; const { UIViewportDialogService, DisplaySetService } = servicesManager.services;
const { viewportIndex, displaySetInstanceUID } = evt; const { viewportIndex, displaySetInstanceUID } = evt;
const srDisplaySet = DisplaySetService.getDisplaySetByUID(displaySetInstanceUID)
return new Promise(async function(resolve, reject) { return new Promise(async function(resolve, reject) {
const promptResult = await _askTrackMeasurements( const promptResult = await _askTrackMeasurements(
@ -37,6 +38,7 @@ function promptUser({ servicesManager, extensionManager }, ctx, evt) {
resolve({ resolve({
userResponse: promptResult, userResponse: promptResult,
displaySetInstanceUID: evt.displaySetInstanceUID, displaySetInstanceUID: evt.displaySetInstanceUID,
srSeriesInstanceUID: srDisplaySet.SeriesInstanceUID,
viewportIndex, viewportIndex,
StudyInstanceUID, StudyInstanceUID,
SeriesInstanceUIDs, SeriesInstanceUIDs,

View File

@ -260,7 +260,8 @@ function PanelStudyBrowserTracking({
setExpandedStudyInstanceUIDs(updatedExpandedStudyInstanceUIDs); setExpandedStudyInstanceUIDs(updatedExpandedStudyInstanceUIDs);
if (!shouldCollapseStudy) { if (!shouldCollapseStudy) {
requestDisplaySetCreationForStudy(DisplaySetService, StudyInstanceUID); const madeInClient = true
requestDisplaySetCreationForStudy(DisplaySetService, StudyInstanceUID, madeInClient);
} }
} }

View File

@ -1,7 +1,8 @@
function requestDisplaySetCreationForStudy( function requestDisplaySetCreationForStudy(
dataSource, dataSource,
DisplaySetService, DisplaySetService,
StudyInstanceUID StudyInstanceUID,
madeInClient,
) { ) {
if ( if (
DisplaySetService.activeDisplaySets.some( DisplaySetService.activeDisplaySets.some(
@ -11,7 +12,7 @@ function requestDisplaySetCreationForStudy(
return; return;
} }
dataSource.retrieveSeriesMetadata({ StudyInstanceUID }); dataSource.retrieveSeriesMetadata({ StudyInstanceUID, madeInClient });
} }
export default requestDisplaySetCreationForStudy; export default requestDisplaySetCreationForStudy;

View File

@ -15,14 +15,15 @@ const { windowLevelPresets } = defaults;
* @param {*} icon * @param {*} icon
* @param {*} label * @param {*} label
*/ */
function _createButton(type, id, icon, label, commandName, commandOptions) { function _createButton(type, id, icon, label, commandName, commandOptions, tooltip) {
return { return {
id, id,
icon, icon,
label, label,
type, type,
commandName, commandName,
commandOptions commandOptions,
tooltip,
}; };
} }
@ -56,9 +57,14 @@ export default [
groupId: 'MeasurementTools', groupId: 'MeasurementTools',
isRadio: true, // ? isRadio: true, // ?
// Switch? // Switch?
primary: _createToolButton('Length', 'tool-length', 'Length', undefined, { primary: _createToolButton(
toolName: 'Length', 'Length',
}), 'tool-length',
'Length',
undefined,
{ toolName: 'Length' },
'Length'
),
secondary: { secondary: {
icon: 'chevron-down', icon: 'chevron-down',
label: '', label: '',
@ -66,22 +72,29 @@ export default [
tooltip: 'More Measure Tools', tooltip: 'More Measure Tools',
}, },
items: [ items: [
_createToolButton('Length', 'tool-length', 'Length', undefined, { _createToolButton(
toolName: 'Length', 'Length',
}), 'tool-length',
'Length',
undefined,
{ toolName: 'Length' },
'Length Tool'
),
_createToolButton( _createToolButton(
'Bidirectional', 'Bidirectional',
'tool-bidirectional', 'tool-bidirectional',
'Bidirectional', 'Bidirectional',
undefined, undefined,
{ toolName: 'Bidirectional' } { toolName: 'Bidirectional' },
'Bidirectional Tool'
), ),
_createToolButton( _createToolButton(
'ArrowAnnotate', 'ArrowAnnotate',
'tool-annotate', 'tool-annotate',
'Annotation', 'Annotation',
undefined, undefined,
{ toolName: 'ArrowAnnotate' } { toolName: 'ArrowAnnotate' },
'Arrow Annotate'
), ),
_createToolButton( _createToolButton(
'EllipticalRoi', 'EllipticalRoi',
@ -90,7 +103,8 @@ export default [
undefined, undefined,
{ {
toolName: 'EllipticalRoi', toolName: 'EllipticalRoi',
} },
'Ellipse Tool'
), ),
], ],
}, },
@ -117,7 +131,8 @@ export default [
'tool-window-level', 'tool-window-level',
'Window Level', 'Window Level',
undefined, undefined,
{ toolName: 'Wwwc' } { toolName: 'Wwwc' },
'Window Level'
), ),
secondary: { secondary: {
icon: 'chevron-down', icon: 'chevron-down',
@ -172,7 +187,9 @@ export default [
'Reset', 'Reset',
'tool-reset', 'tool-reset',
'Reset View', 'Reset View',
'resetViewport' 'resetViewport',
undefined,
'Reset'
), ),
secondary: { secondary: {
icon: 'chevron-down', icon: 'chevron-down',
@ -185,49 +202,81 @@ export default [
'Reset', 'Reset',
'tool-reset', 'tool-reset',
'Reset View', 'Reset View',
'resetViewport' 'resetViewport',
undefined,
'Reset'
), ),
_createActionButton( _createActionButton(
'rotate-right', 'rotate-right',
'tool-rotate-right', 'tool-rotate-right',
'Rotate Right', 'Rotate Right',
'rotateViewportCW' 'rotateViewportCW',
undefined,
'Rotate +90'
), ),
_createActionButton( _createActionButton(
'flip-horizontal', 'flip-horizontal',
'tool-flip-horizontal', 'tool-flip-horizontal',
'Flip Horizontally', 'Flip Horizontally',
'flipViewportHorizontal' 'flipViewportHorizontal',
undefined,
'Flip Horizontal'
), ),
_createToolButton( _createToolButton(
'StackScroll', 'StackScroll',
'tool-stack-scroll', 'tool-stack-scroll',
'Stack Scroll', 'Stack Scroll',
undefined, undefined,
{ toolName: 'StackScroll' } { toolName: 'StackScroll' },
'Stack Scroll'
),
_createToolButton(
'Magnify',
'tool-magnify',
'Magnify',
undefined,
{ toolName: 'Magnify' },
'Magnify'
), ),
_createToolButton('Magnify', 'tool-magnify', 'Magnify', undefined, {
toolName: 'Magnify',
}),
_createActionButton( _createActionButton(
'invert', 'invert',
'tool-invert', 'tool-invert',
'Invert', 'Invert',
'invertViewport' 'invertViewport',
undefined,
'Invert Colors'
),
_createToggleButton(
'cine',
'tool-cine',
'Cine',
'toggleCine',
undefined,
'Cine'
),
_createToolButton(
'Angle',
'tool-angle',
'Angle',
undefined,
{ toolName: 'Angle' },
'Angle'
),
_createToolButton(
'DragProbe',
'tool-probe',
'Probe',
undefined,
{ toolName: 'DragProbe' },
'Probe'
), ),
_createToggleButton('cine', 'tool-cine', 'Cine', 'toggleCine'),
_createToolButton('Angle', 'tool-angle', 'Angle', undefined, {
toolName: 'Angle',
}),
_createToolButton('DragProbe', 'tool-probe', 'Probe', undefined, {
toolName: 'DragProbe',
}),
_createToolButton( _createToolButton(
'Rectangle', 'Rectangle',
'tool-rectangle', 'tool-rectangle',
'Rectangle', 'Rectangle',
undefined, undefined,
{ toolName: 'RectangleRoi' } { toolName: 'RectangleRoi' },
'Rectangle'
), ),
], ],
}, },

View File

@ -20,6 +20,7 @@
"cm": "npx git-cz", "cm": "npx git-cz",
"build": "lerna run build:viewer --stream", "build": "lerna run build:viewer --stream",
"build:ci": "lerna run build:viewer:ci --stream", "build:ci": "lerna run build:viewer:ci --stream",
"build:qa": "lerna run build:viewer:qa --stream",
"build:ui:deploy-preview": "lerna run build:ui:deploy-preview --stream", "build:ui:deploy-preview": "lerna run build:ui:deploy-preview --stream",
"build:demo": "lerna run build:viewer:demo --stream", "build:demo": "lerna run build:viewer:demo --stream",
"dev": "lerna run dev:viewer --stream", "dev": "lerna run dev:viewer --stream",

View File

@ -71,7 +71,7 @@ class HangingProtocolService {
this.customAttributeRetrievalCallbacks this.customAttributeRetrievalCallbacks
); );
// if there is no pre-defiend protocol // if there is no pre-defined protocol
if (!protocol || protocol.id === undefined) { if (!protocol || protocol.id === undefined) {
const matchedProtocol = this.ProtocolEngine.run(metaData); const matchedProtocol = this.ProtocolEngine.run(metaData);
this._setProtocol(matchedProtocol); this._setProtocol(matchedProtocol);

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -70,7 +70,10 @@ const ThumbnailTracked = ({
position="right" position="right"
content={ content={
<div className="flex flex-row flex-1"> <div className="flex flex-row flex-1">
<div className="flex flex-col flex-1 pr-4"> <div className="flex items-center justify-center pr-4 flex-2">
<Icon name="info-link" className="text-primary-active" />
</div>
<div className="flex flex-col flex-1">
<span> <span>
Series is Series is
<span className="text-white"> <span className="text-white">
@ -86,9 +89,7 @@ const ThumbnailTracked = ({
</span> </span>
)} )}
</div> </div>
<div className="flex items-center justify-center flex-2">
<Icon name="info-link" className="text-primary-active" />
</div>
</div> </div>
} }
> >

View File

@ -19,6 +19,7 @@
"scripts": { "scripts": {
"build:viewer": "cross-env NODE_ENV=production node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/webpack.pwa.js --progress", "build:viewer": "cross-env NODE_ENV=production node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/webpack.pwa.js --progress",
"build:viewer:ci": "cross-env NODE_ENV=production PUBLIC_URL=/ APP_CONFIG=config/netlify.js QUICK_BUILD=true node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/webpack.pwa.js", "build:viewer:ci": "cross-env NODE_ENV=production PUBLIC_URL=/ APP_CONFIG=config/netlify.js QUICK_BUILD=true node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/webpack.pwa.js",
"build:viewer:qa": "cross-env NODE_ENV=production APP_CONFIG=config/google.js node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/webpack.pwa.js --progress",
"build:viewer:demo": "cross-env NODE_ENV=production APP_CONFIG=config/demo.js HTML_TEMPLATE=rollbar.html QUICK_BUILD=true node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --progress --config .webpack/webpack.pwa.js", "build:viewer:demo": "cross-env NODE_ENV=production APP_CONFIG=config/demo.js HTML_TEMPLATE=rollbar.html QUICK_BUILD=true node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --progress --config .webpack/webpack.pwa.js",
"dev": "cross-env NODE_ENV=development webpack serve --config .webpack/webpack.pwa.js", "dev": "cross-env NODE_ENV=development webpack serve --config .webpack/webpack.pwa.js",
"dev:orthanc": "cross-env NODE_ENV=development PROXY_TARGET=/dicom-web PROXY_DOMAIN=http://localhost:8042 APP_CONFIG=config/docker_nginx-orthanc.js webpack serve --config .webpack/webpack.pwa.js", "dev:orthanc": "cross-env NODE_ENV=development PROXY_TARGET=/dicom-web PROXY_DOMAIN=http://localhost:8042 APP_CONFIG=config/docker_nginx-orthanc.js webpack serve --config .webpack/webpack.pwa.js",

View File

@ -1,19 +1,15 @@
window.config = { window.config = {
routerBasename: '/', routerBasename: '/',
enableGoogleCloudAdapter: true, enableGoogleCloudAdapter: false,
healthcareApiEndpoint: 'https://healthcare.googleapis.com/v1beta1',
servers: {
// This is an array, but we'll only use the first entry for now
dicomWeb: [],
},
// This is an array, but we'll only use the first entry for now // This is an array, but we'll only use the first entry for now
oidc: [ oidc: [
{ {
// ~ REQUIRED // ~ REQUIRED
// Authorization Server URL // Authorization Server URL
authority: 'https://accounts.google.com', authority: 'https://accounts.google.com',
client_id: 'YOURCLIENTID.apps.googleusercontent.com', client_id:
redirect_uri: '/callback', // `OHIFStandaloneViewer.js` '723928408739-k9k9r3i44j32rhu69vlnibipmmk9i57p.apps.googleusercontent.com',
redirect_uri: '/callback',
response_type: 'id_token token', response_type: 'id_token token',
scope: scope:
'email profile openid https://www.googleapis.com/auth/cloudplatformprojects.readonly https://www.googleapis.com/auth/cloud-healthcare', // email profile openid 'email profile openid https://www.googleapis.com/auth/cloudplatformprojects.readonly https://www.googleapis.com/auth/cloud-healthcare', // email profile openid
@ -24,5 +20,46 @@ window.config = {
revokeAccessTokenOnSignout: true, revokeAccessTokenOnSignout: true,
}, },
], ],
studyListFunctionsEnabled: true, // whiteLabelling: {},
extensions: [],
modes: [],
showStudyList: true,
// filterQueryParam: false,
dataSources: [
{
friendlyName: 'dcmjs DICOMWeb Server',
namespace: 'org.ohif.default.dataSourcesModule.dicomweb',
sourceName: 'dicomweb',
configuration: {
name: 'GCP',
wadoUriRoot:
'https://healthcare.googleapis.com/v1/projects/ohif-cloud-healthcare/locations/us-east4/datasets/ohif-qa-dataset/dicomStores/ohif-qa-2/dicomWeb',
qidoRoot:
'https://healthcare.googleapis.com/v1/projects/ohif-cloud-healthcare/locations/us-east4/datasets/ohif-qa-dataset/dicomStores/ohif-qa-2/dicomWeb',
wadoRoot:
'https://healthcare.googleapis.com/v1/projects/ohif-cloud-healthcare/locations/us-east4/datasets/ohif-qa-dataset/dicomStores/ohif-qa-2/dicomWeb',
qidoSupportsIncludeField: true,
imageRendering: 'wadors',
thumbnailRendering: 'wadors',
enableStudyLazyLoad: true,
supportsFuzzyMatching: true,
supportsWildcard: false,
},
},
{
friendlyName: 'dicom json',
namespace: 'org.ohif.default.dataSourcesModule.dicomjson',
sourceName: 'dicomjson',
configuration: {
name: 'json',
},
},
{
friendlyName: 'dicom local',
namespace: 'org.ohif.default.dataSourcesModule.dicomlocal',
sourceName: 'dicomlocal',
configuration: {},
},
],
defaultDataSourceName: 'dicomweb',
}; };

View File

@ -39,9 +39,11 @@ async function defaultRouteInit({
const { unsubscribe: seriesAddedUnsubscribe } = DicomMetadataStore.subscribe( const { unsubscribe: seriesAddedUnsubscribe } = DicomMetadataStore.subscribe(
DicomMetadataStore.EVENTS.SERIES_ADDED, DicomMetadataStore.EVENTS.SERIES_ADDED,
({ StudyInstanceUID }) => { ({ StudyInstanceUID, madeInClient }) => {
const studyMetadata = DicomMetadataStore.getStudy(StudyInstanceUID); const studyMetadata = DicomMetadataStore.getStudy(StudyInstanceUID);
HangingProtocolService.run(studyMetadata); if (!madeInClient) {
HangingProtocolService.run(studyMetadata);
}
} }
); );
unsubscriptions.push(seriesAddedUnsubscribe); unsubscriptions.push(seriesAddedUnsubscribe);