From 2410c6a50904c1235993900e837876cc26af019b Mon Sep 17 00:00:00 2001 From: Bill Wallace Date: Tue, 18 Feb 2025 18:19:09 -0500 Subject: [PATCH] fix: cache thumbnail in display set (#4782) --- .circleci/config.yml | 12 ++++----- .../src/getToolbarModule.ts | 8 ++++++ .../SegmentationService.ts | 3 ++- .../Panels/StudyBrowser/PanelStudyBrowser.tsx | 7 +++--- .../src/Panels/WrappedPanelStudyBrowser.tsx | 12 +++------ .../TrackedMeasurementsContext.tsx | 3 --- .../src/getPanelModule.tsx | 9 +------ .../PanelStudyBrowserTracking.tsx | 25 +++++++++++-------- .../PanelStudyBrowserTracking/index.tsx | 16 +++--------- platform/core/src/types/DisplaySet.ts | 6 +++++ 10 files changed, 47 insertions(+), 54 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d05ddd4b3..8079e8eb1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -341,8 +341,10 @@ jobs: steps: - install_bun - run: - name: Install Xvfb - command: sudo apt-get update && sudo apt-get install -y xvfb + name: Install System Dependencies + command: | + sudo apt-get update + sudo apt-get install -y xvfb libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 - run: name: Start Xvfb command: Xvfb :99 -screen 0 1920x1080x24 & @@ -351,13 +353,11 @@ jobs: name: Export Display Variable command: export DISPLAY=:99 - cypress/install: - install-browsers: true install-command: bun install --no-save package-manager: yarn - cypress/run-tests: - cypress-command: - npx wait-on@latest http://localhost:3000 && cd platform/app && npx cypress run --record - --browser chrome --parallel + cypress-command: | + npx wait-on@latest http://localhost:3000 && cd platform/app && npx cypress run --record --parallel start-command: bun run test:data && bun run test:e2e:serve DOCKER_MULTIARCH_MANIFEST: diff --git a/extensions/cornerstone-dicom-seg/src/getToolbarModule.ts b/extensions/cornerstone-dicom-seg/src/getToolbarModule.ts index d2bc01b06..fdd32c1c7 100644 --- a/extensions/cornerstone-dicom-seg/src/getToolbarModule.ts +++ b/extensions/cornerstone-dicom-seg/src/getToolbarModule.ts @@ -25,6 +25,14 @@ export function getToolbarModule({ servicesManager }: withAppTypes) { }; } + const activeSegmentation = segmentationService.getActiveSegmentation(viewportId); + if (!Object.keys(activeSegmentation.segments).length) { + return { + disabled: true, + disabledText: 'Add segment to enable this tool', + }; + } + const toolGroup = toolGroupService.getToolGroupForViewport(viewportId); if (!toolGroup) { diff --git a/extensions/cornerstone/src/services/SegmentationService/SegmentationService.ts b/extensions/cornerstone/src/services/SegmentationService/SegmentationService.ts index 49e672af7..4290cc4e5 100644 --- a/extensions/cornerstone/src/services/SegmentationService/SegmentationService.ts +++ b/extensions/cornerstone/src/services/SegmentationService/SegmentationService.ts @@ -809,7 +809,8 @@ class SegmentationService extends PubSubService { if (!segmentIndex) { // grab the next available segment index based on the object keys, // so basically get the highest segment index value + 1 - segmentIndex = Math.max(...Object.keys(csSegmentation.segments).map(Number)) + 1; + const segmentKeys = Object.keys(csSegmentation.segments); + segmentIndex = segmentKeys.length === 0 ? 1 : Math.max(...segmentKeys.map(Number)) + 1; } // update the segmentation diff --git a/extensions/default/src/Panels/StudyBrowser/PanelStudyBrowser.tsx b/extensions/default/src/Panels/StudyBrowser/PanelStudyBrowser.tsx index c19b1d61b..f6ae36733 100644 --- a/extensions/default/src/Panels/StudyBrowser/PanelStudyBrowser.tsx +++ b/extensions/default/src/Panels/StudyBrowser/PanelStudyBrowser.tsx @@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react'; import { useImageViewer } from '@ohif/ui'; import { useViewportGrid } from '@ohif/ui-next'; import { StudyBrowser } from '@ohif/ui-next'; -import { utils } from '@ohif/core'; +import { useSystem, utils } from '@ohif/core'; import { useNavigate } from 'react-router-dom'; import { Separator } from '@ohif/ui-next'; import { PanelStudyBrowserHeader } from './PanelStudyBrowserHeader'; @@ -16,13 +16,12 @@ const { sortStudyInstances, formatDate, createStudyBrowserTabs } = utils; * @param {*} param0 */ function PanelStudyBrowser({ - servicesManager, getImageSrc, getStudiesForPatientByMRN, requestDisplaySetCreationForStudy, dataSource, - commandsManager, -}: withAppTypes) { +}) { + const { servicesManager, commandsManager } = useSystem(); const { hangingProtocolService, displaySetService, uiNotificationService, customizationService } = servicesManager.services; const navigate = useNavigate(); diff --git a/extensions/default/src/Panels/WrappedPanelStudyBrowser.tsx b/extensions/default/src/Panels/WrappedPanelStudyBrowser.tsx index 9553ace13..35b32ec9a 100644 --- a/extensions/default/src/Panels/WrappedPanelStudyBrowser.tsx +++ b/extensions/default/src/Panels/WrappedPanelStudyBrowser.tsx @@ -5,6 +5,7 @@ import PanelStudyBrowser from './StudyBrowser/PanelStudyBrowser'; import getImageSrcFromImageId from './getImageSrcFromImageId'; import getStudiesForPatientByMRN from './getStudiesForPatientByMRN'; import requestDisplaySetCreationForStudy from './requestDisplaySetCreationForStudy'; +import { useSystem } from '@ohif/core'; /** * Wraps the PanelStudyBrowser and provides features afforded by managers/services @@ -13,7 +14,8 @@ import requestDisplaySetCreationForStudy from './requestDisplaySetCreationForStu * @param {object} commandsManager * @param {object} extensionManager */ -function WrappedPanelStudyBrowser({ extensionManager, servicesManager, commandsManager }) { +function WrappedPanelStudyBrowser() { + const { extensionManager } = useSystem(); // TODO: This should be made available a different way; route should have // already determined our datasource const [dataSource] = extensionManager.getActiveDataSource(); @@ -29,8 +31,6 @@ function WrappedPanelStudyBrowser({ extensionManager, servicesManager, commandsM return ( ( - - ), + component: props => , }, { name: 'trackedMeasurements', diff --git a/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx b/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx index 2b4078be5..626c85970 100644 --- a/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx +++ b/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx @@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import PropTypes from 'prop-types'; -import { utils } from '@ohif/core'; +import { useSystem, utils } from '@ohif/core'; import { useImageViewer, Dialog, ButtonEnums } from '@ohif/ui'; import { useViewportGrid } from '@ohif/ui-next'; import { StudyBrowser } from '@ohif/ui-next'; @@ -30,13 +30,12 @@ const thumbnailNoImageModalities = [ * @param {*} param0 */ export default function PanelStudyBrowserTracking({ - servicesManager, getImageSrc, getStudiesForPatientByMRN, requestDisplaySetCreationForStudy, dataSource, - commandsManager, -}: withAppTypes) { +}) { + const { servicesManager, commandsManager } = useSystem(); const { displaySetService, uiDialogService, @@ -183,7 +182,7 @@ export default function PanelStudyBrowserTracking({ // so wait a bit of time to allow the viewports preferential loading // which improves user experience of responsiveness significantly on slower // systems. - window.setTimeout(() => setHasLoadedViewports(true), 250); + window.setTimeout(() => setHasLoadedViewports(true), 1000); } return; @@ -211,7 +210,15 @@ export default function PanelStudyBrowserTracking({ return; } // When the image arrives, render it and store the result in the thumbnailImgSrcMap - newImageSrcEntry[dSet.displaySetInstanceUID] = await getImageSrc(imageId); + let { thumbnailSrc } = displaySet; + if (!thumbnailSrc && displaySet.getThumbnailSrc) { + thumbnailSrc = await displaySet.getThumbnailSrc(); + } + if (!thumbnailSrc) { + let thumbnailSrc = await getImageSrc(imageId); + displaySet.thumbnailSrc = thumbnailSrc; + } + newImageSrcEntry[dSet.displaySetInstanceUID] = thumbnailSrc; setThumbnailImageSrcMap(prevState => { return { ...prevState, ...newImageSrcEntry }; @@ -532,7 +539,6 @@ export default function PanelStudyBrowserTracking({ } PanelStudyBrowserTracking.propTypes = { - servicesManager: PropTypes.object.isRequired, dataSource: PropTypes.shape({ getImageIdsForDisplaySet: PropTypes.func.isRequired, }).isRequired, @@ -593,13 +599,12 @@ function _mapDisplaySets( displaySets .filter(ds => !ds.excludeFromThumbnailBrowser) .forEach(ds => { - const imageSrc = thumbnailImageSrcMap[ds.displaySetInstanceUID]; + const { thumbnailSrc, displaySetInstanceUID } = ds; // thumbnailImageSrcMap[ds.displaySetInstanceUID]; const componentType = _getComponentType(ds); const array = componentType === 'thumbnailTracked' ? thumbnailDisplaySets : thumbnailNoImageDisplaySets; - const { displaySetInstanceUID } = ds; const loadingProgress = displaySetLoadingState?.[displaySetInstanceUID]; const thumbnailProps = { @@ -614,7 +619,7 @@ function _mapDisplaySets( messages: ds.messages, StudyInstanceUID: ds.StudyInstanceUID, componentType, - imageSrc, + imageSrc: thumbnailSrc || thumbnailImageSrcMap[displaySetInstanceUID], dragData: { type: 'displayset', displaySetInstanceUID, diff --git a/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/index.tsx b/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/index.tsx index 7ed1a10cc..962384ae1 100644 --- a/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/index.tsx +++ b/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/index.tsx @@ -4,6 +4,7 @@ import PropTypes from 'prop-types'; import PanelStudyBrowserTracking from './PanelStudyBrowserTracking'; import getImageSrcFromImageId from './getImageSrcFromImageId'; import { requestDisplaySetCreationForStudy } from '@ohif/extension-default'; +import { useSystem } from '@ohif/core'; function _getStudyForPatientUtility(extensionManager) { const utilityModule = extensionManager.getModuleEntry( @@ -21,11 +22,8 @@ function _getStudyForPatientUtility(extensionManager) { * @param {object} commandsManager * @param {object} extensionManager */ -function WrappedPanelStudyBrowserTracking({ - commandsManager, - extensionManager, - servicesManager, -}: withAppTypes) { +function WrappedPanelStudyBrowserTracking() { + const { extensionManager } = useSystem(); const dataSource = extensionManager.getActiveDataSource()[0]; const getStudiesForPatientByMRN = _getStudyForPatientUtility(extensionManager); @@ -41,8 +39,6 @@ function WrappedPanelStudyBrowserTracking({ return ( ; SeriesDate?: string; SeriesTime?: string; instance?: InstanceMetadata;