feat(HangingProtocol): add protocol generator back (#3128)
This commit is contained in:
parent
f7c886878d
commit
514ea3ccea
@ -79,6 +79,14 @@ const testProtocol = {
|
||||
numberOfPriorsReferenced: -1,
|
||||
};
|
||||
|
||||
function testProtocolGenerator({ servicesManager }) {
|
||||
servicesManager.services.TestService.toCall();
|
||||
|
||||
return {
|
||||
protocol: testProtocol,
|
||||
};
|
||||
}
|
||||
|
||||
const studyMatch = {
|
||||
StudyInstanceUID: 'studyMatch',
|
||||
StudyDescription: 'A PETCT study type',
|
||||
@ -107,41 +115,80 @@ const displaySet3 = {
|
||||
|
||||
const studyMatchDisplaySets = [displaySet3, displaySet2, displaySet1];
|
||||
|
||||
function checkHpsBestMatch(hps) {
|
||||
hps.run({ studies: [studyMatch], displaySets: studyMatchDisplaySets });
|
||||
const { hpAlreadyApplied, viewportMatchDetails } = hps.getMatchDetails();
|
||||
expect(hpAlreadyApplied).toMatchObject(new Map([[0, false]]));
|
||||
expect(viewportMatchDetails.size).toBe(1);
|
||||
expect(viewportMatchDetails.get(0)).toMatchObject({
|
||||
viewportOptions: {
|
||||
viewportId: 'ctAXIAL',
|
||||
viewportType: 'volume',
|
||||
orientation: 'axial',
|
||||
toolGroupId: 'ctToolGroup',
|
||||
},
|
||||
// Matches ds1 because it matches 2 rules, a required and an optional
|
||||
// ds2 fails to match required and ds3 fails to match an optional.
|
||||
displaySetsInfo: [
|
||||
{
|
||||
SeriesInstanceUID: 'ds1',
|
||||
displaySetInstanceUID: 'displaySet1',
|
||||
displaySetOptions: {},
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
describe('HangingProtocolService', () => {
|
||||
const mockedFunction = jest.fn();
|
||||
const commandsManager = {};
|
||||
const hps = new HangingProtocolServiceClass(commandsManager);
|
||||
const servicesManager = {
|
||||
services: {
|
||||
TestService: {
|
||||
toCall: mockedFunction,
|
||||
},
|
||||
},
|
||||
};
|
||||
const hps = new HangingProtocolServiceClass(commandsManager, servicesManager);
|
||||
let initialScaling;
|
||||
|
||||
beforeAll(() => {
|
||||
hps.addProtocol(testProtocol.id, testProtocol);
|
||||
afterEach(() => {
|
||||
mockedFunction.mockClear();
|
||||
});
|
||||
|
||||
it('has one protocol', () => {
|
||||
expect(hps.getProtocols().length).toBe(1);
|
||||
describe('with a static protocol', () => {
|
||||
beforeAll(() => {
|
||||
hps.addProtocol(testProtocol.id, testProtocol);
|
||||
});
|
||||
|
||||
it('has one protocol', () => {
|
||||
expect(hps.getProtocols().length).toBe(1);
|
||||
});
|
||||
|
||||
describe('run', () => {
|
||||
it('matches best image match', () => {
|
||||
checkHpsBestMatch(hps);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('run', () => {
|
||||
it('matches best image match', () => {
|
||||
hps.run({ studies: [studyMatch], displaySets: studyMatchDisplaySets });
|
||||
const { hpAlreadyApplied, viewportMatchDetails } = hps.getMatchDetails();
|
||||
expect(hpAlreadyApplied).toMatchObject(new Map([[0, false]]));
|
||||
expect(viewportMatchDetails.size).toBe(1);
|
||||
expect(viewportMatchDetails.get(0)).toMatchObject({
|
||||
viewportOptions: {
|
||||
viewportId: 'ctAXIAL',
|
||||
viewportType: 'volume',
|
||||
orientation: 'axial',
|
||||
toolGroupId: 'ctToolGroup',
|
||||
},
|
||||
// Matches ds1 because it matches 2 rules, a required and an optional
|
||||
// ds2 fails to match required and ds3 fails to match an optional.
|
||||
displaySetsInfo: [
|
||||
{
|
||||
SeriesInstanceUID: 'ds1',
|
||||
displaySetInstanceUID: 'displaySet1',
|
||||
displaySetOptions: {},
|
||||
},
|
||||
],
|
||||
describe('with protocol generator', () => {
|
||||
beforeAll(() => {
|
||||
hps.addProtocol(testProtocol.id, testProtocolGenerator);
|
||||
});
|
||||
|
||||
it('has one protocol', () => {
|
||||
expect(hps.getProtocols().length).toBe(1);
|
||||
});
|
||||
|
||||
describe('run', () => {
|
||||
it('matches best image match', () => {
|
||||
checkHpsBestMatch(hps);
|
||||
});
|
||||
|
||||
it('uses services manager', () => {
|
||||
hps.run({ studies: [studyMatch], displaySets: studyMatchDisplaySets });
|
||||
expect(mockedFunction).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -16,7 +16,7 @@ const EVENTS = {
|
||||
'event::hanging_protocol_applied_for_viewport',
|
||||
};
|
||||
|
||||
type Protocol = HangingProtocol.Protocol;
|
||||
type Protocol = HangingProtocol.Protocol | HangingProtocol.ProtocolGenerator;
|
||||
|
||||
class HangingProtocolService {
|
||||
studies: StudyMetadata[];
|
||||
@ -180,7 +180,21 @@ class HangingProtocolService {
|
||||
public getProtocolById(id: string): HangingProtocol.Protocol {
|
||||
const protocol = this.protocols.get(id);
|
||||
|
||||
return protocol;
|
||||
if (protocol instanceof Function) {
|
||||
try {
|
||||
const { protocol: generatedProtocol } = this._getProtocolFromGenerator(
|
||||
protocol
|
||||
);
|
||||
|
||||
return generatedProtocol;
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
`Error while executing protocol generator for protocol ${id}: ${error}`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return this._validateProtocol(protocol);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -434,6 +448,23 @@ class HangingProtocolService {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
private _getProtocolFromGenerator(
|
||||
protocolGenerator: HangingProtocol.ProtocolGenerator
|
||||
): {
|
||||
protocol: HangingProtocol.Protocol;
|
||||
} {
|
||||
const { protocol } = protocolGenerator({
|
||||
servicesManager: this._servicesManager,
|
||||
commandsManager: this._commandsManager,
|
||||
});
|
||||
|
||||
const validatedProtocol = this._validateProtocol(protocol);
|
||||
|
||||
return {
|
||||
protocol: validatedProtocol,
|
||||
};
|
||||
}
|
||||
|
||||
getViewportsRequireUpdate(viewportIndex, displaySetInstanceUID) {
|
||||
const newDisplaySetInstanceUID = displaySetInstanceUID;
|
||||
const protocol = this.protocol;
|
||||
|
||||
@ -151,6 +151,9 @@ type Protocol = {
|
||||
syncDataForViewports?: boolean;
|
||||
};
|
||||
|
||||
type ProtocolGenerator = ({ servicesManager: any, commandsManager: any }) => {
|
||||
protocol: Protocol;
|
||||
};
|
||||
|
||||
export type {
|
||||
SetProtocolOptions,
|
||||
@ -171,6 +174,6 @@ export type {
|
||||
DisplaySetInfo,
|
||||
GlobalProtocolOptions,
|
||||
ViewportSpecificProtocolOptions,
|
||||
DisplaySetAndViewportOptions
|
||||
|
||||
DisplaySetAndViewportOptions,
|
||||
ProtocolGenerator,
|
||||
};
|
||||
|
||||
@ -78,7 +78,20 @@ do not overlap, with the suggested id being `${moduleId}.${simpleName}`. The
|
||||
'default' name is used as the hanging protocol id when no other protocol applies,
|
||||
and can be set as the last module listed containing 'default'.
|
||||
|
||||
See the typescript definitions for more details on the structure.
|
||||
A hanging protocol can also be defined with a generator.
|
||||
A generator is a function we can write this way:
|
||||
|
||||
```ts
|
||||
function protocolGenerator({ servicesManager, commandsManager }) {
|
||||
// Some computations using services and commands ...
|
||||
|
||||
return {
|
||||
protocol: generatedProtocol
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See the typescript definitions for more details on the structure of protocols.
|
||||
|
||||
## Custom Attribute
|
||||
In some situations, you might want to match based on a custom attribute and not the DICOM tags. For instance,
|
||||
|
||||
18
yarn.lock
18
yarn.lock
@ -2405,6 +2405,14 @@
|
||||
detect-gpu "^4.0.45"
|
||||
lodash.clonedeep "4.5.0"
|
||||
|
||||
"@cornerstonejs/core@^0.25.1":
|
||||
version "0.25.1"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-0.25.1.tgz#7e5c70858018d99417b61965ac606754542f77ad"
|
||||
integrity sha512-/Ve9qwGyRRK1uUCrefh9cVG3OIaaS9LQoTUk9YMUbsoWxd6JitXh31XVHjlvNtBYGMRVdz+uGPS2zSxq1vi4aA==
|
||||
dependencies:
|
||||
detect-gpu "^4.0.45"
|
||||
lodash.clonedeep "4.5.0"
|
||||
|
||||
"@cornerstonejs/streaming-image-volume-loader@^0.8.2":
|
||||
version "0.8.2"
|
||||
resolved "https://registry.npmjs.org/@cornerstonejs/streaming-image-volume-loader/-/streaming-image-volume-loader-0.8.2.tgz#058a591501e7fe7ebbe195695c92d047a288290f"
|
||||
@ -2413,12 +2421,12 @@
|
||||
"@cornerstonejs/core" "^0.25.0"
|
||||
cornerstone-wado-image-loader "^4.7.0"
|
||||
|
||||
"@cornerstonejs/tools@^0.34.0":
|
||||
version "0.34.0"
|
||||
resolved "https://registry.npmjs.org/@cornerstonejs/tools/-/tools-0.34.0.tgz#d164f575b4870cea2f3300aaf88722a5f47e61f4"
|
||||
integrity sha512-J+pcLsAobcX3oHuDOmaWvXLfofBCa7wivuKjkuEajssgm+pUHp+hAt+LAZz0fy1m2ZGOFUZn6TQjGbQg/nrYEQ==
|
||||
"@cornerstonejs/tools@^0.34.2":
|
||||
version "0.34.2"
|
||||
resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-0.34.2.tgz#645c97583066a872fd35188153cd21b26625473e"
|
||||
integrity sha512-rbdQuSXGJ++ARS6eUAkBZi0tjmUKVtad0QPk0SZZXlDC2QAQRyIfq7n7oF2AaIR/0ngarTekUzuIy2nKiaOT+Q==
|
||||
dependencies:
|
||||
"@cornerstonejs/core" "^0.25.0"
|
||||
"@cornerstonejs/core" "^0.25.1"
|
||||
lodash.clonedeep "4.5.0"
|
||||
lodash.get "^4.4.2"
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user