From adedc8c382e18a2e86a569e3d023cc55a157363f Mon Sep 17 00:00:00 2001 From: Joe Boccanfuso <109477394+jbocce@users.noreply.github.com> Date: Wed, 30 Aug 2023 09:27:48 -0400 Subject: [PATCH] feat(data source UI config): Popup the configuration dialogue whenever a data source is not fully configured (#3620) --- extensions/cornerstone-dicom-sr/package.json | 6 +-- extensions/cornerstone/package.json | 10 ++-- .../DataSourceConfigurationComponent.tsx | 40 +++++++++++----- .../DataSourceConfigurationModalComponent.tsx | 13 ++++-- .../GoogleCloudDataSourceConfigurationAPI.ts | 11 ++++- extensions/measurement-tracking/package.json | 4 +- platform/app/package.json | 2 +- platform/app/src/routes/DataSourceWrapper.tsx | 12 ++++- platform/core/package.json | 2 +- yarn.lock | 46 +++++++++---------- 10 files changed, 93 insertions(+), 53 deletions(-) diff --git a/extensions/cornerstone-dicom-sr/package.json b/extensions/cornerstone-dicom-sr/package.json index ce1530172..6090a360f 100644 --- a/extensions/cornerstone-dicom-sr/package.json +++ b/extensions/cornerstone-dicom-sr/package.json @@ -44,9 +44,9 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/adapters": "^1.11.1", - "@cornerstonejs/core": "^1.11.1", - "@cornerstonejs/tools": "^1.11.1", + "@cornerstonejs/adapters": "^1.11.4", + "@cornerstonejs/core": "^1.11.4", + "@cornerstonejs/tools": "^1.11.4", "classnames": "^2.3.2" } } diff --git a/extensions/cornerstone/package.json b/extensions/cornerstone/package.json index b3e1d8f0d..7d11734d2 100644 --- a/extensions/cornerstone/package.json +++ b/extensions/cornerstone/package.json @@ -36,7 +36,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.11.1", + "@cornerstonejs/dicom-image-loader": "^1.11.4", "@ohif/core": "3.7.0-beta.61", "@ohif/ui": "3.7.0-beta.61", "dcmjs": "^0.29.6", @@ -52,10 +52,10 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/adapters": "^1.11.1", - "@cornerstonejs/core": "^1.11.1", - "@cornerstonejs/streaming-image-volume-loader": "^1.11.1", - "@cornerstonejs/tools": "^1.11.1", + "@cornerstonejs/adapters": "^1.11.4", + "@cornerstonejs/core": "^1.11.4", + "@cornerstonejs/streaming-image-volume-loader": "^1.11.4", + "@cornerstonejs/tools": "^1.11.4", "@kitware/vtk.js": "27.3.1", "html2canvas": "^1.4.1", "lodash.debounce": "4.0.8", diff --git a/extensions/default/src/Components/DataSourceConfigurationComponent.tsx b/extensions/default/src/Components/DataSourceConfigurationComponent.tsx index 768f55696..c9606c54e 100644 --- a/extensions/default/src/Components/DataSourceConfigurationComponent.tsx +++ b/extensions/default/src/Components/DataSourceConfigurationComponent.tsx @@ -1,4 +1,4 @@ -import React, { ReactElement, useEffect, useState } from 'react'; +import React, { ReactElement, useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Icon, useModal } from '@ohif/ui'; import { ExtensionManager, ServicesManager, Types } from '@ohif/core'; @@ -48,6 +48,9 @@ function DataSourceConfigurationComponent({ const configAPI = configurationAPIFactory(activeDataSourceDef.sourceName); setConfigurationAPI(configAPI); + // New configuration API means that the existing configured items must be cleared. + setConfiguredItems(null); + configAPI.getConfiguredItems().then(list => { if (shouldUpdate) { setConfiguredItems(list); @@ -68,22 +71,35 @@ function DataSourceConfigurationComponent({ }; }, []); + const showConfigurationModal = useCallback(() => { + show({ + content: DataSourceConfigurationModalComponent, + title: t('Configure Data Source'), + contentProps: { + configurationAPI, + configuredItems, + onHide: hide, + }, + }); + }, [configurationAPI, configuredItems]); + + useEffect(() => { + if (!configurationAPI || !configuredItems) { + return; + } + + if (configuredItems.length !== configurationAPI.getItemLabels().length) { + // Not the correct number of configured items, so show the modal to configure the data source. + showConfigurationModal(); + } + }, [configurationAPI, configuredItems, showConfigurationModal]); + return configuredItems ? (
- show({ - content: DataSourceConfigurationModalComponent, - title: t('Configure Data Source'), - contentProps: { - configurationAPI, - configuredItems, - onHide: hide, - }, - }) - } + onClick={showConfigurationModal} > {configuredItems.map((item, itemIndex) => { return ( diff --git a/extensions/default/src/Components/DataSourceConfigurationModalComponent.tsx b/extensions/default/src/Components/DataSourceConfigurationModalComponent.tsx index 74145d3b0..b10267740 100644 --- a/extensions/default/src/Components/DataSourceConfigurationModalComponent.tsx +++ b/extensions/default/src/Components/DataSourceConfigurationModalComponent.tsx @@ -27,14 +27,19 @@ function DataSourceConfigurationModalComponent({ const [selectedItems, setSelectedItems] = useState(configuredItems); - // Determines whether to show the full configuration for the data source. - // This typically occurs when the configuration component is first displayed. - const [showFullConfig, setShowFullConfig] = useState(true); - const [errorMessage, setErrorMessage] = useState(); const [itemLabels] = useState(configurationAPI.getItemLabels()); + // Determines whether to show the full/existing configuration for the data source. + // A full or complete configuration is one where the data source (path) has the + // maximum/required number of path items. Anything less is considered not complete and + // the configuration starts from scratch (i.e. as if no items are configured at all). + // TODO: consider configuration starting from a partial (i.e. non-empty) configuration + const [showFullConfig, setShowFullConfig] = useState( + itemLabels.length === configuredItems.length + ); + /** * The index of the selected item that is considered current and for which * its sub-items should be displayed in the items list component. When the diff --git a/extensions/default/src/DataSourceConfigurationAPI/GoogleCloudDataSourceConfigurationAPI.ts b/extensions/default/src/DataSourceConfigurationAPI/GoogleCloudDataSourceConfigurationAPI.ts index d95cbd8ea..919592379 100644 --- a/extensions/default/src/DataSourceConfigurationAPI/GoogleCloudDataSourceConfigurationAPI.ts +++ b/extensions/default/src/DataSourceConfigurationAPI/GoogleCloudDataSourceConfigurationAPI.ts @@ -145,10 +145,19 @@ class GoogleCloudDataSourceConfigurationAPI const url = dataSourceDefinition.configuration.wadoUriRoot; const projectsIndex = url.indexOf('projects'); + // Split the configured URL into (essentially) pairs (i.e. item type followed by item) + // Explicitly: ['projects','aProject','locations','aLocation','datasets','aDataSet','dicomStores','aDicomStore'] + // Note that a partial configuration will have a subset of the above. const urlSplit = url.substring(projectsIndex).split('/'); const configuredItems = []; - for (let itemType = 0; itemType < 4; itemType += 1) { + + for ( + let itemType = 0; + // the number of configured items is either the max (4) or the number extracted from the url split + itemType < 4 && (itemType + 1) * 2 < urlSplit.length; + itemType += 1 + ) { if (itemType === ItemType.projects) { const projectId = urlSplit[1]; const projectUrl = `${initialUrl}/projects/${projectId}`; diff --git a/extensions/measurement-tracking/package.json b/extensions/measurement-tracking/package.json index 4672f381e..f06b179be 100644 --- a/extensions/measurement-tracking/package.json +++ b/extensions/measurement-tracking/package.json @@ -30,8 +30,8 @@ "start": "yarn run dev" }, "peerDependencies": { - "@cornerstonejs/core": "^1.11.1", - "@cornerstonejs/tools": "^1.11.1", + "@cornerstonejs/core": "^1.11.4", + "@cornerstonejs/tools": "^1.11.4", "@ohif/core": "3.7.0-beta.61", "@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.61", "@ohif/ui": "3.7.0-beta.61", diff --git a/platform/app/package.json b/platform/app/package.json index e4bd26f66..ac3397a07 100644 --- a/platform/app/package.json +++ b/platform/app/package.json @@ -50,7 +50,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.11.1", + "@cornerstonejs/dicom-image-loader": "^1.11.4", "@ohif/core": "3.7.0-beta.61", "@ohif/extension-cornerstone": "3.7.0-beta.61", "@ohif/extension-cornerstone-dicom-rt": "3.7.0-beta.61", diff --git a/platform/app/src/routes/DataSourceWrapper.tsx b/platform/app/src/routes/DataSourceWrapper.tsx index c137546d9..91ae58642 100644 --- a/platform/app/src/routes/DataSourceWrapper.tsx +++ b/platform/app/src/routes/DataSourceWrapper.tsx @@ -125,6 +125,7 @@ function DataSourceWrapper(props) { useEffect(() => { const dataSourceChangedCallback = () => { + setIsLoading(false); setIsDataSourceInitialized(false); setDataSourcePath(''); setDataSource(extensionManager.getActiveDataSource()[0]); @@ -191,7 +192,16 @@ function DataSourceWrapper(props) { (!isLoading && (newOffset !== previousOffset || isLocationUpdated)); if (isDataInvalid) { - getData().catch(() => navigate('/notfoundserver', '_self')); + getData().catch(() => { + // If there is a data source configuration API, then the Worklist will popup the dialog to attempt to configure it + // and attempt to resolve this issue. + if (dataSource.getConfig().configurationAPI) { + return; + } + + // No data source configuration API, so navigate to the not found server page. + navigate('/notfoundserver', '_self'); + }); } } catch (ex) { console.warn(ex); diff --git a/platform/core/package.json b/platform/core/package.json index a866a113f..9c0f71b5f 100644 --- a/platform/core/package.json +++ b/platform/core/package.json @@ -35,7 +35,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.11.1", + "@cornerstonejs/dicom-image-loader": "^1.11.4", "@ohif/ui": "3.7.0-beta.61", "cornerstone-math": "0.1.9", "dicom-parser": "^1.8.21" diff --git a/yarn.lock b/yarn.lock index 583f87236..24e1a3e59 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1376,10 +1376,10 @@ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== -"@cornerstonejs/adapters@^1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-1.11.1.tgz#d6c2b0dc0742a0ffd76e9ed86f911bbd8bc94c05" - integrity sha512-ggSToAWv6fn7J4mq412P6xGV5IdbtHqRR4ZGap12ytus9HCCZLZ3a+lWx21+Rc9zILj8H/58WWb/pYvN0Itp5g== +"@cornerstonejs/adapters@^1.11.4": + version "1.11.4" + resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-1.11.4.tgz#b318fe3180b7ceda5537420e8cd4e8d2ddac68f3" + integrity sha512-Qb7qfg0HD06yvpu8KgXkstvmrTUIbFft2HWblUbLe0gxO3ze+1LE2ZAT2qXyvC+nfchPTH2Ybo1D3yBxO7CPdQ== dependencies: "@babel/runtime-corejs2" "^7.17.8" buffer "^6.0.3" @@ -1428,43 +1428,43 @@ resolved "https://registry.yarnpkg.com/@cornerstonejs/codec-openjph/-/codec-openjph-2.4.2.tgz#e96721d56f6ec96f7f95c16321d88cc8467d8d81" integrity sha512-lgdvBvvNezleY+4pIe2ceUsJzlZe/0PipdeubQ3vZZOz3xxtHHMR1XFCl4fgd8gosR8COHuD7h6q+MwgrwBsng== -"@cornerstonejs/core@^1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-1.11.1.tgz#308904eabcd54bf8529ba174ff714a2aa7cd0be7" - integrity sha512-QgGVRiS2ceDSC0kZlYyYw6owqh6rn7FaYuyJAYis1JCk1yG6xIUfcb6GMuubuEgEammc26i8EfU1H5FLxpHm2g== +"@cornerstonejs/core@^1.11.4": + version "1.11.4" + resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-1.11.4.tgz#035a950a04641a103924ab93b30f257fd884fc8c" + integrity sha512-5kS6xgBimkfjjvd/o+6o4c0NvYVw2lCGDvow3hC5V7aCd6Pn8eo2BaU45QJ8y0A0NJ9xmtr37yb3v8+7lfkGSw== dependencies: "@kitware/vtk.js" "27.3.1" detect-gpu "^5.0.22" gl-matrix "^3.4.3" lodash.clonedeep "4.5.0" -"@cornerstonejs/dicom-image-loader@^1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-1.11.1.tgz#0a7786b97828038f6faca088b40cc2b96c7db362" - integrity sha512-5/ocRRoYiwKKcKR01oGwWQp3imPEEYJcHull7MuwMWS1mZgYvok0QGs5Wz51rY8qJZCuM7nvkKxI21YzQkxISw== +"@cornerstonejs/dicom-image-loader@^1.11.4": + version "1.11.4" + resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-1.11.4.tgz#4daa4f91e9a5f23fa8f39ebb3c73dcc148184b68" + integrity sha512-Hw5XS+SN7VF/C70CzYd8alK/91SccSbNArVc9erwrBP4EmLWOj9XmKMNiV7KXS7d60G0nEAzCKo+e0wQWOvxWA== dependencies: "@cornerstonejs/codec-charls" "^1.2.3" "@cornerstonejs/codec-libjpeg-turbo-8bit" "^1.2.2" "@cornerstonejs/codec-openjpeg" "^1.2.2" "@cornerstonejs/codec-openjph" "^2.4.2" - "@cornerstonejs/core" "^1.11.1" + "@cornerstonejs/core" "^1.11.4" dicom-parser "^1.8.9" pako "^2.0.4" uuid "^9.0.0" -"@cornerstonejs/streaming-image-volume-loader@^1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@cornerstonejs/streaming-image-volume-loader/-/streaming-image-volume-loader-1.11.1.tgz#4f48b9af36da090f51e91b9736d892c4450244cd" - integrity sha512-S++wH3u037Gw5I51DWNwvqYaJl9W8vNhebTSzQIgZO3TVShzJo+0zQWdrsXrqOSzn9+0d4H6yEdxjKvsDRYBMw== +"@cornerstonejs/streaming-image-volume-loader@^1.11.4": + version "1.11.4" + resolved "https://registry.yarnpkg.com/@cornerstonejs/streaming-image-volume-loader/-/streaming-image-volume-loader-1.11.4.tgz#ca166f7488e8bba78e8e2216b5fc00e36ed2000b" + integrity sha512-gucQKRjU+UET1BGho4gOi0iy9iT0WoUnuXqb3zS9y7FrBr10VW6F51kbm+BaS0H0PTHqlC5nwHNrsxWavOqleg== dependencies: - "@cornerstonejs/core" "^1.11.1" + "@cornerstonejs/core" "^1.11.4" -"@cornerstonejs/tools@^1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-1.11.1.tgz#537caff00b53b7d37ea31d5aa67ec09298ce8057" - integrity sha512-kt6UTHT24PffiEDuHSTOiRTSfYHaluWTY27bigr0wdnrMYMlO0oignFXiSJAJ0FzLZUhuRZeN7qs1fLXhOlcrA== +"@cornerstonejs/tools@^1.11.4": + version "1.11.4" + resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-1.11.4.tgz#20ae1501d6f18346230f4b9bf62e23e30343407a" + integrity sha512-OLo69mbL2mgAUKuXSFLif+aJtbqT6hlWI5F6MsqgVun0BP1qLn2FgCfNwSphco4ejjiJG9CSnPBhfdcCxveaoA== dependencies: - "@cornerstonejs/core" "^1.11.1" + "@cornerstonejs/core" "^1.11.4" lodash.clonedeep "4.5.0" lodash.get "^4.4.2"