diff --git a/.docker/Viewer-v3.x/default.conf.template b/.docker/Viewer-v3.x/default.conf.template index 153ea7086..11206da2a 100644 --- a/.docker/Viewer-v3.x/default.conf.template +++ b/.docker/Viewer-v3.x/default.conf.template @@ -5,8 +5,6 @@ server { root /usr/share/nginx/html; index index.html index.htm; try_files $uri $uri/ /index.html; - add_header Cross-Origin-Opener-Policy same-origin; - add_header Cross-Origin-Embedder-Policy require-corp; add_header Cross-Origin-Resource-Policy same-origin; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; diff --git a/.docker/Viewer-v3.x/default.ssl.conf.template b/.docker/Viewer-v3.x/default.ssl.conf.template index 06ed4e505..04a36da8b 100644 --- a/.docker/Viewer-v3.x/default.ssl.conf.template +++ b/.docker/Viewer-v3.x/default.ssl.conf.template @@ -7,8 +7,6 @@ server { root /usr/share/nginx/html; index index.html index.htm; try_files $uri $uri/ /index.html; - add_header Cross-Origin-Opener-Policy same-origin; - add_header Cross-Origin-Embedder-Policy require-corp; add_header Cross-Origin-Resource-Policy same-origin; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; diff --git a/.webpack/webpack.base.js b/.webpack/webpack.base.js index 440c26c95..025c8bd13 100644 --- a/.webpack/webpack.base.js +++ b/.webpack/webpack.base.js @@ -57,10 +57,6 @@ if (!process.env.APP_CONFIG) { } module.exports = (env, argv, { SRC_DIR, ENTRY }) => { - if (!process.env.NODE_ENV) { - throw new Error('process.env.NODE_ENV not set'); - } - const mode = NODE_ENV === 'production' ? 'production' : 'development'; const isProdBuild = NODE_ENV === 'production'; const isQuickBuild = QUICK_BUILD === 'true'; @@ -108,7 +104,7 @@ module.exports = (env, argv, { SRC_DIR, ENTRY }) => { exclude: /node_modules/, loader: 'babel-loader', options: { - plugins: ['react-refresh/babel'], + plugins: isProdBuild ? [] : ['react-refresh/babel'], }, }, ]), diff --git a/extensions/cornerstone-dicom-pmap/package.json b/extensions/cornerstone-dicom-pmap/package.json index 01dca5243..8ddc92f99 100644 --- a/extensions/cornerstone-dicom-pmap/package.json +++ b/extensions/cornerstone-dicom-pmap/package.json @@ -46,8 +46,8 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/adapters": "^2.2.4", - "@cornerstonejs/core": "^2.2.4", + "@cornerstonejs/adapters": "^2.2.20", + "@cornerstonejs/core": "^2.2.20", "@kitware/vtk.js": "32.1.0", "react-color": "^2.19.3" } diff --git a/extensions/cornerstone-dicom-seg/package.json b/extensions/cornerstone-dicom-seg/package.json index 63b90eabc..9a2aa3df7 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": "^2.2.4", - "@cornerstonejs/core": "^2.2.4", + "@cornerstonejs/adapters": "^2.2.20", + "@cornerstonejs/core": "^2.2.20", "@kitware/vtk.js": "32.1.0", "react-color": "^2.19.3" } diff --git a/extensions/cornerstone-dicom-sr/package.json b/extensions/cornerstone-dicom-sr/package.json index 16c243561..a2ce25aae 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": "^2.2.4", - "@cornerstonejs/core": "^2.2.4", - "@cornerstonejs/tools": "^2.2.4", + "@cornerstonejs/adapters": "^2.2.20", + "@cornerstonejs/core": "^2.2.20", + "@cornerstonejs/tools": "^2.2.20", "classnames": "^2.3.2" } } diff --git a/extensions/cornerstone-dynamic-volume/package.json b/extensions/cornerstone-dynamic-volume/package.json index bb8b94c65..9fefe3f03 100644 --- a/extensions/cornerstone-dynamic-volume/package.json +++ b/extensions/cornerstone-dynamic-volume/package.json @@ -42,8 +42,8 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/core": "^2.2.4", - "@cornerstonejs/tools": "^2.2.4", + "@cornerstonejs/core": "^2.2.20", + "@cornerstonejs/tools": "^2.2.20", "classnames": "^2.3.2" } } diff --git a/extensions/cornerstone/package.json b/extensions/cornerstone/package.json index 6270e722c..757b2c342 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.4", "@cornerstonejs/codec-openjph": "^2.4.5", - "@cornerstonejs/dicom-image-loader": "^2.2.4", + "@cornerstonejs/dicom-image-loader": "^2.2.20", "@icr/polyseg-wasm": "^0.4.0", "@ohif/core": "3.9.1", "@ohif/ui": "3.9.1", @@ -55,9 +55,9 @@ }, "dependencies": { "@babel/runtime": "^7.20.13", - "@cornerstonejs/adapters": "^2.2.4", - "@cornerstonejs/core": "^2.2.4", - "@cornerstonejs/tools": "^2.2.4", + "@cornerstonejs/adapters": "^2.2.20", + "@cornerstonejs/core": "^2.2.20", + "@cornerstonejs/tools": "^2.2.20", "@icr/polyseg-wasm": "^0.4.0", "@kitware/vtk.js": "32.1.0", "html2canvas": "^1.4.1", diff --git a/extensions/cornerstone/src/index.tsx b/extensions/cornerstone/src/index.tsx index 47d630c10..41f4c33ff 100644 --- a/extensions/cornerstone/src/index.tsx +++ b/extensions/cornerstone/src/index.tsx @@ -45,7 +45,7 @@ import { useSegmentationPresentationStore, useSynchronizersStore, } from './stores'; -import { useToggleOneUpViewportGridStore } from '../../default/src/stores/useToggleOneUpViewportGridStore'; +import { useToggleOneUpViewportGridStore } from '@ohif/extension-default'; import { useActiveViewportSegmentationRepresentations } from './hooks/useActiveViewportSegmentationRepresentations'; import { useMeasurements } from './hooks/useMeasurements'; import getPanelModule from './getPanelModule'; diff --git a/extensions/cornerstone/src/init.tsx b/extensions/cornerstone/src/init.tsx index 4b9c13d54..565844169 100644 --- a/extensions/cornerstone/src/init.tsx +++ b/extensions/cornerstone/src/init.tsx @@ -38,6 +38,7 @@ import { SegmentationRepresentations } from '@cornerstonejs/tools/enums'; import { useLutPresentationStore } from './stores/useLutPresentationStore'; import { usePositionPresentationStore } from './stores/usePositionPresentationStore'; import { useSegmentationPresentationStore } from './stores/useSegmentationPresentationStore'; +import { imageRetrieveMetadataProvider } from '@cornerstonejs/core/utilities'; const { registerColormap } = csUtilities.colormap; @@ -135,9 +136,21 @@ export default async function init({ cornerstoneStreamingDynamicImageVolumeLoader ); - hangingProtocolService.registerImageLoadStrategy('interleaveCenter', interleaveCenterLoader); - hangingProtocolService.registerImageLoadStrategy('interleaveTopToBottom', interleaveTopToBottom); - hangingProtocolService.registerImageLoadStrategy('nth', nthLoader); + // Register strategies using the wrapper + const imageLoadStrategies = { + interleaveCenter: interleaveCenterLoader, + interleaveTopToBottom: interleaveTopToBottom, + nth: nthLoader, + }; + + Object.entries(imageLoadStrategies).forEach(([name, strategyFn]) => { + hangingProtocolService.registerImageLoadStrategy( + name, + createMetadataWrappedStrategy(strategyFn) + ); + }); + + // ... existing code ... // add metadata providers metaData.addProvider( @@ -296,6 +309,28 @@ function initializeWebWorkerProgressHandler(uiNotificationService) { }); } +/** + * Creates a wrapped image load strategy with metadata handling + * @param strategyFn - The image loading strategy function to wrap + * @returns A wrapped strategy function that handles metadata configuration + */ +const createMetadataWrappedStrategy = (strategyFn: (args: any) => any) => { + return (args: any) => { + const clonedConfig = imageRetrieveMetadataProvider.clone(); + imageRetrieveMetadataProvider.clear(); + + try { + const result = strategyFn(args); + return result; + } finally { + // Ensure metadata is always restored, even if there's an error + setTimeout(() => { + imageRetrieveMetadataProvider.restore(clonedConfig); + }, 10); + } + }; +}; + function CPUModal() { return (
diff --git a/extensions/cornerstone/src/initMeasurementService.ts b/extensions/cornerstone/src/initMeasurementService.ts index 9433bb5ef..f0d863363 100644 --- a/extensions/cornerstone/src/initMeasurementService.ts +++ b/extensions/cornerstone/src/initMeasurementService.ts @@ -59,10 +59,10 @@ const initMeasurementService = ( 'Crosshairs', Length.matchingCriteria, () => { - console.warn('Crosshairs mapping not implemented.'); + return null; }, () => { - console.warn('Crosshairs mapping not implemented.'); + return null; } ); diff --git a/extensions/cornerstone/src/services/ViewportService/CornerstoneViewportService.ts b/extensions/cornerstone/src/services/ViewportService/CornerstoneViewportService.ts index 329610148..f156be60a 100644 --- a/extensions/cornerstone/src/services/ViewportService/CornerstoneViewportService.ts +++ b/extensions/cornerstone/src/services/ViewportService/CornerstoneViewportService.ts @@ -1043,6 +1043,11 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi // Store the current position presentations for each viewport. viewports.forEach(({ id: viewportId }) => { const presentation = this._getPositionPresentation(viewportId); + + // During a resize, the slice index should remain unchanged. This is a temporary fix for + // a larger issue regarding the definition of slice index with slab thickness. + // We need to revisit this to make it more robust and understandable. + delete presentation.viewReference.sliceIndex; this.beforeResizePositionPresentations.set(viewportId, presentation); }); @@ -1051,10 +1056,12 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi renderingEngine.resize(isImmediate); renderingEngine.render(); - // Reset the camera for viewports that should reset their camera on resize, + // Reset the camera for all viewports using position presentation to maintain relative size/position // which means only those viewports that have a zoom level of 1. this.beforeResizePositionPresentations.forEach((positionPresentation, viewportId) => { - this.setPresentations(viewportId, { positionPresentation }); + this.setPresentations(viewportId, { + positionPresentation, + }); }); // Resize and render the rendering engine again. diff --git a/extensions/cornerstone/src/utils/interleaveTopToBottom.ts b/extensions/cornerstone/src/utils/interleaveTopToBottom.ts index fc5447a42..9caad9087 100644 --- a/extensions/cornerstone/src/utils/interleaveTopToBottom.ts +++ b/extensions/cornerstone/src/utils/interleaveTopToBottom.ts @@ -108,7 +108,7 @@ export default function interleaveTopToBottom({ volumes.forEach(volume => { const requests = volume.getImageLoadRequests(); - if (!requests.length || !requests[0] || !requests[0].imageId) { + if (!requests?.[0]?.imageId) { return; } diff --git a/extensions/default/src/DicomJSONDataSource/index.js b/extensions/default/src/DicomJSONDataSource/index.js index bb0a9b43d..fa4fd60fc 100644 --- a/extensions/default/src/DicomJSONDataSource/index.js +++ b/extensions/default/src/DicomJSONDataSource/index.js @@ -93,7 +93,7 @@ function createDicomJSONApi(dicomJsonConfig) { const { query } = qs.parseUrl(instance.url); - // Add imageId specific mapping to this data as the URL isn't necessarliy WADO-URI. + // Add imageId specific mapping to this data as the URL isn't necessarily WADO-URI. metadataProvider.addImageIdToUIDs(imageId, { StudyInstanceUID, SeriesInstanceUID, diff --git a/extensions/default/src/DicomLocalDataSource/index.js b/extensions/default/src/DicomLocalDataSource/index.js index 42c1c6033..a0ea9fb4f 100644 --- a/extensions/default/src/DicomLocalDataSource/index.js +++ b/extensions/default/src/DicomLocalDataSource/index.js @@ -142,9 +142,7 @@ function createDicomLocalApi(dicomLocalConfig) { study.series.forEach(aSeries => { const { SeriesInstanceUID } = aSeries; - const isMultiframe = aSeries.instances[0].NumberOfFrames > 1; - - aSeries.instances.forEach((instance, index) => { + aSeries.instances.forEach(instance => { const { url: imageId, StudyInstanceUID, @@ -153,14 +151,22 @@ function createDicomLocalApi(dicomLocalConfig) { } = instance; instance.imageId = imageId; - - // Add imageId specific mapping to this data as the URL isn't necessarily WADO-URI. - metadataProvider.addImageIdToUIDs(imageId, { - StudyInstanceUID, - SeriesInstanceUID, - SOPInstanceUID, - frameIndex: isMultiframe ? index : 1, - }); + const numberOfFrames = instance.NumberOfFrames || 1; + // Process all frames consistently, whether single or multiframe + for (let i = 0; i < numberOfFrames; i++) { + const frameNumber = i + 1; + const frameImageId = implementation.getImageIdsForInstance({ + instance, + frame: frameNumber, + }); + // Add imageId specific mapping to this data as the URL isn't necessarily WADO-URI. + metadataProvider.addImageIdToUIDs(frameImageId, { + StudyInstanceUID, + SeriesInstanceUID, + SOPInstanceUID, + frameNumber: numberOfFrames > 1 ? frameNumber : undefined, + }); + } }); DicomMetadataStore._broadcastEvent(EVENTS.INSTANCES_ADDED, { @@ -209,9 +215,11 @@ function createDicomLocalApi(dicomLocalConfig) { return imageIds; }, getImageIdsForInstance({ instance, frame }) { - if (instance.imageId) { - return instance.imageId; - } + // Important: Never use instance.imageId because it might be multiframe, + // which would make it an invalid imageId. + // if (instance.imageId) { + // return instance.imageId; + // } const { StudyInstanceUID, SeriesInstanceUID, SOPInstanceUID } = instance; const storedInstance = DicomMetadataStore.getInstance( diff --git a/extensions/default/src/DicomWebDataSource/index.js b/extensions/default/src/DicomWebDataSource/index.js index 8f5f9ae86..29dbdd324 100644 --- a/extensions/default/src/DicomWebDataSource/index.js +++ b/extensions/default/src/DicomWebDataSource/index.js @@ -434,23 +434,32 @@ function createDicomWebApi(dicomWebConfig, servicesManager) { instance.wadoRoot = dicomWebConfig.wadoRoot; instance.wadoUri = dicomWebConfig.wadoUri; - const imageId = implementation.getImageIdsForInstance({ - instance, - }); + const { StudyInstanceUID, SeriesInstanceUID, SOPInstanceUID } = instance; + + const numberOfFrames = instance.NumberOfFrames || 1; + // Process all frames consistently, whether single or multiframe + for (let i = 0; i < numberOfFrames; i++) { + const frameNumber = i + 1; + const frameImageId = implementation.getImageIdsForInstance({ + instance, + frame: frameNumber, + }); + // Add imageId specific mapping to this data as the URL isn't necessarily WADO-URI. + metadataProvider.addImageIdToUIDs(frameImageId, { + StudyInstanceUID, + SeriesInstanceUID, + SOPInstanceUID, + frameNumber: numberOfFrames > 1 ? frameNumber : undefined, + }); + } // Adding imageId to each instance // Todo: This is not the best way I can think of to let external // metadata handlers know about the imageId that is stored in the store - instance.imageId = imageId; - - // Adding UIDs to metadataProvider - // Note: storing imageURI in metadataProvider since stack viewports - // will use the same imageURI - metadataProvider.addImageIdToUIDs(imageId, { - StudyInstanceUID, - SeriesInstanceUID: instance.SeriesInstanceUID, - SOPInstanceUID: instance.SOPInstanceUID, + const imageId = implementation.getImageIdsForInstance({ + instance, }); + instance.imageId = imageId; }); DicomMetadataStore.addInstances(naturalizedInstances, madeInClient); diff --git a/extensions/measurement-tracking/package.json b/extensions/measurement-tracking/package.json index db523a2eb..0e79d6ca5 100644 --- a/extensions/measurement-tracking/package.json +++ b/extensions/measurement-tracking/package.json @@ -32,8 +32,8 @@ "start": "yarn run dev" }, "peerDependencies": { - "@cornerstonejs/core": "^2.2.4", - "@cornerstonejs/tools": "^2.2.4", + "@cornerstonejs/core": "^2.2.20", + "@cornerstonejs/tools": "^2.2.20", "@ohif/core": "3.9.1", "@ohif/extension-cornerstone-dicom-sr": "3.9.1", "@ohif/extension-default": "3.9.1", diff --git a/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx b/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx index 3c1df9190..9ed5e1e91 100644 --- a/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx +++ b/extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx @@ -9,6 +9,7 @@ import { StudyBrowser } from '@ohif/ui-next'; import { useTrackedMeasurements } from '../../getContextModule'; import { Separator } from '@ohif/ui-next'; import { PanelStudyBrowserHeader } from '@ohif/extension-default'; +import { useAppConfig } from '@state'; import { defaultActionIcons, defaultViewPresets } from './constants'; const { formatDate, createStudyBrowserTabs } = utils; @@ -27,7 +28,7 @@ const thumbnailNoImageModalities = [ * * @param {*} param0 */ -function PanelStudyBrowserTracking({ +export default function PanelStudyBrowserTracking({ servicesManager, getImageSrc, getStudiesForPatientByMRN, @@ -45,6 +46,10 @@ function PanelStudyBrowserTracking({ customizationService, } = servicesManager.services; const navigate = useNavigate(); + const { mode: studyMode } = customizationService.getCustomization('PanelStudyBrowser.studyMode', { + id: 'default', + mode: 'all', + }); const { t } = useTranslation('Common'); @@ -55,7 +60,8 @@ function PanelStudyBrowserTracking({ const [{ activeViewportId, viewports, isHangingProtocolLayout }, viewportGridService] = useViewportGrid(); const [trackedMeasurements, sendTrackedMeasurementsEvent] = useTrackedMeasurements(); - const [activeTabName, setActiveTabName] = useState('all'); + + const [activeTabName, setActiveTabName] = useState(studyMode); const [expandedStudyInstanceUIDs, setExpandedStudyInstanceUIDs] = useState([ ...StudyInstanceUIDs, ]); @@ -117,6 +123,10 @@ function PanelStudyBrowserTracking({ const { trackedSeries } = trackedMeasurements.context; + useEffect(() => { + setActiveTabName(studyMode); + }, [studyMode]); + // ~~ studyDisplayList useEffect(() => { // Fetch all studies for the patient in each primary study @@ -528,8 +538,6 @@ PanelStudyBrowserTracking.propTypes = { requestDisplaySetCreationForStudy: PropTypes.func.isRequired, }; -export default PanelStudyBrowserTracking; - function getImageIdForThumbnail(displaySet: any, imageIds: any) { let imageId; if (displaySet.isDynamicVolume) { diff --git a/modes/longitudinal/src/customizations.tsx b/modes/longitudinal/src/customizations.tsx index 649a8bd46..4b8326b3d 100644 --- a/modes/longitudinal/src/customizations.tsx +++ b/modes/longitudinal/src/customizations.tsx @@ -6,6 +6,11 @@ export const performCustomizations = customizationService => { id: 'PanelSegmentation.disableEditing', disableEditing: true, }, + // to only show current study in the panel study browser + // { + // id: 'PanelStudyBrowser.studyMode', + // mode: 'primary', + // }, // To disable editing in the MeasurementTable // { // id: 'PanelMeasurement.disableEditing', diff --git a/modes/preclinical-4d/src/index.tsx b/modes/preclinical-4d/src/index.tsx index 23ac99294..21fc1baed 100644 --- a/modes/preclinical-4d/src/index.tsx +++ b/modes/preclinical-4d/src/index.tsx @@ -84,7 +84,7 @@ function modeFactory({ modeConfiguration }) { lesionStats: 'Lesion Statistics', minValue: 'Minimum Value', maxValue: 'Maximum Value', - meanValue: 'Mean Value', + meanValue: 'Mean Value (ml)', volume: 'Volume', suvPeak: 'SUV Peak', suvMax: 'Maximum SUV', diff --git a/modes/tmtv/src/index.ts b/modes/tmtv/src/index.ts index ef383e65d..9c1ba1702 100644 --- a/modes/tmtv/src/index.ts +++ b/modes/tmtv/src/index.ts @@ -120,7 +120,7 @@ function modeFactory({ modeConfiguration }) { minValue: 'Minimum Value', maxValue: 'Maximum Value', meanValue: 'Mean Value', - volume: 'Volume', + volume: 'Volume (ml)', suvPeak: 'SUV Peak', suvMax: 'Maximum SUV', suvMaxIJK: 'SUV Max IJK', diff --git a/platform/app/.recipes/Nginx-Dcm4chee-Keycloak/config/nginx.conf b/platform/app/.recipes/Nginx-Dcm4chee-Keycloak/config/nginx.conf index 30b0089c4..79043d928 100644 --- a/platform/app/.recipes/Nginx-Dcm4chee-Keycloak/config/nginx.conf +++ b/platform/app/.recipes/Nginx-Dcm4chee-Keycloak/config/nginx.conf @@ -221,8 +221,6 @@ http { location / { add_header Cache-Control "no-store, no-cache, must-revalidate"; - add_header 'Cross-Origin-Opener-Policy' 'same-origin' always; - add_header 'Cross-Origin-Embedder-Policy' 'require-corp' always; } location /keycloak/ { diff --git a/platform/app/.recipes/Nginx-Dcm4chee/config/nginx.conf b/platform/app/.recipes/Nginx-Dcm4chee/config/nginx.conf index 8d9ca8f54..ae7e84ad6 100644 --- a/platform/app/.recipes/Nginx-Dcm4chee/config/nginx.conf +++ b/platform/app/.recipes/Nginx-Dcm4chee/config/nginx.conf @@ -79,8 +79,6 @@ http { index index.html; try_files $uri $uri/ /index.html; add_header Cache-Control "no-store, no-cache, must-revalidate"; - add_header Cross-Origin-Opener-Policy 'same-origin' always; - add_header Cross-Origin-Embedder-Policy 'require-corp' always; } } } diff --git a/platform/app/.recipes/Nginx-Orthanc-Keycloak/config/nginx.conf b/platform/app/.recipes/Nginx-Orthanc-Keycloak/config/nginx.conf index 1ad9f512d..272a478a3 100644 --- a/platform/app/.recipes/Nginx-Orthanc-Keycloak/config/nginx.conf +++ b/platform/app/.recipes/Nginx-Orthanc-Keycloak/config/nginx.conf @@ -191,8 +191,6 @@ http { location / { add_header Cache-Control "no-store, no-cache, must-revalidate"; - add_header 'Cross-Origin-Opener-Policy' 'same-origin' always; - add_header 'Cross-Origin-Embedder-Policy' 'require-corp' always; } location /keycloak/ { diff --git a/platform/app/.recipes/Nginx-Orthanc/config/nginx.conf b/platform/app/.recipes/Nginx-Orthanc/config/nginx.conf index 57946cddf..0b559ca73 100644 --- a/platform/app/.recipes/Nginx-Orthanc/config/nginx.conf +++ b/platform/app/.recipes/Nginx-Orthanc/config/nginx.conf @@ -78,8 +78,6 @@ http { index index.html; try_files $uri $uri/ /index.html; add_header Cache-Control "no-store, no-cache, must-revalidate"; - add_header 'Cross-Origin-Opener-Policy' 'same-origin' always; - add_header 'Cross-Origin-Embedder-Policy' 'require-corp' always; } } diff --git a/platform/app/.recipes/deprecated-recipes/OpenResty-Orthanc-Keycloak/config/nginx.conf b/platform/app/.recipes/deprecated-recipes/OpenResty-Orthanc-Keycloak/config/nginx.conf index 9e496b79d..98bc01c2a 100644 --- a/platform/app/.recipes/deprecated-recipes/OpenResty-Orthanc-Keycloak/config/nginx.conf +++ b/platform/app/.recipes/deprecated-recipes/OpenResty-Orthanc-Keycloak/config/nginx.conf @@ -182,8 +182,6 @@ http { index index.html; try_files $uri $uri/ /index.html; add_header Cache-Control "no-store, no-cache, must-revalidate"; - add_header 'Cross-Origin-Opener-Policy' 'same-origin' always; - add_header 'Cross-Origin-Embedder-Policy' 'require-corp' always; } # EXAMPLE: Reverse Proxy, no auth diff --git a/platform/app/.recipes/deprecated-recipes/OpenResty-Orthanc/config/nginx.conf b/platform/app/.recipes/deprecated-recipes/OpenResty-Orthanc/config/nginx.conf index aff59a130..777e49703 100644 --- a/platform/app/.recipes/deprecated-recipes/OpenResty-Orthanc/config/nginx.conf +++ b/platform/app/.recipes/deprecated-recipes/OpenResty-Orthanc/config/nginx.conf @@ -118,8 +118,6 @@ http { index index.html; try_files $uri $uri/ /index.html; add_header Cache-Control "no-store, no-cache, must-revalidate"; - add_header 'Cross-Origin-Opener-Policy' 'same-origin' always; - add_header 'Cross-Origin-Embedder-Policy' 'require-corp' always; } # EXAMPLE: Redirect server error pages to the static page /40x.html diff --git a/platform/app/.webpack/webpack.pwa.js b/platform/app/.webpack/webpack.pwa.js index cd6487589..1d11c0dff 100644 --- a/platform/app/.webpack/webpack.pwa.js +++ b/platform/app/.webpack/webpack.pwa.js @@ -133,8 +133,6 @@ module.exports = (env, argv) => { new InjectManifest({ swDest: 'sw.js', swSrc: path.join(SRC_DIR, 'service-worker.js'), - // Increase the limit to 4mb: - maximumFileSizeToCacheInBytes: 5 * 1024 * 1024, // Need to exclude the theme as it is updated independently exclude: [/theme/], // Cache large files for the manifests to avoid warning messages @@ -174,10 +172,6 @@ module.exports = (env, argv) => { disableDotRule: true, index: PUBLIC_URL + 'index.html', }, - headers: { - 'Cross-Origin-Embedder-Policy': 'require-corp', - 'Cross-Origin-Opener-Policy': 'same-origin', - }, devMiddleware: { writeToDisk: true, }, @@ -206,5 +200,9 @@ module.exports = (env, argv) => { ); } + mergedConfig.watchOptions = { + ignored: /node_modules\/@cornerstonejs/, + }; + return mergedConfig; }; diff --git a/platform/app/.webpack/writePluginImportsFile.js b/platform/app/.webpack/writePluginImportsFile.js index c913e779e..29accd913 100644 --- a/platform/app/.webpack/writePluginImportsFile.js +++ b/platform/app/.webpack/writePluginImportsFile.js @@ -73,7 +73,10 @@ function getRuntimeLoadModesExtensions(modules) { dynamicLoad.push( ` if( module==="${packageName}") {`, ` const imported = await window.browserImportFunction('${module.importPath}');`, - ' return ' + (module.globalName ? `window["${module.globalName}"];` : `imported["${module.importName || 'default'}"];`), + ' return ' + + (module.globalName + ? `window["${module.globalName}"];` + : `imported["${module.importName || 'default'}"];`), ' }' ); return; @@ -201,12 +204,6 @@ function writePluginImportsFile(SRC_DIR, DIST_DIR) { 'dist' ); - console.warn('copy plugins', [ - ...copyPluginPublicToDistBuild, - ...copyPluginPublicToDistLink, - ...copyPluginDistToDistBuild, - ...copyPluginDistToDistLink, - ]); return [ ...copyPluginPublicToDistBuild, ...copyPluginPublicToDistLink, diff --git a/platform/app/package.json b/platform/app/package.json index 8e197985a..10f29691a 100644 --- a/platform/app/package.json +++ b/platform/app/package.json @@ -53,7 +53,7 @@ "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.4", "@cornerstonejs/codec-openjph": "^2.4.5", - "@cornerstonejs/dicom-image-loader": "^2.2.4", + "@cornerstonejs/dicom-image-loader": "^2.2.20", "@emotion/serialize": "^1.1.3", "@ohif/core": "3.9.1", "@ohif/extension-cornerstone": "3.9.1", diff --git a/platform/app/public/serve.json b/platform/app/public/serve.json index dbbe3ba69..8616a96ba 100644 --- a/platform/app/public/serve.json +++ b/platform/app/public/serve.json @@ -1,12 +1,3 @@ { - "rewrites": [{ "source": "*", "destination": "index.html" }], - "headers": [ - { - "source": "**/*", - "headers": [ - { "key": "Cross-Origin-Embedder-Policy", "value": "require-corp" }, - { "key": "Cross-Origin-Opener-Policy", "value": "same-origin" } - ] - } - ] + "rewrites": [{ "source": "*", "destination": "index.html" }] } diff --git a/platform/app/tailwind.css b/platform/app/tailwind.css index 510fdf6ec..492349705 100644 --- a/platform/app/tailwind.css +++ b/platform/app/tailwind.css @@ -2,7 +2,3 @@ @tailwind base; @tailwind components; @tailwind utilities; - -* { - min-height: 0 !important; -} diff --git a/platform/core/package.json b/platform/core/package.json index 687d08065..0653c2eb3 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.4", "@cornerstonejs/codec-openjph": "^2.4.5", - "@cornerstonejs/dicom-image-loader": "^2.2.4", + "@cornerstonejs/dicom-image-loader": "^2.2.20", "@ohif/ui": "3.9.1", "cornerstone-math": "0.1.9", "dicom-parser": "^1.8.21" diff --git a/platform/core/src/classes/MetadataProvider.ts b/platform/core/src/classes/MetadataProvider.ts index d9cc2e323..08c421fef 100644 --- a/platform/core/src/classes/MetadataProvider.ts +++ b/platform/core/src/classes/MetadataProvider.ts @@ -8,7 +8,6 @@ import toNumber from '../utils/toNumber'; import combineFrameInstance from '../utils/combineFrameInstance'; class MetadataProvider { - private readonly studies: Map = new Map(); private readonly imageURIToUIDs: Map = new Map(); private readonly imageUIDsByImageId: Map = new Map(); // Can be used to store custom metadata for a specific type. @@ -17,6 +16,10 @@ class MetadataProvider { private readonly customMetadata: Map = new Map(); addImageIdToUIDs(imageId, uids) { + if (!imageId) { + throw new Error('MetadataProvider::Empty imageId'); + } + // This method is a fallback for when you don't have WADO-URI or WADO-RS. // You can add instances fetched by any method by calling addInstance, and hook an imageId to point at it here. // An example would be dicom hosted at some random site. @@ -35,6 +38,10 @@ class MetadataProvider { } _getInstance(imageId) { + if (!imageId) { + throw new Error('MetadataProvider::Empty imageId'); + } + const uids = this.getUIDsFromImageID(imageId); if (!uids) { @@ -455,17 +462,6 @@ class MetadataProvider { } getUIDsFromImageID(imageId) { - if (!imageId) { - throw new Error('MetadataProvider::Empty imageId'); - } - // TODO: adding csiv here is not really correct. Probably need to use - // metadataProvider.addImageIdToUIDs(imageId, { - // StudyInstanceUID, - // SeriesInstanceUID, - // SOPInstanceUID, - // }) - // somewhere else - const cachedUIDs = this.imageUIDsByImageId.get(imageId); if (cachedUIDs) { return cachedUIDs; diff --git a/platform/core/src/services/CustomizationService/CustomizationService.ts b/platform/core/src/services/CustomizationService/CustomizationService.ts index a36104d50..4830dfe59 100644 --- a/platform/core/src/services/CustomizationService/CustomizationService.ts +++ b/platform/core/src/services/CustomizationService/CustomizationService.ts @@ -280,7 +280,7 @@ export default class CustomizationService extends PubSubService { return customization; } const parent = this.getCustomization(customizationType); - const result = parent ? Object.assign(Object.create(parent), customization) : customization; + const result = parent ? Object.assign({}, parent, customization) : customization; // Execute an nested type information return result.transform?.(this) || result; } diff --git a/platform/core/src/services/StudyPrefetcherService/StudyPrefetcherService.ts b/platform/core/src/services/StudyPrefetcherService/StudyPrefetcherService.ts index 5b5853d65..398974eb3 100644 --- a/platform/core/src/services/StudyPrefetcherService/StudyPrefetcherService.ts +++ b/platform/core/src/services/StudyPrefetcherService/StudyPrefetcherService.ts @@ -679,7 +679,7 @@ class StudyPrefetcherService extends PubSubService { this._displaySetLoadingStates.clear(); this._imageIdsToDisplaySetsMap.clear(); this._inflightRequests.clear(); - this.imageLoadPoolManager.clearRequestStack(IMAGE_REQUEST_TYPE); + this.imageLoadPoolManager.clearRequestStack(this.requestType); this._broadcastEvent(this.EVENTS.SERVICE_STOPPED, {}); } diff --git a/platform/core/src/types/AppTypes.ts b/platform/core/src/types/AppTypes.ts index 07db43b48..8d820b956 100644 --- a/platform/core/src/types/AppTypes.ts +++ b/platform/core/src/types/AppTypes.ts @@ -81,6 +81,7 @@ declare global { } export interface Config { + studyBrowserMode?: 'all' | 'primary'; routerBasename?: string; customizationService?: CustomizationServiceType; extensions?: string[]; diff --git a/platform/core/src/utils/combineFrameInstance.ts b/platform/core/src/utils/combineFrameInstance.ts index 6385bfbd0..cf70232cf 100644 --- a/platform/core/src/utils/combineFrameInstance.ts +++ b/platform/core/src/utils/combineFrameInstance.ts @@ -1,3 +1,5 @@ +import { vec3 } from 'gl-matrix'; + /** * Combine the Per instance frame data, the shared frame data * and the root data objects. @@ -9,25 +11,28 @@ * single frame data. (eg frame is undefined is the same as frame===1). */ const combineFrameInstance = (frame, instance) => { - const { PerFrameFunctionalGroupsSequence, SharedFunctionalGroupsSequence, NumberOfFrames } = - instance; + const { + PerFrameFunctionalGroupsSequence, + SharedFunctionalGroupsSequence, + NumberOfFrames, + SpacingBetweenSlices, + } = instance; if (PerFrameFunctionalGroupsSequence || NumberOfFrames > 1) { const frameNumber = Number.parseInt(frame || 1); - const shared = ( - SharedFunctionalGroupsSequence ? Object.values(SharedFunctionalGroupsSequence[0]) : [] - ) - .filter(it => !!it) - .map(it => it[0]) - .filter(it => it !== undefined && typeof it === 'object'); - const perFrame = ( - PerFrameFunctionalGroupsSequence - ? Object.values(PerFrameFunctionalGroupsSequence[frameNumber - 1]) - : [] - ) - .filter(it => !!it) - .map(it => it[0]) - .filter(it => it !== undefined && typeof it === 'object'); + const shared = SharedFunctionalGroupsSequence + ? Object.values(SharedFunctionalGroupsSequence[0]) + .filter(Boolean) + .map(it => it[0]) + .filter(it => typeof it === 'object') + : []; + + const perFrame = PerFrameFunctionalGroupsSequence + ? Object.values(PerFrameFunctionalGroupsSequence[frameNumber - 1]) + .filter(Boolean) + .map(it => it[0]) + .filter(it => typeof it === 'object') + : []; // this is to fix NM multiframe datasets with position and orientation // information inside DetectorInformationSequence @@ -35,9 +40,40 @@ const combineFrameInstance = (frame, instance) => { instance.ImageOrientationPatient = instance.DetectorInformationSequence[0].ImageOrientationPatient; } + + let ImagePositionPatientToUse = instance.ImagePositionPatient; + if (!instance.ImagePositionPatient && instance.DetectorInformationSequence) { - instance.ImagePositionPatient = instance.DetectorInformationSequence[0].ImagePositionPatient; + const imagePositionPatient = instance.DetectorInformationSequence[0].ImagePositionPatient; + const imageOrientationPatient = instance.ImageOrientationPatient; + + // Calculate the position for the current frame + if (imageOrientationPatient && SpacingBetweenSlices) { + const rowOrientation = vec3.fromValues( + imageOrientationPatient[0], + imageOrientationPatient[1], + imageOrientationPatient[2] + ); + + const colOrientation = vec3.fromValues( + imageOrientationPatient[3], + imageOrientationPatient[4], + imageOrientationPatient[5] + ); + + const normalVector = vec3.cross(vec3.create(), rowOrientation, colOrientation); + + const position = vec3.scaleAndAdd( + vec3.create(), + imagePositionPatient, + normalVector, + SpacingBetweenSlices * (frameNumber - 1) + ); + + ImagePositionPatientToUse = [position[0], position[1], position[2]]; + } } + console.debug('🚀 ~ ImagePositionPatientToUse:', ImagePositionPatientToUse); const newInstance = Object.assign(instance, { frameNumber: frameNumber }); @@ -52,7 +88,8 @@ const combineFrameInstance = (frame, instance) => { // back to the dicomMetaStore so we don't have to do this again. return { ...newInstance, - ImagePositionPatient: newInstance.ImagePositionPatient ?? [0, 0, frameNumber], + ImagePositionPatient: ImagePositionPatientToUse ?? + newInstance.ImagePositionPatient ?? [0, 0, frameNumber], }; } else { return instance; diff --git a/platform/docs/docs/assets/img/iframe-basic.png b/platform/docs/docs/assets/img/iframe-basic.png index 25ea20708..5934a9422 100644 Binary files a/platform/docs/docs/assets/img/iframe-basic.png and b/platform/docs/docs/assets/img/iframe-basic.png differ diff --git a/platform/docs/docs/deployment/build-for-production.md b/platform/docs/docs/deployment/build-for-production.md index d1dd508bd..dbd89a8a9 100644 --- a/platform/docs/docs/deployment/build-for-production.md +++ b/platform/docs/docs/deployment/build-for-production.md @@ -102,18 +102,12 @@ directory: yarn global add http-server # Change the directory to the platform/app +cd platform/app # Serve the files in our current directory npx serve ./dist -c ../public/serve.json ``` -:::caution -In the video below notice that there is `platform/viewer` which has been renamed to `platform/app` in the latest version -::: - -
- -
### Automating Builds and Deployments diff --git a/platform/docs/docs/deployment/cors.md b/platform/docs/docs/deployment/cors.md index 135c9f961..b55e72f7b 100644 --- a/platform/docs/docs/deployment/cors.md +++ b/platform/docs/docs/deployment/cors.md @@ -1,5 +1,5 @@ --- -sidebar_position: 7 +sidebar_position: 8 --- # Cross-Origin Information for OHIF @@ -7,42 +7,10 @@ sidebar_position: 7 This document describes various security configurations, settings and environments/contexts needed to fully leverage OHIF’s capabilities. One may need some configurations while others might need ALL of them - it all depends on the environment OHIF is expected to run in. In particular, three of OHIF’s features depend on these configurations: -- [OHIF’s use of SharedArrayBuffer](#sharedarraybuffer) - [Embedding OHIF in an iframe](#embedding-ohif-in-an-iframe) - [XMLHttpRequests to fetch data from data sources](#cors-in-ohif) - -## SharedArrayBuffer -A `SharedArrayBuffer` is a JavaScript object that is similar to an `ArrayBuffer` but can be shared between web workers and the window that spawned them via the `postMessage` API. See [SharedArrayBuffer in MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer) for more information. - -:::tip -To turn off Shared Array Buffer completely, just set `useSharedArrayBuffer` to `false` in the [OHIF configuration](../configuration/configurationFiles.md). But keep in mind that you will not get the performance boost that Shared Array Buffer offers for decoding and rendering big volumes where web workers write to the same memory space. -::: - -### Security Requirements - -In order to use `SharedArrayBuffer` objects in the browser, the following security conditions must be met: - -- The page must be served in a [secure context](#secure-context). -- The page must have [cross-origin isolation](#cross-origin-isolation) enabled. - -### `SharedArrayBuffer` in OHIF - -OHIF uses `SharedArrayBuffer` in its volume loader (from Cornerstone3D). It comes with the benefit of improved performance and optimization at the cost of some configuration to use it. - -As such, if the following popup is shown when launching OHIF then the OHIF server will have to be configured to permit the loading of volumetric images and data. Note that stack viewports are still available and functional even when this error is present. - -![OHIF in non-secure context](../assets/img/ohif-non-secure-context.png) - -To better determine which (if not all) of the [security requirements](#security-requirements) are lacking, have a look at the browser console. - -Output in the console similar to the following indicates that OHIF is not running in a [secure context](#secure-context). - -![browser console for non-secure context](../assets/img/browser-console-non-secure-context.png) - -Absence of the above error in the console together with the presence of the Cross Origin Isolation popup warning, likely indicates that either or both of the [COOP](#coop---cross-origin-opener-policy) and/or [COEP](#coep---cross-origin-embedder-policy) headers are not set for OHIF. - ## Embedding OHIF in an iframe As described [here](./iframe.md), there are cases where OHIF will be embedded in an iframe. The following links provide more information for setting up and configuring OHIF to work in an iframe: @@ -64,9 +32,6 @@ URLs that are NOT local must be delivered over `https://` or `wss://` (i.e. TLS) A page embedded in an iframe is considered secure if it itself and every one of its embedding ancestors are delivered securely. Otherwise it is deemed insecure. -### Why does OHIF require a secure context? - -Beyond all of the inherent benefits of a secure connection, OHIF requires a secure context so that it can utilize [SharedArrayBuffer](#sharedarraybuffer) objects for volume rendering. ### Configuring/setting up a secure context @@ -143,91 +108,8 @@ add_header 'Access-Control-Allow-Origin' '*' always; ``` ::: -## COOP - Cross-Origin Opener Policy -The COOP HTTP response header restricts the global, root document of the page from being referenced and accessed by another cross-origin document that might open the page in a window. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy) for more information. -### Header Values Pertinent to OHIF (see [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy#syntax) for more information) - -|Value|Description| -|-----|-----------| -|same-origin|Restricts the document to be referenced by openers of the same origin only.| - -### COOP in OHIF - -COOP is required for [SharedArrayBuffer](#sharedarraybuffer) usage in OHIF. See also [Troubleshooting Cross-origin Isolation in OHIF](#troubleshooting-cross-origin-isolation-in-ohif). - -## COEP - Cross-Origin Embedder Policy - -The COEP HTTP response header restricts cross-origin documents from being embedded into a document (e.g. in an iframe, video, image, etc). See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy) for more information. - -### Header Values Pertinent to OHIF (see [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy#syntax) for more information) - -|Value|Description| -|-----|-----------| -|require-corp|Permits the document to load either of the following embedded resources:
  • Those from the same origin
  • Cross-origin resources embedded by a DOM element that has the appropriate [crossorigin attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin) set
  • Cross-origin resources with the appropriate [CORP response header](#corp---cross-origin-resource-policy)
-|credentialless|See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy#syntax) for more information| - -### COEP in OHIF - -COEP is required for [SharedArrayBuffer](#sharedarraybuffer) usage in OHIF. See also [Troubleshooting Cross-origin Isolation in OHIF](#troubleshooting-cross-origin-isolation-in-ohif). - -## Cross-origin Isolation - -Cross-origin isolation is [enabled](https://web.dev/cross-origin-isolation-guide/#enable-cross-origin-isolation) for a web page when the following COOP and COEP headers are set. -- [COOP](#coop---cross-origin-opener-policy) with `same-origin` -- [COEP](#coep---cross-origin-embedder-policy) with `require-corp` or `credentialless` - -### iframe - -An iframe is considered to have cross-origin isolation enabled if it itself has the appropriate COOP and COEP headers set as well as every one of its embedding ancestors. - -### Troubleshooting Cross-origin Isolation in OHIF - -The [SharedArrayBuffer in OHIF](#sharedarraybuffer-in-ohif) section describes how to determine if there are problems with cross-origin isolation in OHIF. If it is determined that COOP and/or COEP is indeed an issue, then the COOP and COEP headers must be set for OHIF. How to accomplish this varies per server or service that is hosting OHIF. The following are just a few examples. - -:::tip -In the default dev environment, the following can be set in the webpack.pwa.js file… - -```javascript -devServer: { - headers: { - "Cross-Origin-Opener-Policy": "same-origin", - "Cross-Origin-Embedder-Policy": "require-corp" - } -} -``` -::: - -:::tip -If deploying OHIF using Netlify, the Netlify configuration [file](https://docs.netlify.com/configure-builds/file-based-configuration/) can be used to configure the headers as such… - -``` -[[headers]] - # Define which paths this specific [[headers]] block will cover. - for = "/*" - - [headers.values] - Cross-Origin-Opener-Policy = "same-origin" - Cross-Origin-Embedder-Policy = "require-corp" -``` -::: - -:::tip -If OHIF is served behind nginx, then the headers can be set in the nginx.conf file as follows. The [template nginx configuration file](https://github.com/OHIF/Viewers/blob/master/.docker/Viewer-v3.x/default.conf.template) for creating a [OHIF Docker image](./docker.md#building-the-docker-image) has an example of this too. -```nginx -server { - location / { - add_header Cross-Origin-Opener-Policy same-origin; - add_header Cross-Origin-Embedder-Policy require-corp; - } -} -``` -::: - -## CORP - Cross-Origin Resource Policy - -The CORP HTTP response header indicates which origins can read and use a resource. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cross-Origin_Resource_Policy) for more information. ### Header Values (see [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cross-Origin_Resource_Policy#usage) for more information) @@ -239,12 +121,6 @@ The CORP HTTP response header indicates which origins can read and use a resourc ### OHIF and CORP -There are two scenarios where the CORP header is relevant to OHIF: - -- [PDF from a Cross Origin DICOMweb Data Source](#pdf-from-a-cross-origin-dicomweb-data-source) -- [OHIF as a Cross-origin Resource in an iframe](#ohif-as-a-cross-origin-resource-in-an-iframe) - -Both these scenarios stem from the fact that OHIF has to be served with the [COEP](#coep---cross-origin-embedder-policy) header to support [SharedArrayBuffer](#sharedarraybuffer). #### PDF from a Cross Origin DICOMweb Data Source @@ -266,48 +142,3 @@ If the dcm4chee server and the OHIF server are hosted on the same site, then the add_header 'Cross-Origin-Resource-Policy' 'same-site' always; ``` ::: - -#### OHIF as a Cross-origin Resource in an iframe - -There are cases where [OHIF is embedded in an iframe](./iframe.md) and the embedding page is from a different origin. Again due to the [security requirements for SharedArrayBuffer](#security-requirements), [both OHIF and the embedding page](#iframe) must have the appropriate COEP header. In this scenario, OHIF is the cross-origin resource and since the ` -
- -::tip -Since `@cornerstonejs/tools` depends on `@cornerstonejs/core`, if you need the changes -you made in `@cornerstonejs/core` to be reflected in `@cornerstonejs/tools`, you need to -also link `@cornerstonejs/core` to `@cornerstonejs/tools`. - -```sh -cd /path/to/cornerstonejs-core -# for the core -yarn link - -cd /path/to/cornerstonejs-tools -yarn link "@cornerstonejs/core" - -# for the tools -yarn link - -# inside OHIF -cd /path/to/OHIFViewer -yarn link "@cornerstonejs/core" -yarn link "@cornerstonejs/tools" -``` +You can take a look at the Cornerstonejs tutorial for linking https://www.cornerstonejs.org/docs/contribute/linking diff --git a/platform/docs/docs/faq/technical.md b/platform/docs/docs/faq/technical.md index 4b446e5ab..bee5b8f7e 100644 --- a/platform/docs/docs/faq/technical.md +++ b/platform/docs/docs/faq/technical.md @@ -2,14 +2,6 @@ -## Why do I keep seeing a Cross Origin Isolation warning -If you encounter a warning while running OHIF indicating that your application is not cross-origin isolated, it implies that volume rendering, such as MPR, will not function properly since they depend on Shared Array Buffers. To resolve this issue, we recommend referring to our comprehensive guide on Cross Origin Isolation available at [our dedicated cors page](../deployment/cors.md). - -## What if my setup does not support the Shared Array Buffers API? -You can simply disable that by adding the `useSharedArrayBuffer: 'FALSE'` (notice the string FALSE), and the volumes will only use a regular -array buffer which is a bit slower but will work on all browsers. - - ## Viewer opens but does not show any thumbnails Thumbnails may not appear in your DICOMWeb application for various reasons. This guide focuses on one primary scenario, which is you are using @@ -274,6 +266,10 @@ which then it will look like ![alt text](faq-measure-5.png) +:::info +There is also dedicated example for this in the [cornerstone3D examples](https://www.cornerstonejs.org/live-examples/dynamicallyaddannotations). +::: + ## How do I sort the series in the study panel by a specific value diff --git a/platform/docs/docs/migration-guide/3p8-to-3p9/0-general.md b/platform/docs/docs/migration-guide/3p8-to-3p9/0-general.md index 8a96e70e2..098196e67 100644 --- a/platform/docs/docs/migration-guide/3p8-to-3p9/0-general.md +++ b/platform/docs/docs/migration-guide/3p8-to-3p9/0-general.md @@ -97,6 +97,35 @@ import { ReactComponent as arrowDown } from './../../assets/icons/arrow-down.svg We have removed the Polyfill.io script from the Viewer. If you require polyfills, you can add them to your project manually. This change primarily affects Internet Explorer, which Microsoft has already [ended support for](https://learn.microsoft.com/en-us/lifecycle/faq/internet-explorer-microsoft-edge#is-internet-explorer-11-the-last-version-of-internet-explorer-). +--- + +## Webpack changes + +We previously were copying dicom-image-loader wasm files to the public folder via + +```js +// platform/app/.webpack/webpack.pwa.js +{ + from: '../../../node_modules/@cornerstonejs/dicom-image-loader/dist/dynamic-import', + to: DIST_DIR, +}, +``` + +but now after our upgrade to Cornerstone 3D 2.0, we don't need to do this anymore. + + +--- +## Scroll utility + + +The `jumpToSlice` utility has been relocated from `@cornerstonejs/tools` utilities to `@cornerstonejs/core/utilities`. + +migration + +```js +import { jumpToSlice } from '@cornerstonejs/core/utilities'; +``` + --- @@ -178,9 +207,19 @@ Now: --- +## CustomizationService + +The `CustomizationService` uses `contentF` instead of `content`. + +So make sure your customizations are updated accordingly. + +--- + ## SidePanel auto switch if open -In `basic viewer` mode, if the side panel is open and the segmentation panel is active, adding a measurement will automatically switch to the measurement panel. This switch won't occur if the side panel is closed. To enable or disable this feature, adjust your mode configuration accordingly. +In `basic viewer` mode, when the side panel is open and the segmentation panel is active, adding a measurement will automatically switch to the measurement panel. This switch won't happen if the side panel is closed. To enable or disable this feature, adjust your mode configuration accordingly. + +To prevent this behavior, remove the following code from your mode: ```js panelService.addActivatePanelTriggers('your.panel.id', [ diff --git a/platform/docs/docs/migration-guide/3p8-to-3p9/7-UI.md b/platform/docs/docs/migration-guide/3p8-to-3p9/7-UI.md index 71e625d93..2be4fabf0 100644 --- a/platform/docs/docs/migration-guide/3p8-to-3p9/7-UI.md +++ b/platform/docs/docs/migration-guide/3p8-to-3p9/7-UI.md @@ -2,9 +2,6 @@ title: UI --- - - - ## New Components You can explore our new playground at `docs.ohif.org/ui` to see the latest components and their properties. We haven't provided a migration guide yet because the old components are still available. Feel free to update your codebase, including custom extensions and UI, to use the new Button, Dropdown, Icons, and other new components from `@ohif/ui-next`. The old methods (importing from `@ohif/ui`) will continue to work for now. However, the new components have a slightly different API, and we plan to deprecate the old components in a future release, as we see the new ones as the future of OHIF. @@ -147,3 +144,13 @@ All the DropDown and Icons are now in the @ohif/ui-next package. --- + + +## ui, ui-next configs + +We currently have two component libraries that we plan to merge in the future, so we need to maintain both configurations. If your styles aren't applying correctly, ensure you update both `platform/ui-next/tailwind.config.js` and `platform/ui/tailwind.config.js`. + + +### addIcon from ui-next + +if you add custom icons, you may need to add them using a new `addIcon` utility which adds the icon to both `ui` and `ui-next`. diff --git a/platform/docs/docs/platform/extensions/modules/data-source.md b/platform/docs/docs/platform/extensions/modules/data-source.md index 7b7a2d506..aeec72dba 100644 --- a/platform/docs/docs/platform/extensions/modules/data-source.md +++ b/platform/docs/docs/platform/extensions/modules/data-source.md @@ -84,7 +84,7 @@ important api endpoints that you need to implement: - `initialize`: This method is called when the data source is first created in the mode.tsx, it is used to initialize the data source and set the configuration. For instance, `dicomwebDatasource` uses this method to grab the StudyInstanceUID from the URL and set it as the active study, as opposed to `dicomJSONDatasource` which uses url in the browser to fetch the data and store it in a cache - `query.studies.search`: This is used in the study panel on the left to fetch the prior studies for the same MRN which is then used to display on the `All` tab. it is also used in the Worklist to show all the studies from the server. - `query.series.search`: This is used to fetch the series information for a given study that is expanded in the Worklist. -- `retrieve.bulkDataURI`: used to render RTSTUCTURESET in the viewport. +- `retrieve.bulkDataURI`: used to render RTSTUCTURESET in the viewport. It is an object that contains `enabled` as property and other options that are specific to the data source. - `retrieve.series.metadata`: It is a crucial end point that is used to fetch series level metadata which for hanging displaySets and displaySet creation. - `store.dicom`: If you don't need store functionality, you can skip this method. This is used to store the data in the backend. diff --git a/platform/docs/docs/platform/extensions/modules/toolbar.md b/platform/docs/docs/platform/extensions/modules/toolbar.md index b353a0304..6d772b930 100644 --- a/platform/docs/docs/platform/extensions/modules/toolbar.md +++ b/platform/docs/docs/platform/extensions/modules/toolbar.md @@ -137,7 +137,52 @@ this pattern, where multiple toolbar buttons are using the same evaluator but wi }, ``` + +#### Viewport and Modality Support Evaluation + +The toolbar system now uses a more robust approach for evaluating button states based on viewport types and modalities: + +**Viewport Type Support**: + +Use `evaluate.viewport.supported` to disable buttons for specific viewport types: + +```js +{ + name: 'evaluate.viewport.supported', + unsupportedViewportTypes: ['volume3d', 'video', 'sm'] +} +``` + +**Modality Support**: +Use `evaluate.modality.supported` to control button state based on modalities: + +```js +{ + name: 'evaluate.modality.supported', + supportedModalities: ['CT', 'MR'], // Enable only for these modalities + // OR + unsupportedModalities: ['US'] // Disable for these modalities +} +``` + #### Composing evaluators +Multiple evaluators can be combined to create complex conditions: + +```js +evaluate: [ + 'evaluate.cine', + { + name: 'evaluate.viewport.supported', + unsupportedViewportTypes: ['volume3d'] + }, + { + name: 'evaluate.modality.supported', + supportedModalities: ['CT'] + } +] +``` + +This evaluation system provides more precise control over when toolbar buttons are enabled or disabled based on the active viewport's characteristics. You can choose to set up multiple evaluators for a single button. This comes in handy when you need to assess the button according to various conditions. For example, we aim to prevent the Cine player from showing up on the 3D viewport, so we have: diff --git a/platform/docs/docs/platform/services/data/SegmentationService.md b/platform/docs/docs/platform/services/data/SegmentationService.md index 31e4b6726..c2eeb6080 100644 --- a/platform/docs/docs/platform/services/data/SegmentationService.md +++ b/platform/docs/docs/platform/services/data/SegmentationService.md @@ -5,50 +5,141 @@ sidebar_label: Segmentation Service # Segmentation Service -## Overview - -Using Segmentation Service you can create, edit and delete segmentation data, and -change appearance of the segmentation including color, opacity and visibility. - -Segmentations in OHIF are based on the Segmentations in Cornerstone3D. You can -read more about it in the [Cornerstone Segmentation](https://www.cornerstonejs.org/docs/concepts/cornerstone-tools/segmentation/). OHIF currently only supports -one representation of the segmentation data. ## Events -There are seven events that get publish in `MeasurementService`: +```typescript +SEGMENTATION_MODIFIED // When a segmentation is updated +SEGMENTATION_DATA_MODIFIED // When segmentation data changes +SEGMENTATION_ADDED // When new segmentation is added +SEGMENTATION_REMOVED // When segmentation is removed +SEGMENT_LOADING_COMPLETE // When segment group adds pixel data to volume +SEGMENTATION_LOADING_COMPLETE // When full segmentation volume is filled +``` -| Event | Description | -| --------------------- | ------------------------------------------------------ | -| SEGMENTATION_MODIFIED | Fires when a segmentation is updated e.g., segment added, removed etc.| -| SEGMENTATION_DATA_MODIFIED | Fires when the segmentation data changes | -| SEGMENTATION_ADDED | Fires when a new segmentation is added to OHIF | -| SEGMENTATION_REMOVED | Fires when a segmentation is removed from OHIF | -| SEGMENT_LOADING_COMPLETE | Fires when a segment group adds its pixel data to the volume | -| SEGMENTATION_LOADING_COMPLETE | Fires when the full segmentation volume is filled with its segments | +## Core APIs +### Creation Methods -## API +```typescript +createLabelmapForDisplaySet( + displaySet, + { + segmentationId?: string, + label: string, + segments?: { + [segmentIndex: number]: Partial + } + } +) +``` -### Segmentation Creation +### Segmentation Management -- `createEmptyLabelmapForDisplaySetUID`: based on a reference displaySet, create a new segmentation. E.g., create a new segmentation based on a CT series -- `createSegmentationForSEGDisplaySet`: given a segDisplaySet loaded by a sopClassHandler, create a new segmentation -- `addSegmentationRepresentationToToolGroup`: given the toolGroupId, add the given segmentationId to the toolGroup. +```typescript +setActiveSegmentation(viewportId, segmentationId) +getSegmentations() +getSegmentation(segmentationId) +jumpToSegmentCenter(segmentationId, segmentIndex, viewportId) +highlightSegment(segmentationId, segmentIndex, viewportId) +``` +### Segment Operations -### Segmentation Behavior +```typescript +addSegment(segmentationId, { + segmentIndex?: number, + label?: string, + color?: [number, number, number, number], // RGBA + visibility?: boolean, + isLocked?: boolean, + active?: boolean +}) -- setActiveSegmentationForToolGroup, getSegmentations, getSegmentation, jumpToSegmentCenter, highlightSegment +setSegmentColor(viewportId, segmentationId, segmentIndex, color) +setSegmentVisibility(viewportId, segmentationId, segmentIndex, visibility) +``` +## Data Structures -### Segment Behavior +### Segmentation Object -- setSegmentLocked, removeSegment, addSegment, setSegmentLocked, setSegmentLabel, setActiveSegment, -setSegmentRGBAColor +```typescript +interface Segmentation { + segmentationId: string; + label: string; + segments: { + [segmentIndex: number]: { + segmentIndex: number; + label: string; + locked: boolean; + cachedStats: { [key: string]: unknown }; + active: boolean; + } + }; + representationData: RepresentationsData; +} +``` -### Segmentation Configuration +## Code Examples -Setters +### Creating a Segmentation -- setSegmentVisibility, setSegmentColor, setSegmentRGBA, setSegmentOpacity, toggleSegmentationVisibility, +```typescript +const displaySet = displaySetService.getDisplaySetByUID(displaySetUID); +const segmentationId = await segmentationService.createLabelmapForDisplaySet( + displaySet, + { + label: 'New Segmentation', + segments: { + 1: { + label: 'First Segment', + active: true + } + } + } +); +``` + +### Managing Active Segmentations + +```typescript +segmentationService.setActiveSegmentation('viewport-1', segmentationId); +``` + +### Adding Segments + +```typescript +segmentationService.addSegment(segmentationId, { + label: 'Tumor', + color: [255, 0, 0, 255], // RGBA format + active: true +}); +``` + +### Visibility Management + +```typescript +// Set segment visibility +segmentationService.setSegmentVisibility( + 'viewport-1', + segmentationId, + 1, // segmentIndex + true // visible +); + +// Get viewport IDs with segmentation +const viewportIds = segmentationService.getViewportIdsWithSegmentation(segmentationId); +``` + +### Segment Styling + +```typescript +// Set segment color +segmentationService.setSegmentColor( + 'viewport-1', + segmentationId, + 1, // segmentIndex + [255, 0, 0, 255] // RGBA +); +``` diff --git a/platform/docs/package.json b/platform/docs/package.json index c86400b43..efe7aaff4 100644 --- a/platform/docs/package.json +++ b/platform/docs/package.json @@ -41,16 +41,16 @@ ] }, "dependencies": { - "@docusaurus/core": "3.6.0", - "@docusaurus/faster": "3.6.0", - "@docusaurus/plugin-client-redirects": "3.6.0", - "@docusaurus/plugin-google-gtag": "3.6.0", - "@docusaurus/plugin-ideal-image": "3.6.0", - "@docusaurus/plugin-pwa": "3.6.0", - "@docusaurus/preset-classic": "3.6.0", - "@docusaurus/remark-plugin-npm2yarn": "3.6.0", - "@docusaurus/theme-classic": "3.6.0", - "@docusaurus/theme-live-codeblock": "3.6.0", + "@docusaurus/core": "3.6.1", + "@docusaurus/faster": "3.6.1", + "@docusaurus/plugin-client-redirects": "3.6.1", + "@docusaurus/plugin-google-gtag": "3.6.1", + "@docusaurus/plugin-ideal-image": "3.6.1", + "@docusaurus/plugin-pwa": "3.6.1", + "@docusaurus/preset-classic": "3.6.1", + "@docusaurus/remark-plugin-npm2yarn": "3.6.1", + "@docusaurus/theme-classic": "3.6.1", + "@docusaurus/theme-live-codeblock": "3.6.1", "@mdx-js/react": "3.0.1", "@radix-ui/react-accordion": "^1.2.0", "@radix-ui/react-checkbox": "^1.1.1", diff --git a/platform/ui-next/src/components/DataRow/DataRow.tsx b/platform/ui-next/src/components/DataRow/DataRow.tsx index 781855fb3..de584b398 100644 --- a/platform/ui-next/src/components/DataRow/DataRow.tsx +++ b/platform/ui-next/src/components/DataRow/DataRow.tsx @@ -139,14 +139,7 @@ const DataRow: React.FC = ({ className="whitespace-pre-wrap" > {indentation} - {cleanText.includes(':') ? ( - <> - {cleanText.split(':')[0]}: - {cleanText.split(':')[1]} - - ) : ( - {cleanText} - )} + {cleanText} ); }; @@ -199,14 +192,14 @@ const DataRow: React.FC = ({ {/* Hover Overlay */}
- {/* Number Box */} -
- {number} -
+ {/* Number Box */} +
+ {number} +
{/* Color Circle (Optional) */} {colorHex && ( @@ -313,10 +306,16 @@ const DataRow: React.FC = ({ - {details && details.primary?.length > 0 && ( + {/* Details Section */} + {details && (details.primary?.length > 0 || details.secondary?.length > 0) && (
-
- {renderDetails(details.primary)} +
+ {details.primary?.length > 0 && renderDetails(details.primary)} + {details.secondary?.length > 0 && ( +
+ {renderDetails(details.secondary)} +
+ )}
)} diff --git a/platform/ui-next/src/components/SegmentationTable/SegmentationSegments.tsx b/platform/ui-next/src/components/SegmentationTable/SegmentationSegments.tsx index 98b8f016b..3e666b0b3 100644 --- a/platform/ui-next/src/components/SegmentationTable/SegmentationSegments.tsx +++ b/platform/ui-next/src/components/SegmentationTable/SegmentationSegments.tsx @@ -34,7 +34,7 @@ export const SegmentationSegments: React.FC<{ } const segmentCount = Object.keys(representationToUse.segments).length; - const height = mode === 'collapsed' ? 'h-[600px]' : `h-[${segmentCount * 200}px]`; + const height = mode === 'collapsed' ? 'h-[900px]' : `h-[${segmentCount * 200}px]`; return (
+
{ return ( -
+
{getCloseIcon()} {tabs.length === 1 ? getOneTabComponent() : getTabGridComponent()}
diff --git a/platform/ui/src/tailwind.css b/platform/ui/src/tailwind.css index 1c23d4c61..52d0b3630 100644 --- a/platform/ui/src/tailwind.css +++ b/platform/ui/src/tailwind.css @@ -5,10 +5,6 @@ @tailwind components; @tailwind utilities; -* { - min-height: 0 !important; -} - @layer base { html { font-family: 'Inter', sans-serif; diff --git a/yarn.lock b/yarn.lock index 2565a5062..4284680a7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2580,10 +2580,10 @@ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== -"@cornerstonejs/adapters@^2.2.4": - version "2.2.4" - resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-2.2.4.tgz#6f5edf17dc5f76cb6c80d67a4b70c38c1ca05700" - integrity sha512-sWatnhu93NjaT8MsrJIsexpxzFrUmtxrS6lSBca9CWNDMLR1t8boff6fmvGKE8TYbQkPQZrytRJBSw5O6pWdMg== +"@cornerstonejs/adapters@^2.2.20": + version "2.2.20" + resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-2.2.20.tgz#82fd0775a6ac4e138bda4f3dad412593133b16a9" + integrity sha512-o9c3eTJa7D0wgdkAdg33/BET5+BgM5qjt6Xmd/QSXsghPyJcmvnxIzKS+upt2///u+f8q4aaiL3dgsVzNc6L9g== dependencies: "@babel/runtime-corejs2" "^7.17.8" buffer "^6.0.3" @@ -2616,19 +2616,19 @@ resolved "https://registry.yarnpkg.com/@cornerstonejs/codec-openjph/-/codec-openjph-2.4.5.tgz#8690b61a86fa53ef38a70eee9d665a79229517c0" integrity sha512-MZCUy8VG0VG5Nl1l58+g+kH3LujAzLYTfJqkwpWI2gjSrGXnP6lgwyy4GmPRZWVoS40/B1LDNALK905cNWm+sg== -"@cornerstonejs/core@^2.2.4": - version "2.2.4" - resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-2.2.4.tgz#eeb4e383a332e43186299cb19ddd46dad1013437" - integrity sha512-nw14sTuz02o2W8a0WT0dH4J1B7iZ4KZU5r0KDnYkpDHjL1Y30lmSt098Pxb4Z9Xj+GJYunlWv962RtVhnWbSZA== +"@cornerstonejs/core@^2.2.20": + version "2.2.20" + resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-2.2.20.tgz#a39176c0f832ce2d91f414a2f06010c54c3b99b0" + integrity sha512-1gfARz1tqoAnic1rTGILF9MbwC0YICCNWS+k5vCkf+1ZX3XYepMt3bV3GPPAcTDJ2t6t20Ii1xdKueDn3BSIXw== dependencies: - "@kitware/vtk.js" "32.1.0" + "@kitware/vtk.js" "32.1.1" comlink "^4.4.1" gl-matrix "^3.4.3" -"@cornerstonejs/dicom-image-loader@^2.2.4": - version "2.2.4" - resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-2.2.4.tgz#117635b11a0230381fe31a5119271b472f7048d5" - integrity sha512-DwRZrTaVrrH7aGqFibcL+Ijnygtd3sxovxREzHWqGrmmxpwsm+aA9Z5nXeg58hk5Kvd0Zt8iwlrtcnTeD2DPiw== +"@cornerstonejs/dicom-image-loader@^2.2.20": + version "2.2.20" + resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-2.2.20.tgz#3d1d448ac2c7010ae29359209f5a6b1790777930" + integrity sha512-pYyYzPbbwOU9tH84WAhBK/+XdJ/Gc3hYfsrsuGk3ufVsdjRywvjGviSOYN4My0w++ezanaSFdPNcghtqdL8etQ== dependencies: "@cornerstonejs/codec-charls" "^1.2.3" "@cornerstonejs/codec-libjpeg-turbo-8bit" "^1.2.2" @@ -2639,10 +2639,10 @@ pako "^2.0.4" uuid "^9.0.0" -"@cornerstonejs/tools@^2.2.4": - version "2.2.4" - resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-2.2.4.tgz#3fa5e99daffc73434d7385885dda09e17820756c" - integrity sha512-pEqJzAp4/ZtVmWqPG7C/hH/09dt6OBoRq5fiEJE/mxJXbe77FeDq5zQy8Irv7IkDpXpnc8kL+6L9Zb5awc3uRA== +"@cornerstonejs/tools@^2.2.20": + version "2.2.20" + resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-2.2.20.tgz#d2fcbc1b6f585f4094bb5d03d3ae87862e1df092" + integrity sha512-rS7KNfLjwtZ0MzP9eT5EDKBDoEh/Nt5htJxj9b/BvL2W6X/vyF361tWYf/L2dIo0NdR6LBYds3Gdm31y+b7drA== dependencies: "@types/offscreencanvas" "2019.7.3" comlink "^4.4.1" @@ -2806,10 +2806,10 @@ "@docsearch/css" "3.6.2" algoliasearch "^4.19.1" -"@docusaurus/babel@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/babel/-/babel-3.6.0.tgz#735a003207925bd782dd08ffa5d8b3503c1f8d72" - integrity sha512-7CsoQFiadoq7AHSUIQNkI/lGfg9AQ2ZBzsf9BqfZGXkHwWDy6twuohEaG0PgQv1npSRSAB2dioVxhRSErnqKNA== +"@docusaurus/babel@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/babel/-/babel-3.6.1.tgz#5f48a275934b8164ccac3a6fd1fca3741374c884" + integrity sha512-JcKaunW8Ml2nTnfnvFc55T00Y+aCpNWnf1KY/gG+wWxHYDH0IdXOOz+k6NAlEAerW8+VYLfUqRIqHZ7N/DVXvQ== dependencies: "@babel/core" "^7.25.9" "@babel/generator" "^7.25.9" @@ -2821,23 +2821,23 @@ "@babel/runtime" "^7.25.9" "@babel/runtime-corejs3" "^7.25.9" "@babel/traverse" "^7.25.9" - "@docusaurus/logger" "3.6.0" - "@docusaurus/utils" "3.6.0" + "@docusaurus/logger" "3.6.1" + "@docusaurus/utils" "3.6.1" babel-plugin-dynamic-import-node "^2.3.3" fs-extra "^11.1.1" tslib "^2.6.0" -"@docusaurus/bundler@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/bundler/-/bundler-3.6.0.tgz#bdd060ba4d009211348e4e973a3bf4861cf0996b" - integrity sha512-o5T9HXkPKH0OQAifTxEXaebcO8kaz3tU1+wlIShZ2DKJHlsyWX3N4rToWBHroWnV/ZCT2XN3kLRzXASqrnb9Tw== +"@docusaurus/bundler@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/bundler/-/bundler-3.6.1.tgz#240343d31f39638f987caf54793c09820270ecd5" + integrity sha512-vHSEx8Ku9x/gfIC6k4xb8J2nTxagLia0KvZkPZhxfkD1+n8i+Dj4BZPWTmv+kCA17RbgAvECG0XRZ0/ZEspQBQ== dependencies: "@babel/core" "^7.25.9" - "@docusaurus/babel" "3.6.0" - "@docusaurus/cssnano-preset" "3.6.0" - "@docusaurus/logger" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils" "3.6.0" + "@docusaurus/babel" "3.6.1" + "@docusaurus/cssnano-preset" "3.6.1" + "@docusaurus/logger" "3.6.1" + "@docusaurus/types" "3.6.1" + "@docusaurus/utils" "3.6.1" autoprefixer "^10.4.14" babel-loader "^9.2.1" clean-css "^5.3.2" @@ -2858,18 +2858,18 @@ webpack "^5.95.0" webpackbar "^6.0.1" -"@docusaurus/core@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-3.6.0.tgz#b23fc7e253a49cc3e5ac9e091354f497cc0b101b" - integrity sha512-lvRgMoKJJSRDt9+HhAqFcICV4kp/mw1cJJrLxIw4Q2XZnFGM1XUuwcbuaqWmGog+NcOLZaPCcCtZbn60EMCtjQ== +"@docusaurus/core@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-3.6.1.tgz#260d78e1eb7129ccb441fa944b5f7e6f492ac6cb" + integrity sha512-cDKxPihiM2z7G+4QtpTczS7uxNfNG6naSqM65OmAJET0CFRHbc9mDlLFtQF0lsVES91SHqfcGaaLZmi2FjdwWA== dependencies: - "@docusaurus/babel" "3.6.0" - "@docusaurus/bundler" "3.6.0" - "@docusaurus/logger" "3.6.0" - "@docusaurus/mdx-loader" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-common" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" + "@docusaurus/babel" "3.6.1" + "@docusaurus/bundler" "3.6.1" + "@docusaurus/logger" "3.6.1" + "@docusaurus/mdx-loader" "3.6.1" + "@docusaurus/utils" "3.6.1" + "@docusaurus/utils-common" "3.6.1" + "@docusaurus/utils-validation" "3.6.1" boxen "^6.2.1" chalk "^4.1.2" chokidar "^3.5.3" @@ -2907,21 +2907,22 @@ webpack-dev-server "^4.15.2" webpack-merge "^6.0.1" -"@docusaurus/cssnano-preset@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-3.6.0.tgz#02378e53e9568ed5fc8871d4fc158ea96fd7421c" - integrity sha512-h3jlOXqqzNSoU+C4CZLNpFtD+v2xr1UBf4idZpwMgqid9r6lb5GS7tWKnQnauio6OipacbHbDXEX3JyT1PlDkg== +"@docusaurus/cssnano-preset@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-3.6.1.tgz#dc07b15f37d5c7bc1e59255ce0fa8825dde2dfb7" + integrity sha512-ZxYUmNeyQHW2w4/PJ7d07jQDuxzmKr9uPAQ6IVe5dTkeIeV0mDBB3jOLeJkNoI42Ru9JKEqQ9aVDtM9ct6QHnw== dependencies: cssnano-preset-advanced "^6.1.2" postcss "^8.4.38" postcss-sort-media-queries "^5.2.0" tslib "^2.6.0" -"@docusaurus/faster@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/faster/-/faster-3.6.0.tgz#70540e689fd16e26e6105fe689a1347b8ac93834" - integrity sha512-9X06/KHD3f4CKm0SjZQIK3UDE/XvouAMiAlYMPV5LprubFlxVQecZG9QnfOe7VIfUh9IuPiDPuGg17yy0efwww== +"@docusaurus/faster@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/faster/-/faster-3.6.1.tgz#f564abe9904c4132ca32164012f8427270c257c8" + integrity sha512-W3a9m7Q/fEeOpOw9/XktLCHRtp1sV2AdZWMCjH3kP1jY1TDyLFFiHJ0+1uwVpOw4/oPJqZSTRKP+IdW4+65NgQ== dependencies: + "@docusaurus/types" "3.6.1" "@rspack/core" "^1.0.14" "@swc/core" "^1.7.39" "@swc/html" "^1.7.39" @@ -2931,33 +2932,33 @@ tslib "^2.6.0" webpack "^5.95.0" -"@docusaurus/logger@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-3.6.0.tgz#c7349c2636087f55f573a60a3c7f69b87d59974d" - integrity sha512-BcQhoXilXW0607cH/kO6P5Gt5KxCGfoJ+QDKNf3yO2S09/RsITlW+0QljXPbI3DklTrHrhRDmgGk1yX4nUhWTA== +"@docusaurus/logger@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-3.6.1.tgz#724b7f9d8c435c9933d52792458659471ec90919" + integrity sha512-OvetI/nnOMBSqCkUzKAQhnIjhxduECK4qTu3tq/8/h/qqvLsvKURojm04WPE54L+Uy+UXMas0hnbBJd8zDlEOw== dependencies: chalk "^4.1.2" tslib "^2.6.0" -"@docusaurus/lqip-loader@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/lqip-loader/-/lqip-loader-3.6.0.tgz#c40cbe74690455e5c65749d4a9a2bc00806a91a9" - integrity sha512-jEQjnKAjhgyZ/aQf0Tbl3eDpp1j0C/GojE/cv2Bad89o+luV1OAOs9UHDRyKwWQfN+se0D9kFxkfsfwYxMpI8A== +"@docusaurus/lqip-loader@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/lqip-loader/-/lqip-loader-3.6.1.tgz#b5a4956b8906b2087e2f9429c63ddaff184f8f77" + integrity sha512-H/VVvnvFupFhQ81FuTyA/XHxEZPKh99T6Wg6KgN+/yvcn7869RdgrlDhKDnXZ7j2u80eFsVNjAcPfW1cSAtK6A== dependencies: - "@docusaurus/logger" "3.6.0" + "@docusaurus/logger" "3.6.1" file-loader "^6.2.0" lodash "^4.17.21" sharp "^0.32.3" tslib "^2.6.0" -"@docusaurus/mdx-loader@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-3.6.0.tgz#f8ba7af9d59473a7182f6a9307e0432f8dce905b" - integrity sha512-GhRzL1Af/AdSSrGesSPOU/iP/aXadTGmVKuysCxZDrQR2RtBtubQZ9aw+KvdFVV7R4K/CsbgD6J5oqrXlEPk3Q== +"@docusaurus/mdx-loader@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-3.6.1.tgz#6482e6f2f32ccab4a74d8b64d7eeec4fdf9be475" + integrity sha512-KPIsYi0S3X3/rNrW3V1fgOu5t6ahYWc31zTHHod8pacFxdmk9Uf6uuw+Jd6Cly1ilgal+41Ku+s0gmMuqKqiqg== dependencies: - "@docusaurus/logger" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" + "@docusaurus/logger" "3.6.1" + "@docusaurus/utils" "3.6.1" + "@docusaurus/utils-validation" "3.6.1" "@mdx-js/mdx" "^3.0.0" "@slorber/remark-comment" "^1.0.0" escape-html "^1.0.3" @@ -2994,12 +2995,12 @@ react-helmet-async "*" react-loadable "npm:@docusaurus/react-loadable@5.5.2" -"@docusaurus/module-type-aliases@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-3.6.0.tgz#44083c34a53db1dde06364b4e7f2d144fa2d5394" - integrity sha512-szTrIN/6/fuk0xkf3XbRfdTFJzRQ8d1s3sQj5++58wltrT7v3yn1149oc9ryYjMpRcbsarGloQwMu7ofPe4XPg== +"@docusaurus/module-type-aliases@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-3.6.1.tgz#2780e19411d0c8b16d46a032eae9e60e742ae681" + integrity sha512-J+q1jgm7TnEfVIUZImSFeLA1rghb6nwtoB9siHdcgKpDqFJ9/S7xhQL2aEKE7iZMZYzpu+2F390E9A7GkdEJNA== dependencies: - "@docusaurus/types" "3.6.0" + "@docusaurus/types" "3.6.1" "@types/history" "^4.7.11" "@types/react" "*" "@types/react-router-config" "*" @@ -3007,34 +3008,34 @@ react-helmet-async "*" react-loadable "npm:@docusaurus/react-loadable@6.0.0" -"@docusaurus/plugin-client-redirects@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-client-redirects/-/plugin-client-redirects-3.6.0.tgz#54155826e9e5da625e296eb93e346c11c1541a78" - integrity sha512-LIqRT6dtgxdENQH8XYwOOyxfKuzFD1ayJmIDCp9Yi/rbdcPE4vvTcESLGXOKvcyWZSfyCu+JA8Tyk4qpp+2J0w== +"@docusaurus/plugin-client-redirects@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-client-redirects/-/plugin-client-redirects-3.6.1.tgz#a035708ff13234a30dbaa84526ab12a102e00d07" + integrity sha512-gY1LEQw4zSLSPNVxZk9mDj5ct+sJNux0SiY1PbMiI9sK8xXqkTC7QuRyrxRPelSZX9K4nyhK8PjYbVXAN+GUWQ== dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/logger" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-common" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" + "@docusaurus/core" "3.6.1" + "@docusaurus/logger" "3.6.1" + "@docusaurus/utils" "3.6.1" + "@docusaurus/utils-common" "3.6.1" + "@docusaurus/utils-validation" "3.6.1" eta "^2.2.0" fs-extra "^11.1.1" lodash "^4.17.21" tslib "^2.6.0" -"@docusaurus/plugin-content-blog@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.6.0.tgz#9128175b4c3ce885d9090183d74c60813844ea8d" - integrity sha512-o4aT1/E0Ldpzs/hQff5uyoSriAhS/yqBhqSn+fvSw465AaqRsva6O7CZSYleuBq6x2bewyE3QJq2PcTiHhAd8g== +"@docusaurus/plugin-content-blog@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.6.1.tgz#1127d35e1a443e87f9674f955acf7864bc62bfed" + integrity sha512-FUmsn3xg/XD/K/4FQd8XHrs92aQdZO5LUtpHnRvO1/6DY87SMz6B6ERAN9IGQQld//M2/LVTHkZy8oVhQZQHIQ== dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/logger" "3.6.0" - "@docusaurus/mdx-loader" "3.6.0" - "@docusaurus/theme-common" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-common" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" + "@docusaurus/core" "3.6.1" + "@docusaurus/logger" "3.6.1" + "@docusaurus/mdx-loader" "3.6.1" + "@docusaurus/theme-common" "3.6.1" + "@docusaurus/types" "3.6.1" + "@docusaurus/utils" "3.6.1" + "@docusaurus/utils-common" "3.6.1" + "@docusaurus/utils-validation" "3.6.1" cheerio "1.0.0-rc.12" feed "^4.2.2" fs-extra "^11.1.1" @@ -3046,20 +3047,20 @@ utility-types "^3.10.0" webpack "^5.88.1" -"@docusaurus/plugin-content-docs@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.6.0.tgz#15cae4bf81da0b0ddce09d53b10b7209116ea9c2" - integrity sha512-c5gZOxocJKO/Zev2MEZInli+b+VNswDGuKHE6QtFgidhAJonwjh2kwj967RvWFaMMk62HlLJLZ+IGK2XsVy4Aw== +"@docusaurus/plugin-content-docs@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.6.1.tgz#7c461b33ecc41e27fc02830bcde54378f68b2512" + integrity sha512-Uq8kyn5DYCDmkUlB9sWChhWghS4lUFNiQU+RXcAXJ3qCVXsBpPsh6RF+npQG1N+j4wAbjydM1iLLJJzp+x3eMQ== dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/logger" "3.6.0" - "@docusaurus/mdx-loader" "3.6.0" - "@docusaurus/module-type-aliases" "3.6.0" - "@docusaurus/theme-common" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-common" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" + "@docusaurus/core" "3.6.1" + "@docusaurus/logger" "3.6.1" + "@docusaurus/mdx-loader" "3.6.1" + "@docusaurus/module-type-aliases" "3.6.1" + "@docusaurus/theme-common" "3.6.1" + "@docusaurus/types" "3.6.1" + "@docusaurus/utils" "3.6.1" + "@docusaurus/utils-common" "3.6.1" + "@docusaurus/utils-validation" "3.6.1" "@types/react-router-config" "^5.0.7" combine-promises "^1.1.0" fs-extra "^11.1.1" @@ -3069,95 +3070,95 @@ utility-types "^3.10.0" webpack "^5.88.1" -"@docusaurus/plugin-content-pages@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.6.0.tgz#5dd284bf063baaba1e0305c90b1dd0d5acc7e466" - integrity sha512-RKHhJrfkadHc7+tt1cP48NWifOrhkSRMPdXNYytzhoQrXlP6Ph+3tfQ4/n+nT0S3Y9+wwRxYqRqA380ZLt+QtQ== +"@docusaurus/plugin-content-pages@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.6.1.tgz#7d3dcdcc49e3c31ed13dceab830ee7fd9a1c4658" + integrity sha512-TZtL+2zq20gqGalzoIT2rEF1T4YCZ26jTvlCJXs78+incIajfdHtmdOq7rQW0oV7oqTjpGllbp788nY/vY9jgw== dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/mdx-loader" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" + "@docusaurus/core" "3.6.1" + "@docusaurus/mdx-loader" "3.6.1" + "@docusaurus/types" "3.6.1" + "@docusaurus/utils" "3.6.1" + "@docusaurus/utils-validation" "3.6.1" fs-extra "^11.1.1" tslib "^2.6.0" webpack "^5.88.1" -"@docusaurus/plugin-debug@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-3.6.0.tgz#0a6da9ba31a0acb176ae2762b4d6b96b1906c826" - integrity sha512-o8T1Rl94COLdSlKvjYLQpRJQRU8WWZ8EX1B0yV0dQLNN8reyH7MQW+6z1ig4sQFfH3pnjPWVGHfuEjcib5m7Eg== +"@docusaurus/plugin-debug@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-3.6.1.tgz#e73fca0307b864b000c98b7110009c6b4a3efc2b" + integrity sha512-DeKPZtoVExDSYCbzoz7y5Dhc6+YPqRWfVGwEEUyKopSyQYefp0OV8hvASmbJCn2WyThRgspOUhog3FSEhz+agw== dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils" "3.6.0" + "@docusaurus/core" "3.6.1" + "@docusaurus/types" "3.6.1" + "@docusaurus/utils" "3.6.1" fs-extra "^11.1.1" react-json-view-lite "^1.2.0" tslib "^2.6.0" -"@docusaurus/plugin-google-analytics@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.6.0.tgz#9e8245eef1bee95e44ef2af92ce3e844a8e93e64" - integrity sha512-kgRFbfpi6Hshj75YUztKyEMtI/kw0trPRwoTN4g+W1NK99R/vh8phTvhBTIMnDbetU79795LkwfG0rZ/ce6zWQ== +"@docusaurus/plugin-google-analytics@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.6.1.tgz#f20027f75cd45830eefcd7a172ded8b15de0b516" + integrity sha512-ZEoERiDHxSfhaEeT35ukQ892NzGHWiUvfxUsnPiRuGEhMoQlxMSp60shBuSZ1sUKuZlndoEl5qAXJg09Wls/Sg== dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" + "@docusaurus/core" "3.6.1" + "@docusaurus/types" "3.6.1" + "@docusaurus/utils-validation" "3.6.1" tslib "^2.6.0" -"@docusaurus/plugin-google-gtag@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.6.0.tgz#bed8381fe3ab357d56a565f657e38d8ea6272703" - integrity sha512-nqu4IfjaO4UX+dojHL2BxHRS+sKj31CIMWYo49huQ3wTET0Oc3u/WGTaKd3ShTPDhkgiRhTOSTPUwJWrU55nHg== +"@docusaurus/plugin-google-gtag@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.6.1.tgz#db08bfcef319c494e5969c0d96d62bd8f43469db" + integrity sha512-u/E9vXUsZxYaV6Brvfee8NiH/iR0cMml9P/ifz4EpH/Jfxdbw8rbCT0Nm/h7EFgEY48Uqkl5huSbIvFB9n8aTQ== dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" + "@docusaurus/core" "3.6.1" + "@docusaurus/types" "3.6.1" + "@docusaurus/utils-validation" "3.6.1" "@types/gtag.js" "^0.0.12" tslib "^2.6.0" -"@docusaurus/plugin-google-tag-manager@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.6.0.tgz#326382de05888ea4317837be736eabd635adbc71" - integrity sha512-OU6c5xI0nOVbEc9eImGvvsgNWe4vGm97t/W3aLHjWsHyNk3uwFNBQMHRvBUwAi9k/K3kyC5E7DWnc67REhdLOw== +"@docusaurus/plugin-google-tag-manager@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.6.1.tgz#f3aa3cd0e7e6be793e5af3fe048a6ad12c3f0211" + integrity sha512-By+NKkGYV8tSo8/RyS1OXikOtqsko5jJZ/uioJfBjsBGgSbiMJ+Y/HogFBke0mgSvf7NPGKZTbYm5+FJ8YUtPQ== dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" + "@docusaurus/core" "3.6.1" + "@docusaurus/types" "3.6.1" + "@docusaurus/utils-validation" "3.6.1" tslib "^2.6.0" -"@docusaurus/plugin-ideal-image@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-ideal-image/-/plugin-ideal-image-3.6.0.tgz#41ffed294bd18ef7f9d4bf0d2d248a4bb890d62a" - integrity sha512-6BaZU7mX+RH+lRFPm5nj3GGfAsjsJ1JHjp0Xjb4ilfte7L2IZkTl6MPpvAzyPC0qIUxfXRcJs4qd/HUE0xcTlw== +"@docusaurus/plugin-ideal-image@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-ideal-image/-/plugin-ideal-image-3.6.1.tgz#3c0bb8e398ef0b7ea1ee313ee1e774de93f2b941" + integrity sha512-hiGRPPlsM02aEOPlQc9rVnrckbVR6HswG7yDpZOtBEhw+ysXFsl/8gzAxFBL4ogKjN28WrlMCn/6IIkxY/EyOQ== dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/lqip-loader" "3.6.0" + "@docusaurus/core" "3.6.1" + "@docusaurus/lqip-loader" "3.6.1" "@docusaurus/responsive-loader" "^1.7.0" - "@docusaurus/theme-translations" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" + "@docusaurus/theme-translations" "3.6.1" + "@docusaurus/types" "3.6.1" + "@docusaurus/utils-validation" "3.6.1" "@slorber/react-ideal-image" "^0.0.12" react-waypoint "^10.3.0" sharp "^0.32.3" tslib "^2.6.0" webpack "^5.88.1" -"@docusaurus/plugin-pwa@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-pwa/-/plugin-pwa-3.6.0.tgz#9851d1dd52bf8bf75f7d97e9f42cb6e29cacb68d" - integrity sha512-IVUJIBeGwbIkrI8HgVkw3eonw23wq5EjPOioXzht4Dql1Bb13xF/SmO6Bj8NE2KNmlubOKRKwLy8gYpB3i8cmQ== +"@docusaurus/plugin-pwa@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-pwa/-/plugin-pwa-3.6.1.tgz#541501c814d1b5d9681f8a55224e24b121ab7c75" + integrity sha512-GsbpsgpAwdBpDpeVzk3UPNUQAc0oGU+0GL5s1LmFgqfpql5C7ZnkwD9FmW6lvieabQjC+Ga0d0zDqu20coqIRQ== dependencies: "@babel/core" "^7.25.9" "@babel/preset-env" "^7.25.9" - "@docusaurus/bundler" "3.6.0" - "@docusaurus/core" "3.6.0" - "@docusaurus/logger" "3.6.0" - "@docusaurus/theme-common" "3.6.0" - "@docusaurus/theme-translations" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" + "@docusaurus/bundler" "3.6.1" + "@docusaurus/core" "3.6.1" + "@docusaurus/logger" "3.6.1" + "@docusaurus/theme-common" "3.6.1" + "@docusaurus/theme-translations" "3.6.1" + "@docusaurus/types" "3.6.1" + "@docusaurus/utils" "3.6.1" + "@docusaurus/utils-validation" "3.6.1" babel-loader "^9.2.1" clsx "^2.0.0" core-js "^3.31.1" @@ -3168,39 +3169,39 @@ workbox-precaching "^7.0.0" workbox-window "^7.0.0" -"@docusaurus/plugin-sitemap@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.6.0.tgz#c7c93f75f03391ca9071da48563fc4faa84966bc" - integrity sha512-YB5XMdf9FjLhgbHY/cDbYhVxsgcpPIjxY9769HUgFOB7GVzItTLOR71W035R1BiR2CA5QAn3XOSg36WLRxlhQQ== +"@docusaurus/plugin-sitemap@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.6.1.tgz#c842019a64d8dd12b64145115e60771d482db997" + integrity sha512-i8R/GTKew4Cufb+7YQTwfPcNOhKTJzZ1VZ5OqQwI9c3pZK2TltQyhqKDVN94KCTbSSKvOYYytYfRAB2uPnH1/A== dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/logger" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-common" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" + "@docusaurus/core" "3.6.1" + "@docusaurus/logger" "3.6.1" + "@docusaurus/types" "3.6.1" + "@docusaurus/utils" "3.6.1" + "@docusaurus/utils-common" "3.6.1" + "@docusaurus/utils-validation" "3.6.1" fs-extra "^11.1.1" sitemap "^7.1.1" tslib "^2.6.0" -"@docusaurus/preset-classic@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-3.6.0.tgz#71561f366a266be571022764eb8b9e5618f573eb" - integrity sha512-kpGNdQzr/Dpm7o3b1iaQrz4DMDx3WIeBbl4V4P4maa2zAQkTdlaP4CMgA5oKrRrpqPLnQFsUM/b+qf2glhl2Tw== +"@docusaurus/preset-classic@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-3.6.1.tgz#196540ca8495075d24eb724af3bf4c75d2412754" + integrity sha512-b90Y1XRH9e+oa/E3NmiFEFOwgYUd+knFcZUy81nM3FJs038WbEA0T55NQsuPW0s7nOsCShQ7dVFyKxV+Wp31Nw== dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/plugin-content-blog" "3.6.0" - "@docusaurus/plugin-content-docs" "3.6.0" - "@docusaurus/plugin-content-pages" "3.6.0" - "@docusaurus/plugin-debug" "3.6.0" - "@docusaurus/plugin-google-analytics" "3.6.0" - "@docusaurus/plugin-google-gtag" "3.6.0" - "@docusaurus/plugin-google-tag-manager" "3.6.0" - "@docusaurus/plugin-sitemap" "3.6.0" - "@docusaurus/theme-classic" "3.6.0" - "@docusaurus/theme-common" "3.6.0" - "@docusaurus/theme-search-algolia" "3.6.0" - "@docusaurus/types" "3.6.0" + "@docusaurus/core" "3.6.1" + "@docusaurus/plugin-content-blog" "3.6.1" + "@docusaurus/plugin-content-docs" "3.6.1" + "@docusaurus/plugin-content-pages" "3.6.1" + "@docusaurus/plugin-debug" "3.6.1" + "@docusaurus/plugin-google-analytics" "3.6.1" + "@docusaurus/plugin-google-gtag" "3.6.1" + "@docusaurus/plugin-google-tag-manager" "3.6.1" + "@docusaurus/plugin-sitemap" "3.6.1" + "@docusaurus/theme-classic" "3.6.1" + "@docusaurus/theme-common" "3.6.1" + "@docusaurus/theme-search-algolia" "3.6.1" + "@docusaurus/types" "3.6.1" "@docusaurus/react-loadable@5.5.2": version "5.5.2" @@ -3210,10 +3211,10 @@ "@types/react" "*" prop-types "^15.6.2" -"@docusaurus/remark-plugin-npm2yarn@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/remark-plugin-npm2yarn/-/remark-plugin-npm2yarn-3.6.0.tgz#b0e287c88ded88de576f1e2eb74d466062d73c35" - integrity sha512-Imh0v68hFWSWlcE7qLlnZD9r4bQOzM6rcWTh6mPpfx2zHAai+so+SJmrMwZ1AJGfC08Y7Ch2Q/G4AThalXRVqQ== +"@docusaurus/remark-plugin-npm2yarn@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/remark-plugin-npm2yarn/-/remark-plugin-npm2yarn-3.6.1.tgz#9098b41101fe99214ac837954ef6365c046f909f" + integrity sha512-ve8xXfyB4oQwtYMgZoFxWWyp/aa3mobt4jLRjNHwRLQ6Jy7bMmFQ7uX99ExDttyGme2ABX4/vDNYfXDRdKm91Q== dependencies: mdast-util-mdx "^3.0.0" npm-to-yarn "^3.0.0" @@ -3228,24 +3229,24 @@ dependencies: loader-utils "^2.0.0" -"@docusaurus/theme-classic@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-3.6.0.tgz#8f34b65c85f5082deb3633a893974d2eee309121" - integrity sha512-sAXNfwPL6uRD+BuHuKXZfAXud7SS7IK/JdrPuzyQxdO1gJKzI5GFfe1ED1QoJDNWJWJ01JHE5rSnwYLEADc2rQ== +"@docusaurus/theme-classic@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-3.6.1.tgz#dff4c7732b590e231dfb764e1d9a8acb5cf28954" + integrity sha512-5lVUmIXk7zp+n9Ki2lYWrmhbd6mssOlKCnnDJvY4QDi3EgjRisIu5g4yKXoWTIbiqE7m7q/dS9cbeShEtfkKng== dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/logger" "3.6.0" - "@docusaurus/mdx-loader" "3.6.0" - "@docusaurus/module-type-aliases" "3.6.0" - "@docusaurus/plugin-content-blog" "3.6.0" - "@docusaurus/plugin-content-docs" "3.6.0" - "@docusaurus/plugin-content-pages" "3.6.0" - "@docusaurus/theme-common" "3.6.0" - "@docusaurus/theme-translations" "3.6.0" - "@docusaurus/types" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-common" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" + "@docusaurus/core" "3.6.1" + "@docusaurus/logger" "3.6.1" + "@docusaurus/mdx-loader" "3.6.1" + "@docusaurus/module-type-aliases" "3.6.1" + "@docusaurus/plugin-content-blog" "3.6.1" + "@docusaurus/plugin-content-docs" "3.6.1" + "@docusaurus/plugin-content-pages" "3.6.1" + "@docusaurus/theme-common" "3.6.1" + "@docusaurus/theme-translations" "3.6.1" + "@docusaurus/types" "3.6.1" + "@docusaurus/utils" "3.6.1" + "@docusaurus/utils-common" "3.6.1" + "@docusaurus/utils-validation" "3.6.1" "@mdx-js/react" "^3.0.0" clsx "^2.0.0" copy-text-to-clipboard "^3.2.0" @@ -3260,15 +3261,15 @@ tslib "^2.6.0" utility-types "^3.10.0" -"@docusaurus/theme-common@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-3.6.0.tgz#9a061d278df76da0f70a9465cd0b7299c14d03d3" - integrity sha512-frjlYE5sRs+GuPs4XXlp9aMLI2O4H5FPpznDAXBrCm+8EpWRiIb443ePMxM3IyMCQ5bwFlki0PI9C+r4apstnw== +"@docusaurus/theme-common@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-3.6.1.tgz#d160516db9482ab19f7921d8a75093885d04d3de" + integrity sha512-18iEYNpMvarGfq9gVRpGowSZD24vZ39Iz4acqaj64180i54V9el8tVnhNr/wRvrUm1FY30A1NHLqnMnDz4rYEQ== dependencies: - "@docusaurus/mdx-loader" "3.6.0" - "@docusaurus/module-type-aliases" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-common" "3.6.0" + "@docusaurus/mdx-loader" "3.6.1" + "@docusaurus/module-type-aliases" "3.6.1" + "@docusaurus/utils" "3.6.1" + "@docusaurus/utils-common" "3.6.1" "@types/history" "^4.7.11" "@types/react" "*" "@types/react-router-config" "*" @@ -3278,34 +3279,34 @@ tslib "^2.6.0" utility-types "^3.10.0" -"@docusaurus/theme-live-codeblock@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-live-codeblock/-/theme-live-codeblock-3.6.0.tgz#de670b60c9acfdf03feb79e32a3be0d90fe11647" - integrity sha512-EphCTxJZgnEvgA1kdbr+R/cBu3fdawA2ooQji8EKPKg9i4Uex0xfFGhWja/0SaMKGqmfHRz9SY8I7j75O3cluw== +"@docusaurus/theme-live-codeblock@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-live-codeblock/-/theme-live-codeblock-3.6.1.tgz#748f2864df9ad2cdbb4f370b816ad1dc2d2bc175" + integrity sha512-8GdnkwaNxb0dmRHGDlO+5QXdz9mrLni/wqai06LSGOTRv+GY3JC2Zov/KKkHZxx5MNFagqq01sGdn1TBBrS9jg== dependencies: - "@docusaurus/core" "3.6.0" - "@docusaurus/theme-common" "3.6.0" - "@docusaurus/theme-translations" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" + "@docusaurus/core" "3.6.1" + "@docusaurus/theme-common" "3.6.1" + "@docusaurus/theme-translations" "3.6.1" + "@docusaurus/utils-validation" "3.6.1" "@philpl/buble" "^0.19.7" clsx "^2.0.0" fs-extra "^11.1.1" react-live "^4.1.6" tslib "^2.6.0" -"@docusaurus/theme-search-algolia@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.6.0.tgz#47dcfca68f50163abce411dd9b181855a9ec9c83" - integrity sha512-4IwRUkxjrisR8LXBHeE4d2btraWdMficbgiVL3UHvJURmyvgzMBZQP8KrK8rjdXeu8SuRxSmeV6NSVomRvdbEg== +"@docusaurus/theme-search-algolia@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.6.1.tgz#a9cc9c9517a22459354703cf33d469e7263d3854" + integrity sha512-BjmuiFRpQP1WEm8Mzu1Bb0Wdas6G65VHXDDNr7XTKgbstxalE6vuxt0ioXTDFS2YVep5748aVhKvnxR9gm2Liw== dependencies: "@docsearch/react" "^3.5.2" - "@docusaurus/core" "3.6.0" - "@docusaurus/logger" "3.6.0" - "@docusaurus/plugin-content-docs" "3.6.0" - "@docusaurus/theme-common" "3.6.0" - "@docusaurus/theme-translations" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-validation" "3.6.0" + "@docusaurus/core" "3.6.1" + "@docusaurus/logger" "3.6.1" + "@docusaurus/plugin-content-docs" "3.6.1" + "@docusaurus/theme-common" "3.6.1" + "@docusaurus/theme-translations" "3.6.1" + "@docusaurus/utils" "3.6.1" + "@docusaurus/utils-validation" "3.6.1" algoliasearch "^4.18.0" algoliasearch-helper "^3.13.3" clsx "^2.0.0" @@ -3315,10 +3316,10 @@ tslib "^2.6.0" utility-types "^3.10.0" -"@docusaurus/theme-translations@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-3.6.0.tgz#93994e931f340c1712c81ac80dbab5750c24634f" - integrity sha512-L555X8lWE3fv8VaF0Bc1VnAgi10UvRKFcvADHiYR7Gj37ItaWP5i7xLHsSw7fi/SHTXe5wfIeCFNqUYHyCOHAQ== +"@docusaurus/theme-translations@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-3.6.1.tgz#d6bbb20141ca70f352201f2f412b6b8d988d86b4" + integrity sha512-bNm5G6sueUezvyhsBegA1wwM38yW0BnqpZTE9KHO2yKnkERNMaV5x/yPJ/DNCOHjJtCcJ5Uz55g2AS75Go31xA== dependencies: fs-extra "^11.1.1" tslib "^2.6.0" @@ -3342,10 +3343,10 @@ webpack "^5.88.1" webpack-merge "^5.9.0" -"@docusaurus/types@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-3.6.0.tgz#8fa82332a7c7b8093b5c55e1115f5854ce484978" - integrity sha512-jADLgoZGWhAzThr+mRiyuFD4OUzt6jHnb7NRArRKorgxckqUBaPyFOau9hhbcSTHtU6ceyeWjN7FDt7uG2Hplw== +"@docusaurus/types@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-3.6.1.tgz#0e55a0a51a3e55658b0845af83d5fe17c495978e" + integrity sha512-hCB1hj9DYutVYBisnPNobz9SzEmCcf1EetJv09O49Cov3BqOkm+vnnjB3d957YJMtpLGQoKBeN/FF1DZ830JwQ== dependencies: "@mdx-js/mdx" "^3.0.0" "@types/history" "^4.7.11" @@ -3357,34 +3358,36 @@ webpack "^5.95.0" webpack-merge "^5.9.0" -"@docusaurus/utils-common@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-3.6.0.tgz#11855ea503132bbcaba6ca4d351293ff10a75d34" - integrity sha512-diUDNfbw33GaZMmKwdTckT2IBfVouXLXRD+zphH9ywswuaEIKqixvuf5g41H7MBBrlMsxhna3uTMoB4B/OPDcA== +"@docusaurus/utils-common@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-3.6.1.tgz#994160470e6bd2c0eb771f2132883d21b3b6830f" + integrity sha512-LX1qiTiC0aS8c92uZ+Wj2iNCNJyYZJIKY8/nZDKNMBfo759VYVS3RX3fKP3DznB+16sYp7++MyCz/T6fOGaRfw== dependencies: + "@docusaurus/types" "3.6.1" tslib "^2.6.0" -"@docusaurus/utils-validation@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-3.6.0.tgz#5557ca14fa64ac29e6f70e61006be721395ecde5" - integrity sha512-CRHiKKJEKA0GFlfOf71JWHl7PtwOyX0+Zg9ep9NFEZv6Lcx3RJ9nhl7p8HRjPL6deyYceavM//BsfW4pCI4BtA== +"@docusaurus/utils-validation@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-3.6.1.tgz#8e4b5bd8b71f55228543e3fda1301e9fb83df1c6" + integrity sha512-+iMd6zRl5cJQm7nUP+7pSO/oAXsN79eHO34ME7l2YJt4GEAr70l5kkD58u2jEPpp+wSXT70c7x2A2lzJI1E8jw== dependencies: - "@docusaurus/logger" "3.6.0" - "@docusaurus/utils" "3.6.0" - "@docusaurus/utils-common" "3.6.0" + "@docusaurus/logger" "3.6.1" + "@docusaurus/utils" "3.6.1" + "@docusaurus/utils-common" "3.6.1" fs-extra "^11.2.0" joi "^17.9.2" js-yaml "^4.1.0" lodash "^4.17.21" tslib "^2.6.0" -"@docusaurus/utils@3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-3.6.0.tgz#192785da6fd62dfd83d6f1879c3aa45547f5df23" - integrity sha512-VKczAutI4mptiAw/WcYEu5WeVhQ6Q1zdIUl64SGw9K++9lziH+Kt10Ee8l2dMpRkiUk6zzK20kMNlX2WCUwXYQ== +"@docusaurus/utils@3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-3.6.1.tgz#4e4f80be294671bfb83910352d3625878134bf48" + integrity sha512-nS3WCvepwrnBEgSG5vQu40XG95lC9Jeh/odV5u5IhU1eQFEGDst9xBi6IK5yZdsGvbuaXBZLZtOqWYtuuFa/rQ== dependencies: - "@docusaurus/logger" "3.6.0" - "@docusaurus/utils-common" "3.6.0" + "@docusaurus/logger" "3.6.1" + "@docusaurus/types" "3.6.1" + "@docusaurus/utils-common" "3.6.1" "@svgr/webpack" "^8.1.0" escape-string-regexp "^4.0.0" file-loader "^6.2.0" @@ -4025,6 +4028,28 @@ worker-loader "3.0.8" xmlbuilder2 "3.0.2" +"@kitware/vtk.js@32.1.1": + version "32.1.1" + resolved "https://registry.yarnpkg.com/@kitware/vtk.js/-/vtk.js-32.1.1.tgz#20179cb5f65f33dea4626a948afe24eb16364f8a" + integrity sha512-rrh+PvmjpMDCOsgr7B8ZVxnF75TXjUJOVleMO5QJFh7DP+31927l9DJA4WRiJU7mbpYuZGt8/vAojO5fCizUkA== + dependencies: + "@babel/runtime" "7.22.11" + "@types/webxr" "^0.5.5" + commander "9.2.0" + d3-scale "4.0.2" + fast-deep-equal "^3.1.3" + fflate "0.7.3" + gl-matrix "3.4.3" + globalthis "1.0.3" + seedrandom "3.0.5" + shader-loader "1.3.1" + shelljs "0.8.5" + spark-md5 "3.0.2" + stream-browserify "3.0.0" + webworker-promise "0.5.0" + worker-loader "3.0.8" + xmlbuilder2 "3.0.2" + "@leichtgewicht/ip-codec@^2.0.1": version "2.0.5" resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz#4fc56c15c580b9adb7dc3c333a134e540b44bfb1"