diff --git a/extensions/cornerstone-dicom-seg/package.json b/extensions/cornerstone-dicom-seg/package.json index 88eee447c..982eb1868 100644 --- a/extensions/cornerstone-dicom-seg/package.json +++ b/extensions/cornerstone-dicom-seg/package.json @@ -46,8 +46,8 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/adapters": "^1.70.8", - "@cornerstonejs/core": "^1.70.8", + "@cornerstonejs/adapters": "^1.70.9", + "@cornerstonejs/core": "^1.70.9", "@kitware/vtk.js": "30.3.3", "react-color": "^2.19.3" } diff --git a/extensions/cornerstone-dicom-seg/src/utils/hydrationUtils.ts b/extensions/cornerstone-dicom-seg/src/utils/hydrationUtils.ts index ad5898ee9..8726d9dc4 100644 --- a/extensions/cornerstone-dicom-seg/src/utils/hydrationUtils.ts +++ b/extensions/cornerstone-dicom-seg/src/utils/hydrationUtils.ts @@ -138,7 +138,7 @@ function getUpdatedViewportsForSegmentation({ const { hangingProtocolService, displaySetService, segmentationService, viewportGridService } = servicesManager.services; - const { viewports } = viewportGridService.getState(); + const { viewports, isHangingProtocolLayout } = viewportGridService.getState(); const viewport = getTargetViewport({ viewportId, viewportGridService }); const targetViewportId = viewport.viewportOptions.viewportId; @@ -153,7 +153,8 @@ function getUpdatedViewportsForSegmentation({ const updatedViewports = hangingProtocolService.getViewportsRequireUpdate( targetViewportId, - referenceDisplaySetInstanceUID + referenceDisplaySetInstanceUID, + isHangingProtocolLayout ); viewports.forEach((viewport, viewportId) => { diff --git a/extensions/cornerstone-dicom-sr/package.json b/extensions/cornerstone-dicom-sr/package.json index a6fbd908c..f325b2604 100644 --- a/extensions/cornerstone-dicom-sr/package.json +++ b/extensions/cornerstone-dicom-sr/package.json @@ -46,9 +46,9 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/adapters": "^1.70.8", - "@cornerstonejs/core": "^1.70.8", - "@cornerstonejs/tools": "^1.70.8", + "@cornerstonejs/adapters": "^1.70.9", + "@cornerstonejs/core": "^1.70.9", + "@cornerstonejs/tools": "^1.70.9", "classnames": "^2.3.2" } } diff --git a/extensions/cornerstone-dynamic-volume/package.json b/extensions/cornerstone-dynamic-volume/package.json index b0e6b1764..46ea7b748 100644 --- a/extensions/cornerstone-dynamic-volume/package.json +++ b/extensions/cornerstone-dynamic-volume/package.json @@ -42,9 +42,9 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/core": "^1.70.8", - "@cornerstonejs/streaming-image-volume-loader": "^1.70.8", - "@cornerstonejs/tools": "^1.70.8", + "@cornerstonejs/core": "^1.70.9", + "@cornerstonejs/streaming-image-volume-loader": "^1.70.9", + "@cornerstonejs/tools": "^1.70.9", "classnames": "^2.3.2" } } diff --git a/extensions/cornerstone/package.json b/extensions/cornerstone/package.json index db2c5cfc0..db6cca3e8 100644 --- a/extensions/cornerstone/package.json +++ b/extensions/cornerstone/package.json @@ -38,7 +38,7 @@ "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.2", "@cornerstonejs/codec-openjph": "^2.4.2", - "@cornerstonejs/dicom-image-loader": "^1.70.8", + "@cornerstonejs/dicom-image-loader": "^1.70.9", "@icr/polyseg-wasm": "^0.4.0", "@ohif/core": "3.8.0-beta.85", "@ohif/ui": "3.8.0-beta.85", @@ -55,10 +55,10 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/adapters": "^1.70.8", - "@cornerstonejs/core": "^1.70.8", - "@cornerstonejs/streaming-image-volume-loader": "^1.70.8", - "@cornerstonejs/tools": "^1.70.8", + "@cornerstonejs/adapters": "^1.70.9", + "@cornerstonejs/core": "^1.70.9", + "@cornerstonejs/streaming-image-volume-loader": "^1.70.9", + "@cornerstonejs/tools": "^1.70.9", "@icr/polyseg-wasm": "^0.4.0", "@kitware/vtk.js": "30.3.3", "html2canvas": "^1.4.1", diff --git a/extensions/cornerstone/src/hps/mpr.ts b/extensions/cornerstone/src/hps/mpr.ts index ea2219163..fa54ffde6 100644 --- a/extensions/cornerstone/src/hps/mpr.ts +++ b/extensions/cornerstone/src/hps/mpr.ts @@ -14,17 +14,7 @@ export const mpr: Types.HangingProtocol.Protocol = { numberOfPriorsReferenced: 0, protocolMatchingRules: [], imageLoadStrategy: 'nth', - callbacks: { - // Switches out of MPR mode when the layout change button is used - onLayoutChange: [ - { - commandName: 'toggleHangingProtocol', - commandOptions: { protocolId: 'mpr' }, - context: 'DEFAULT', - }, - ], - // Turns off crosshairs when switching out of MPR mode - }, + callbacks: {}, displaySetSelectors: { activeDisplaySet: { seriesMatchingRules: [ diff --git a/extensions/cornerstone/src/initCornerstoneTools.js b/extensions/cornerstone/src/initCornerstoneTools.js index b40946ff9..cdbf662d4 100644 --- a/extensions/cornerstone/src/initCornerstoneTools.js +++ b/extensions/cornerstone/src/initCornerstoneTools.js @@ -44,6 +44,7 @@ import ImageOverlayViewerTool from './tools/ImageOverlayViewerTool'; export default function initCornerstoneTools(configuration = {}) { CrosshairsTool.isAnnotation = false; ReferenceLinesTool.isAnnotation = false; + AdvancedMagnifyTool.isAnnotation = false; init(configuration); addTool(PanTool); diff --git a/extensions/default/src/Panels/PanelStudyBrowser.tsx b/extensions/default/src/Panels/PanelStudyBrowser.tsx index e1b65d401..e1e6c30c0 100644 --- a/extensions/default/src/Panels/PanelStudyBrowser.tsx +++ b/extensions/default/src/Panels/PanelStudyBrowser.tsx @@ -25,7 +25,8 @@ function PanelStudyBrowser({ // doesn't have to have such an intense shape. This works well enough for now. // Tabs --> Studies --> DisplaySets --> Thumbnails const { StudyInstanceUIDs } = useImageViewer(); - const [{ activeViewportId, viewports }, viewportGridService] = useViewportGrid(); + const [{ activeViewportId, viewports, isHangingProtocolLayout }, viewportGridService] = + useViewportGrid(); const [activeTabName, setActiveTabName] = useState('primary'); const [expandedStudyInstanceUIDs, setExpandedStudyInstanceUIDs] = useState([ ...StudyInstanceUIDs, @@ -40,7 +41,8 @@ function PanelStudyBrowser({ try { updatedViewports = hangingProtocolService.getViewportsRequireUpdate( viewportId, - displaySetInstanceUID + displaySetInstanceUID, + isHangingProtocolLayout ); } catch (error) { console.warn(error); diff --git a/extensions/default/src/Toolbar/ToolbarLayoutSelector.tsx b/extensions/default/src/Toolbar/ToolbarLayoutSelector.tsx index e39066d21..0f4b2e0c8 100644 --- a/extensions/default/src/Toolbar/ToolbarLayoutSelector.tsx +++ b/extensions/default/src/Toolbar/ToolbarLayoutSelector.tsx @@ -58,6 +58,10 @@ const generateAdvancedPresets = ({ servicesManager }) => { } const displaySetInsaneUIDs = viewportGridService.getDisplaySetsUIDsForViewport(viewportId); + if (!displaySetInsaneUIDs) { + return []; + } + const displaySets = displaySetInsaneUIDs.map(uid => displaySetService.getDisplaySetByUID(uid)); return hangingProtocols diff --git a/extensions/default/src/commandsModule.ts b/extensions/default/src/commandsModule.ts index e302e860b..76507b203 100644 --- a/extensions/default/src/commandsModule.ts +++ b/extensions/default/src/commandsModule.ts @@ -286,6 +286,7 @@ const commandsModule = ({ const findOrCreateViewport = layoutFindOrCreate.bind( null, hangingProtocolService, + isHangingProtocolLayout, stateReduce.viewportsByPosition ); @@ -303,7 +304,7 @@ const commandsModule = ({ toggleOneUp() { const viewportGridState = viewportGridService.getState(); - const { activeViewportId, viewports, layout } = viewportGridState; + const { activeViewportId, viewports, layout, isHangingProtocolLayout } = viewportGridState; const { displaySetInstanceUIDs, displaySetOptions, viewportOptions } = viewports.get(activeViewportId); @@ -330,7 +331,8 @@ const commandsModule = ({ .map(displaySetInstanceUID => hangingProtocolService.getViewportsRequireUpdate( viewportIdToUpdate, - displaySetInstanceUID + displaySetInstanceUID, + isHangingProtocolLayout ) ) .flat(); @@ -511,7 +513,8 @@ const commandsModule = ({ currentDisplaySets.sort(dsSortFn); - const { activeViewportId, viewports } = viewportGridService.getState(); + const { activeViewportId, viewports, isHangingProtocolLayout } = + viewportGridService.getState(); const { displaySetInstanceUIDs } = viewports.get(activeViewportId); @@ -545,7 +548,8 @@ const commandsModule = ({ try { updatedViewports = hangingProtocolService.getViewportsRequireUpdate( activeViewportId, - displaySetInstanceUID + displaySetInstanceUID, + isHangingProtocolLayout ); } catch (error) { console.warn(error); diff --git a/extensions/default/src/findViewportsByPosition.ts b/extensions/default/src/findViewportsByPosition.ts index c5fbafd35..7d0d10f83 100644 --- a/extensions/default/src/findViewportsByPosition.ts +++ b/extensions/default/src/findViewportsByPosition.ts @@ -16,6 +16,7 @@ import { StateSyncService } from '@ohif/core'; */ export const findOrCreateViewport = ( hangingProtocolService, + isHangingProtocolLayout, viewportsByPosition, position: number, positionId: string, @@ -31,8 +32,13 @@ export const findOrCreateViewport = ( if (!options.inDisplay) { options.inDisplay = [...viewportsByPosition.initialInDisplay]; } - // See if there is a default viewport for new views. - const missing = hangingProtocolService.getMissingViewport(protocolId, stageIndex, options); + + // See if there is a default viewport for new views + const missing = hangingProtocolService.getMissingViewport( + isHangingProtocolLayout ? protocolId : 'default', + stageIndex, + options + ); if (missing) { const displaySetInstanceUIDs = missing.displaySetsInfo.map(it => it.displaySetInstanceUID); options.inDisplay.push(...displaySetInstanceUIDs); diff --git a/extensions/default/src/getSopClassHandlerModule.js b/extensions/default/src/getSopClassHandlerModule.js index bdbb7057d..28a677ff7 100644 --- a/extensions/default/src/getSopClassHandlerModule.js +++ b/extensions/default/src/getSopClassHandlerModule.js @@ -37,6 +37,8 @@ function getDisplaySetInfo(instances) { const { isDynamicVolume, timePoints } = dynamicVolumeInfo; let displaySetInfo; + const { appConfig } = appContext; + if (isDynamicVolume) { const timePoint = timePoints[0]; const instancesMap = new Map(); @@ -46,9 +48,9 @@ function getDisplaySetInfo(instances) { const firstTimePointInstances = timePoint.map(imageId => instancesMap.get(imageId)); - displaySetInfo = isDisplaySetReconstructable(firstTimePointInstances); + displaySetInfo = isDisplaySetReconstructable(firstTimePointInstances, appConfig); } else { - displaySetInfo = isDisplaySetReconstructable(instances); + displaySetInfo = isDisplaySetReconstructable(instances, appConfig); } return { diff --git a/extensions/measurement-tracking/package.json b/extensions/measurement-tracking/package.json index ff87ce3aa..24f1d4ba8 100644 --- a/extensions/measurement-tracking/package.json +++ b/extensions/measurement-tracking/package.json @@ -32,8 +32,8 @@ "start": "yarn run dev" }, "peerDependencies": { - "@cornerstonejs/core": "^1.70.8", - "@cornerstonejs/tools": "^1.70.8", + "@cornerstonejs/core": "^1.70.9", + "@cornerstonejs/tools": "^1.70.9", "@ohif/core": "3.8.0-beta.85", "@ohif/extension-cornerstone-dicom-sr": "3.8.0-beta.85", "@ohif/ui": "3.8.0-beta.85", diff --git a/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx b/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx index 4d9dc3a4d..05cce40ec 100644 --- a/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx +++ b/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx @@ -34,7 +34,8 @@ function PanelStudyBrowserTracking({ // doesn't have to have such an intense shape. This works well enough for now. // Tabs --> Studies --> DisplaySets --> Thumbnails const { StudyInstanceUIDs } = useImageViewer(); - const [{ activeViewportId, viewports }, viewportGridService] = useViewportGrid(); + const [{ activeViewportId, viewports, isHangingProtocolLayout }, viewportGridService] = + useViewportGrid(); const [trackedMeasurements, sendTrackedMeasurementsEvent] = useTrackedMeasurements(); const [activeTabName, setActiveTabName] = useState('primary'); const [expandedStudyInstanceUIDs, setExpandedStudyInstanceUIDs] = useState([ @@ -51,7 +52,8 @@ function PanelStudyBrowserTracking({ try { updatedViewports = hangingProtocolService.getViewportsRequireUpdate( viewportId, - displaySetInstanceUID + displaySetInstanceUID, + isHangingProtocolLayout ); } catch (error) { console.warn(error); diff --git a/modes/basic-test-mode/src/moreTools.ts b/modes/basic-test-mode/src/moreTools.ts index d1f34ec09..98ef45de6 100644 --- a/modes/basic-test-mode/src/moreTools.ts +++ b/modes/basic-test-mode/src/moreTools.ts @@ -138,8 +138,8 @@ const moreTools = [ createButton({ id: 'Magnify', icon: 'tool-magnify', - label: 'Magnify', - tooltip: 'Magnify', + label: 'Zoom-in', + tooltip: 'Zoom-in', commands: setToolActiveToolbar, evaluate: 'evaluate.cornerstoneTool', }), @@ -169,8 +169,8 @@ const moreTools = [ createButton({ id: 'AdvancedMagnify', icon: 'icon-tool-loupe', - label: 'Loupe', - tooltip: 'Loupe', + label: 'Magnify Probe', + tooltip: 'Magnify Probe', commands: 'toggleActiveDisabledToolbar', evaluate: 'evaluate.cornerstoneTool.toggle.ifStrictlyDisabled', }), diff --git a/modes/longitudinal/src/moreTools.ts b/modes/longitudinal/src/moreTools.ts index 101aebf80..0550ef839 100644 --- a/modes/longitudinal/src/moreTools.ts +++ b/modes/longitudinal/src/moreTools.ts @@ -138,8 +138,8 @@ const moreTools = [ createButton({ id: 'Magnify', icon: 'tool-magnify', - label: 'Magnify', - tooltip: 'Magnify', + label: 'Zoom-in', + tooltip: 'Zoom-in', commands: setToolActiveToolbar, evaluate: 'evaluate.cornerstoneTool', }), @@ -161,8 +161,8 @@ const moreTools = [ createButton({ id: 'AdvancedMagnify', icon: 'icon-tool-loupe', - label: 'Loupe', - tooltip: 'Loupe', + label: 'Magnify Probe', + tooltip: 'Magnify Probe', commands: 'toggleActiveDisabledToolbar', evaluate: 'evaluate.cornerstoneTool.toggle.ifStrictlyDisabled', }), diff --git a/modes/segmentation/src/toolbarButtons.ts b/modes/segmentation/src/toolbarButtons.ts index 1d1b445be..11229f031 100644 --- a/modes/segmentation/src/toolbarButtons.ts +++ b/modes/segmentation/src/toolbarButtons.ts @@ -207,8 +207,8 @@ const toolbarButtons: Button[] = [ createButton({ id: 'Magnify', icon: 'tool-magnify', - label: 'Magnify', - tooltip: 'Magnify', + label: 'Zoom-in', + tooltip: 'Zoom-in', commands: setToolActiveToolbar, evaluate: 'evaluate.cornerstoneTool', }), @@ -238,8 +238,8 @@ const toolbarButtons: Button[] = [ createButton({ id: 'AdvancedMagnify', icon: 'icon-tool-loupe', - label: 'Loupe', - tooltip: 'Loupe', + label: 'Magnify Probe', + tooltip: 'Magnify Probe', commands: 'toggleActiveDisabledToolbar', evaluate: 'evaluate.cornerstoneTool.toggle.ifStrictlyDisabled', }), diff --git a/platform/app/cypress/integration/study-list/OHIFStudyList.spec.js b/platform/app/cypress/integration/study-list/OHIFStudyList.spec.js index e59df25cf..437880aaa 100644 --- a/platform/app/cypress/integration/study-list/OHIFStudyList.spec.js +++ b/platform/app/cypress/integration/study-list/OHIFStudyList.spec.js @@ -47,6 +47,8 @@ describe('OHIF Study List', function () { '[data-cy="mode-basic-test-1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1"]' ).click(); cy.get('[data-cy="return-to-work-list"]').click(); + cy.wait(2000); + cy.get('@searchResult2').should($list => { expect($list.length).to.be.eq(1); expect($list).to.contain('Juno'); @@ -72,6 +74,8 @@ describe('OHIF Study List', function () { '[data-cy="mode-basic-test-1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1"]' ).click(); cy.get('[data-cy="return-to-work-list"]').click(); + cy.wait(2000); + cy.get('@searchResult2').should($list => { expect($list.length).to.be.eq(1); expect($list).to.contain('0000003'); @@ -82,6 +86,7 @@ describe('OHIF Study List', function () { cy.get('@AccessionNumber').type('321'); //Wait result list to be displayed cy.waitStudyList(); + cy.wait(2000); cy.get('@searchResult2').should($list => { expect($list.length).to.be.eq(1); expect($list).to.contain('321'); @@ -92,11 +97,15 @@ describe('OHIF Study List', function () { cy.get('@AccessionNumber').type('0000155811'); //Wait result list to be displayed cy.waitStudyList(); + cy.wait(2000); + cy.get('[data-cy="studyRow-1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1"]').click(); cy.get( '[data-cy="mode-basic-test-1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1"]' ).click(); cy.get('[data-cy="return-to-work-list"]').click(); + cy.wait(2000); + cy.get('@searchResult2').should($list => { expect($list.length).to.be.eq(1); expect($list).to.contain('0000155811'); @@ -107,6 +116,8 @@ describe('OHIF Study List', function () { cy.get('@StudyDescription').type('PETCT'); //Wait result list to be displayed cy.waitStudyList(); + cy.wait(2000); + cy.get('@searchResult2').should($list => { expect($list.length).to.be.eq(1); expect($list).to.contain('PETCT'); @@ -117,13 +128,15 @@ describe('OHIF Study List', function () { cy.get('@StudyDescription').type('PETCT'); //Wait result list to be displayed cy.waitStudyList(); + cy.wait(2000); + cy.get('[data-cy="studyRow-1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1"]').click(); cy.get( '[data-cy="mode-basic-test-1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1"]' ).click(); cy.get('[data-cy="return-to-work-list"]').click(); + cy.wait(2000); - cy.wait(1000); cy.get('@searchResult2').should($list => { expect($list.length).to.be.eq(1); expect($list).to.contain('PETCT'); diff --git a/platform/app/package.json b/platform/app/package.json index 9215119e6..fd75a8e8f 100644 --- a/platform/app/package.json +++ b/platform/app/package.json @@ -54,7 +54,7 @@ "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.2", "@cornerstonejs/codec-openjph": "^2.4.5", - "@cornerstonejs/dicom-image-loader": "^1.70.8", + "@cornerstonejs/dicom-image-loader": "^1.70.9", "@emotion/serialize": "^1.1.3", "@ohif/core": "3.8.0-beta.85", "@ohif/extension-cornerstone": "3.8.0-beta.85", diff --git a/platform/app/src/App.tsx b/platform/app/src/App.tsx index ec170ab40..35a9c094b 100644 --- a/platform/app/src/App.tsx +++ b/platform/app/src/App.tsx @@ -62,6 +62,13 @@ function App({ config, defaultExtensions, defaultModes }) { const appConfigState = init.appConfig; const { routerBasename, modes, dataSources, oidc, showStudyList } = appConfigState; + // get the maximum 3D texture size + const canvas = document.createElement('canvas'); + const gl = canvas.getContext('webgl2'); + + const max3DTextureSize = gl.getParameter(gl.MAX_3D_TEXTURE_SIZE); + appConfigState.max3DTextureSize = max3DTextureSize; + const { uiDialogService, uiModalService, diff --git a/platform/app/src/components/ViewportGrid.tsx b/platform/app/src/components/ViewportGrid.tsx index ab0e09112..45a74910a 100644 --- a/platform/app/src/components/ViewportGrid.tsx +++ b/platform/app/src/components/ViewportGrid.tsx @@ -103,20 +103,12 @@ function ViewerViewportGrid(props) { const _getUpdatedViewports = useCallback( (viewportId, displaySetInstanceUID) => { - if (!isHangingProtocolLayout) { - return [ - { - viewportId, - displaySetInstanceUIDs: [displaySetInstanceUID], - }, - ]; - } - let updatedViewports = []; try { updatedViewports = hangingProtocolService.getViewportsRequireUpdate( viewportId, - displaySetInstanceUID + displaySetInstanceUID, + isHangingProtocolLayout ); } catch (error) { console.warn(error); diff --git a/platform/core/package.json b/platform/core/package.json index c70ae3a3a..c3f16be3a 100644 --- a/platform/core/package.json +++ b/platform/core/package.json @@ -37,7 +37,7 @@ "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.2", "@cornerstonejs/codec-openjph": "^2.4.2", - "@cornerstonejs/dicom-image-loader": "^1.70.8", + "@cornerstonejs/dicom-image-loader": "^1.70.9", "@ohif/ui": "3.8.0-beta.85", "cornerstone-math": "0.1.9", "dicom-parser": "^1.8.21" diff --git a/platform/core/src/services/HangingProtocolService/HangingProtocolService.ts b/platform/core/src/services/HangingProtocolService/HangingProtocolService.ts index 524a45615..317d7ae41 100644 --- a/platform/core/src/services/HangingProtocolService/HangingProtocolService.ts +++ b/platform/core/src/services/HangingProtocolService/HangingProtocolService.ts @@ -601,17 +601,25 @@ export default class HangingProtocolService extends PubSubService { }; } - getViewportsRequireUpdate(viewportId, displaySetInstanceUID) { - const { displaySetService } = this._servicesManager.services; - const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID); - if (displaySet?.unsupported) { - throw new Error('Unsupported displaySet'); - } + /** + * This will return the viewports that need to be updated based on the + * hanging protocol layout and the displaySetInstanceUID that needs to be updated. + * + * This is useful, when for instance we drag and drop a displaySet into a viewport + * which is in MPR, and we need to update the other viewports that are showing the same + * layout. + * + * However, sometimes since we get out of sync with the hanging protocol layout, when + * the user use the custom grid layout, we should not update the other viewports, and that is + * when the isHangingProtocolLayout is set to false. + * + * @param viewportId - the id of the viewport that needs to be updated + * @param displaySetInstanceUID - the displaySetInstanceUID that needs to be updated + * @param isHangingProtocolLayout - whether the layout is a hanging protocol layout + * @returns + */ + getViewportsRequireUpdate(viewportId, displaySetInstanceUID, isHangingProtocolLayout = true) { const newDisplaySetInstanceUID = displaySetInstanceUID; - const protocol = this.protocol; - const protocolStage = protocol.stages[this.stageIndex]; - const protocolViewports = protocolStage.viewports; - const defaultReturn = [ { viewportId, @@ -619,6 +627,19 @@ export default class HangingProtocolService extends PubSubService { }, ]; + if (!isHangingProtocolLayout) { + return defaultReturn; + } + + const { displaySetService } = this._servicesManager.services; + const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID); + if (displaySet?.unsupported) { + throw new Error('Unsupported displaySet'); + } + const protocol = this.protocol; + const protocolStage = protocol.stages[this.stageIndex]; + const protocolViewports = protocolStage.viewports; + if (!protocolViewports) { return defaultReturn; } @@ -1084,9 +1105,8 @@ export default class HangingProtocolService extends PubSubService { options ): HangingProtocol.ViewportMatchDetails { if (this.protocol.id !== protocolId) { - throw new Error( - `Currently applied protocol ${this.protocol.id} is different from ${protocolId}` - ); + console.warn('setting protocol'); + this.protocol = this.getProtocolById(protocolId); } const protocol = this.protocol; const stage = protocol.stages[stageIdx]; diff --git a/platform/core/src/utils/isDisplaySetReconstructable.js b/platform/core/src/utils/isDisplaySetReconstructable.js index c32b565b0..00decb83a 100644 --- a/platform/core/src/utils/isDisplaySetReconstructable.js +++ b/platform/core/src/utils/isDisplaySetReconstructable.js @@ -10,7 +10,7 @@ const iopTolerance = 0.01; * * @param {Object[]} instances An array of `OHIFInstanceMetadata` objects. */ -export default function isDisplaySetReconstructable(instances) { +export default function isDisplaySetReconstructable(instances, appConfig) { if (!instances.length) { return { value: false }; } @@ -18,6 +18,14 @@ export default function isDisplaySetReconstructable(instances) { const isMultiframe = firstInstance.NumberOfFrames > 1; + if (appConfig) { + const rows = toNumber(firstInstance.Rows); + const columns = toNumber(firstInstance.Columns); + + if (rows > appConfig.max3DTextureSize || columns > appConfig.max3DTextureSize) { + return { value: false }; + } + } // We used to check is reconstructable modalities here, but the logic is removed // in favor of the calculation by metadata (orientation and positions) diff --git a/platform/docs/docs/migration-guide/from-3p7-to-3p8.md b/platform/docs/docs/migration-guide/from-3p7-to-3p8.md index 48ea73890..dde25c341 100644 --- a/platform/docs/docs/migration-guide/from-3p7-to-3p8.md +++ b/platform/docs/docs/migration-guide/from-3p7-to-3p8.md @@ -135,3 +135,8 @@ Additional Resources ## leftPanelDefaultClosed and rightPanelDefaultClosed Now they are renamed to `leftPanelClosed` and `rightPanelClosed` respectively. + + +## StudyInstanceUID in the URL param + +Previously there were two params that you could choose: seriesInstanceUID and seriesInstanceUIDs, they have been replaced with seriesInstanceUIDs so even if you would like to filter one series use ``seriesInstanceUIDs` diff --git a/platform/docs/docs/platform/services/data/StateSyncService.md b/platform/docs/docs/platform/services/data/StateSyncService.md index 6688c5eca..49fdbf0c3 100644 --- a/platform/docs/docs/platform/services/data/StateSyncService.md +++ b/platform/docs/docs/platform/services/data/StateSyncService.md @@ -69,7 +69,6 @@ list as state stores are added: * `viewportGridStore` has viewport grid restore information for returning to an earlier grid layout. * `reuseIdMap` has a map of names to display sets for preserving user changes to hp display set selections. * `hanging` has a map of the hanging protocol stage information applied (HPInfo) -* `toggleHangingProtocol` has the previously applied hanging protocol, to toggle an HP off. ### Cornerstone Extension Stores diff --git a/platform/ui/src/components/Thumbnail/Thumbnail.tsx b/platform/ui/src/components/Thumbnail/Thumbnail.tsx index 578f4a73f..c527102d1 100644 --- a/platform/ui/src/components/Thumbnail/Thumbnail.tsx +++ b/platform/ui/src/components/Thumbnail/Thumbnail.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import { useDrag } from 'react-dnd'; @@ -35,6 +35,19 @@ const Thumbnail = ({ }, }); + const [lastTap, setLastTap] = useState(0); + + const handleTouchEnd = e => { + const currentTime = new Date().getTime(); + const tapLength = currentTime - lastTap; + if (tapLength < 300 && tapLength > 0) { + onDoubleClick(e); + } else { + onClick(e); + } + setLastTap(currentTime); + }; + return (