feat(hp): Add displayArea option for Hanging protocols and example with Mamo(#3808)
This commit is contained in:
parent
cb30b97610
commit
18ac08ed86
@ -51,7 +51,6 @@ provided by the <a href="https://ohif.org/">Open Health Imaging Foundation (OHIF
|
|||||||
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-video.webp?raw=true" alt="VIDEO" width="350"/> | Video | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=2.25.96975534054447904995905761963464388233) |
|
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-video.webp?raw=true" alt="VIDEO" width="350"/> | Video | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=2.25.96975534054447904995905761963464388233) |
|
||||||
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/microscopy.webp?raw=true" alt="microscopy" width="350"/> | Slide Microscopy | [Demo](https://viewer.ohif.org/microscopy?StudyInstanceUIDs=2.25.141277760791347900862109212450152067508) |
|
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/microscopy.webp?raw=true" alt="microscopy" width="350"/> | Slide Microscopy | [Demo](https://viewer.ohif.org/microscopy?StudyInstanceUIDs=2.25.141277760791347900862109212450152067508) |
|
||||||
|
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
The OHIF Viewer can retrieve
|
The OHIF Viewer can retrieve
|
||||||
|
|||||||
@ -32,6 +32,7 @@ module.exports = {
|
|||||||
'@babel/transform-destructuring',
|
'@babel/transform-destructuring',
|
||||||
'@babel/plugin-transform-runtime',
|
'@babel/plugin-transform-runtime',
|
||||||
'@babel/plugin-transform-typescript',
|
'@babel/plugin-transform-typescript',
|
||||||
|
'@babel/plugin-transform-class-static-block',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
production: {
|
production: {
|
||||||
|
|||||||
@ -573,6 +573,8 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
|||||||
initialImageIndexToUse = this._getInitialImageIndexForViewport(viewportInfo, imageIds) || 0;
|
initialImageIndexToUse = this._getInitialImageIndexForViewport(viewportInfo, imageIds) || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { rotation, flipHorizontal, displayArea } = viewportInfo.getViewportOptions();
|
||||||
|
|
||||||
const properties = { ...presentations.lutPresentation?.properties };
|
const properties = { ...presentations.lutPresentation?.properties };
|
||||||
if (!presentations.lutPresentation?.properties) {
|
if (!presentations.lutPresentation?.properties) {
|
||||||
const { voi, voiInverted, colormap } = displaySetOptions[0];
|
const { voi, voiInverted, colormap } = displaySetOptions[0];
|
||||||
@ -598,6 +600,15 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
|
|||||||
return viewport.setStack(imageIds, initialImageIndexToUse).then(() => {
|
return viewport.setStack(imageIds, initialImageIndexToUse).then(() => {
|
||||||
viewport.setProperties({ ...properties });
|
viewport.setProperties({ ...properties });
|
||||||
this.setPresentations(viewport.id, presentations);
|
this.setPresentations(viewport.id, presentations);
|
||||||
|
if (displayArea) {
|
||||||
|
viewport.setDisplayArea(displayArea);
|
||||||
|
}
|
||||||
|
if (rotation) {
|
||||||
|
viewport.setProperties({ rotation });
|
||||||
|
}
|
||||||
|
if (flipHorizontal) {
|
||||||
|
viewport.setCamera({ flipHorizontal: true });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -41,7 +41,7 @@
|
|||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-i18next": "^12.2.2",
|
"react-i18next": "^12.2.2",
|
||||||
"react-window": "^1.8.9",
|
"react-window": "^1.8.9",
|
||||||
"webpack": "^5.50.0",
|
"webpack": "^5.89.0",
|
||||||
"webpack-merge": "^5.7.3"
|
"webpack-merge": "^5.7.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import hpMNGrid from './hpMNGrid';
|
import hpMNGrid from './hangingprotocols/hpMNGrid';
|
||||||
import hpMNCompare from './hpCompare';
|
import hpMNCompare from './hangingprotocols/hpCompare';
|
||||||
|
import hpMammography from './hangingprotocols/hpMammo';
|
||||||
|
import hpScale from './hangingprotocols/hpScale';
|
||||||
|
|
||||||
const defaultProtocol = {
|
const defaultProtocol = {
|
||||||
id: 'default',
|
id: 'default',
|
||||||
@ -114,6 +116,14 @@ function getHangingProtocolModule() {
|
|||||||
name: hpMNCompare.id,
|
name: hpMNCompare.id,
|
||||||
protocol: hpMNCompare,
|
protocol: hpMNCompare,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: hpMammography.id,
|
||||||
|
protocol: hpMammography,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: hpScale.id,
|
||||||
|
protocol: hpScale,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -120,9 +120,9 @@ const hpMNCompare: Types.HangingProtocol.Protocol = {
|
|||||||
{
|
{
|
||||||
id: 'Two Studies',
|
id: 'Two Studies',
|
||||||
weight: 1000,
|
weight: 1000,
|
||||||
|
// is there a second study or in another work the attribute
|
||||||
|
// studyInstanceUIDsIndex that we get from prior should not be null
|
||||||
attribute: 'StudyInstanceUID',
|
attribute: 'StudyInstanceUID',
|
||||||
// The 'from' attribute says where to get the 'attribute' value from. In this case
|
|
||||||
// prior means the second study in the study list.
|
|
||||||
from: 'prior',
|
from: 'prior',
|
||||||
required: true,
|
required: true,
|
||||||
constraint: {
|
constraint: {
|
||||||
201
extensions/default/src/hangingprotocols/hpMammo.ts
Normal file
201
extensions/default/src/hangingprotocols/hpMammo.ts
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
import {
|
||||||
|
RCC,
|
||||||
|
RMLO,
|
||||||
|
LCC,
|
||||||
|
LMLO,
|
||||||
|
RCCPrior,
|
||||||
|
LCCPrior,
|
||||||
|
RMLOPrior,
|
||||||
|
LMLOPrior,
|
||||||
|
} from './mammoDisplaySetSelector';
|
||||||
|
|
||||||
|
const rightDisplayArea = {
|
||||||
|
storeAsInitialCamera: true,
|
||||||
|
imageArea: [0.8, 0.8],
|
||||||
|
imageCanvasPoint: {
|
||||||
|
imagePoint: [0, 0.5],
|
||||||
|
canvasPoint: [0, 0.5],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const leftDisplayArea = {
|
||||||
|
storeAsInitialCamera: true,
|
||||||
|
imageArea: [0.8, 0.8],
|
||||||
|
imageCanvasPoint: {
|
||||||
|
imagePoint: [1, 0.5],
|
||||||
|
canvasPoint: [1, 0.5],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const hpMammography = {
|
||||||
|
id: '@ohif/hpMammo',
|
||||||
|
hasUpdatedPriorsInformation: false,
|
||||||
|
name: 'Mammography Breast Screening',
|
||||||
|
protocolMatchingRules: [
|
||||||
|
{
|
||||||
|
id: 'Mammography',
|
||||||
|
weight: 150,
|
||||||
|
attribute: 'ModalitiesInStudy',
|
||||||
|
constraint: {
|
||||||
|
contains: 'MG',
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'numberOfImages',
|
||||||
|
attribute: 'numberOfDisplaySetsWithImages',
|
||||||
|
constraint: {
|
||||||
|
greaterThan: 2,
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
toolGroupIds: ['default'],
|
||||||
|
displaySetSelectors: {
|
||||||
|
RCC,
|
||||||
|
LCC,
|
||||||
|
RMLO,
|
||||||
|
LMLO,
|
||||||
|
RCCPrior,
|
||||||
|
LCCPrior,
|
||||||
|
RMLOPrior,
|
||||||
|
LMLOPrior,
|
||||||
|
},
|
||||||
|
|
||||||
|
stages: [
|
||||||
|
{
|
||||||
|
name: 'CC/MLO',
|
||||||
|
viewportStructure: {
|
||||||
|
type: 'grid',
|
||||||
|
layoutType: 'grid',
|
||||||
|
properties: {
|
||||||
|
rows: 2,
|
||||||
|
columns: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
viewports: [
|
||||||
|
{
|
||||||
|
viewportOptions: {
|
||||||
|
toolGroupId: 'default',
|
||||||
|
displayArea: leftDisplayArea,
|
||||||
|
// flipHorizontal: true,
|
||||||
|
// rotation: 180,
|
||||||
|
allowUnmatchedView: true,
|
||||||
|
},
|
||||||
|
displaySets: [
|
||||||
|
{
|
||||||
|
id: 'RCC',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
viewportOptions: {
|
||||||
|
toolGroupId: 'default',
|
||||||
|
// flipHorizontal: true,
|
||||||
|
displayArea: rightDisplayArea,
|
||||||
|
allowUnmatchedView: true,
|
||||||
|
},
|
||||||
|
displaySets: [
|
||||||
|
{
|
||||||
|
id: 'LCC',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
viewportOptions: {
|
||||||
|
toolGroupId: 'default',
|
||||||
|
displayArea: leftDisplayArea,
|
||||||
|
// rotation: 180,
|
||||||
|
// flipHorizontal: true,
|
||||||
|
allowUnmatchedView: true,
|
||||||
|
},
|
||||||
|
displaySets: [
|
||||||
|
{
|
||||||
|
id: 'RMLO',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
viewportOptions: {
|
||||||
|
toolGroupId: 'default',
|
||||||
|
displayArea: rightDisplayArea,
|
||||||
|
// flipHorizontal: true,
|
||||||
|
allowUnmatchedView: true,
|
||||||
|
},
|
||||||
|
displaySets: [
|
||||||
|
{
|
||||||
|
id: 'LMLO',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// Compare CC current/prior top/bottom
|
||||||
|
{
|
||||||
|
name: 'CC compare',
|
||||||
|
viewportStructure: {
|
||||||
|
type: 'grid',
|
||||||
|
layoutType: 'grid',
|
||||||
|
properties: {
|
||||||
|
rows: 2,
|
||||||
|
columns: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
viewports: [
|
||||||
|
{
|
||||||
|
viewportOptions: {
|
||||||
|
toolGroupId: 'default',
|
||||||
|
displayArea: leftDisplayArea,
|
||||||
|
flipHorizontal: true,
|
||||||
|
rotation: 180,
|
||||||
|
},
|
||||||
|
displaySets: [
|
||||||
|
{
|
||||||
|
id: 'RCC',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
viewportOptions: {
|
||||||
|
toolGroupId: 'default',
|
||||||
|
flipHorizontal: true,
|
||||||
|
displayArea: rightDisplayArea,
|
||||||
|
},
|
||||||
|
displaySets: [
|
||||||
|
{
|
||||||
|
id: 'LCC',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
viewportOptions: {
|
||||||
|
toolGroupId: 'default',
|
||||||
|
displayArea: leftDisplayArea,
|
||||||
|
flipHorizontal: true,
|
||||||
|
},
|
||||||
|
displaySets: [
|
||||||
|
{
|
||||||
|
id: 'RCCPrior',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
viewportOptions: {
|
||||||
|
toolGroupId: 'default',
|
||||||
|
displayArea: rightDisplayArea,
|
||||||
|
},
|
||||||
|
displaySets: [
|
||||||
|
{
|
||||||
|
id: 'LCCPrior',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
// Indicates it is prior aware, but will work with no priors
|
||||||
|
numberOfPriorsReferenced: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default hpMammography;
|
||||||
131
extensions/default/src/hangingprotocols/hpScale.ts
Normal file
131
extensions/default/src/hangingprotocols/hpScale.ts
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import { Types } from '@ohif/core';
|
||||||
|
|
||||||
|
const displayAreaScale1: Types.HangingProtocol.DisplayArea = {
|
||||||
|
type: 'SCALE',
|
||||||
|
scale: 1,
|
||||||
|
storeAsInitialCamera: true,
|
||||||
|
};
|
||||||
|
const displayAreaScale15: Types.HangingProtocol.DisplayArea = { ...displayAreaScale1, scale: 15 };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This hanging protocol can be activated on the primary mode by directly
|
||||||
|
* referencing it in a URL or by directly including it within a mode, e.g.:
|
||||||
|
* `&hangingProtocolId=@ohif/mnGrid` added to the viewer URL
|
||||||
|
* It is not included in the viewer mode by default.
|
||||||
|
*/
|
||||||
|
const hpScale: Types.HangingProtocol.Protocol = {
|
||||||
|
id: '@ohif/hpScale',
|
||||||
|
description: 'Has various hanging protocol grid layouts',
|
||||||
|
name: 'Scale Images',
|
||||||
|
protocolMatchingRules: [
|
||||||
|
{
|
||||||
|
id: 'OneOrMoreSeries',
|
||||||
|
weight: 25,
|
||||||
|
attribute: 'numberOfDisplaySetsWithImages',
|
||||||
|
constraint: {
|
||||||
|
greaterThan: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
toolGroupIds: ['default'],
|
||||||
|
displaySetSelectors: {
|
||||||
|
defaultDisplaySetId: {
|
||||||
|
seriesMatchingRules: [
|
||||||
|
{
|
||||||
|
attribute: 'numImageFrames',
|
||||||
|
constraint: {
|
||||||
|
greaterThan: { value: 0 },
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
// This display set will select the specified items by preference
|
||||||
|
// It has no affect if nothing is specified in the URL.
|
||||||
|
{
|
||||||
|
attribute: 'isDisplaySetFromUrl',
|
||||||
|
weight: 10,
|
||||||
|
constraint: {
|
||||||
|
equals: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultViewport: {
|
||||||
|
viewportOptions: {
|
||||||
|
viewportType: 'stack',
|
||||||
|
toolGroupId: 'default',
|
||||||
|
displayArea: displayAreaScale1,
|
||||||
|
allowUnmatchedView: true,
|
||||||
|
},
|
||||||
|
displaySets: [
|
||||||
|
{
|
||||||
|
id: 'defaultDisplaySetId',
|
||||||
|
matchedDisplaySetsIndex: -1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
stages: [
|
||||||
|
// A 1x1 stage - should be automatically activated if there is only 1 viewable instance
|
||||||
|
{
|
||||||
|
name: 'Scale 1:1',
|
||||||
|
stageActivation: {
|
||||||
|
enabled: {
|
||||||
|
minViewportsMatched: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
viewportStructure: {
|
||||||
|
layoutType: 'grid',
|
||||||
|
properties: {
|
||||||
|
rows: 1,
|
||||||
|
columns: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
viewports: [
|
||||||
|
{
|
||||||
|
viewportOptions: {
|
||||||
|
toolGroupId: 'default',
|
||||||
|
allowUnmatchedView: true,
|
||||||
|
displayArea: displayAreaScale1,
|
||||||
|
},
|
||||||
|
displaySets: [
|
||||||
|
{
|
||||||
|
id: 'defaultDisplaySetId',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Scale 1:15',
|
||||||
|
stageActivation: {
|
||||||
|
enabled: {
|
||||||
|
minViewportsMatched: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
viewportStructure: {
|
||||||
|
layoutType: 'grid',
|
||||||
|
properties: {
|
||||||
|
rows: 1,
|
||||||
|
columns: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
viewports: [
|
||||||
|
{
|
||||||
|
viewportOptions: {
|
||||||
|
toolGroupId: 'default',
|
||||||
|
allowUnmatchedView: true,
|
||||||
|
displayArea: displayAreaScale15,
|
||||||
|
},
|
||||||
|
displaySets: [
|
||||||
|
{
|
||||||
|
id: 'defaultDisplaySetId',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
numberOfPriorsReferenced: -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default hpScale;
|
||||||
15
extensions/default/src/hangingprotocols/index.ts
Normal file
15
extensions/default/src/hangingprotocols/index.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import viewCodeAttribute from './viewCode';
|
||||||
|
import lateralityAttribute from './laterality';
|
||||||
|
import registerHangingProtocolAttributes from './registerHangingProtocolAttributes';
|
||||||
|
import hpMammography from './hpMammo';
|
||||||
|
import hpMNGrid from './hpMNGrid';
|
||||||
|
import hpCompare from './hpCompare';
|
||||||
|
|
||||||
|
export {
|
||||||
|
viewCodeAttribute,
|
||||||
|
lateralityAttribute,
|
||||||
|
hpMammography as hpMammo,
|
||||||
|
hpMNGrid,
|
||||||
|
hpCompare,
|
||||||
|
registerHangingProtocolAttributes,
|
||||||
|
};
|
||||||
9
extensions/default/src/hangingprotocols/laterality.ts
Normal file
9
extensions/default/src/hangingprotocols/laterality.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export default displaySet => {
|
||||||
|
const frameAnatomy =
|
||||||
|
displaySet?.images?.[0]?.SharedFunctionalGroupsSequence?.[0]?.FrameAnatomySequence?.[0];
|
||||||
|
if (!frameAnatomy) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const laterality = frameAnatomy?.FrameLaterality;
|
||||||
|
return laterality;
|
||||||
|
};
|
||||||
@ -0,0 +1,214 @@
|
|||||||
|
const priorStudyMatchingRules = [
|
||||||
|
{
|
||||||
|
// The priorInstance is a study counter that indicates what position this study is in
|
||||||
|
// and the value comes from the options parameter.
|
||||||
|
attribute: 'studyInstanceUIDsIndex',
|
||||||
|
from: 'options',
|
||||||
|
required: true,
|
||||||
|
constraint: {
|
||||||
|
equals: { value: 1 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const currentStudyMatchingRules = [
|
||||||
|
{
|
||||||
|
// The priorInstance is a study counter that indicates what position this study is in
|
||||||
|
// and the value comes from the options parameter.
|
||||||
|
attribute: 'studyInstanceUIDsIndex',
|
||||||
|
from: 'options',
|
||||||
|
required: true,
|
||||||
|
constraint: {
|
||||||
|
equals: { value: 0 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const LCCSeriesMatchingRules = [
|
||||||
|
{
|
||||||
|
weight: 10,
|
||||||
|
attribute: 'ViewCode',
|
||||||
|
constraint: {
|
||||||
|
contains: 'SCT:399162004',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
weight: 5,
|
||||||
|
attribute: 'PatientOrientation',
|
||||||
|
constraint: {
|
||||||
|
contains: 'L',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
weight: 20,
|
||||||
|
attribute: 'SeriesDescription',
|
||||||
|
constraint: {
|
||||||
|
contains: 'L CC',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const RCCSeriesMatchingRules = [
|
||||||
|
{
|
||||||
|
weight: 10,
|
||||||
|
attribute: 'ViewCode',
|
||||||
|
constraint: {
|
||||||
|
contains: 'SCT:399162004',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
weight: 5,
|
||||||
|
attribute: 'PatientOrientation',
|
||||||
|
constraint: {
|
||||||
|
equals: ['P', 'L'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
attribute: 'PatientOrientation',
|
||||||
|
constraint: {
|
||||||
|
doesNotEqual: ['A', 'R'],
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
weight: 20,
|
||||||
|
attribute: 'SeriesDescription',
|
||||||
|
constraint: {
|
||||||
|
contains: 'CC',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const LMLOSeriesMatchingRules = [
|
||||||
|
{
|
||||||
|
weight: 10,
|
||||||
|
attribute: 'ViewCode',
|
||||||
|
constraint: {
|
||||||
|
contains: 'SCT:399368009',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
weight: 0,
|
||||||
|
attribute: 'ViewCode',
|
||||||
|
constraint: {
|
||||||
|
doesNotEqual: 'SCT:399162004',
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
weight: 5,
|
||||||
|
attribute: 'PatientOrientation',
|
||||||
|
constraint: {
|
||||||
|
equals: ['A', 'R'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
weight: 20,
|
||||||
|
attribute: 'SeriesDescription',
|
||||||
|
constraint: {
|
||||||
|
contains: 'L MLO',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const RMLOSeriesMatchingRules = [
|
||||||
|
{
|
||||||
|
weight: 10,
|
||||||
|
attribute: 'ViewCode',
|
||||||
|
constraint: {
|
||||||
|
contains: 'SCT:399368009',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
attribute: 'ViewCode',
|
||||||
|
constraint: {
|
||||||
|
doesNotEqual: 'SCT:399162004',
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
attribute: 'PatientOrientation',
|
||||||
|
constraint: {
|
||||||
|
doesNotContain: ['P', 'FL'],
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
weight: 5,
|
||||||
|
attribute: 'PatientOrientation',
|
||||||
|
constraint: {
|
||||||
|
equals: ['P', 'L'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
weight: 5,
|
||||||
|
attribute: 'PatientOrientation',
|
||||||
|
constraint: {
|
||||||
|
equals: ['A', 'FR'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
weight: 20,
|
||||||
|
attribute: 'SeriesDescription',
|
||||||
|
constraint: {
|
||||||
|
contains: 'R MLO',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
attribute: 'SeriesDescription',
|
||||||
|
required: true,
|
||||||
|
constraint: {
|
||||||
|
doesNotContain: 'CC',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
attribute: 'SeriesDescription',
|
||||||
|
required: true,
|
||||||
|
constraint: {
|
||||||
|
doesNotEqual: 'L MLO',
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const RCC = {
|
||||||
|
seriesMatchingRules: RCCSeriesMatchingRules,
|
||||||
|
studyMatchingRules: currentStudyMatchingRules,
|
||||||
|
};
|
||||||
|
|
||||||
|
const RCCPrior = {
|
||||||
|
seriesMatchingRules: RCCSeriesMatchingRules,
|
||||||
|
studyMatchingRules: priorStudyMatchingRules,
|
||||||
|
};
|
||||||
|
|
||||||
|
const LCC = {
|
||||||
|
seriesMatchingRules: LCCSeriesMatchingRules,
|
||||||
|
studyMatchingRules: currentStudyMatchingRules,
|
||||||
|
};
|
||||||
|
|
||||||
|
const LCCPrior = {
|
||||||
|
seriesMatchingRules: LCCSeriesMatchingRules,
|
||||||
|
studyMatchingRules: priorStudyMatchingRules,
|
||||||
|
};
|
||||||
|
|
||||||
|
const RMLO = {
|
||||||
|
seriesMatchingRules: RMLOSeriesMatchingRules,
|
||||||
|
studyMatchingRules: currentStudyMatchingRules,
|
||||||
|
};
|
||||||
|
|
||||||
|
const RMLOPrior = {
|
||||||
|
seriesMatchingRules: RMLOSeriesMatchingRules,
|
||||||
|
studyMatchingRules: priorStudyMatchingRules,
|
||||||
|
};
|
||||||
|
|
||||||
|
const LMLO = {
|
||||||
|
seriesMatchingRules: LMLOSeriesMatchingRules,
|
||||||
|
studyMatchingRules: currentStudyMatchingRules,
|
||||||
|
};
|
||||||
|
|
||||||
|
const LMLOPrior = {
|
||||||
|
seriesMatchingRules: LMLOSeriesMatchingRules,
|
||||||
|
studyMatchingRules: priorStudyMatchingRules,
|
||||||
|
};
|
||||||
|
|
||||||
|
export { RCC, LCC, RMLO, LMLO, RCCPrior, LCCPrior, RMLOPrior, LMLOPrior };
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
import viewCode from './viewCode';
|
||||||
|
import laterality from './laterality';
|
||||||
|
|
||||||
|
export default function registerHangingProtocolAttributes({ servicesManager }) {
|
||||||
|
const { hangingProtocolService } = servicesManager.services;
|
||||||
|
hangingProtocolService.addCustomAttribute('ViewCode', 'View Code Designator:Value', viewCode);
|
||||||
|
hangingProtocolService.addCustomAttribute('Laterality', 'Laterality of object', laterality);
|
||||||
|
}
|
||||||
11
extensions/default/src/hangingprotocols/viewCode.ts
Normal file
11
extensions/default/src/hangingprotocols/viewCode.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
export default displaySet => {
|
||||||
|
const ViewCodeSequence = displaySet?.images[0]?.ViewCodeSequence[0];
|
||||||
|
if (!ViewCodeSequence) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const { CodingSchemeDesignator, CodeValue } = ViewCodeSequence;
|
||||||
|
if (!CodingSchemeDesignator || !CodeValue) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return `${CodingSchemeDesignator}:${CodeValue}`;
|
||||||
|
};
|
||||||
@ -2,6 +2,7 @@ import { DicomMetadataStore, classes } from '@ohif/core';
|
|||||||
import { calculateSUVScalingFactors } from '@cornerstonejs/calculate-suv';
|
import { calculateSUVScalingFactors } from '@cornerstonejs/calculate-suv';
|
||||||
|
|
||||||
import getPTImageIdInstanceMetadata from './getPTImageIdInstanceMetadata';
|
import getPTImageIdInstanceMetadata from './getPTImageIdInstanceMetadata';
|
||||||
|
import { registerHangingProtocolAttributes } from './hangingprotocols';
|
||||||
|
|
||||||
const metadataProvider = classes.MetadataProvider;
|
const metadataProvider = classes.MetadataProvider;
|
||||||
|
|
||||||
@ -60,6 +61,9 @@ export default function init({
|
|||||||
// afterwards.
|
// afterwards.
|
||||||
stateSyncService.register('viewportsByPosition', { clearOnModeExit: true });
|
stateSyncService.register('viewportsByPosition', { clearOnModeExit: true });
|
||||||
|
|
||||||
|
// Adds extra custom attributes for use by hanging protocols
|
||||||
|
registerHangingProtocolAttributes({ servicesManager });
|
||||||
|
|
||||||
// Function to process and subscribe to events for a given set of commands and listeners
|
// Function to process and subscribe to events for a given set of commands and listeners
|
||||||
const subscribeToEvents = listeners => {
|
const subscribeToEvents = listeners => {
|
||||||
Object.entries(listeners).forEach(([event, commands]) => {
|
Object.entries(listeners).forEach(([event, commands]) => {
|
||||||
|
|||||||
@ -43,7 +43,7 @@
|
|||||||
"i18next": "^17.0.3"
|
"i18next": "^17.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"webpack": "^5.50.0",
|
"webpack": "^5.89.0",
|
||||||
"webpack-merge": "^5.7.3"
|
"webpack-merge": "^5.7.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,7 +48,7 @@
|
|||||||
"i18next": "^17.0.3"
|
"i18next": "^17.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"webpack": "^5.50.0",
|
"webpack": "^5.89.0",
|
||||||
"webpack-merge": "^5.7.3"
|
"webpack-merge": "^5.7.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,7 +49,7 @@
|
|||||||
"i18next": "^17.0.3"
|
"i18next": "^17.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"webpack": "^5.50.0",
|
"webpack": "^5.89.0",
|
||||||
"webpack-merge": "^5.7.3"
|
"webpack-merge": "^5.7.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -70,7 +70,7 @@
|
|||||||
"dotenv": "^14.1.0",
|
"dotenv": "^14.1.0",
|
||||||
"eslint": "^5.0.1",
|
"eslint": "^5.0.1",
|
||||||
"eslint-loader": "^2.0.0",
|
"eslint-loader": "^2.0.0",
|
||||||
"webpack": "^5.50.0",
|
"webpack": "^5.89.0",
|
||||||
"webpack-cli": "^4.7.2",
|
"webpack-cli": "^4.7.2",
|
||||||
"webpack-merge": "^5.7.3"
|
"webpack-merge": "^5.7.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,7 +47,7 @@
|
|||||||
"i18next": "^17.0.3"
|
"i18next": "^17.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"webpack": "^5.50.0",
|
"webpack": "^5.89.0",
|
||||||
"webpack-merge": "^5.7.3"
|
"webpack-merge": "^5.7.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ const PUBLIC_URL = process.env.PUBLIC_URL || '/';
|
|||||||
const APP_CONFIG = process.env.APP_CONFIG || 'config/default.js';
|
const APP_CONFIG = process.env.APP_CONFIG || 'config/default.js';
|
||||||
const PROXY_TARGET = process.env.PROXY_TARGET;
|
const PROXY_TARGET = process.env.PROXY_TARGET;
|
||||||
const PROXY_DOMAIN = process.env.PROXY_DOMAIN;
|
const PROXY_DOMAIN = process.env.PROXY_DOMAIN;
|
||||||
|
const OHIF_PORT = Number(process.env.OHIF_PORT || 3000);
|
||||||
const ENTRY_TARGET = process.env.ENTRY_TARGET || `${SRC_DIR}/index.js`;
|
const ENTRY_TARGET = process.env.ENTRY_TARGET || `${SRC_DIR}/index.js`;
|
||||||
const Dotenv = require('dotenv-webpack');
|
const Dotenv = require('dotenv-webpack');
|
||||||
const writePluginImportFile = require('./writePluginImportsFile.js');
|
const writePluginImportFile = require('./writePluginImportsFile.js');
|
||||||
@ -143,7 +144,7 @@ module.exports = (env, argv) => {
|
|||||||
// http2: true,
|
// http2: true,
|
||||||
// https: true,
|
// https: true,
|
||||||
open: true,
|
open: true,
|
||||||
port: 3000,
|
port: OHIF_PORT,
|
||||||
client: {
|
client: {
|
||||||
overlay: { errors: true, warnings: false },
|
overlay: { errors: true, warnings: false },
|
||||||
},
|
},
|
||||||
|
|||||||
86
platform/app/cypress/integration/ImageConsistency.spec.js
Normal file
86
platform/app/cypress/integration/ImageConsistency.spec.js
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import { utilities } from '@cornerstonejs/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add tests to ensure image consistency and quality
|
||||||
|
*/
|
||||||
|
|
||||||
|
const testPixel = (dx, dy, expectedPixel) => {
|
||||||
|
cy.get('.cornerstone-canvas').then(v => {
|
||||||
|
const canvas = v[0];
|
||||||
|
cy.log(
|
||||||
|
'testPixel canvas',
|
||||||
|
dx,
|
||||||
|
dy,
|
||||||
|
expectedPixel,
|
||||||
|
canvas.width,
|
||||||
|
canvas.height,
|
||||||
|
canvas.style.width,
|
||||||
|
canvas.style.height
|
||||||
|
);
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
cy.window()
|
||||||
|
.its('cornerstone')
|
||||||
|
.then(cornerstone => {
|
||||||
|
const { viewport } = cornerstone.getEnabledElements()[0];
|
||||||
|
const imageData = viewport.getImageData();
|
||||||
|
// cy.log("imageData", imageData);
|
||||||
|
const origin = viewport.worldToCanvas(imageData.origin);
|
||||||
|
const orX = origin[0] * devicePixelRatio;
|
||||||
|
const orY = origin[1] * devicePixelRatio;
|
||||||
|
const x = Math.round(orX + dx);
|
||||||
|
const y = Math.round(orY + dy);
|
||||||
|
cy.log('testPixel origin x,y point x,y', orX, orY, x, y);
|
||||||
|
// cy.log('world origin', imageData.origin);
|
||||||
|
// cy.log('focal', viewport.getCamera().focalPoint,
|
||||||
|
// viewport.worldToCanvas(viewport.getCamera().focalPoint));
|
||||||
|
const pixelData = ctx.getImageData(x, y, 1, 1);
|
||||||
|
|
||||||
|
expect(pixelData.data[0]).closeTo(expectedPixel, 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('CS3D Image Consistency and Quality', () => {
|
||||||
|
const setupStudySeries = (studyUID, seriesUID) => {
|
||||||
|
cy.checkStudyRouteInViewer(
|
||||||
|
studyUID,
|
||||||
|
`&seriesInstanceUID=${seriesUID}&hangingProtocolId=@ohif/hpScale`
|
||||||
|
);
|
||||||
|
cy.initCornerstoneToolsAliases();
|
||||||
|
cy.initCommonElementsAliases();
|
||||||
|
};
|
||||||
|
|
||||||
|
it('TG18 Resolution Test Displayed 1:1', () => {
|
||||||
|
setupStudySeries(
|
||||||
|
'2.16.124.113543.6004.101.103.20021117.061159.1',
|
||||||
|
'2.16.124.113543.6004.101.103.20021117.061159.1.004'
|
||||||
|
);
|
||||||
|
testPixel(1018, 1028, 255);
|
||||||
|
// Horizontal and vertical delta from this should not be contaminated
|
||||||
|
// by values from center
|
||||||
|
testPixel(1019, 1028, 0);
|
||||||
|
testPixel(1018, 1029, 0);
|
||||||
|
testPixel(1017, 1028, 0);
|
||||||
|
testPixel(1018, 1027, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Missing test data - todo
|
||||||
|
it.skip('8 bit image displayable', () => {
|
||||||
|
setupStudySeries('1.3.46.670589.17.1.7.1.1.7', '1.3.46.670589.17.1.7.2.1.7');
|
||||||
|
|
||||||
|
// Compare with dcm2jpg generated values or by manually computing WL values
|
||||||
|
testPixel(258, 257, 171);
|
||||||
|
testPixel(259, 257, 166);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip('12 bit image displayable and zoom with pixel spacing', () => {
|
||||||
|
setupStudySeries(
|
||||||
|
'1.3.6.1.4.1.25403.345050719074.3824.20170125113417.1',
|
||||||
|
'1.3.6.1.4.1.25403.345050719074.3824.20170125113608.5'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Compare with dcm2jpg generated values or by manually computing WL values
|
||||||
|
testPixel(258, 277, 120);
|
||||||
|
testPixel(259, 277, 122);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -111,6 +111,34 @@ window.config = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
namespace: '@ohif/extension-default.dataSourcesModule.dicomweb',
|
||||||
|
sourceName: 'dicomweb2',
|
||||||
|
configuration: {
|
||||||
|
friendlyName: 'AWS S3 Static wado secondary server',
|
||||||
|
name: 'aws',
|
||||||
|
wadoUriRoot: 'https://d28o5kq0jsoob5.cloudfront.net/dicomweb',
|
||||||
|
qidoRoot: 'https://d28o5kq0jsoob5.cloudfront.net/dicomweb',
|
||||||
|
wadoRoot: 'https://d28o5kq0jsoob5.cloudfront.net/dicomweb',
|
||||||
|
qidoSupportsIncludeField: false,
|
||||||
|
supportsReject: false,
|
||||||
|
imageRendering: 'wadors',
|
||||||
|
thumbnailRendering: 'wadors',
|
||||||
|
enableStudyLazyLoad: true,
|
||||||
|
supportsFuzzyMatching: false,
|
||||||
|
supportsWildcard: true,
|
||||||
|
staticWado: true,
|
||||||
|
singlepart: 'bulkdata,video',
|
||||||
|
// whether the data source should use retrieveBulkData to grab metadata,
|
||||||
|
// and in case of relative path, what would it be relative to, options
|
||||||
|
// are in the series level or study level (some servers like series some study)
|
||||||
|
bulkDataURI: {
|
||||||
|
enabled: true,
|
||||||
|
relativeResolution: 'studies',
|
||||||
|
},
|
||||||
|
omitQuotationForMultipartRequest: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
friendlyName: 'StaticWado default data',
|
friendlyName: 'StaticWado default data',
|
||||||
namespace: '@ohif/extension-default.dataSourcesModule.dicomweb',
|
namespace: '@ohif/extension-default.dataSourcesModule.dicomweb',
|
||||||
|
|||||||
@ -24,6 +24,18 @@ export type DisplaySetAndViewportOptions = {
|
|||||||
displaySetOptions: DisplaySetOptions;
|
displaySetOptions: DisplaySetOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type DisplayArea = {
|
||||||
|
type?: 'SCALE' | 'FIT';
|
||||||
|
scale?: number;
|
||||||
|
interpolationType?: any;
|
||||||
|
imageArea?: [number, number]; // areaX, areaY
|
||||||
|
imageCanvasPoint?: {
|
||||||
|
imagePoint: [number, number]; // imageX, imageY
|
||||||
|
canvasPoint?: [number, number]; // canvasX, canvasY
|
||||||
|
};
|
||||||
|
storeAsInitialCamera?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export type SetProtocolOptions = {
|
export type SetProtocolOptions = {
|
||||||
/** Used to provide a mapping of what keys are provided for which viewport.
|
/** Used to provide a mapping of what keys are provided for which viewport.
|
||||||
* For example, a Chest XRay might use have the display set selector id of
|
* For example, a Chest XRay might use have the display set selector id of
|
||||||
@ -155,6 +167,7 @@ export type ViewportOptions = {
|
|||||||
id?: string;
|
id?: string;
|
||||||
orientation?: CustomOption<string>;
|
orientation?: CustomOption<string>;
|
||||||
viewportId?: string;
|
viewportId?: string;
|
||||||
|
displayArea?: DisplayArea;
|
||||||
initialImageOptions?: CustomOption<initialImageOptions>;
|
initialImageOptions?: CustomOption<initialImageOptions>;
|
||||||
syncGroups?: CustomOption<SyncGroup>[];
|
syncGroups?: CustomOption<SyncGroup>[];
|
||||||
customViewportProps?: Record<string, unknown>;
|
customViewportProps?: Record<string, unknown>;
|
||||||
|
|||||||
@ -293,6 +293,7 @@ alternative data source (or even specify different default hotkeys).
|
|||||||
| `APP_CONFIG` | Which [configuration file][config-file] to copy to output as `app-config.js` | `config/default.js` |
|
| `APP_CONFIG` | Which [configuration file][config-file] to copy to output as `app-config.js` | `config/default.js` |
|
||||||
| `PROXY_TARGET` | When developing, proxy requests that match this pattern to `PROXY_DOMAIN` | `undefined` |
|
| `PROXY_TARGET` | When developing, proxy requests that match this pattern to `PROXY_DOMAIN` | `undefined` |
|
||||||
| `PROXY_DOMAIN` | When developing, proxy requests from `PROXY_TARGET` to `PROXY_DOMAIN` | `undefined` |
|
| `PROXY_DOMAIN` | When developing, proxy requests from `PROXY_TARGET` to `PROXY_DOMAIN` | `undefined` |
|
||||||
|
| `OHIF_PORT` | The port to run the webpack server on for PWA builds. | `3000` |
|
||||||
|
|
||||||
You can also create a new config file and specify its path relative to the build
|
You can also create a new config file and specify its path relative to the build
|
||||||
output's root by setting the `APP_CONFIG` environment variable. You can set the
|
output's root by setting the `APP_CONFIG` environment variable. You can set the
|
||||||
|
|||||||
@ -281,21 +281,22 @@ A list of criteria for the protocol along with the provided points for ranking.
|
|||||||
},
|
},
|
||||||
```
|
```
|
||||||
|
|
||||||
### `from` attribute
|
### `from` attribute (optional)
|
||||||
The from attribute allows getting the attribute to test from some other object
|
The `from` attribute allows you to retrieve the attribute to test from another object, such as the previous study, the overall list of studies, or another provided value from a module.
|
||||||
such as the prior study, the list of studies overall or another module provided
|
|
||||||
value. Some of the possible attributes are:
|
|
||||||
|
|
||||||
* `prior`: To get the value from the prior study.
|
The values provided by OHIF which you can use are:
|
||||||
* `activeStudy`: To match the active study
|
|
||||||
* `studies`: To match the list of studies to display
|
|
||||||
* `displaySets`: The display sets for the current study
|
|
||||||
* `allDisplaySets`: Alll available display sets
|
|
||||||
* `instance`: An instance from the current display set being tested
|
|
||||||
* `options`: Gets the options object itself, eg if you want a simple top level
|
|
||||||
value.
|
|
||||||
|
|
||||||
### displaySetSelectors
|
- `activeStudy`: to use the metadata of the active study to match
|
||||||
|
- `studies`: to use the metadata of the list of studies (all studies) to match
|
||||||
|
- `allDisplaySets`: all available display sets
|
||||||
|
- `displaySets`: if the selector has matched a study, these are the display sets for that study
|
||||||
|
- `prior`: the metadata of the first study in the list of studies that is not the active study
|
||||||
|
- `options`: during matching, we also provide an options object with the following information that you can use as the `from` value:
|
||||||
|
- `studyInstanceUIDsIndex`: the index of the study in the list of studies
|
||||||
|
- `instance`: the metadata of the instance being matched, which is exactly the displaySet.instance metadata.
|
||||||
|
|
||||||
|
|
||||||
|
### displaySetSelectors (mandatory)
|
||||||
Defines the display sets that the protocol will use for arrangement.
|
Defines the display sets that the protocol will use for arrangement.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
|||||||
@ -60,7 +60,7 @@
|
|||||||
"react-window": "^1.8.9",
|
"react-window": "^1.8.9",
|
||||||
"react-with-direction": "^1.3.1",
|
"react-with-direction": "^1.3.1",
|
||||||
"swiper": "^8.4.2",
|
"swiper": "^8.4.2",
|
||||||
"webpack": "^5.81.0"
|
"webpack": "^5.89.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.23.2",
|
"@babel/core": "^7.23.2",
|
||||||
|
|||||||
@ -22557,7 +22557,7 @@ webpack-virtual-modules@^0.6.1:
|
|||||||
resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.1.tgz#ac6fdb9c5adb8caecd82ec241c9631b7a3681b6f"
|
resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.1.tgz#ac6fdb9c5adb8caecd82ec241c9631b7a3681b6f"
|
||||||
integrity sha512-poXpCylU7ExuvZK8z+On3kX+S8o/2dQ/SVYueKA0D4WEMXROXgY8Ez50/bQEUmvoSMMrWcrJqCHuhAbsiwg7Dg==
|
integrity sha512-poXpCylU7ExuvZK8z+On3kX+S8o/2dQ/SVYueKA0D4WEMXROXgY8Ez50/bQEUmvoSMMrWcrJqCHuhAbsiwg7Dg==
|
||||||
|
|
||||||
webpack@5, webpack@^5.50.0, webpack@^5.73.0, webpack@^5.81.0, webpack@^5.90.3:
|
webpack@5, webpack@^5.50.0, webpack@^5.73.0, webpack@^5.89.0, webpack@^5.90.3:
|
||||||
version "5.91.0"
|
version "5.91.0"
|
||||||
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.91.0.tgz#ffa92c1c618d18c878f06892bbdc3373c71a01d9"
|
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.91.0.tgz#ffa92c1c618d18c878f06892bbdc3373c71a01d9"
|
||||||
integrity sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==
|
integrity sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user