chore(prettier): full repo linting and code reformatting once and for all (#3627)
This commit is contained in:
1 parent
01500a2d4c
commit
9045ddaedc
656 files changed
+21737
-20628
No files matched your search
@@ -1,7 +1,5 @@
|
||||
{
|
||||
"files": [
|
||||
"README.md"
|
||||
],
|
||||
"files": ["README.md"],
|
||||
"imageSize": 100,
|
||||
"commit": false,
|
||||
"contributors": [
|
||||
@@ -10,83 +8,63 @@
|
||||
"name": "Erik Ziegler",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/607793?v=4",
|
||||
"profile": "https://github.com/swederik",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
"contributions": ["code"]
|
||||
},
|
||||
{
|
||||
"login": "evren217",
|
||||
"name": "Evren Ozkan",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/4920551?v=4",
|
||||
"profile": "https://github.com/evren217",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
"contributions": ["code"]
|
||||
},
|
||||
{
|
||||
"login": "galelis",
|
||||
"name": "Gustavo André Lelis",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/2378326?v=4",
|
||||
"profile": "https://github.com/galelis",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
"contributions": ["code"]
|
||||
},
|
||||
{
|
||||
"login": "dannyrb",
|
||||
"name": "Danny Brown",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/5797588?v=4",
|
||||
"profile": "http://dannyrb.com/",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
"contributions": ["code"]
|
||||
},
|
||||
{
|
||||
"login": "allcontributors",
|
||||
"name": "allcontributors[bot]",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/46843839?v=4",
|
||||
"profile": "https://github.com/all-contributors/all-contributors-bot",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
"contributions": ["doc"]
|
||||
},
|
||||
{
|
||||
"login": "ivan-aksamentov",
|
||||
"name": "Ivan Aksamentov",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/9403403?v=4",
|
||||
"profile": "https://github.com/ivan-aksamentov",
|
||||
"contributions": [
|
||||
"code",
|
||||
"test"
|
||||
]
|
||||
"contributions": ["code", "test"]
|
||||
},
|
||||
{
|
||||
"login": "igoroctaviano",
|
||||
"name": "Igor Octaviano",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/13886933?v=4",
|
||||
"profile": "http://igoroctaviano.com",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
"contributions": ["code"]
|
||||
},
|
||||
{
|
||||
"login": "dlwire",
|
||||
"name": "David Wire",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/1167291?v=4",
|
||||
"profile": "https://github.com/dlwire",
|
||||
"contributions": [
|
||||
"code",
|
||||
"test"
|
||||
]
|
||||
"contributions": ["code", "test"]
|
||||
},
|
||||
{
|
||||
"login": "pavertomato",
|
||||
"name": "Egor Lezhnin",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/878990?v=4",
|
||||
"profile": "http://egor.lezhn.in",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
"contributions": ["code"]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
||||
@@ -3,12 +3,10 @@ const webpackCommon = require('./../../../.webpack/webpack.base.js');
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
|
||||
const ENTRY = {
|
||||
app: `${SRC_DIR}/index.ts`,
|
||||
};
|
||||
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
return webpackCommon(env, argv, { SRC_DIR, DIST_DIR, ENTRY });
|
||||
};
|
||||
@@ -36,11 +36,6 @@ module.exports = (env, argv) => {
|
||||
libraryTarget: 'umd',
|
||||
filename: pkg.main,
|
||||
},
|
||||
externals: [
|
||||
/\b(vtk.js)/,
|
||||
/\b(dcmjs)/,
|
||||
/\b(gl-matrix)/,
|
||||
/^@cornerstonejs/,
|
||||
],
|
||||
externals: [/\b(vtk.js)/, /\b(dcmjs)/, /\b(gl-matrix)/, /^@cornerstonejs/],
|
||||
});
|
||||
};
|
||||
@@ -1 +1 @@
|
||||
module.exports = require("../../babel.config.js");
|
||||
module.exports = require('../../babel.config.js');
|
||||
@@ -26,9 +26,7 @@ describe('getAttribute', () => {
|
||||
|
||||
expect(getAttribute(nullElement, defaultValue)).toEqual(defaultValue);
|
||||
expect(getAttribute(undefinedElement, defaultValue)).toEqual(defaultValue);
|
||||
expect(getAttribute(noValuePresentElement, defaultValue)).toEqual(
|
||||
defaultValue
|
||||
);
|
||||
expect(getAttribute(noValuePresentElement, defaultValue)).toEqual(defaultValue);
|
||||
});
|
||||
|
||||
it('should return 48 for element with value 0', () => {
|
||||
|
||||
@@ -28,9 +28,7 @@ describe('getAuthorizationHeader', () => {
|
||||
};
|
||||
|
||||
const expectedAuthorizationHeader = {
|
||||
Authorization: `Basic ${btoa(
|
||||
validServerWithoutPassword.requestOptions.auth
|
||||
)}`,
|
||||
Authorization: `Basic ${btoa(validServerWithoutPassword.requestOptions.auth)}`,
|
||||
};
|
||||
|
||||
const authentication = getAuthorizationHeader(validServerWithoutPassword);
|
||||
|
||||
@@ -23,9 +23,7 @@ describe('getModalities', () => {
|
||||
vr: 'MOCKED_VALUE',
|
||||
};
|
||||
|
||||
expect(getModalities(Modality, ModalitiesInStudy)).toEqual(
|
||||
ModalitiesInStudy
|
||||
);
|
||||
expect(getModalities(Modality, ModalitiesInStudy)).toEqual(ModalitiesInStudy);
|
||||
});
|
||||
|
||||
test('should return only the modalitues that exists in ModalitiesInStudy', () => {
|
||||
@@ -67,8 +65,6 @@ describe('getModalities', () => {
|
||||
vr: 'ANOTHER_VR',
|
||||
};
|
||||
|
||||
expect(getModalities(Modality, ModalitiesInStudy)).toEqual(
|
||||
ModalitiesInStudy
|
||||
);
|
||||
expect(getModalities(Modality, ModalitiesInStudy)).toEqual(ModalitiesInStudy);
|
||||
});
|
||||
});
|
||||
@@ -32,12 +32,7 @@ describe('getName', () => {
|
||||
it('should return A for element when Alphabetic is [A, B, C, D]', () => {
|
||||
const returnValue = 'A';
|
||||
const element = {
|
||||
Value: [
|
||||
{ Alphabetic: 'A' },
|
||||
{ Alphabetic: 'B' },
|
||||
{ Alphabetic: 'C' },
|
||||
{ Alphabetic: 'D' },
|
||||
],
|
||||
Value: [{ Alphabetic: 'A' }, { Alphabetic: 'B' }, { Alphabetic: 'C' }, { Alphabetic: 'D' }],
|
||||
};
|
||||
expect(getName(element, null)).toEqual(returnValue);
|
||||
});
|
||||
|
||||
@@ -26,9 +26,7 @@ describe('getNumber', () => {
|
||||
|
||||
expect(getNumber(nullElement, defaultValue)).toEqual(defaultValue);
|
||||
expect(getNumber(undefinedElement, defaultValue)).toEqual(defaultValue);
|
||||
expect(getNumber(noValuePresentElement, defaultValue)).toEqual(
|
||||
defaultValue
|
||||
);
|
||||
expect(getNumber(noValuePresentElement, defaultValue)).toEqual(defaultValue);
|
||||
});
|
||||
|
||||
it('should return 2.0 for element when element.Value[0] = 2', () => {
|
||||
|
||||
@@ -26,9 +26,7 @@ describe('getString', () => {
|
||||
|
||||
expect(getString(nullElement, defaultValue)).toEqual(defaultValue);
|
||||
expect(getString(undefinedElement, defaultValue)).toEqual(defaultValue);
|
||||
expect(getString(noValuePresentElement, defaultValue)).toEqual(
|
||||
defaultValue
|
||||
);
|
||||
expect(getString(noValuePresentElement, defaultValue)).toEqual(defaultValue);
|
||||
});
|
||||
|
||||
it('should return A,B,C,D for element when element.Value[0] = [A, B, C, D]', () => {
|
||||
|
||||
@@ -14,13 +14,6 @@ const DICOMWeb = {
|
||||
getString,
|
||||
};
|
||||
|
||||
export {
|
||||
getAttribute,
|
||||
getAuthorizationHeader,
|
||||
getModalities,
|
||||
getName,
|
||||
getNumber,
|
||||
getString,
|
||||
};
|
||||
export { getAttribute, getAuthorizationHeader, getModalities, getName, getNumber, getString };
|
||||
|
||||
export default DICOMWeb;
|
||||
@@ -1,9 +1,9 @@
|
||||
// import { api } from 'dicomweb-client'
|
||||
|
||||
const api = {
|
||||
DICOMwebClient: jest.fn().mockImplementation(function() {
|
||||
DICOMwebClient: jest.fn().mockImplementation(function () {
|
||||
this.retrieveStudyMetadata = jest.fn().mockResolvedValue([]);
|
||||
this.retrieveSeriesMetadata = jest.fn(function(options) {
|
||||
this.retrieveSeriesMetadata = jest.fn(function (options) {
|
||||
const { studyInstanceUID, seriesInstanceUID } = options;
|
||||
return Promise.resolve([{ studyInstanceUID, seriesInstanceUID }]);
|
||||
});
|
||||
|
||||
@@ -94,10 +94,7 @@ describe('CommandsManager', () => {
|
||||
|
||||
describe('getCommand()', () => {
|
||||
it('returns undefined if context does not exist', () => {
|
||||
const result = commandsManager.getCommand(
|
||||
'TestCommand',
|
||||
'NonExistentContext'
|
||||
);
|
||||
const result = commandsManager.getCommand('TestCommand', 'NonExistentContext');
|
||||
|
||||
expect(result).toBe(undefined);
|
||||
});
|
||||
@@ -131,9 +128,7 @@ describe('CommandsManager', () => {
|
||||
|
||||
describe('runCommand()', () => {
|
||||
it('Logs a warning if commandName not found in context', () => {
|
||||
const result = commandsManager.runCommand(
|
||||
'CommandThatDoesNotExistInAnyContext'
|
||||
);
|
||||
const result = commandsManager.runCommand('CommandThatDoesNotExistInAnyContext');
|
||||
|
||||
expect(result).toBe(undefined);
|
||||
expect(log.warn.mock.calls[0][0]).toEqual(
|
||||
@@ -149,16 +144,8 @@ describe('CommandsManager', () => {
|
||||
};
|
||||
|
||||
commandsManager.createContext(contextName);
|
||||
commandsManager.registerCommand(
|
||||
contextName,
|
||||
'TestCommand',
|
||||
commandWithNoCommmandFn
|
||||
);
|
||||
const result = commandsManager.runCommand(
|
||||
'TestCommand',
|
||||
null,
|
||||
contextName
|
||||
);
|
||||
commandsManager.registerCommand(contextName, 'TestCommand', commandWithNoCommmandFn);
|
||||
const result = commandsManager.runCommand('TestCommand', null, contextName);
|
||||
|
||||
expect(result).toBe(undefined);
|
||||
expect(log.warn.mock.calls[0][0]).toEqual(
|
||||
@@ -192,9 +179,7 @@ describe('CommandsManager', () => {
|
||||
commandsManager.runCommand('TestCommand', runCommandOptions, 'VIEWER');
|
||||
|
||||
expect(command.commandFn.mock.calls.length).toBe(1);
|
||||
expect(command.commandFn.mock.calls[0][0].test).toEqual(
|
||||
runCommandOptions.test
|
||||
);
|
||||
expect(command.commandFn.mock.calls[0][0].test).toEqual(runCommandOptions.test);
|
||||
});
|
||||
|
||||
it('Returns the result of commandFn', () => {
|
||||
|
||||
@@ -181,30 +181,27 @@ export class CommandsManager {
|
||||
const commands =
|
||||
(Array.isArray(toRun) && toRun) ||
|
||||
((toRun as Command).commandName && [toRun]) ||
|
||||
(Array.isArray((toRun as Commands).commands) &&
|
||||
(toRun as Commands).commands);
|
||||
(Array.isArray((toRun as Commands).commands) && (toRun as Commands).commands);
|
||||
if (!commands) {
|
||||
console.log("Command isn't runnable", toRun);
|
||||
return;
|
||||
}
|
||||
|
||||
let result;
|
||||
(commands as Command[]).forEach(
|
||||
({ commandName, commandOptions, context }) => {
|
||||
if (commandName) {
|
||||
result = this.runCommand(
|
||||
commandName,
|
||||
{
|
||||
...commandOptions,
|
||||
...options,
|
||||
},
|
||||
context
|
||||
);
|
||||
} else {
|
||||
console.warn('No command name supplied in', toRun);
|
||||
}
|
||||
(commands as Command[]).forEach(({ commandName, commandOptions, context }) => {
|
||||
if (commandName) {
|
||||
result = this.runCommand(
|
||||
commandName,
|
||||
{
|
||||
...commandOptions,
|
||||
...options,
|
||||
},
|
||||
context
|
||||
);
|
||||
} else {
|
||||
console.warn('No command name supplied in', toRun);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -21,11 +21,7 @@ describe('HotkeysManager', () => {
|
||||
});
|
||||
it('has expected properties', () => {
|
||||
const allProperties = Object.keys(hotkeysManager);
|
||||
const expectedProperties = [
|
||||
'hotkeyDefinitions',
|
||||
'hotkeyDefaults',
|
||||
'isEnabled',
|
||||
];
|
||||
const expectedProperties = ['hotkeyDefinitions', 'hotkeyDefaults', 'isEnabled'];
|
||||
|
||||
const containsAllExpectedProperties = expectedProperties.every(expected =>
|
||||
allProperties.includes(expected)
|
||||
@@ -134,21 +130,16 @@ describe('HotkeysManager', () => {
|
||||
|
||||
hotkeysManager.registerHotkeys(definition);
|
||||
|
||||
const numOfHotkeyDefinitions = Object.keys(
|
||||
hotkeysManager.hotkeyDefinitions
|
||||
).length;
|
||||
const numOfHotkeyDefinitions = Object.keys(hotkeysManager.hotkeyDefinitions).length;
|
||||
|
||||
const commandHash = objectHash({
|
||||
commandName: definition.commandName,
|
||||
commandOptions: definition.commandOptions,
|
||||
});
|
||||
const hotkeyDefinitionForRegisteredCommand =
|
||||
hotkeysManager.hotkeyDefinitions[commandHash];
|
||||
const hotkeyDefinitionForRegisteredCommand = hotkeysManager.hotkeyDefinitions[commandHash];
|
||||
|
||||
expect(numOfHotkeyDefinitions).toBe(1);
|
||||
expect(Object.keys(hotkeysManager.hotkeyDefinitions)[0]).toEqual(
|
||||
commandHash
|
||||
);
|
||||
expect(Object.keys(hotkeysManager.hotkeyDefinitions)[0]).toEqual(commandHash);
|
||||
expect(hotkeyDefinitionForRegisteredCommand).toEqual(definition);
|
||||
});
|
||||
it('calls hotkeys.bind for the group of keys', () => {
|
||||
@@ -182,9 +173,7 @@ describe('HotkeysManager', () => {
|
||||
|
||||
hotkeysManager.restoreDefaultBindings();
|
||||
|
||||
expect(hotkeysManager.setHotkeys.mock.calls[0][0]).toEqual(
|
||||
hotkeysManager.hotkeyDefaults
|
||||
);
|
||||
expect(hotkeysManager.setHotkeys.mock.calls[0][0]).toEqual(hotkeysManager.hotkeyDefaults);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -174,14 +174,7 @@ export class HotkeysManager {
|
||||
* @returns {undefined}
|
||||
*/
|
||||
registerHotkeys(
|
||||
{
|
||||
commandName,
|
||||
commandOptions = {},
|
||||
context,
|
||||
keys,
|
||||
label,
|
||||
isEditable,
|
||||
}: Hotkey = {},
|
||||
{ commandName, commandOptions = {}, context, keys, label, isEditable }: Hotkey = {},
|
||||
extension
|
||||
) {
|
||||
if (!commandName) {
|
||||
@@ -189,9 +182,7 @@ export class HotkeysManager {
|
||||
}
|
||||
|
||||
const commandHash = objectHash({ commandName, commandOptions });
|
||||
const options = Object.keys(commandOptions).length
|
||||
? JSON.stringify(commandOptions)
|
||||
: 'no';
|
||||
const options = Object.keys(commandOptions).length ? JSON.stringify(commandOptions) : 'no';
|
||||
const previouslyRegisteredDefinition = this.hotkeyDefinitions[commandHash];
|
||||
|
||||
if (previouslyRegisteredDefinition) {
|
||||
@@ -255,11 +246,7 @@ export class HotkeysManager {
|
||||
hotkeys.bind(combinedKeys, evt => {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
this._commandsManager.runCommand(
|
||||
commandName,
|
||||
{ evt, ...commandOptions },
|
||||
context
|
||||
);
|
||||
this._commandsManager.runCommand(commandName, { evt, ...commandOptions }, context);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ class ImageSet {
|
||||
)
|
||||
);
|
||||
|
||||
const distanceImagePairs = images.map(function(image: Image) {
|
||||
const distanceImagePairs = images.map(function (image: Image) {
|
||||
const ippVec = new Vector3(..._getImagePositionPatient(image));
|
||||
const positionVector = refIppVec.clone().sub(ippVec);
|
||||
const distance = positionVector.dot(scanAxisNormal);
|
||||
@@ -118,13 +118,13 @@ class ImageSet {
|
||||
};
|
||||
});
|
||||
|
||||
distanceImagePairs.sort(function(a, b) {
|
||||
distanceImagePairs.sort(function (a, b) {
|
||||
return b.distance - a.distance;
|
||||
});
|
||||
|
||||
const sortedImages = distanceImagePairs.map(a => a.image);
|
||||
|
||||
images.sort(function(a, b) {
|
||||
images.sort(function (a, b) {
|
||||
return sortedImages.indexOf(a) - sortedImages.indexOf(b);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -58,12 +58,7 @@ class MetadataProvider {
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
SOPInstanceUID,
|
||||
frameNumber,
|
||||
} = uids;
|
||||
const { StudyInstanceUID, SeriesInstanceUID, SOPInstanceUID, frameNumber } = uids;
|
||||
|
||||
const instance = DicomMetadataStore.getInstance(
|
||||
StudyInstanceUID,
|
||||
@@ -75,9 +70,7 @@ class MetadataProvider {
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
(frameNumber && combineFrameInstance(frameNumber, instance)) || instance
|
||||
);
|
||||
return (frameNumber && combineFrameInstance(frameNumber, instance)) || instance;
|
||||
}
|
||||
|
||||
get(query, imageId, options = { fallback: false }) {
|
||||
@@ -107,11 +100,7 @@ class MetadataProvider {
|
||||
return this.get(INSTANCE, imageId);
|
||||
}
|
||||
|
||||
getTagFromInstance(
|
||||
naturalizedTagOrWADOImageLoaderTag,
|
||||
instance,
|
||||
options = { fallback: false }
|
||||
) {
|
||||
getTagFromInstance(naturalizedTagOrWADOImageLoaderTag, instance, options = { fallback: false }) {
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
@@ -122,10 +111,7 @@ class MetadataProvider {
|
||||
}
|
||||
|
||||
// Maybe its a legacy dicomImageLoader tag then:
|
||||
return this._getCornerstoneDICOMImageLoaderTag(
|
||||
naturalizedTagOrWADOImageLoaderTag,
|
||||
instance
|
||||
);
|
||||
return this._getCornerstoneDICOMImageLoaderTag(naturalizedTagOrWADOImageLoaderTag, instance);
|
||||
}
|
||||
|
||||
_getCornerstoneDICOMImageLoaderTag(wadoImageLoaderTag, instance) {
|
||||
@@ -198,9 +184,7 @@ class MetadataProvider {
|
||||
imageOrientationPatient: toNumber(ImageOrientationPatient),
|
||||
rowCosines: toNumber(rowCosines || [0, 1, 0]),
|
||||
columnCosines: toNumber(columnCosines || [0, 0, -1]),
|
||||
imagePositionPatient: toNumber(
|
||||
instance.ImagePositionPatient || [0, 0, 0]
|
||||
),
|
||||
imagePositionPatient: toNumber(instance.ImagePositionPatient || [0, 0, 0]),
|
||||
sliceThickness: toNumber(instance.SliceThickness),
|
||||
sliceLocation: toNumber(instance.SliceLocation),
|
||||
pixelSpacing: toNumber(PixelSpacing || 1),
|
||||
@@ -254,12 +238,8 @@ class MetadataProvider {
|
||||
if (WindowCenter === undefined || WindowWidth === undefined) {
|
||||
return;
|
||||
}
|
||||
const windowCenter = Array.isArray(WindowCenter)
|
||||
? WindowCenter
|
||||
: [WindowCenter];
|
||||
const windowWidth = Array.isArray(WindowWidth)
|
||||
? WindowWidth
|
||||
: [WindowWidth];
|
||||
const windowCenter = Array.isArray(WindowCenter) ? WindowCenter : [WindowCenter];
|
||||
const windowWidth = Array.isArray(WindowWidth) ? WindowWidth : [WindowWidth];
|
||||
|
||||
metadata = {
|
||||
windowCenter: toNumber(windowCenter),
|
||||
@@ -296,16 +276,11 @@ class MetadataProvider {
|
||||
? RadiopharmaceuticalInformationSequence[0]
|
||||
: RadiopharmaceuticalInformationSequence;
|
||||
|
||||
const {
|
||||
RadiopharmaceuticalStartTime,
|
||||
RadionuclideTotalDose,
|
||||
RadionuclideHalfLife,
|
||||
} = RadiopharmaceuticalInformation;
|
||||
const { RadiopharmaceuticalStartTime, RadionuclideTotalDose, RadionuclideHalfLife } =
|
||||
RadiopharmaceuticalInformation;
|
||||
|
||||
const radiopharmaceuticalInfo = {
|
||||
radiopharmaceuticalStartTime: dicomParser.parseTM(
|
||||
RadiopharmaceuticalStartTime
|
||||
),
|
||||
radiopharmaceuticalStartTime: dicomParser.parseTM(RadiopharmaceuticalStartTime),
|
||||
radionuclideTotalDose: RadionuclideTotalDose,
|
||||
radionuclideHalfLife: RadionuclideHalfLife,
|
||||
};
|
||||
@@ -318,11 +293,7 @@ class MetadataProvider {
|
||||
case WADO_IMAGE_LOADER_TAGS.OVERLAY_PLANE_MODULE:
|
||||
const overlays = [];
|
||||
|
||||
for (
|
||||
let overlayGroup = 0x00;
|
||||
overlayGroup <= 0x1e;
|
||||
overlayGroup += 0x02
|
||||
) {
|
||||
for (let overlayGroup = 0x00; overlayGroup <= 0x1e; overlayGroup += 0x02) {
|
||||
let groupStr = `60${overlayGroup.toString(16)}`;
|
||||
|
||||
if (groupStr.length === 3) {
|
||||
|
||||
@@ -59,17 +59,11 @@ describe('ExtensionManager.ts', () => {
|
||||
extensionManager.registerExtension = jest.fn();
|
||||
|
||||
// SUT
|
||||
const fakeExtensions = [
|
||||
{ one: '1' },
|
||||
[{ two: '2' }, fakeConfiguration],
|
||||
{ three: '3 ' },
|
||||
];
|
||||
const fakeExtensions = [{ one: '1' }, [{ two: '2' }, fakeConfiguration], { three: '3 ' }];
|
||||
await extensionManager.registerExtensions(fakeExtensions);
|
||||
|
||||
// Assert
|
||||
expect(extensionManager.registerExtension.mock.calls[1][1]).toEqual(
|
||||
fakeConfiguration
|
||||
);
|
||||
expect(extensionManager.registerExtension.mock.calls[1][1]).toEqual(fakeConfiguration);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -104,15 +98,11 @@ describe('ExtensionManager.ts', () => {
|
||||
const undefinedExtension = undefined;
|
||||
const nullExtension = null;
|
||||
|
||||
await expect(
|
||||
extensionManager.registerExtension(undefinedExtension)
|
||||
).rejects.toThrow(
|
||||
await expect(extensionManager.registerExtension(undefinedExtension)).rejects.toThrow(
|
||||
new Error('Attempting to register a null/undefined extension.')
|
||||
);
|
||||
|
||||
await expect(
|
||||
extensionManager.registerExtension(nullExtension)
|
||||
).rejects.toThrow(
|
||||
await expect(extensionManager.registerExtension(nullExtension)).rejects.toThrow(
|
||||
new Error('Attempting to register a null/undefined extension.')
|
||||
);
|
||||
});
|
||||
@@ -120,9 +110,9 @@ describe('ExtensionManager.ts', () => {
|
||||
it('logs a warning if the extension does not have an id', async () => {
|
||||
const extensionWithoutId = {};
|
||||
|
||||
await expect(
|
||||
extensionManager.registerExtension(extensionWithoutId)
|
||||
).rejects.toThrow(new Error('Extension ID not set'));
|
||||
await expect(extensionManager.registerExtension(extensionWithoutId)).rejects.toThrow(
|
||||
new Error('Extension ID not set')
|
||||
);
|
||||
});
|
||||
|
||||
it('tracks which extensions have been registered', () => {
|
||||
@@ -156,9 +146,7 @@ describe('ExtensionManager.ts', () => {
|
||||
extensionManager.registerExtension(extensionWithBadModule);
|
||||
|
||||
expect(log.warn.mock.calls.length).toBe(1);
|
||||
expect(log.warn.mock.calls[0][0]).toContain(
|
||||
'Null or undefined returned when registering'
|
||||
);
|
||||
expect(log.warn.mock.calls[0][0]).toContain('Null or undefined returned when registering');
|
||||
});
|
||||
|
||||
it('logs an error if an exception is thrown while retrieving a module', async () => {
|
||||
@@ -169,9 +157,7 @@ describe('ExtensionManager.ts', () => {
|
||||
},
|
||||
};
|
||||
|
||||
await expect(
|
||||
extensionManager.registerExtension(extensionWithBadModule)
|
||||
).rejects.toThrow();
|
||||
await expect(extensionManager.registerExtension(extensionWithBadModule)).rejects.toThrow();
|
||||
});
|
||||
|
||||
it('successfully passes dependencies to each module along with extension configuration', () => {
|
||||
|
||||
@@ -145,12 +145,8 @@ export default class ExtensionManager extends PubSubService {
|
||||
}
|
||||
|
||||
public onModeExit(): void {
|
||||
const {
|
||||
registeredExtensionIds,
|
||||
_servicesManager,
|
||||
_commandsManager,
|
||||
_extensionLifeCycleHooks,
|
||||
} = this;
|
||||
const { registeredExtensionIds, _servicesManager, _commandsManager, _extensionLifeCycleHooks } =
|
||||
this;
|
||||
|
||||
registeredExtensionIds.forEach(extensionId => {
|
||||
const onModeExit = _extensionLifeCycleHooks.onModeExit[extensionId];
|
||||
@@ -181,10 +177,7 @@ export default class ExtensionManager extends PubSubService {
|
||||
* @param {Object[]} extensions - Array of extensions
|
||||
*/
|
||||
public registerExtensions = async (
|
||||
extensions: (
|
||||
| ExtensionRegister
|
||||
| [ExtensionRegister, ExtensionConfiguration]
|
||||
)[],
|
||||
extensions: (ExtensionRegister | [ExtensionRegister, ExtensionConfiguration])[],
|
||||
dataSources: unknown[] = []
|
||||
): Promise<void> => {
|
||||
// Todo: we ideally should be able to run registrations in parallel
|
||||
@@ -203,11 +196,7 @@ export default class ExtensionManager extends PubSubService {
|
||||
// for (const extension of extensions)
|
||||
const ohifExtension = extension[0];
|
||||
const configuration = extension[1];
|
||||
await this.registerExtension(
|
||||
ohifExtension,
|
||||
configuration,
|
||||
dataSources
|
||||
);
|
||||
await this.registerExtension(ohifExtension, configuration, dataSources);
|
||||
} else {
|
||||
await this.registerExtension(extension, {}, dataSources);
|
||||
}
|
||||
@@ -260,13 +249,11 @@ export default class ExtensionManager extends PubSubService {
|
||||
}
|
||||
|
||||
if (extension.onModeEnter) {
|
||||
this._extensionLifeCycleHooks.onModeEnter[extensionId] =
|
||||
extension.onModeEnter;
|
||||
this._extensionLifeCycleHooks.onModeEnter[extensionId] = extension.onModeEnter;
|
||||
}
|
||||
|
||||
if (extension.onModeExit) {
|
||||
this._extensionLifeCycleHooks.onModeExit[extensionId] =
|
||||
extension.onModeExit;
|
||||
this._extensionLifeCycleHooks.onModeExit[extensionId] = extension.onModeExit;
|
||||
}
|
||||
|
||||
// Register Modules
|
||||
@@ -284,11 +271,7 @@ export default class ExtensionManager extends PubSubService {
|
||||
this._initCommandsModule(extensionModule);
|
||||
break;
|
||||
case MODULE_TYPES.DATA_SOURCE:
|
||||
this._initDataSourcesModule(
|
||||
extensionModule,
|
||||
extensionId,
|
||||
dataSources
|
||||
);
|
||||
this._initDataSourcesModule(extensionModule, extensionId, dataSources);
|
||||
break;
|
||||
case MODULE_TYPES.HANGING_PROTOCOL:
|
||||
this._initHangingProtocolsModule(extensionModule, extensionId);
|
||||
@@ -425,10 +408,7 @@ export default class ExtensionManager extends PubSubService {
|
||||
* @param dataSourceDef the data source definition to be added
|
||||
* @param activate flag to indicate if the added data source should be set to the active data source
|
||||
*/
|
||||
addDataSource(
|
||||
dataSourceDef: DataSourceDefinition,
|
||||
options = { activate: false }
|
||||
) {
|
||||
addDataSource(dataSourceDef: DataSourceDefinition, options = { activate: false }) {
|
||||
const existingDataSource = this.getDataSources(dataSourceDef.sourceName);
|
||||
if (existingDataSource?.[0]) {
|
||||
// The data source already exists and cannot be added.
|
||||
@@ -448,10 +428,7 @@ export default class ExtensionManager extends PubSubService {
|
||||
* @param dataSourceName the name of the data source to update
|
||||
* @param dataSourceConfiguration the new configuration to update the data source with
|
||||
*/
|
||||
updateDataSourceConfiguration(
|
||||
dataSourceName: string,
|
||||
dataSourceConfiguration: any
|
||||
) {
|
||||
updateDataSourceConfiguration(dataSourceName: string, dataSourceConfiguration: any) {
|
||||
const existingDataSource = this.getDataSources(dataSourceName);
|
||||
if (!existingDataSource?.[0]) {
|
||||
// Cannot update a non existent data source.
|
||||
@@ -465,10 +442,7 @@ export default class ExtensionManager extends PubSubService {
|
||||
|
||||
if (this.activeDataSource === dataSourceName) {
|
||||
// When the active data source is changed/set, fire an event to indicate that its configuration has changed.
|
||||
this._broadcastEvent(
|
||||
ExtensionManager.EVENTS.ACTIVE_DATA_SOURCE_CHANGED,
|
||||
dataSourceDef
|
||||
);
|
||||
this._broadcastEvent(ExtensionManager.EVENTS.ACTIVE_DATA_SOURCE_CHANGED, dataSourceDef);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -502,9 +476,7 @@ export default class ExtensionManager extends PubSubService {
|
||||
dataSources: Array<DataSourceDefinition> = []
|
||||
): void {
|
||||
extensionModule.forEach(element => {
|
||||
this.modulesMap[
|
||||
`${extensionId}.${MODULE_TYPES.DATA_SOURCE}.${element.name}`
|
||||
] = element;
|
||||
this.modulesMap[`${extensionId}.${MODULE_TYPES.DATA_SOURCE}.${element.name}`] = element;
|
||||
});
|
||||
|
||||
extensionModule.forEach(element => {
|
||||
@@ -539,8 +511,7 @@ export default class ExtensionManager extends PubSubService {
|
||||
Object.keys(definitions).forEach(commandName => {
|
||||
const commandDefinition = definitions[commandName];
|
||||
const commandHasContextThatDoesNotExist =
|
||||
commandDefinition.context &&
|
||||
!this._commandsManager.getContext(commandDefinition.context);
|
||||
commandDefinition.context && !this._commandsManager.getContext(commandDefinition.context);
|
||||
|
||||
if (commandHasContextThatDoesNotExist) {
|
||||
this._commandsManager.createContext(commandDefinition.context);
|
||||
|
||||
@@ -33,10 +33,7 @@ import {
|
||||
PanelService,
|
||||
} from './services';
|
||||
|
||||
import {
|
||||
DisplaySetMessage,
|
||||
DisplaySetMessageList,
|
||||
} from './services/DisplaySetService';
|
||||
import { DisplaySetMessage, DisplaySetMessageList } from './services/DisplaySetService';
|
||||
|
||||
import IWebApiDataSource from './DataSources/IWebApiDataSource';
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ const extensionManager = {
|
||||
registeredExtensionIds: [],
|
||||
moduleEntries: {},
|
||||
|
||||
getModuleEntry: function(id) {
|
||||
getModuleEntry: function (id) {
|
||||
return this.moduleEntries[id];
|
||||
},
|
||||
};
|
||||
@@ -20,7 +20,7 @@ const commandsManager = {};
|
||||
|
||||
const ohifOverlayItem = {
|
||||
id: 'ohif.overlayItem',
|
||||
content: function(props) {
|
||||
content: function (props) {
|
||||
return {
|
||||
label: this.label,
|
||||
value: props[this.attribute],
|
||||
@@ -59,29 +59,27 @@ describe('CustomizationService.ts', () => {
|
||||
it('configurationRegistered', () => {
|
||||
configuration.testItem = testItem;
|
||||
customizationService.init(extensionManager);
|
||||
expect(customizationService.getGlobalCustomization('testItem')).toBe(
|
||||
testItem
|
||||
);
|
||||
expect(customizationService.getGlobalCustomization('testItem')).toBe(testItem);
|
||||
});
|
||||
|
||||
it('defaultRegistered', () => {
|
||||
extensionManager.registeredExtensionIds.push('@testExtension');
|
||||
extensionManager.moduleEntries[
|
||||
'@testExtension.customizationModule.default'
|
||||
] = { name: 'default', value: [testItem] };
|
||||
extensionManager.moduleEntries['@testExtension.customizationModule.default'] = {
|
||||
name: 'default',
|
||||
value: [testItem],
|
||||
};
|
||||
customizationService.init(extensionManager);
|
||||
expect(customizationService.getGlobalCustomization('testItem')).toBe(
|
||||
testItem
|
||||
);
|
||||
expect(customizationService.getGlobalCustomization('testItem')).toBe(testItem);
|
||||
});
|
||||
});
|
||||
|
||||
describe('customizationType', () => {
|
||||
it('inherits type', () => {
|
||||
extensionManager.registeredExtensionIds.push('@testExtension');
|
||||
extensionManager.moduleEntries[
|
||||
'@testExtension.customizationModule.default'
|
||||
] = { name: 'default', value: [ohifOverlayItem] };
|
||||
extensionManager.moduleEntries['@testExtension.customizationModule.default'] = {
|
||||
name: 'default',
|
||||
value: [ohifOverlayItem],
|
||||
};
|
||||
configuration.testItem = testItem;
|
||||
customizationService.init(extensionManager);
|
||||
|
||||
@@ -96,9 +94,10 @@ describe('CustomizationService.ts', () => {
|
||||
|
||||
it('inline default inherits type', () => {
|
||||
extensionManager.registeredExtensionIds.push('@testExtension');
|
||||
extensionManager.moduleEntries[
|
||||
'@testExtension.customizationModule.default'
|
||||
] = { name: 'default', value: [ohifOverlayItem] };
|
||||
extensionManager.moduleEntries['@testExtension.customizationModule.default'] = {
|
||||
name: 'default',
|
||||
value: [ohifOverlayItem],
|
||||
};
|
||||
configuration.testItem = testItem;
|
||||
customizationService.init(extensionManager);
|
||||
|
||||
@@ -121,20 +120,17 @@ describe('CustomizationService.ts', () => {
|
||||
describe('mode customization', () => {
|
||||
it('onModeEnter can add extensions', () => {
|
||||
extensionManager.registeredExtensionIds.push('@testExtension');
|
||||
extensionManager.moduleEntries[
|
||||
'@testExtension.customizationModule.default'
|
||||
] = { name: 'default', value: [ohifOverlayItem] };
|
||||
extensionManager.moduleEntries['@testExtension.customizationModule.default'] = {
|
||||
name: 'default',
|
||||
value: [ohifOverlayItem],
|
||||
};
|
||||
customizationService.init(extensionManager);
|
||||
|
||||
expect(
|
||||
customizationService.getModeCustomization('testItem')
|
||||
).toBeUndefined();
|
||||
expect(customizationService.getModeCustomization('testItem')).toBeUndefined();
|
||||
|
||||
customizationService.addModeCustomizations([testItem]);
|
||||
|
||||
expect(
|
||||
customizationService.getGlobalCustomization('testItem')
|
||||
).toBeUndefined();
|
||||
expect(customizationService.getGlobalCustomization('testItem')).toBeUndefined();
|
||||
|
||||
const item = customizationService.getModeCustomization('testItem');
|
||||
|
||||
@@ -147,16 +143,15 @@ describe('CustomizationService.ts', () => {
|
||||
|
||||
it('global customizations override modes', () => {
|
||||
extensionManager.registeredExtensionIds.push('@testExtension');
|
||||
extensionManager.moduleEntries[
|
||||
'@testExtension.customizationModule.default'
|
||||
] = { name: 'default', value: [ohifOverlayItem] };
|
||||
extensionManager.moduleEntries['@testExtension.customizationModule.default'] = {
|
||||
name: 'default',
|
||||
value: [ohifOverlayItem],
|
||||
};
|
||||
configuration.testItem = testItem;
|
||||
customizationService.init(extensionManager);
|
||||
|
||||
// Add a mode customization that would otherwise fail below
|
||||
customizationService.addModeCustomizations([
|
||||
{ ...testItem, label: 'other' },
|
||||
]);
|
||||
customizationService.addModeCustomizations([{ ...testItem, label: 'other' }]);
|
||||
|
||||
const item = customizationService.getModeCustomization('testItem');
|
||||
|
||||
|
||||
@@ -107,10 +107,7 @@ export default class CustomizationService extends PubSubService {
|
||||
return this.modeCustomizations;
|
||||
}
|
||||
|
||||
public setModeCustomization(
|
||||
customizationId: string,
|
||||
customization: Customization
|
||||
): void {
|
||||
public setModeCustomization(customizationId: string, customization: Customization): void {
|
||||
this.modeCustomizations[customizationId] = merge(
|
||||
this.modeCustomizations[customizationId] || {},
|
||||
customization
|
||||
@@ -155,10 +152,7 @@ export default class CustomizationService extends PubSubService {
|
||||
}
|
||||
|
||||
public hasModeCustomization(customizationId: string) {
|
||||
return (
|
||||
this.globalCustomizations[customizationId] ||
|
||||
this.modeCustomizations[customizationId]
|
||||
);
|
||||
return this.globalCustomizations[customizationId] || this.modeCustomizations[customizationId];
|
||||
}
|
||||
/**
|
||||
* get is an alias for getModeCustomization, as it is the generic getter
|
||||
@@ -186,9 +180,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(Object.create(parent), customization) : customization;
|
||||
// Execute an nested type information
|
||||
return result.transform?.(this) || result;
|
||||
}
|
||||
@@ -213,10 +205,7 @@ export default class CustomizationService extends PubSubService {
|
||||
* the modes. They include things like settings for the search screen.
|
||||
* Reset does NOT clear global customizations.
|
||||
*/
|
||||
getGlobalCustomization(
|
||||
id: string,
|
||||
defaultValue?: Customization
|
||||
): Customization | void {
|
||||
getGlobalCustomization(id: string, defaultValue?: Customization): Customization | void {
|
||||
return this.transform(this.globalCustomizations[id] ?? defaultValue);
|
||||
}
|
||||
|
||||
@@ -225,15 +214,10 @@ export default class CustomizationService extends PubSubService {
|
||||
this._broadcastGlobalCustomizationModified();
|
||||
}
|
||||
|
||||
protected setConfigGlobalCustomization(
|
||||
configuration: AppConfigCustomization
|
||||
): void {
|
||||
protected setConfigGlobalCustomization(configuration: AppConfigCustomization): void {
|
||||
this.globalCustomizations = {};
|
||||
const keys = flattenNestedStrings(configuration.globalCustomizations);
|
||||
this.readCustomizationTypes(
|
||||
v => keys[v.name] && v.customization,
|
||||
this.globalCustomizations
|
||||
);
|
||||
this.readCustomizationTypes(v => keys[v.name] && v.customization, this.globalCustomizations);
|
||||
|
||||
// TODO - iterate over customizations, loading them from the extension
|
||||
// manager.
|
||||
@@ -264,10 +248,7 @@ export default class CustomizationService extends PubSubService {
|
||||
this.addReferences(value, isGlobal);
|
||||
} else {
|
||||
const useId = value.id || id;
|
||||
this[isGlobal ? 'setGlobalCustomization' : 'setModeCustomization'](
|
||||
useId as string,
|
||||
value
|
||||
);
|
||||
this[isGlobal ? 'setGlobalCustomization' : 'setModeCustomization'](useId as string, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,9 +54,7 @@ function _getStudyInstanceUIDs() {
|
||||
}
|
||||
|
||||
function _getStudy(StudyInstanceUID) {
|
||||
return _model.studies.find(
|
||||
aStudy => aStudy.StudyInstanceUID === StudyInstanceUID
|
||||
);
|
||||
return _model.studies.find(aStudy => aStudy.StudyInstanceUID === StudyInstanceUID);
|
||||
}
|
||||
|
||||
function _getSeries(StudyInstanceUID, SeriesInstanceUID) {
|
||||
@@ -66,9 +64,7 @@ function _getSeries(StudyInstanceUID, SeriesInstanceUID) {
|
||||
return;
|
||||
}
|
||||
|
||||
return study.series.find(
|
||||
aSeries => aSeries.SeriesInstanceUID === SeriesInstanceUID
|
||||
);
|
||||
return study.series.find(aSeries => aSeries.SeriesInstanceUID === SeriesInstanceUID);
|
||||
}
|
||||
|
||||
function _getInstance(StudyInstanceUID, SeriesInstanceUID, SOPInstanceUID) {
|
||||
@@ -78,9 +74,7 @@ function _getInstance(StudyInstanceUID, SeriesInstanceUID, SOPInstanceUID) {
|
||||
return;
|
||||
}
|
||||
|
||||
return series.instances.find(
|
||||
instance => instance.SOPInstanceUID === SOPInstanceUID
|
||||
);
|
||||
return series.instances.find(instance => instance.SOPInstanceUID === SOPInstanceUID);
|
||||
}
|
||||
|
||||
function _getInstanceByImageId(imageId) {
|
||||
@@ -102,20 +96,14 @@ function _getInstanceByImageId(imageId) {
|
||||
* @param {*} metadata metadata inform of key value pairs
|
||||
* @returns
|
||||
*/
|
||||
function _updateMetadataForSeries(
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
metadata
|
||||
) {
|
||||
function _updateMetadataForSeries(StudyInstanceUID, SeriesInstanceUID, metadata) {
|
||||
const study = _getStudy(StudyInstanceUID);
|
||||
|
||||
if (!study) {
|
||||
return;
|
||||
}
|
||||
|
||||
const series = study.series.find(
|
||||
aSeries => aSeries.SeriesInstanceUID === SeriesInstanceUID
|
||||
);
|
||||
const series = study.series.find(aSeries => aSeries.SeriesInstanceUID === SeriesInstanceUID);
|
||||
|
||||
const { instances } = series;
|
||||
// update all instances metadata for this series with the new metadata
|
||||
@@ -149,9 +137,7 @@ const BaseImplementation = {
|
||||
|
||||
// If Arraybuffer, parse to DICOMJSON before naturalizing.
|
||||
if (dicomJSONDatasetOrP10ArrayBuffer instanceof ArrayBuffer) {
|
||||
const dicomData = dcmjs.data.DicomMessage.readFile(
|
||||
dicomJSONDatasetOrP10ArrayBuffer
|
||||
);
|
||||
const dicomData = dcmjs.data.DicomMessage.readFile(dicomJSONDatasetOrP10ArrayBuffer);
|
||||
|
||||
dicomJSONDataset = dicomData.dict;
|
||||
} else {
|
||||
@@ -161,18 +147,14 @@ const BaseImplementation = {
|
||||
let naturalizedDataset;
|
||||
|
||||
if (dicomJSONDataset['SeriesInstanceUID'] === undefined) {
|
||||
naturalizedDataset = dcmjs.data.DicomMetaDictionary.naturalizeDataset(
|
||||
dicomJSONDataset
|
||||
);
|
||||
naturalizedDataset = dcmjs.data.DicomMetaDictionary.naturalizeDataset(dicomJSONDataset);
|
||||
} else {
|
||||
naturalizedDataset = dicomJSONDataset;
|
||||
}
|
||||
|
||||
const { StudyInstanceUID } = naturalizedDataset;
|
||||
|
||||
let study = _model.studies.find(
|
||||
study => study.StudyInstanceUID === StudyInstanceUID
|
||||
);
|
||||
let study = _model.studies.find(study => study.StudyInstanceUID === StudyInstanceUID);
|
||||
|
||||
if (!study) {
|
||||
_model.studies.push(createStudyMetadata(StudyInstanceUID));
|
||||
@@ -184,9 +166,7 @@ const BaseImplementation = {
|
||||
addInstances(instances, madeInClient = false) {
|
||||
const { StudyInstanceUID, SeriesInstanceUID } = instances[0];
|
||||
|
||||
let study = _model.studies.find(
|
||||
study => study.StudyInstanceUID === StudyInstanceUID
|
||||
);
|
||||
let study = _model.studies.find(study => study.StudyInstanceUID === StudyInstanceUID);
|
||||
|
||||
if (!study) {
|
||||
_model.studies.push(createStudyMetadata(StudyInstanceUID));
|
||||
@@ -236,9 +216,7 @@ const BaseImplementation = {
|
||||
addStudy(study) {
|
||||
const { StudyInstanceUID } = study;
|
||||
|
||||
const existingStudy = _model.studies.find(
|
||||
study => study.StudyInstanceUID === StudyInstanceUID
|
||||
);
|
||||
const existingStudy = _model.studies.find(study => study.StudyInstanceUID === StudyInstanceUID);
|
||||
|
||||
if (!existingStudy) {
|
||||
const newStudy = createStudyMetadata(StudyInstanceUID);
|
||||
|
||||
@@ -12,14 +12,12 @@ function createStudyMetadata(StudyInstanceUID) {
|
||||
* @param {object} instance
|
||||
* @returns {bool} true if series were added; false if series already exist
|
||||
*/
|
||||
addInstanceToSeries: function(instance) {
|
||||
addInstanceToSeries: function (instance) {
|
||||
const { SeriesInstanceUID } = instance;
|
||||
if (!this.StudyDescription) {
|
||||
this.StudyDescription = instance.StudyDescription;
|
||||
}
|
||||
const existingSeries = this.series.find(
|
||||
s => s.SeriesInstanceUID === SeriesInstanceUID
|
||||
);
|
||||
const existingSeries = this.series.find(s => s.SeriesInstanceUID === SeriesInstanceUID);
|
||||
|
||||
if (existingSeries) {
|
||||
existingSeries.instances.push(instance);
|
||||
@@ -39,23 +37,19 @@ function createStudyMetadata(StudyInstanceUID) {
|
||||
* @param {string} instances[].StudyDescription
|
||||
* @returns {bool} true if series were added; false if series already exist
|
||||
*/
|
||||
addInstancesToSeries: function(instances) {
|
||||
addInstancesToSeries: function (instances) {
|
||||
const { SeriesInstanceUID } = instances[0];
|
||||
if (!this.StudyDescription) {
|
||||
this.StudyDescription = instances[0].StudyDescription;
|
||||
}
|
||||
const existingSeries = this.series.find(
|
||||
s => s.SeriesInstanceUID === SeriesInstanceUID
|
||||
);
|
||||
const existingSeries = this.series.find(s => s.SeriesInstanceUID === SeriesInstanceUID);
|
||||
|
||||
if (existingSeries) {
|
||||
// Only add instances not already present, so generate a map
|
||||
// of existing instances and filter the to add by things
|
||||
// already present.
|
||||
const sopMap = {};
|
||||
existingSeries.instances.forEach(
|
||||
it => (sopMap[it.SOPInstanceUID] = it)
|
||||
);
|
||||
existingSeries.instances.forEach(it => (sopMap[it.SOPInstanceUID] = it));
|
||||
const newInstances = instances.filter(it => !sopMap[it.SOPInstanceUID]);
|
||||
existingSeries.instances.push(...newInstances);
|
||||
} else {
|
||||
@@ -64,10 +58,8 @@ function createStudyMetadata(StudyInstanceUID) {
|
||||
}
|
||||
},
|
||||
|
||||
setSeriesMetadata: function(SeriesInstanceUID, seriesMetadata) {
|
||||
let existingSeries = this.series.find(
|
||||
s => s.SeriesInstanceUID === SeriesInstanceUID
|
||||
);
|
||||
setSeriesMetadata: function (SeriesInstanceUID, seriesMetadata) {
|
||||
let existingSeries = this.series.find(s => s.SeriesInstanceUID === SeriesInstanceUID);
|
||||
|
||||
if (existingSeries) {
|
||||
existingSeries = Object.assign(existingSeries, seriesMetadata);
|
||||
|
||||
@@ -19,15 +19,11 @@ const filterInstances = (
|
||||
if (!dsInstances) {
|
||||
console.warn('No instances in', ds);
|
||||
} else {
|
||||
dsInstances.forEach(instance =>
|
||||
dsInstancesSOP.add(instance.SOPInstanceUID)
|
||||
);
|
||||
dsInstances.forEach(instance => dsInstancesSOP.add(instance.SOPInstanceUID));
|
||||
}
|
||||
});
|
||||
|
||||
return instances.filter(
|
||||
instance => !dsInstancesSOP.has(instance.SOPInstanceUID)
|
||||
);
|
||||
return instances.filter(instance => !dsInstancesSOP.has(instance.SOPInstanceUID));
|
||||
};
|
||||
|
||||
export default class DisplaySetService extends PubSubService {
|
||||
@@ -119,9 +115,7 @@ export default class DisplaySetService extends PubSubService {
|
||||
return this.activeDisplaySets;
|
||||
}
|
||||
|
||||
public getDisplaySetsForSeries = (
|
||||
seriesInstanceUID: string
|
||||
): DisplaySet[] => {
|
||||
public getDisplaySetsForSeries = (seriesInstanceUID: string): DisplaySet[] => {
|
||||
return [...displaySetCache.values()].filter(
|
||||
displaySet => displaySet.SeriesInstanceUID === seriesInstanceUID
|
||||
);
|
||||
@@ -137,9 +131,7 @@ export default class DisplaySetService extends PubSubService {
|
||||
: [...this.getDisplaySetCache().values()];
|
||||
|
||||
const displaySet = displaySets.find(ds => {
|
||||
return (
|
||||
ds.images && ds.images.some(i => i.SOPInstanceUID === sopInstanceUID)
|
||||
);
|
||||
return ds.images && ds.images.some(i => i.SOPInstanceUID === sopInstanceUID);
|
||||
});
|
||||
|
||||
return displaySet;
|
||||
@@ -195,18 +187,13 @@ export default class DisplaySetService extends PubSubService {
|
||||
* @param {*} param1: settings: initialViewportSettings by HP or callbacks after rendering
|
||||
* @returns {string[]} - added displaySetInstanceUIDs
|
||||
*/
|
||||
makeDisplaySets = (
|
||||
input,
|
||||
{ batch = false, madeInClient = false, settings = {} } = {}
|
||||
) => {
|
||||
makeDisplaySets = (input, { batch = false, madeInClient = false, settings = {} } = {}) => {
|
||||
if (!input || !input.length) {
|
||||
throw new Error('No instances were provided.');
|
||||
}
|
||||
|
||||
if (batch && !input[0].length) {
|
||||
throw new Error(
|
||||
'Batch displaySet creation does not contain array of array of instances.'
|
||||
);
|
||||
throw new Error('Batch displaySet creation does not contain array of array of instances.');
|
||||
}
|
||||
|
||||
// If array of instances => One instance.
|
||||
@@ -215,10 +202,7 @@ export default class DisplaySetService extends PubSubService {
|
||||
if (batch) {
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
const instances = input[i];
|
||||
const displaySets = this.makeDisplaySetForInstances(
|
||||
instances,
|
||||
settings
|
||||
);
|
||||
const displaySets = this.makeDisplaySetForInstances(instances, settings);
|
||||
|
||||
displaySetsAdded.push(...displaySets);
|
||||
}
|
||||
@@ -272,22 +256,16 @@ export default class DisplaySetService extends PubSubService {
|
||||
* @param settings
|
||||
* @returns
|
||||
*/
|
||||
public makeDisplaySetForInstances(
|
||||
instancesSrc: InstanceMetadata[],
|
||||
settings
|
||||
): DisplaySet[] {
|
||||
public makeDisplaySetForInstances(instancesSrc: InstanceMetadata[], settings): DisplaySet[] {
|
||||
// creating a sopClassUID list and for each sopClass associate its respective
|
||||
// instance list
|
||||
const instancesForSetSOPClasses = instancesSrc.reduce(
|
||||
(sopClassList, instance) => {
|
||||
if (!(instance.SOPClassUID in sopClassList)) {
|
||||
sopClassList[instance.SOPClassUID] = [];
|
||||
}
|
||||
sopClassList[instance.SOPClassUID].push(instance);
|
||||
return sopClassList;
|
||||
},
|
||||
{}
|
||||
);
|
||||
const instancesForSetSOPClasses = instancesSrc.reduce((sopClassList, instance) => {
|
||||
if (!(instance.SOPClassUID in sopClassList)) {
|
||||
sopClassList[instance.SOPClassUID] = [];
|
||||
}
|
||||
sopClassList[instance.SOPClassUID].push(instance);
|
||||
return sopClassList;
|
||||
}, {});
|
||||
// for each sopClassUID, call the old makeDisplaySetForInstances with a
|
||||
// instance list composed only by instances with the same sopClassUID and
|
||||
// accumulate the displaySets in the variable allDisplaySets
|
||||
@@ -319,17 +297,13 @@ export default class DisplaySetService extends PubSubService {
|
||||
* @param settings are settings to add
|
||||
* @returns Array of the display sets added.
|
||||
*/
|
||||
private _makeDisplaySetForInstances(
|
||||
instancesSrc: InstanceMetadata[],
|
||||
settings
|
||||
): DisplaySet[] {
|
||||
private _makeDisplaySetForInstances(instancesSrc: InstanceMetadata[], settings): DisplaySet[] {
|
||||
// Some of the sop class handlers take a direct reference to instances
|
||||
// so make sure it gets copied here so that they have their own ref
|
||||
let instances = [...instancesSrc];
|
||||
const instance = instances[0];
|
||||
|
||||
const existingDisplaySets =
|
||||
this.getDisplaySetsForSeries(instance.SeriesInstanceUID) || [];
|
||||
const existingDisplaySets = this.getDisplaySetsForSeries(instance.SeriesInstanceUID) || [];
|
||||
|
||||
const SOPClassHandlerIds = this.SOPClassHandlerIds;
|
||||
const allDisplaySets = [];
|
||||
@@ -357,9 +331,7 @@ export default class DisplaySetService extends PubSubService {
|
||||
this.activeDisplaySetsChanged = true;
|
||||
instances = filterInstances(instances, [addedDs]);
|
||||
this._addActiveDisplaySets([addedDs]);
|
||||
this.setDisplaySetMetadataInvalidated(
|
||||
addedDs.displaySetInstanceUID
|
||||
);
|
||||
this.setDisplaySetMetadataInvalidated(addedDs.displaySetInstanceUID);
|
||||
}
|
||||
// This means that all instances already existed or got added to
|
||||
// existing display sets, and had an invalidated event fired
|
||||
@@ -405,9 +377,7 @@ export default class DisplaySetService extends PubSubService {
|
||||
// applying the default sopClassUID handler
|
||||
if (allDisplaySets.length === 0) {
|
||||
// applying hp-defined viewport settings to the displaysets
|
||||
const handler = this.extensionManager.getModuleEntry(
|
||||
this.unsuportedSOPClassHandler
|
||||
);
|
||||
const handler = this.extensionManager.getModuleEntry(this.unsuportedSOPClassHandler);
|
||||
const displaySets = handler.getDisplaySetsFromSeries(instances);
|
||||
if (displaySets?.length) {
|
||||
displaySets.forEach(ds => {
|
||||
|
||||
@@ -9,12 +9,7 @@ import validate from './lib/validator';
|
||||
* @param {object[]} options.displaySets is a list of the display sets
|
||||
* @return {Object} Matching Object with score and details (which rule passed or failed)
|
||||
*/
|
||||
const match = (
|
||||
metadataInstance,
|
||||
rules = [],
|
||||
customAttributeRetrievalCallbacks,
|
||||
options
|
||||
) => {
|
||||
const match = (metadataInstance, rules = [], customAttributeRetrievalCallbacks, options) => {
|
||||
const validateOptions = {
|
||||
format: 'grouped',
|
||||
};
|
||||
@@ -46,12 +41,13 @@ const match = (
|
||||
const { attribute, from = 'metadataInstance' } = rule;
|
||||
// Do not use the custom attribute from the metadataInstance since it is subject to change
|
||||
if (customAttributeRetrievalCallbacks.hasOwnProperty(attribute)) {
|
||||
readValues[attribute] = customAttributeRetrievalCallbacks[
|
||||
attribute
|
||||
].callback.call(rule, metadataInstance, options);
|
||||
readValues[attribute] = customAttributeRetrievalCallbacks[attribute].callback.call(
|
||||
rule,
|
||||
metadataInstance,
|
||||
options
|
||||
);
|
||||
} else {
|
||||
readValues[attribute] =
|
||||
fromSrc[from]?.[attribute] ?? instance?.[attribute];
|
||||
readValues[attribute] = fromSrc[from]?.[attribute] ?? instance?.[attribute];
|
||||
}
|
||||
|
||||
// Format the constraint as required by Validate.js
|
||||
|
||||
@@ -149,10 +149,7 @@ describe('HangingProtocolService', () => {
|
||||
},
|
||||
},
|
||||
};
|
||||
const hangingProtocolService = new HangingProtocolService(
|
||||
commandsManager,
|
||||
servicesManager
|
||||
);
|
||||
const hangingProtocolService = new HangingProtocolService(commandsManager, servicesManager);
|
||||
let initialScaling;
|
||||
|
||||
afterEach(() => {
|
||||
@@ -177,10 +174,7 @@ describe('HangingProtocolService', () => {
|
||||
|
||||
describe('with protocol generator', () => {
|
||||
beforeAll(() => {
|
||||
hangingProtocolService.addProtocol(
|
||||
testProtocol.id,
|
||||
testProtocolGenerator
|
||||
);
|
||||
hangingProtocolService.addProtocol(testProtocol.id, testProtocolGenerator);
|
||||
});
|
||||
|
||||
it('has one protocol', () => {
|
||||
|
||||
@@ -8,10 +8,7 @@ import IDisplaySet from '../DisplaySetService/IDisplaySet';
|
||||
import { CommandsManager } from '../../classes';
|
||||
import ServicesManager from '../ServicesManager';
|
||||
import * as HangingProtocol from '../../types/HangingProtocol';
|
||||
import {
|
||||
isDisplaySetFromUrl,
|
||||
sopInstanceLocation,
|
||||
} from './custom-attribute/isDisplaySetFromUrl';
|
||||
import { isDisplaySetFromUrl, sopInstanceLocation } from './custom-attribute/isDisplaySetFromUrl';
|
||||
import numberOfDisplaySetsWithImages from './custom-attribute/numberOfDisplaySetsWithImages';
|
||||
import seriesDescriptionsFromDisplaySets from './custom-attribute/seriesDescriptionsFromDisplaySets';
|
||||
import uuidv4 from '../../utils/uuidv4';
|
||||
@@ -37,8 +34,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
// Fired when the stages within the current protocol are known to have
|
||||
// the status set - that is, they are activated (or deactivated).
|
||||
STAGE_ACTIVATION: 'event::hanging_protocol_stage_activation',
|
||||
CUSTOM_IMAGE_LOAD_PERFORMED:
|
||||
'event::hanging_protocol_custom_image_load_performed',
|
||||
CUSTOM_IMAGE_LOAD_PERFORMED: 'event::hanging_protocol_custom_image_load_performed',
|
||||
};
|
||||
|
||||
public static REGISTRATION = {
|
||||
@@ -74,8 +70,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
customAttributeRetrievalCallbacks = {
|
||||
NumberOfStudyRelatedSeries: {
|
||||
name: 'The number of series in the study',
|
||||
callback: metadata =>
|
||||
metadata.NumberOfStudyRelatedSeries ?? metadata.series?.length,
|
||||
callback: metadata => metadata.NumberOfStudyRelatedSeries ?? metadata.series?.length,
|
||||
},
|
||||
NumberOfSeriesRelatedInstances: {
|
||||
name: 'The number of instances in the display set',
|
||||
@@ -278,9 +273,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
|
||||
if (protocol instanceof Function) {
|
||||
try {
|
||||
const { protocol: generatedProtocol } = this._getProtocolFromGenerator(
|
||||
protocol
|
||||
);
|
||||
const { protocol: generatedProtocol } = this._getProtocolFromGenerator(protocol);
|
||||
|
||||
return generatedProtocol;
|
||||
} catch (error) {
|
||||
@@ -304,9 +297,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
*/
|
||||
public addProtocol(protocolId: string, protocol: Protocol): void {
|
||||
if (this.protocols.has(protocolId)) {
|
||||
console.warn(
|
||||
`A protocol with id ${protocolId} already exists. It will be overwritten.`
|
||||
);
|
||||
console.warn(`A protocol with id ${protocolId} already exists. It will be overwritten.`);
|
||||
}
|
||||
|
||||
if (!(protocol instanceof Function)) {
|
||||
@@ -356,9 +347,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
* specifically, but will show another study instead.
|
||||
*/
|
||||
public setActiveStudyUID(activeStudyUID: string): void {
|
||||
this.activeStudy = this.studies.find(
|
||||
it => it.StudyInstanceUID === activeStudyUID
|
||||
);
|
||||
this.activeStudy = this.studies.find(it => it.StudyInstanceUID === activeStudyUID);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -410,9 +399,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
public hasCustomImageLoadStrategy(): boolean {
|
||||
return (
|
||||
this.activeImageLoadStrategyName !== null &&
|
||||
this.registeredImageLoadStrategies[
|
||||
this.activeImageLoadStrategyName
|
||||
] instanceof Function
|
||||
this.registeredImageLoadStrategies[this.activeImageLoadStrategyName] instanceof Function
|
||||
);
|
||||
}
|
||||
|
||||
@@ -436,9 +423,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
* @returns A boolean indicating whether a custom image load should be performed or not.
|
||||
*/
|
||||
public getShouldPerformCustomImageLoad(): boolean {
|
||||
return (
|
||||
this.hasCustomImageLoadStrategy() && !this.getCustomImageLoadPerformed()
|
||||
);
|
||||
return this.hasCustomImageLoadStrategy() && !this.getCustomImageLoadPerformed();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -464,10 +449,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
public addCustomAttribute(
|
||||
attributeId: string,
|
||||
attributeName: string,
|
||||
callback: (
|
||||
metadata: Record<string, unknown>,
|
||||
extraData?: Record<string, unknown>
|
||||
) => unknown,
|
||||
callback: (metadata: Record<string, unknown>, extraData?: Record<string, unknown>) => unknown,
|
||||
options: Record<string, unknown> = {}
|
||||
): void {
|
||||
this.customAttributeRetrievalCallbacks[attributeId] = {
|
||||
@@ -483,9 +465,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
* if no strategy is set, the default strategy is used
|
||||
*/
|
||||
runImageLoadStrategy(data): boolean {
|
||||
const loader = this.registeredImageLoadStrategies[
|
||||
this.activeImageLoadStrategyName
|
||||
];
|
||||
const loader = this.registeredImageLoadStrategies[this.activeImageLoadStrategyName];
|
||||
const loadedData = loader({
|
||||
data,
|
||||
displaySetsMatchDetails: this.displaySetMatchDetails,
|
||||
@@ -504,9 +484,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
return true;
|
||||
}
|
||||
|
||||
_validateProtocol(
|
||||
protocol: HangingProtocol.Protocol
|
||||
): HangingProtocol.Protocol {
|
||||
_validateProtocol(protocol: HangingProtocol.Protocol): HangingProtocol.Protocol {
|
||||
protocol.id = protocol.id || protocol.name;
|
||||
const defaultViewportOptions = {
|
||||
toolGroupId: 'default',
|
||||
@@ -570,9 +548,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
private _getProtocolFromGenerator(
|
||||
protocolGenerator: HangingProtocol.ProtocolGenerator
|
||||
): {
|
||||
private _getProtocolFromGenerator(protocolGenerator: HangingProtocol.ProtocolGenerator): {
|
||||
protocol: HangingProtocol.Protocol;
|
||||
} {
|
||||
const { protocol } = protocolGenerator({
|
||||
@@ -589,9 +565,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
|
||||
getViewportsRequireUpdate(viewportId, displaySetInstanceUID) {
|
||||
const { displaySetService } = this._servicesManager.services;
|
||||
const displaySet = displaySetService.getDisplaySetByUID(
|
||||
displaySetInstanceUID
|
||||
);
|
||||
const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
|
||||
if (displaySet?.unsupported) {
|
||||
throw new Error('Unsupported displaySet');
|
||||
}
|
||||
@@ -643,12 +617,9 @@ export default class HangingProtocolService extends PubSubService {
|
||||
// if the viewport is not empty, then we check the displaySets it is showing
|
||||
// currently, which means we need to check if the requested updated displaySet
|
||||
// follow the same rules as the current displaySets
|
||||
const {
|
||||
id: displaySetSelectorId,
|
||||
matchedDisplaySetsIndex = 0,
|
||||
} = protocolViewport.displaySets[0];
|
||||
const displaySetSelector =
|
||||
protocol.displaySetSelectors[displaySetSelectorId];
|
||||
const { id: displaySetSelectorId, matchedDisplaySetsIndex = 0 } =
|
||||
protocolViewport.displaySets[0];
|
||||
const displaySetSelector = protocol.displaySetSelectors[displaySetSelectorId];
|
||||
|
||||
if (!displaySetSelector) {
|
||||
return defaultReturn;
|
||||
@@ -704,15 +675,13 @@ export default class HangingProtocolService extends PubSubService {
|
||||
const originalViewportOptions = originalViewport.viewportOptions;
|
||||
const originalDisplaySetOptions = originalViewport.displaySets;
|
||||
|
||||
viewport.viewportOptions = this.getComputedOptions(
|
||||
originalViewportOptions,
|
||||
[newDisplaySetInstanceUID]
|
||||
);
|
||||
viewport.viewportOptions = this.getComputedOptions(originalViewportOptions, [
|
||||
newDisplaySetInstanceUID,
|
||||
]);
|
||||
|
||||
viewport.displaySets = this.getComputedOptions(
|
||||
originalDisplaySetOptions,
|
||||
[newDisplaySetInstanceUID]
|
||||
);
|
||||
viewport.displaySets = this.getComputedOptions(originalDisplaySetOptions, [
|
||||
newDisplaySetInstanceUID,
|
||||
]);
|
||||
}
|
||||
|
||||
const displaySetInstanceUIDs = [];
|
||||
@@ -751,9 +720,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
const { id } = displaySet;
|
||||
const displaySetMatchDetail = displaySetMatchDetails.get(id);
|
||||
|
||||
const {
|
||||
displaySetInstanceUID: oldDisplaySetInstanceUID,
|
||||
} = displaySetMatchDetail;
|
||||
const { displaySetInstanceUID: oldDisplaySetInstanceUID } = displaySetMatchDetail;
|
||||
|
||||
const displaySetInstanceUID =
|
||||
displaySet.id === displaySetSelectorId
|
||||
@@ -781,9 +748,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
): any {
|
||||
// Base case: if options is an array, map over the array and recursively call getComputedOptions
|
||||
if (Array.isArray(options)) {
|
||||
return options.map(option =>
|
||||
this.getComputedOptions(option, displaySetUIDs)
|
||||
);
|
||||
return options.map(option => this.getComputedOptions(option, displaySetUIDs));
|
||||
}
|
||||
|
||||
if (options === null) {
|
||||
@@ -806,8 +771,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
);
|
||||
}
|
||||
|
||||
const callback = this.customAttributeRetrievalCallbacks[customKey]
|
||||
.callback;
|
||||
const callback = this.customAttributeRetrievalCallbacks[customKey].callback;
|
||||
let newOptions = callback.call(options, displaySets);
|
||||
|
||||
if (newOptions === undefined) {
|
||||
@@ -912,18 +876,12 @@ export default class HangingProtocolService extends PubSubService {
|
||||
*
|
||||
* @returns the stage number to apply initially, given the options.
|
||||
*/
|
||||
private _updateStageStatus(
|
||||
options = null as HangingProtocol.SetProtocolOptions
|
||||
) {
|
||||
private _updateStageStatus(options = null as HangingProtocol.SetProtocolOptions) {
|
||||
const stages = this.protocol.stages;
|
||||
for (let i = 0; i < stages.length; i++) {
|
||||
const stage = stages[i];
|
||||
|
||||
const { matchedViewports } = this._matchAllViewports(
|
||||
stage,
|
||||
options,
|
||||
new Map()
|
||||
);
|
||||
const { matchedViewports } = this._matchAllViewports(stage, options, new Map());
|
||||
const activation = stage.stageActivation || {};
|
||||
if (this.matchActivation(matchedViewports, activation.passive, 0)) {
|
||||
if (this.matchActivation(matchedViewports, activation.enabled, 1)) {
|
||||
@@ -942,9 +900,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
});
|
||||
}
|
||||
|
||||
private _findStageIndex(
|
||||
options = null as HangingProtocol.SetProtocolOptions
|
||||
): number | void {
|
||||
private _findStageIndex(options = null as HangingProtocol.SetProtocolOptions): number | void {
|
||||
const stageId = options?.stageId;
|
||||
const protocol = this.protocol;
|
||||
const stages = protocol.stages;
|
||||
@@ -993,10 +949,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
const { imageLoadStrategy } = protocol;
|
||||
if (imageLoadStrategy) {
|
||||
// check if the imageLoadStrategy is a valid strategy
|
||||
if (
|
||||
this.registeredImageLoadStrategies[imageLoadStrategy] instanceof
|
||||
Function
|
||||
) {
|
||||
if (this.registeredImageLoadStrategies[imageLoadStrategy] instanceof Function) {
|
||||
this.activeImageLoadStrategyName = imageLoadStrategy;
|
||||
}
|
||||
}
|
||||
@@ -1006,9 +959,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
|
||||
const stage = this._findStageIndex(options);
|
||||
if (stage === undefined) {
|
||||
throw new Error(
|
||||
`Can't find applicable stage ${protocol.id} ${options?.stageIndex}`
|
||||
);
|
||||
throw new Error(`Can't find applicable stage ${protocol.id} ${options?.stageIndex}`);
|
||||
}
|
||||
this.stageIndex = stage as number;
|
||||
this._updateViewports(options);
|
||||
@@ -1054,11 +1005,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
* undefined if no protocol or stages are set
|
||||
*/
|
||||
_getNumProtocolStages() {
|
||||
if (
|
||||
!this.protocol ||
|
||||
!this.protocol.stages ||
|
||||
!this.protocol.stages.length
|
||||
) {
|
||||
if (!this.protocol || !this.protocol.stages || !this.protocol.stages.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1201,9 +1148,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
) {
|
||||
matchedViewports++;
|
||||
} else {
|
||||
console.log(
|
||||
'Adding an empty set of display sets for mapping purposes'
|
||||
);
|
||||
console.log('Adding an empty set of display sets for mapping purposes');
|
||||
matchDetails.displaySetsInfo = viewport.displaySets.map(it => ({
|
||||
displaySetOptions: it,
|
||||
}));
|
||||
@@ -1236,11 +1181,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
return matchDetails;
|
||||
}
|
||||
for (let i = 0; i < matchDetails.matchingScores.length; i++) {
|
||||
if (
|
||||
inDisplay.indexOf(
|
||||
matchDetails.matchingScores[i].displaySetInstanceUID
|
||||
) === -1
|
||||
) {
|
||||
if (inDisplay.indexOf(matchDetails.matchingScores[i].displaySetInstanceUID) === -1) {
|
||||
const match = matchDetails.matchingScores[i];
|
||||
return match.matchingScore > 0
|
||||
? {
|
||||
@@ -1272,9 +1213,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new Error(
|
||||
`Reused viewport details ${id} with ds ${displaySetUID} not valid`
|
||||
);
|
||||
throw new Error(`Reused viewport details ${id} with ds ${displaySetUID} not valid`);
|
||||
}
|
||||
|
||||
protected _matchViewport(
|
||||
@@ -1296,9 +1235,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
console.warn('No display set selector for', displaySetId);
|
||||
continue;
|
||||
}
|
||||
const { bestMatch, matchingScores } = this._matchImages(
|
||||
displaySetSelector
|
||||
);
|
||||
const { bestMatch, matchingScores } = this._matchImages(displaySetSelector);
|
||||
displaySetMatchDetails.set(displaySetId, bestMatch);
|
||||
|
||||
if (bestMatch) {
|
||||
@@ -1315,10 +1252,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
viewport.displaySets.forEach(displaySetOptions => {
|
||||
const { id, matchedDisplaySetsIndex = 0 } = displaySetOptions;
|
||||
const reuseDisplaySetUID =
|
||||
id &&
|
||||
displaySetSelectorMap[
|
||||
`${activeStudyUID}:${id}:${matchedDisplaySetsIndex || 0}`
|
||||
];
|
||||
id && displaySetSelectorMap[`${activeStudyUID}:${id}:${matchedDisplaySetsIndex || 0}`];
|
||||
const viewportDisplaySetMain = this.displaySetMatchDetails.get(id);
|
||||
|
||||
const viewportDisplaySet = this.findDeduplicatedMatchDetails(
|
||||
@@ -1330,11 +1264,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
// Use the display set provided instead
|
||||
if (reuseDisplaySetUID) {
|
||||
if (viewportOptions.allowUnmatchedView !== true) {
|
||||
this.validateDisplaySetSelectMatch(
|
||||
viewportDisplaySet,
|
||||
id,
|
||||
reuseDisplaySetUID
|
||||
);
|
||||
this.validateDisplaySetSelectMatch(viewportDisplaySet, id, reuseDisplaySetUID);
|
||||
}
|
||||
const displaySetInfo: HangingProtocol.DisplaySetInfo = {
|
||||
displaySetInstanceUID: reuseDisplaySetUID,
|
||||
@@ -1378,8 +1308,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
): void {
|
||||
const { displaySetService } = this._servicesManager.services;
|
||||
const protocolViewportDisplaySets = protocolViewport.displaySets;
|
||||
const numDisplaySetsToSet =
|
||||
displaySetAndViewportOptions.displaySetInstanceUIDs.length;
|
||||
const numDisplaySetsToSet = displaySetAndViewportOptions.displaySetInstanceUIDs.length;
|
||||
|
||||
if (
|
||||
protocolViewportDisplaySets.length > 0 &&
|
||||
@@ -1390,24 +1319,20 @@ export default class HangingProtocolService extends PubSubService {
|
||||
);
|
||||
}
|
||||
|
||||
displaySetAndViewportOptions.displaySetInstanceUIDs.forEach(
|
||||
displaySetInstanceUID => {
|
||||
const displaySet = displaySetService.getDisplaySetByUID(
|
||||
displaySetInstanceUID
|
||||
);
|
||||
displaySetAndViewportOptions.displaySetInstanceUIDs.forEach(displaySetInstanceUID => {
|
||||
const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
|
||||
|
||||
const { displaySets: displaySetsInfo } = protocolViewport;
|
||||
const { displaySets: displaySetsInfo } = protocolViewport;
|
||||
|
||||
for (const displaySetInfo of displaySetsInfo) {
|
||||
const displaySetSelector = displaySetSelectors[displaySetInfo.id];
|
||||
for (const displaySetInfo of displaySetsInfo) {
|
||||
const displaySetSelector = displaySetSelectors[displaySetInfo.id];
|
||||
|
||||
if (!displaySetSelector) {
|
||||
continue;
|
||||
}
|
||||
this._validateRequiredSelectors(displaySetSelector, displaySet);
|
||||
if (!displaySetSelector) {
|
||||
continue;
|
||||
}
|
||||
this._validateRequiredSelectors(displaySetSelector, displaySet);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private _validateRequiredSelectors(
|
||||
@@ -1433,19 +1358,15 @@ export default class HangingProtocolService extends PubSubService {
|
||||
const { displaySetService } = this._servicesManager.services;
|
||||
const { displaySetSelectorMap } = options;
|
||||
if (displaySetSelectorMap) {
|
||||
Object.entries(displaySetSelectorMap).forEach(
|
||||
([key, displaySetInstanceUID]) => {
|
||||
const displaySet = displaySetService.getDisplaySetByUID(
|
||||
displaySetInstanceUID
|
||||
);
|
||||
Object.entries(displaySetSelectorMap).forEach(([key, displaySetInstanceUID]) => {
|
||||
const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
|
||||
|
||||
if (!displaySet) {
|
||||
throw new Error(
|
||||
`The displaySetInstanceUID ${displaySetInstanceUID} is not found in the displaySetService`
|
||||
);
|
||||
}
|
||||
if (!displaySet) {
|
||||
throw new Error(
|
||||
`The displaySetInstanceUID ${displaySetInstanceUID} is not found in the displaySetService`
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1455,20 +1376,12 @@ export default class HangingProtocolService extends PubSubService {
|
||||
// level matching needs to be added in future
|
||||
|
||||
// Todo: handle fusion viewports by not taking the first displaySet rule for the viewport
|
||||
const {
|
||||
id,
|
||||
studyMatchingRules = [],
|
||||
seriesMatchingRules,
|
||||
} = displaySetRules;
|
||||
const { id, studyMatchingRules = [], seriesMatchingRules } = displaySetRules;
|
||||
|
||||
const matchingScores = [];
|
||||
let highestSeriesMatchingScore = 0;
|
||||
|
||||
console.log(
|
||||
'ProtocolEngine::matchImages',
|
||||
studyMatchingRules,
|
||||
seriesMatchingRules
|
||||
);
|
||||
console.log('ProtocolEngine::matchImages', studyMatchingRules, seriesMatchingRules);
|
||||
const matchActiveOnly = this.protocol.numberOfPriorsReferenced === -1;
|
||||
this.studies.forEach((study, studyInstanceUIDsIndex) => {
|
||||
// Skip non-active if active only
|
||||
@@ -1480,35 +1393,22 @@ export default class HangingProtocolService extends PubSubService {
|
||||
it => it.StudyInstanceUID === study.StudyInstanceUID && !it?.unsupported
|
||||
);
|
||||
|
||||
const studyMatchDetails = this.protocolEngine.findMatch(
|
||||
study,
|
||||
studyMatchingRules,
|
||||
{
|
||||
studies: this.studies,
|
||||
displaySets: studyDisplaySets,
|
||||
allDisplaySets: this.displaySets,
|
||||
displaySetMatchDetails: this.displaySetMatchDetails,
|
||||
studyInstanceUIDsIndex,
|
||||
}
|
||||
);
|
||||
const studyMatchDetails = this.protocolEngine.findMatch(study, studyMatchingRules, {
|
||||
studies: this.studies,
|
||||
displaySets: studyDisplaySets,
|
||||
allDisplaySets: this.displaySets,
|
||||
displaySetMatchDetails: this.displaySetMatchDetails,
|
||||
studyInstanceUIDsIndex,
|
||||
});
|
||||
|
||||
// Prevent bestMatch from being updated if the matchDetails' required attribute check has failed
|
||||
if (studyMatchDetails.requiredFailed === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.debug(
|
||||
'study',
|
||||
study.StudyInstanceUID,
|
||||
'display sets #',
|
||||
studyDisplaySets.length
|
||||
);
|
||||
this.debug('study', study.StudyInstanceUID, 'display sets #', studyDisplaySets.length);
|
||||
studyDisplaySets.forEach(displaySet => {
|
||||
const {
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
displaySetInstanceUID,
|
||||
} = displaySet;
|
||||
const { StudyInstanceUID, SeriesInstanceUID, displaySetInstanceUID } = displaySet;
|
||||
const seriesMatchDetails = this.protocolEngine.findMatch(
|
||||
displaySet,
|
||||
seriesMatchingRules,
|
||||
@@ -1523,41 +1423,25 @@ export default class HangingProtocolService extends PubSubService {
|
||||
|
||||
// Prevent bestMatch from being updated if the matchDetails' required attribute check has failed
|
||||
if (seriesMatchDetails.requiredFailed === true) {
|
||||
this.debug(
|
||||
'Display set required failed',
|
||||
displaySet,
|
||||
seriesMatchingRules
|
||||
);
|
||||
this.debug('Display set required failed', displaySet, seriesMatchingRules);
|
||||
return;
|
||||
}
|
||||
|
||||
this.debug('Found displaySet for rules', displaySet);
|
||||
highestSeriesMatchingScore = Math.max(
|
||||
seriesMatchDetails.score,
|
||||
highestSeriesMatchingScore
|
||||
);
|
||||
highestSeriesMatchingScore = Math.max(seriesMatchDetails.score, highestSeriesMatchingScore);
|
||||
|
||||
const matchDetails = {
|
||||
passed: [],
|
||||
failed: [],
|
||||
};
|
||||
|
||||
matchDetails.passed = matchDetails.passed.concat(
|
||||
seriesMatchDetails.details.passed
|
||||
);
|
||||
matchDetails.passed = matchDetails.passed.concat(
|
||||
studyMatchDetails.details.passed
|
||||
);
|
||||
matchDetails.passed = matchDetails.passed.concat(seriesMatchDetails.details.passed);
|
||||
matchDetails.passed = matchDetails.passed.concat(studyMatchDetails.details.passed);
|
||||
|
||||
matchDetails.failed = matchDetails.failed.concat(
|
||||
seriesMatchDetails.details.failed
|
||||
);
|
||||
matchDetails.failed = matchDetails.failed.concat(
|
||||
studyMatchDetails.details.failed
|
||||
);
|
||||
matchDetails.failed = matchDetails.failed.concat(seriesMatchDetails.details.failed);
|
||||
matchDetails.failed = matchDetails.failed.concat(studyMatchDetails.details.failed);
|
||||
|
||||
const totalMatchScore =
|
||||
seriesMatchDetails.score + studyMatchDetails.score;
|
||||
const totalMatchScore = seriesMatchDetails.score + studyMatchDetails.score;
|
||||
|
||||
const imageDetails = {
|
||||
StudyInstanceUID,
|
||||
@@ -1593,17 +1477,11 @@ export default class HangingProtocolService extends PubSubService {
|
||||
},
|
||||
this._getSeriesFieldForDisplaySetSort()
|
||||
);
|
||||
matchingScores.sort((a, b) =>
|
||||
sortingFunction(a.sortingInfo, b.sortingInfo)
|
||||
);
|
||||
matchingScores.sort((a, b) => sortingFunction(a.sortingInfo, b.sortingInfo));
|
||||
|
||||
const bestMatch = matchingScores[0];
|
||||
|
||||
console.log(
|
||||
'ProtocolEngine::matchImages bestMatch',
|
||||
bestMatch,
|
||||
matchingScores
|
||||
);
|
||||
console.log('ProtocolEngine::matchImages bestMatch', bestMatch, matchingScores);
|
||||
|
||||
return {
|
||||
bestMatch,
|
||||
@@ -1672,9 +1550,7 @@ export default class HangingProtocolService extends PubSubService {
|
||||
this.stageIndex = i;
|
||||
|
||||
// Log the new stage
|
||||
this.debug(
|
||||
`ProtocolEngine::setCurrentProtocolStage stage = ${this.stageIndex}`
|
||||
);
|
||||
this.debug(`ProtocolEngine::setCurrentProtocolStage stage = ${this.stageIndex}`);
|
||||
|
||||
// Since stage has changed, we need to update the viewports
|
||||
// and redo matchings
|
||||
|
||||
@@ -92,12 +92,7 @@ export default class ProtocolEngine {
|
||||
* @returns
|
||||
*/
|
||||
findMatch(metaData, rules, options) {
|
||||
return HPMatcher.match(
|
||||
metaData,
|
||||
rules,
|
||||
this.customAttributeRetrievalCallbacks,
|
||||
options
|
||||
);
|
||||
return HPMatcher.match(metaData, rules, this.customAttributeRetrievalCallbacks, options);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,8 +137,7 @@ export default class ProtocolEngine {
|
||||
// if not select the first protocol in the list
|
||||
if (!matched.length) {
|
||||
const protocol =
|
||||
this.protocols.find(protocol => protocol.id === 'default') ??
|
||||
this.protocols[0];
|
||||
this.protocols.find(protocol => protocol.id === 'default') ?? this.protocols[0];
|
||||
console.log('No protocol matches, defaulting to', protocol);
|
||||
return [
|
||||
{
|
||||
@@ -174,9 +168,7 @@ export default class ProtocolEngine {
|
||||
if (!Object.keys(this.matchedProtocolScores).length) {
|
||||
return;
|
||||
}
|
||||
const highestScoringProtocolId = this._largestKeyByValue(
|
||||
this.matchedProtocolScores
|
||||
);
|
||||
const highestScoringProtocolId = this._largestKeyByValue(this.matchedProtocolScores);
|
||||
return this.matchedProtocols.get(highestScoringProtocolId);
|
||||
}
|
||||
}
|
||||
+2
-7
@@ -8,19 +8,14 @@ import { getSplitParam } from '../../../utils';
|
||||
*/
|
||||
const isDisplaySetFromUrl = (displaySet): boolean => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const initialSeriesInstanceUID = getSplitParam(
|
||||
'initialseriesinstanceuid',
|
||||
params
|
||||
);
|
||||
const initialSeriesInstanceUID = getSplitParam('initialseriesinstanceuid', params);
|
||||
const initialSOPInstanceUID = getSplitParam('initialsopinstanceuid', params);
|
||||
if (!initialSeriesInstanceUID && !initialSOPInstanceUID) {
|
||||
return false;
|
||||
}
|
||||
const isSeriesMatch =
|
||||
!initialSeriesInstanceUID ||
|
||||
initialSeriesInstanceUID.some(
|
||||
seriesUID => displaySet.SeriesInstanceUID === seriesUID
|
||||
);
|
||||
initialSeriesInstanceUID.some(seriesUID => displaySet.SeriesInstanceUID === seriesUID);
|
||||
const isSopMatch =
|
||||
!initialSOPInstanceUID ||
|
||||
displaySet.instances?.some?.(instance =>
|
||||
|
||||
+1
-2
@@ -1,6 +1,5 @@
|
||||
export default (study, extraData) => {
|
||||
const ret = extraData?.displaySets?.filter(ds => ds.numImageFrames > 0)
|
||||
?.length;
|
||||
const ret = extraData?.displaySets?.filter(ds => ds.numImageFrames > 0)?.length;
|
||||
console.log('number of display sets with images', ret);
|
||||
return ret;
|
||||
};
|
||||
+1
-2
@@ -1,2 +1 @@
|
||||
export default (study, extraData) =>
|
||||
extraData?.displaySets?.map(ds => ds.SeriesDescription);
|
||||
export default (study, extraData) => extraData?.displaySets?.map(ds => ds.SeriesDescription);
|
||||
@@ -64,8 +64,7 @@ function displayConstraint(attributeId, constraint, attributes) {
|
||||
}
|
||||
|
||||
const attributeText = getAttributeText(attributeId, attributes);
|
||||
const constraintText =
|
||||
attributeText + ' ' + humanize(comparator).toLowerCase() + ' ' + value;
|
||||
const constraintText = attributeText + ' ' + humanize(comparator).toLowerCase() + ' ' + value;
|
||||
|
||||
return constraintText;
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import validate from 'validate.js';
|
||||
* = 'Attenuation' (Fail)
|
||||
*
|
||||
* */
|
||||
validate.validators.equals = function(value, options, key) {
|
||||
validate.validators.equals = function (value, options, key) {
|
||||
const testValue = getTestValue(options);
|
||||
const dicomArrayValue = dicomTagToArray(value);
|
||||
|
||||
@@ -60,7 +60,7 @@ validate.validators.equals = function(value, options, key) {
|
||||
* = 'Attenuation Corrected' (Fail)
|
||||
* = 'Attenuation' (Fail)
|
||||
* */
|
||||
validate.validators.doesNotEqual = function(value, options, key) {
|
||||
validate.validators.doesNotEqual = function (value, options, key) {
|
||||
const testValue = getTestValue(options);
|
||||
const dicomArrayValue = dicomTagToArray(value);
|
||||
|
||||
@@ -103,16 +103,14 @@ validate.validators.doesNotEqual = function(value, options, key) {
|
||||
* testValue = ['Attenuation Corrected', 'Corrected'] (Valid)
|
||||
* = ['Attenuation', 'Corrected'] (Fail)
|
||||
* */
|
||||
validate.validators.includes = function(value, options, key) {
|
||||
validate.validators.includes = function (value, options, key) {
|
||||
const testValue = getTestValue(options);
|
||||
const dicomArrayValue = dicomTagToArray(value);
|
||||
|
||||
if (Array.isArray(testValue)) {
|
||||
const includedValues = testValue.filter(el => dicomArrayValue.includes(el));
|
||||
if (includedValues.length === 0) {
|
||||
return `${key} must include at least one of the following values: ${testValue.join(
|
||||
', '
|
||||
)}`;
|
||||
return `${key} must include at least one of the following values: ${testValue.join(', ')}`;
|
||||
}
|
||||
} else {
|
||||
return `${key} ${testValue} must be an array`;
|
||||
@@ -141,7 +139,7 @@ validate.validators.includes = function(value, options, key) {
|
||||
* testValue = ['Attenuation Corrected', 'Corrected'] (Fail)
|
||||
* = ['Attenuation', 'Corrected'] (Valid)
|
||||
* */
|
||||
validate.validators.doesNotInclude = function(value, options, key) {
|
||||
validate.validators.doesNotInclude = function (value, options, key) {
|
||||
const testValue = getTestValue(options);
|
||||
const dicomArrayValue = dicomTagToArray(value);
|
||||
|
||||
@@ -175,36 +173,23 @@ validate.validators.doesNotInclude = function(value, options, key) {
|
||||
* = ['cat', 'dog'] (Fail)
|
||||
*
|
||||
* */
|
||||
validate.validators.containsI = function(value, options, key) {
|
||||
validate.validators.containsI = function (value, options, key) {
|
||||
const testValue = getTestValue(options);
|
||||
if (Array.isArray(value)) {
|
||||
if (
|
||||
value.some(
|
||||
item => !validate.validators.containsI(item.toLowerCase(), options, key)
|
||||
)
|
||||
) {
|
||||
if (value.some(item => !validate.validators.containsI(item.toLowerCase(), options, key))) {
|
||||
return undefined;
|
||||
}
|
||||
return `No item of ${value.join(',')} contains ${JSON.stringify(
|
||||
testValue
|
||||
)}`;
|
||||
return `No item of ${value.join(',')} contains ${JSON.stringify(testValue)}`;
|
||||
}
|
||||
if (Array.isArray(testValue)) {
|
||||
if (
|
||||
testValue.some(
|
||||
subTest =>
|
||||
!validate.validators.containsI(value, subTest.toLowerCase(), key)
|
||||
)
|
||||
testValue.some(subTest => !validate.validators.containsI(value, subTest.toLowerCase(), key))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
return `${key} must contain at least one of ${testValue.join(',')}`;
|
||||
}
|
||||
if (
|
||||
testValue &&
|
||||
value.indexOf &&
|
||||
value.toLowerCase().indexOf(testValue.toLowerCase()) === -1
|
||||
) {
|
||||
if (testValue && value.indexOf && value.toLowerCase().indexOf(testValue.toLowerCase()) === -1) {
|
||||
return key + 'must contain any case of' + testValue;
|
||||
}
|
||||
};
|
||||
@@ -224,22 +209,16 @@ validate.validators.containsI = function(value, options, key) {
|
||||
* = ['cat', 'dog'] (Fail)
|
||||
*
|
||||
* */
|
||||
validate.validators.contains = function(value, options, key) {
|
||||
validate.validators.contains = function (value, options, key) {
|
||||
const testValue = getTestValue(options);
|
||||
if (Array.isArray(value)) {
|
||||
if (value.some(item => !validate.validators.contains(item, options, key))) {
|
||||
return undefined;
|
||||
}
|
||||
return `No item of ${value.join(',')} contains ${JSON.stringify(
|
||||
testValue
|
||||
)}`;
|
||||
return `No item of ${value.join(',')} contains ${JSON.stringify(testValue)}`;
|
||||
}
|
||||
if (Array.isArray(testValue)) {
|
||||
if (
|
||||
testValue.some(
|
||||
subTest => !validate.validators.contains(value, subTest, key)
|
||||
)
|
||||
) {
|
||||
if (testValue.some(subTest => !validate.validators.contains(value, subTest, key))) {
|
||||
return;
|
||||
}
|
||||
return `${key} must contain at least one of ${testValue.join(',')}`;
|
||||
@@ -264,7 +243,7 @@ validate.validators.contains = function(value, options, key) {
|
||||
* = ['cat', 'dog'] (Valid)
|
||||
*
|
||||
* */
|
||||
validate.validators.doesNotContain = function(value, options, key) {
|
||||
validate.validators.doesNotContain = function (value, options, key) {
|
||||
const containsResult = validate.validators.contains(value, options, key);
|
||||
if (!containsResult) {
|
||||
return `No item of ${value} should contain ${getTestValue(options)}`;
|
||||
@@ -287,7 +266,7 @@ validate.validators.doesNotContain = function(value, options, key) {
|
||||
* = ['cat', 'dog'] (Valid)
|
||||
*
|
||||
* */
|
||||
validate.validators.doesNotContainI = function(value, options, key) {
|
||||
validate.validators.doesNotContainI = function (value, options, key) {
|
||||
const containsResult = validate.validators.containsI(value, options, key);
|
||||
if (!containsResult) {
|
||||
return `No item of ${value} should not contain ${getTestValue(options)}`;
|
||||
@@ -308,7 +287,7 @@ validate.validators.doesNotContainI = function(value, options, key) {
|
||||
* = ['cat', 'dog'] (Fail)
|
||||
*
|
||||
* */
|
||||
validate.validators.startsWith = function(value, options, key) {
|
||||
validate.validators.startsWith = function (value, options, key) {
|
||||
let testValues = getTestValue(options);
|
||||
|
||||
if (typeof testValues === 'string') {
|
||||
@@ -356,7 +335,7 @@ validate.validators.startsWith = function(value, options, key) {
|
||||
* = ['cat', 'dog'] (Fail)
|
||||
*
|
||||
* */
|
||||
validate.validators.endsWith = function(value, options, key) {
|
||||
validate.validators.endsWith = function (value, options, key) {
|
||||
let testValues = getTestValue(options);
|
||||
|
||||
if (typeof testValues === 'string') {
|
||||
@@ -395,7 +374,7 @@ validate.validators.endsWith = function(value, options, key) {
|
||||
* = 40 (Fail)
|
||||
*
|
||||
* */
|
||||
validate.validators.greaterThan = function(value, options, key) {
|
||||
validate.validators.greaterThan = function (value, options, key) {
|
||||
const testValue = getTestValue(options);
|
||||
if (Array.isArray(value) || typeof value === 'string') {
|
||||
return `${key} is not allowed as an array or string`;
|
||||
@@ -421,7 +400,7 @@ validate.validators.greaterThan = function(value, options, key) {
|
||||
* = 20 (Fail)
|
||||
*
|
||||
* */
|
||||
validate.validators.lessThan = function(value, options, key) {
|
||||
validate.validators.lessThan = function (value, options, key) {
|
||||
const testValue = getTestValue(options);
|
||||
if (Array.isArray(testValue)) {
|
||||
if (testValue.length === 1) {
|
||||
@@ -450,7 +429,7 @@ validate.validators.lessThan = function(value, options, key) {
|
||||
* = [45] (Fail)
|
||||
*
|
||||
* */
|
||||
validate.validators.range = function(value, options, key) {
|
||||
validate.validators.range = function (value, options, key) {
|
||||
const testValue = getTestValue(options);
|
||||
if (Array.isArray(testValue) && testValue.length === 2) {
|
||||
const min = Math.min(testValue[0], testValue[1]);
|
||||
|
||||
@@ -17,176 +17,98 @@ describe('validator', () => {
|
||||
describe('equals', () => {
|
||||
it('returned undefined on strictly equals', () => {
|
||||
expect(
|
||||
validate(attributeMap, { listStr: { equals: ['Attenuation'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { listStr: { equals: ['Attenuation'] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { listStr: { equals: 'Attenuation' } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { listStr: { equals: 'Attenuation' } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ listStr: { equals: 'Attenuation Corrected' } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { listStr: { equals: 'Attenuation Corrected' } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ listStr: { equals: ['Attenuation Corrected'] } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { listStr: { equals: ['Attenuation Corrected'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { equals: 'Attenuation Corrected' } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { str: { equals: 'Attenuation Corrected' } }, [options])
|
||||
).toBeUndefined();
|
||||
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ str: { equals: { value: 'Attenuation Corrected' } } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { str: { equals: { value: 'Attenuation Corrected' } } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { equals: ['Attenuation Corrected'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { str: { equals: ['Attenuation Corrected'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { equals: ['Attenuation'] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { equals: ['abc', 'def', 'GHI'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { list: { equals: ['abc', 'def', 'GHI'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { equals: ['abc', 'GHI', 'def'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { list: { equals: ['abc', 'GHI', 'def'] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ list: { equals: { value: ['abc', 'def', 'GHI'] } } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { list: { equals: { value: ['abc', 'def', 'GHI'] } } }, [options])
|
||||
).toBeUndefined();
|
||||
});
|
||||
});
|
||||
describe('doesNotEqual', () => {
|
||||
it('returns undefined if value does not equal ', () => {
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ listStr: { doesNotEqual: 'Attenuation Corrected' } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { listStr: { doesNotEqual: 'Attenuation Corrected' } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ listStr: { doesNotEqual: ['Attenuation Corrected'] } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { listStr: { doesNotEqual: ['Attenuation Corrected'] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { listStr: { doesNotEqual: 'Attenuation' } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { listStr: { doesNotEqual: 'Attenuation' } }, [options])
|
||||
).toBeUndefined();
|
||||
|
||||
expect(
|
||||
validate(attributeMap, { str: { doesNotEqual: 'Attenuation' } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { str: { doesNotEqual: 'Attenuation' } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ str: { doesNotEqual: { value: 'Attenuation' } } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { str: { doesNotEqual: { value: 'Attenuation' } } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { doesNotEqual: ['Attenuation'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { str: { doesNotEqual: ['Attenuation'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { doesNotEqual: ['abc', 'def'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { str: { doesNotEqual: ['abc', 'def'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ list: { doesNotEqual: ['abc', 'GHI', 'def'] } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { list: { doesNotEqual: ['abc', 'GHI', 'def'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ list: { doesNotEqual: ['abc', 'def', 'GHI'] } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { list: { doesNotEqual: ['abc', 'def', 'GHI'] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
});
|
||||
});
|
||||
describe('includes', () => {
|
||||
it('returns match any list includes', () => {
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ listStr: { includes: 'Attenuation Corrected' } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { listStr: { includes: 'Attenuation Corrected' } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ listStr: { includes: ['Attenuation Corrected'] } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { listStr: { includes: ['Attenuation Corrected'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ listStr: { includes: ['Attenuation Corrected', 'Corrected'] } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { listStr: { includes: ['Attenuation Corrected', 'Corrected'] } }, [
|
||||
options,
|
||||
])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ listStr: { includes: ['Attenuation', 'Corrected'] } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { listStr: { includes: ['Attenuation', 'Corrected'] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ str: { includes: ['Attenuation Corrected', 'Corrected'] } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { str: { includes: ['Attenuation Corrected', 'Corrected'] } }, [
|
||||
options,
|
||||
])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ str: { includes: ['Attenuation', 'Corrected'] } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { str: { includes: ['Attenuation', 'Corrected'] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { includes: ['abc'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(validate(attributeMap, { list: { includes: ['abc'] } }, [options])).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { includes: ['GHI', 'HI'] } }, [options])
|
||||
).toBeUndefined();
|
||||
@@ -198,11 +120,7 @@ describe('validator', () => {
|
||||
describe('doesNotInclude', () => {
|
||||
it('returns undefined if list does not includes', () => {
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ listStr: { doesNotInclude: 'Attenuation Corrected' } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { listStr: { doesNotInclude: 'Attenuation Corrected' } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(
|
||||
@@ -214,11 +132,9 @@ describe('validator', () => {
|
||||
)
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ listStr: { doesNotInclude: ['Attenuation', 'Corrected'] } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { listStr: { doesNotInclude: ['Attenuation', 'Corrected'] } }, [
|
||||
options,
|
||||
])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(
|
||||
@@ -228,116 +144,74 @@ describe('validator', () => {
|
||||
)
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ str: { doesNotInclude: ['Attenuation', 'Corrected'] } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { str: { doesNotInclude: ['Attenuation', 'Corrected'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { doesNotInclude: ['Corr'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { list: { doesNotInclude: ['Corr'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { doesNotInclude: 'abc' } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ list: { doesNotInclude: { value: ['abc'] } } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { list: { doesNotInclude: { value: ['abc'] } } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ list: { doesNotInclude: { value: ['att', 'cor'] } } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { list: { doesNotInclude: { value: ['att', 'cor'] } } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ list: { doesNotInclude: { value: ['abc', 'def', 'dog'] } } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { list: { doesNotInclude: { value: ['abc', 'def', 'dog'] } } }, [
|
||||
options,
|
||||
])
|
||||
).not.toBeUndefined();
|
||||
});
|
||||
});
|
||||
describe('containsI', () => {
|
||||
it('returns match any list contains case insensitive', () => {
|
||||
expect(
|
||||
validate(attributeMap, { upper: { containsI: ['hi', 'pre'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { upper: { containsI: ['hi', 'pre'] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(validate(attributeMap, { list: { containsI: 'hi' } }, [options])).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { containsI: 'hi' } }, [options])
|
||||
validate(attributeMap, { list: { containsI: ['ghi', 'bye'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { containsI: ['ghi', 'bye'] } }, [
|
||||
options,
|
||||
])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { containsI: ['bye', 'hi'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { list: { containsI: ['bye', 'hi'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { containsI: ['ig', 'hi'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { upper: { containsI: ['bye', 'per'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { upper: { containsI: ['bye', 'per'] } }, [options])
|
||||
).toBeUndefined();
|
||||
});
|
||||
});
|
||||
describe('contains', () => {
|
||||
it('returns match any list contains', () => {
|
||||
expect(validate(attributeMap, { str: { contains: 'Corr' } }, [options])).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { contains: 'Corr' } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { contains: { value: 'Corr' } } }, [
|
||||
options,
|
||||
])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { contains: ['Corr'] } }, [options])
|
||||
validate(attributeMap, { str: { contains: { value: 'Corr' } } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(validate(attributeMap, { str: { contains: ['Corr'] } }, [options])).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { contains: ['corr'] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { contains: ['Att', 'Wall'] } }, [
|
||||
options,
|
||||
])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { contains: 'GH' } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { contains: ['ab'] } }, [options])
|
||||
validate(attributeMap, { str: { contains: ['Att', 'Wall'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(validate(attributeMap, { list: { contains: 'GH' } }, [options])).toBeUndefined();
|
||||
expect(validate(attributeMap, { list: { contains: ['ab'] } }, [options])).toBeUndefined();
|
||||
|
||||
expect(
|
||||
validate(attributeMap, { list: { contains: ['z', 'bc'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { contains: ['z'] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(validate(attributeMap, { list: { contains: ['z'] } }, [options])).not.toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('doesNotContain', () => {
|
||||
it('returns undefined if string does not contain specified value', () => {
|
||||
expect(
|
||||
validate(attributeMap, { str: { doesNotContain: ['att', 'wall'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { str: { doesNotContain: ['att', 'wall'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { doesNotContain: 'Corr' } }, [options])
|
||||
@@ -346,29 +220,19 @@ describe('validator', () => {
|
||||
validate(attributeMap, { str: { doesNotContain: 'corr' } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { doesNotContain: { value: 'corr' } } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { str: { doesNotContain: { value: 'corr' } } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { doesNotContain: ['att', 'cor'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { str: { doesNotContain: ['att', 'cor'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { doesNotContain: ['Att', 'cor'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { str: { doesNotContain: ['Att', 'cor'] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { doesNotContain: ['bye', 'hi'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { str: { doesNotContain: ['bye', 'hi'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { doesNotContain: ['GHI', 'hi'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { list: { doesNotContain: ['GHI', 'hi'] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { doesNotContain: ['hi'] } }, [options])
|
||||
@@ -384,103 +248,63 @@ describe('validator', () => {
|
||||
validate(attributeMap, { str: { doesNotContainI: 'Corr' } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { doesNotContainI: ['att', 'cor'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { str: { doesNotContainI: ['att', 'cor'] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { doesNotContainI: ['Att', 'wall'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { str: { doesNotContainI: ['Att', 'wall'] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { doesNotContainI: ['bye', 'hi'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { str: { doesNotContainI: ['bye', 'hi'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { doesNotContainI: ['bye', 'ABC'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { list: { doesNotContainI: ['bye', 'ABC'] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { doesNotContainI: 'bye' } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { doesNotContainI: ['bye', 'ABC'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { list: { doesNotContainI: ['bye', 'ABC'] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
});
|
||||
});
|
||||
describe('startsWith', () => {
|
||||
it('returns undefined if string starts with specified value', () => {
|
||||
expect(
|
||||
validate(attributeMap, { str: { startsWith: { value: 'Atte' } } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { str: { startsWith: { value: 'Atte' } } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(validate(attributeMap, { str: { startsWith: 'Att' } }, [options])).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { startsWith: ['cat', 'dog', 'Att'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { startsWith: 'Att' } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { startsWith: ['cat', 'dog', 'Att'] } }, [
|
||||
options,
|
||||
])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { startsWith: ['cat', 'dog'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { str: { startsWith: ['cat', 'dog'] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(validate(attributeMap, { list: { startsWith: ['GH'] } }, [options])).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { startsWith: ['GH'] } }, [options])
|
||||
validate(attributeMap, { list: { startsWith: ['de', 'bye'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { startsWith: ['de', 'bye'] } }, [
|
||||
options,
|
||||
])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { startsWith: ['hi', 'bye'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { list: { startsWith: ['hi', 'bye'] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
});
|
||||
});
|
||||
describe('endsWith', () => {
|
||||
it('returns undefined if string ends with specified value', () => {
|
||||
expect(validate(attributeMap, { str: { endsWith: 'ted' } }, [options])).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { endsWith: 'ted' } }, [options])
|
||||
validate(attributeMap, { str: { endsWith: { value: 'ted' } } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(validate(attributeMap, { str: { endsWith: ['ted'] } }, [options])).toBeUndefined();
|
||||
expect(validate(attributeMap, { str: { endsWith: ['Att'] } }, [options])).not.toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { endsWith: ['cat', 'dog', 'ted'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(validate(attributeMap, { list: { endsWith: ['HI'] } }, [options])).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { endsWith: ['bc', 'dog', 'ted'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { endsWith: { value: 'ted' } } }, [
|
||||
options,
|
||||
])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { endsWith: ['ted'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { endsWith: ['Att'] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { str: { endsWith: ['cat', 'dog', 'ted'] } }, [
|
||||
options,
|
||||
])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { endsWith: ['HI'] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { endsWith: ['bc', 'dog', 'ted'] } }, [
|
||||
options,
|
||||
])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { list: { endsWith: ['bye', 'dog'] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { list: { endsWith: ['bye', 'dog'] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
});
|
||||
});
|
||||
@@ -488,83 +312,47 @@ describe('validator', () => {
|
||||
describe('greaterThan', () => {
|
||||
it('returns undefined on greaterThan', () => {
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ num: { greaterThan: { value: attributeMap.num - 1 } } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { num: { greaterThan: { value: attributeMap.num - 1 } } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { num: { greaterThan: attributeMap.num - 1 } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { num: { greaterThan: attributeMap.num - 1 } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ num: { greaterThan: [attributeMap.num - 1] } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { num: { greaterThan: [attributeMap.num - 1] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ num: { greaterThan: [attributeMap.num + 1] } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { num: { greaterThan: [attributeMap.num + 1] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
});
|
||||
});
|
||||
describe('lessThan', () => {
|
||||
it('returns undefined on lessThan', () => {
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ num: { lessThan: { value: attributeMap.num + 1 } } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { num: { lessThan: { value: attributeMap.num + 1 } } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { num: { lessThan: attributeMap.num + 1 } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { num: { lessThan: attributeMap.num + 1 } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { num: { lessThan: [attributeMap.num + 1] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { num: { lessThan: [attributeMap.num + 1] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { num: { lessThan: [attributeMap.num - 1] } }, [
|
||||
options,
|
||||
])
|
||||
validate(attributeMap, { num: { lessThan: [attributeMap.num - 1] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
});
|
||||
});
|
||||
describe('range', () => {
|
||||
it('returns undefined if the value is between', () => {
|
||||
expect(
|
||||
validate(
|
||||
attributeMap,
|
||||
{ num: { range: [attributeMap.num + 1, attributeMap.num - 1] } },
|
||||
[options]
|
||||
)
|
||||
validate(attributeMap, { num: { range: [attributeMap.num + 1, attributeMap.num - 1] } }, [
|
||||
options,
|
||||
])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { num: { range: [1, 4] } }, [options])
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { num: { range: [1, 2] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { num: { range: [4, 5] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { num: { range: [5] } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(
|
||||
validate(attributeMap, { num: { range: 5 } }, [options])
|
||||
).not.toBeUndefined();
|
||||
expect(validate(attributeMap, { num: { range: [1, 4] } }, [options])).toBeUndefined();
|
||||
expect(validate(attributeMap, { num: { range: [1, 2] } }, [options])).not.toBeUndefined();
|
||||
expect(validate(attributeMap, { num: { range: [4, 5] } }, [options])).not.toBeUndefined();
|
||||
expect(validate(attributeMap, { num: { range: [5] } }, [options])).not.toBeUndefined();
|
||||
expect(validate(attributeMap, { num: { range: 5 } }, [options])).not.toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -126,13 +126,7 @@ describe('MeasurementService.js', () => {
|
||||
|
||||
it('throws Error if no matching criteria provided', () => {
|
||||
expect(() => {
|
||||
measurementService.addMapping(
|
||||
source,
|
||||
annotationType,
|
||||
null,
|
||||
toSourceSchema,
|
||||
toMeasurement
|
||||
);
|
||||
measurementService.addMapping(source, annotationType, null, toSourceSchema, toMeasurement);
|
||||
}).toThrow(new Error('Matching criteria not provided.'));
|
||||
});
|
||||
|
||||
@@ -194,34 +188,16 @@ describe('MeasurementService.js', () => {
|
||||
toSourceSchema,
|
||||
toMeasurement
|
||||
);
|
||||
const measurementId = source.annotationToMeasurement(
|
||||
annotationType,
|
||||
annotation
|
||||
);
|
||||
const mappedAnnotation = source.getAnnotation(
|
||||
annotationType,
|
||||
measurementId
|
||||
);
|
||||
const measurementId = source.annotationToMeasurement(annotationType, annotation);
|
||||
const mappedAnnotation = source.getAnnotation(annotationType, measurementId);
|
||||
|
||||
expect(annotation).toBe(mappedAnnotation);
|
||||
});
|
||||
|
||||
it('get annotation based on source and annotationType', () => {
|
||||
measurementService.addMapping(
|
||||
source,
|
||||
annotationType,
|
||||
{},
|
||||
toSourceSchema,
|
||||
toMeasurement
|
||||
);
|
||||
const measurementId = source.annotationToMeasurement(
|
||||
annotationType,
|
||||
annotation
|
||||
);
|
||||
const mappedAnnotation = source.getAnnotation(
|
||||
annotationType,
|
||||
measurementId
|
||||
);
|
||||
measurementService.addMapping(source, annotationType, {}, toSourceSchema, toMeasurement);
|
||||
const measurementId = source.annotationToMeasurement(annotationType, annotation);
|
||||
const mappedAnnotation = source.getAnnotation(annotationType, measurementId);
|
||||
|
||||
expect(annotation).toBe(mappedAnnotation);
|
||||
});
|
||||
@@ -323,9 +299,7 @@ describe('MeasurementService.js', () => {
|
||||
|
||||
/* Add new measurement */
|
||||
source.annotationToMeasurement(annotationType, newMeasurement);
|
||||
const savedMeasurement = measurementService.getMeasurement(
|
||||
newMeasurement.uid
|
||||
);
|
||||
const savedMeasurement = measurementService.getMeasurement(newMeasurement.uid);
|
||||
|
||||
/* Clear dynamic data */
|
||||
delete newMeasurement.modifiedTimestamp;
|
||||
@@ -384,10 +358,7 @@ describe('MeasurementService.js', () => {
|
||||
let addCallbackWasCalled = false;
|
||||
|
||||
/* Subscribe to add event */
|
||||
measurementService.subscribe(
|
||||
MEASUREMENT_ADDED,
|
||||
() => (addCallbackWasCalled = true)
|
||||
);
|
||||
measurementService.subscribe(MEASUREMENT_ADDED, () => (addCallbackWasCalled = true));
|
||||
|
||||
/* Add new measurement - two calls needed for the start and the other for the completed*/
|
||||
const uid = source.annotationToMeasurement(annotationType, measurement);
|
||||
@@ -409,20 +380,13 @@ describe('MeasurementService.js', () => {
|
||||
let updateCallbackWasCalled = false;
|
||||
|
||||
/* Subscribe to update event */
|
||||
measurementService.subscribe(
|
||||
MEASUREMENT_UPDATED,
|
||||
() => (updateCallbackWasCalled = true)
|
||||
);
|
||||
measurementService.subscribe(MEASUREMENT_UPDATED, () => (updateCallbackWasCalled = true));
|
||||
|
||||
/* Create measurement */
|
||||
const uid = source.annotationToMeasurement(annotationType, measurement);
|
||||
|
||||
/* Update measurement */
|
||||
source.annotationToMeasurement(
|
||||
annotationType,
|
||||
{ uid, ...measurement },
|
||||
true
|
||||
);
|
||||
source.annotationToMeasurement(annotationType, { uid, ...measurement }, true);
|
||||
|
||||
expect(updateCallbackWasCalled).toBe(true);
|
||||
});
|
||||
@@ -468,10 +432,7 @@ describe('MeasurementService.js', () => {
|
||||
let addCallbackWasCalled = false;
|
||||
|
||||
/* Subscribe to add event */
|
||||
measurementService.subscribe(
|
||||
MEASUREMENT_ADDED,
|
||||
() => (addCallbackWasCalled = true)
|
||||
);
|
||||
measurementService.subscribe(MEASUREMENT_ADDED, () => (addCallbackWasCalled = true));
|
||||
|
||||
/* Add new measurement - two calls needed for the start and the other for the completed*/
|
||||
// expect exceptions for unmapped measurements
|
||||
@@ -502,10 +463,7 @@ describe('MeasurementService.js', () => {
|
||||
let removeCallbackWasCalled = false;
|
||||
|
||||
/* Subscribe to add event */
|
||||
measurementService.subscribe(
|
||||
MEASUREMENT_REMOVED,
|
||||
() => (removeCallbackWasCalled = true)
|
||||
);
|
||||
measurementService.subscribe(MEASUREMENT_REMOVED, () => (removeCallbackWasCalled = true));
|
||||
|
||||
/* Add new measurement - two calls needed for the start and the other for the completed*/
|
||||
// expect exceptions for unmapped measurements
|
||||
|
||||
@@ -146,9 +146,7 @@ class MeasurementService extends PubSubService {
|
||||
|
||||
// check if valuetype is valid , and if values are strings
|
||||
if (!valueType || typeof valueType !== 'object') {
|
||||
console.warn(
|
||||
`MeasurementService: addValueType: invalid valueType: ${valueType}`
|
||||
);
|
||||
console.warn(`MeasurementService: addValueType: invalid valueType: ${valueType}`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -178,10 +176,7 @@ class MeasurementService extends PubSubService {
|
||||
return this.measurements.get(measurementUID);
|
||||
}
|
||||
|
||||
public setMeasurementSelected(
|
||||
measurementUID: string,
|
||||
selected: boolean
|
||||
): void {
|
||||
public setMeasurementSelected(measurementUID: string, selected: boolean): void {
|
||||
const measurement = this.getMeasurement(measurementUID);
|
||||
if (!measurement) {
|
||||
return;
|
||||
@@ -230,17 +225,8 @@ class MeasurementService extends PubSubService {
|
||||
version,
|
||||
};
|
||||
|
||||
source.annotationToMeasurement = (
|
||||
annotationType,
|
||||
annotation,
|
||||
isUpdate = false
|
||||
) => {
|
||||
return this.annotationToMeasurement(
|
||||
source,
|
||||
annotationType,
|
||||
annotation,
|
||||
isUpdate
|
||||
);
|
||||
source.annotationToMeasurement = (annotationType, annotation, isUpdate = false) => {
|
||||
return this.annotationToMeasurement(source, annotationType, annotation, isUpdate);
|
||||
};
|
||||
|
||||
source.remove = (measurementUID, eventDetails) => {
|
||||
@@ -281,13 +267,7 @@ class MeasurementService extends PubSubService {
|
||||
* @param {Function} toMeasurementSchema Mapping function to measurement schema
|
||||
* @return void
|
||||
*/
|
||||
addMapping(
|
||||
source,
|
||||
annotationType,
|
||||
matchingCriteria,
|
||||
toAnnotationSchema,
|
||||
toMeasurementSchema
|
||||
) {
|
||||
addMapping(source, annotationType, matchingCriteria, toAnnotationSchema, toMeasurementSchema) {
|
||||
if (!this._isValidSource(source)) {
|
||||
throw new Error('Invalid source.');
|
||||
}
|
||||
@@ -321,11 +301,7 @@ class MeasurementService extends PubSubService {
|
||||
this.mappings[source.uid] = [mapping];
|
||||
}
|
||||
|
||||
log.info(
|
||||
`New measurement mapping added to source '${this._getSourceToString(
|
||||
source
|
||||
)}'.`
|
||||
);
|
||||
log.info(`New measurement mapping added to source '${this._getSourceToString(source)}'.`);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -348,20 +324,13 @@ class MeasurementService extends PubSubService {
|
||||
}
|
||||
|
||||
const measurement = this.getMeasurement(measurementUID);
|
||||
const mapping = this._getMappingByMeasurementSource(
|
||||
measurement,
|
||||
annotationType
|
||||
);
|
||||
const mapping = this._getMappingByMeasurementSource(measurement, annotationType);
|
||||
|
||||
if (mapping) {
|
||||
return mapping.toAnnotationSchema(measurement, annotationType);
|
||||
}
|
||||
|
||||
const matchingMapping = this._getMatchingMapping(
|
||||
source,
|
||||
annotationType,
|
||||
measurement
|
||||
);
|
||||
const matchingMapping = this._getMatchingMapping(source, annotationType, measurement);
|
||||
|
||||
if (matchingMapping) {
|
||||
log.info('Matching mapping found:', matchingMapping);
|
||||
@@ -380,10 +349,7 @@ class MeasurementService extends PubSubService {
|
||||
modifiedTimestamp: Math.floor(Date.now() / 1000),
|
||||
};
|
||||
|
||||
log.info(
|
||||
`Updating internal measurement representation...`,
|
||||
updatedMeasurement
|
||||
);
|
||||
log.info(`Updating internal measurement representation...`, updatedMeasurement);
|
||||
|
||||
this.measurements.set(measurementUID, updatedMeasurement);
|
||||
|
||||
@@ -405,13 +371,7 @@ class MeasurementService extends PubSubService {
|
||||
* @param {object} data The data you wish to add to the source.
|
||||
* @param {function} toMeasurementSchema A function to get the `data` into the same shape as the source annotationType.
|
||||
*/
|
||||
addRawMeasurement(
|
||||
source,
|
||||
annotationType,
|
||||
data,
|
||||
toMeasurementSchema,
|
||||
dataSource = {}
|
||||
) {
|
||||
addRawMeasurement(source, annotationType, data, toMeasurementSchema, dataSource = {}) {
|
||||
if (!this._isValidSource(source)) {
|
||||
log.warn('Invalid source. Exiting early.');
|
||||
return;
|
||||
@@ -425,9 +385,7 @@ class MeasurementService extends PubSubService {
|
||||
}
|
||||
|
||||
if (!this._sourceHasMappings(source)) {
|
||||
log.warn(
|
||||
`No measurement mappings found for '${sourceInfo}' source. Exiting early.`
|
||||
);
|
||||
log.warn(`No measurement mappings found for '${sourceInfo}' source. Exiting early.`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -496,12 +454,7 @@ class MeasurementService extends PubSubService {
|
||||
* @param {boolean} isUpdate is this an update or an add/completed instead?
|
||||
* @return {string} A measurement uid
|
||||
*/
|
||||
annotationToMeasurement(
|
||||
source,
|
||||
annotationType,
|
||||
sourceAnnotationDetail,
|
||||
isUpdate = false
|
||||
) {
|
||||
annotationToMeasurement(source, annotationType, sourceAnnotationDetail, isUpdate = false) {
|
||||
if (!this._isValidSource(source)) {
|
||||
throw new Error('Invalid source.');
|
||||
}
|
||||
@@ -512,9 +465,7 @@ class MeasurementService extends PubSubService {
|
||||
const sourceInfo = this._getSourceToString(source);
|
||||
|
||||
if (!this._sourceHasMappings(source)) {
|
||||
throw new Error(
|
||||
`No measurement mappings found for '${sourceInfo}' source. Exiting early.`
|
||||
);
|
||||
throw new Error(`No measurement mappings found for '${sourceInfo}' source. Exiting early.`);
|
||||
}
|
||||
|
||||
let measurement = {};
|
||||
@@ -599,8 +550,7 @@ class MeasurementService extends PubSubService {
|
||||
remove(measurementUID, source, eventDetails) {
|
||||
if (
|
||||
!measurementUID ||
|
||||
(!this.measurements.has(measurementUID) &&
|
||||
!this.unmappedMeasurements.has(measurementUID))
|
||||
(!this.measurements.has(measurementUID) && !this.unmappedMeasurements.has(measurementUID))
|
||||
) {
|
||||
log.warn(`No uid provided, or unable to find measurement by uid.`);
|
||||
return;
|
||||
@@ -679,9 +629,7 @@ class MeasurementService extends PubSubService {
|
||||
|
||||
_getMappingByMeasurementSource(measurement, annotationType) {
|
||||
if (this._isValidSource(measurement.source)) {
|
||||
return this.mappings[measurement.source.uid].find(
|
||||
m => m.annotationType === annotationType
|
||||
);
|
||||
return this.mappings[measurement.source.uid].find(m => m.annotationType === annotationType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -702,10 +650,7 @@ class MeasurementService extends PubSubService {
|
||||
|
||||
/* Criteria Matching */
|
||||
return sourceMappingsByDefinition.find(({ matchingCriteria }) => {
|
||||
return (
|
||||
measurement.points &&
|
||||
measurement.points.length === matchingCriteria.points
|
||||
);
|
||||
return measurement.points && measurement.points.length === matchingCriteria.points;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -736,10 +681,7 @@ class MeasurementService extends PubSubService {
|
||||
* @return {boolean} Validation if source has mappings
|
||||
*/
|
||||
_sourceHasMappings(source) {
|
||||
return (
|
||||
Array.isArray(this.mappings[source.uid]) &&
|
||||
this.mappings[source.uid].length
|
||||
);
|
||||
return Array.isArray(this.mappings[source.uid]) && this.mappings[source.uid].length;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -38,9 +38,7 @@ describe('ServicesManager', () => {
|
||||
[{ name: 'UIModalTestService', create: jest.fn() }, fakeConfiguration],
|
||||
]);
|
||||
|
||||
expect(servicesManager.registerService.mock.calls[1][1]).toEqual(
|
||||
fakeConfiguration
|
||||
);
|
||||
expect(servicesManager.registerService.mock.calls[1][1]).toEqual(fakeConfiguration);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -78,9 +76,7 @@ describe('ServicesManager', () => {
|
||||
it('tracks which services have been registered', () => {
|
||||
servicesManager.registerService(fakeService);
|
||||
|
||||
expect(servicesManager.registeredServiceNames).toContain(
|
||||
fakeService.name
|
||||
);
|
||||
expect(servicesManager.registeredServiceNames).toContain(fakeService.name);
|
||||
});
|
||||
|
||||
it('logs a warning if the service has an name that has already been registered', () => {
|
||||
@@ -95,9 +91,7 @@ describe('ServicesManager', () => {
|
||||
|
||||
servicesManager.registerService(fakeService, configuration);
|
||||
|
||||
expect(fakeService.create.mock.calls[0][0].configuration.config).toBe(
|
||||
configuration.config
|
||||
);
|
||||
expect(fakeService.create.mock.calls[0][0].configuration.config).toBe(configuration.config);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -19,9 +19,7 @@ export default class ServicesManager {
|
||||
*/
|
||||
registerService(service, configuration = {}) {
|
||||
if (!service) {
|
||||
log.warn(
|
||||
'Attempting to register a null/undefined service. Exiting early.'
|
||||
);
|
||||
log.warn('Attempting to register a null/undefined service. Exiting early.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,11 +90,9 @@ export default class ToolbarService extends PubSubService {
|
||||
}
|
||||
case 'tool': {
|
||||
try {
|
||||
commands.forEach(
|
||||
({ commandName = 'setToolActive', commandOptions, context }) => {
|
||||
commandsManager.runCommand(commandName, commandOptions, context);
|
||||
}
|
||||
);
|
||||
commands.forEach(({ commandName = 'setToolActive', commandOptions, context }) => {
|
||||
commandsManager.runCommand(commandName, commandOptions, context);
|
||||
});
|
||||
|
||||
// only set the primary tool if no error was thrown
|
||||
this.state.primaryToolId = itemId;
|
||||
@@ -110,9 +108,7 @@ export default class ToolbarService extends PubSubService {
|
||||
|
||||
// only toggle if a command was executed
|
||||
this.state.toggles[itemId] =
|
||||
this.state.toggles[itemId] === undefined
|
||||
? true
|
||||
: !this.state.toggles[itemId];
|
||||
this.state.toggles[itemId] === undefined ? true : !this.state.toggles[itemId];
|
||||
|
||||
if (!commands) {
|
||||
break;
|
||||
@@ -213,14 +209,9 @@ export default class ToolbarService extends PubSubService {
|
||||
|
||||
_buttonTypes() {
|
||||
const buttonTypes = {};
|
||||
const registeredToolbarModules = this.extensionManager.modules[
|
||||
'toolbarModule'
|
||||
];
|
||||
const registeredToolbarModules = this.extensionManager.modules['toolbarModule'];
|
||||
|
||||
if (
|
||||
Array.isArray(registeredToolbarModules) &&
|
||||
registeredToolbarModules.length
|
||||
) {
|
||||
if (Array.isArray(registeredToolbarModules) && registeredToolbarModules.length) {
|
||||
registeredToolbarModules.forEach(toolbarModule =>
|
||||
toolbarModule.module.forEach(def => {
|
||||
buttonTypes[def.name] = def;
|
||||
@@ -302,8 +293,6 @@ export default class ToolbarService extends PubSubService {
|
||||
}
|
||||
|
||||
getButtonComponentForUIType(uiType: string) {
|
||||
return uiType
|
||||
? this._buttonTypes()[uiType]?.defaultComponent ?? null
|
||||
: null;
|
||||
return uiType ? this._buttonTypes()[uiType]?.defaultComponent ?? null : null;
|
||||
}
|
||||
}
|
||||
@@ -71,10 +71,7 @@ class UIModalService {
|
||||
* show: showImplementation,
|
||||
* }
|
||||
*/
|
||||
setServiceImplementation({
|
||||
hide: hideImplementation,
|
||||
show: showImplementation,
|
||||
}) {
|
||||
setServiceImplementation({ hide: hideImplementation, show: showImplementation }) {
|
||||
if (hideImplementation) {
|
||||
serviceImplementation._hide = hideImplementation;
|
||||
}
|
||||
|
||||
@@ -38,10 +38,7 @@ class UINotificationService {
|
||||
* show: showImplementation,
|
||||
* }
|
||||
*/
|
||||
public setServiceImplementation({
|
||||
hide: hideImplementation,
|
||||
show: showImplementation,
|
||||
}): void {
|
||||
public setServiceImplementation({ hide: hideImplementation, show: showImplementation }): void {
|
||||
if (hideImplementation) {
|
||||
serviceImplementation._hide = hideImplementation;
|
||||
}
|
||||
|
||||
@@ -26,15 +26,7 @@ const serviceImplementation = {
|
||||
*
|
||||
* @param {ViewportDialogProps} props { content, contentProps, viewportId }
|
||||
*/
|
||||
function _show({
|
||||
viewportId,
|
||||
id,
|
||||
type,
|
||||
message,
|
||||
actions,
|
||||
onSubmit,
|
||||
onOutsideClick,
|
||||
}) {
|
||||
function _show({ viewportId, id, type, message, actions, onSubmit, onOutsideClick }) {
|
||||
return serviceImplementation._show({
|
||||
viewportId,
|
||||
id,
|
||||
@@ -62,10 +54,7 @@ function _hide() {
|
||||
* viewportId,
|
||||
* }
|
||||
*/
|
||||
function setServiceImplementation({
|
||||
hide: hideImplementation,
|
||||
show: showImplementation,
|
||||
}) {
|
||||
function setServiceImplementation({ hide: hideImplementation, show: showImplementation }) {
|
||||
if (hideImplementation) {
|
||||
serviceImplementation._hide = hideImplementation;
|
||||
}
|
||||
|
||||
@@ -18,8 +18,7 @@ const serviceImplementation = {
|
||||
_getUser: () => console.warn('_setUser() NOT IMPLEMENTED'),
|
||||
_getAuthorizationHeader: () => {}, // TODO: have enabled/disabled state?
|
||||
//console.warn('_getAuthorizationHeader() NOT IMPLEMENTED'),
|
||||
_handleUnauthenticated: () =>
|
||||
console.warn('_handleUnauthenticated() NOT IMPLEMENTED'),
|
||||
_handleUnauthenticated: () => console.warn('_handleUnauthenticated() NOT IMPLEMENTED'),
|
||||
_reset: () => console.warn('reset() NOT IMPLEMENTED'),
|
||||
_set: () => console.warn('set() NOT IMPLEMENTED'),
|
||||
};
|
||||
|
||||
@@ -39,8 +39,7 @@ class ViewportGridService extends PubSubService {
|
||||
this.serviceImplementation._getState = getStateImplementation;
|
||||
}
|
||||
if (setActiveViewportIdImplementation) {
|
||||
this.serviceImplementation._setActiveViewport =
|
||||
setActiveViewportIdImplementation;
|
||||
this.serviceImplementation._setActiveViewport = setActiveViewportIdImplementation;
|
||||
}
|
||||
if (setDisplaySetsForViewportsImplementation) {
|
||||
this.serviceImplementation._setDisplaySetsForViewports =
|
||||
@@ -59,8 +58,7 @@ class ViewportGridService extends PubSubService {
|
||||
this.serviceImplementation._set = setImplementation;
|
||||
}
|
||||
if (getNumViewportPanesImplementation) {
|
||||
this.serviceImplementation._getNumViewportPanes =
|
||||
getNumViewportPanesImplementation;
|
||||
this.serviceImplementation._getNumViewportPanes = getNumViewportPanesImplementation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,10 +89,7 @@ class ViewportGridService extends PubSubService {
|
||||
if (updatedViewport) {
|
||||
viewports.push(updatedViewport);
|
||||
} else {
|
||||
console.warn(
|
||||
"ViewportGridService::Didn't find updated viewport",
|
||||
viewport
|
||||
);
|
||||
console.warn("ViewportGridService::Didn't find updated viewport", viewport);
|
||||
}
|
||||
}
|
||||
this._broadcastEvent(ViewportGridService.EVENTS.GRID_STATE_CHANGED, {
|
||||
@@ -158,7 +153,9 @@ class ViewportGridService extends PubSubService {
|
||||
return this.serviceImplementation._getNumViewportPanes();
|
||||
}
|
||||
|
||||
public getLayoutOptionsFromState(state: any): { x: number; y: number; width: number; height: number }[] {
|
||||
public getLayoutOptionsFromState(
|
||||
state: any
|
||||
): { x: number; y: number; width: number; height: number }[] {
|
||||
return Array.from(state.viewports.entries()).map(([_, viewport]) => {
|
||||
return {
|
||||
x: viewport.x,
|
||||
|
||||
@@ -102,11 +102,7 @@ const getPresentationIds = (viewport, viewports): PresentationIds => {
|
||||
if (!viewport) {
|
||||
return;
|
||||
}
|
||||
const {
|
||||
viewportOptions,
|
||||
displaySetInstanceUIDs,
|
||||
displaySetOptions,
|
||||
} = viewport;
|
||||
const { viewportOptions, displaySetInstanceUIDs, displaySetOptions } = viewport;
|
||||
if (!viewportOptions || !displaySetInstanceUIDs?.length) {
|
||||
return;
|
||||
}
|
||||
@@ -128,8 +124,7 @@ const getPresentationIds = (viewport, viewports): PresentationIds => {
|
||||
// only add unique index if the viewport is getting inserted and not updated
|
||||
const isUpdatingSameViewport = Array.from(viewports.values()).some(v => {
|
||||
return (
|
||||
v.displaySetInstanceUIDs.toString() ===
|
||||
viewport.displaySetInstanceUIDs.toString() &&
|
||||
v.displaySetInstanceUIDs.toString() === viewport.displaySetInstanceUIDs.toString() &&
|
||||
v.viewportId === viewport.viewportId
|
||||
);
|
||||
});
|
||||
@@ -143,12 +138,7 @@ const getPresentationIds = (viewport, viewports): PresentationIds => {
|
||||
viewports,
|
||||
isUpdatingSameViewport
|
||||
);
|
||||
addUniqueIndex(
|
||||
lutPresentationArr,
|
||||
'lutPresentationId',
|
||||
viewports,
|
||||
isUpdatingSameViewport
|
||||
);
|
||||
addUniqueIndex(lutPresentationArr, 'lutPresentationId', viewports, isUpdatingSameViewport);
|
||||
|
||||
const lutPresentationId = lutPresentationArr.join(JOIN_STR);
|
||||
const positionPresentationId = positionPresentationArr.join(JOIN_STR);
|
||||
|
||||
+1
-1
@@ -117,6 +117,6 @@ export class PubSubService {
|
||||
consume: function Consume() {
|
||||
this.isConsumed = true;
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -10,9 +10,7 @@ import ToolbarService from './ToolBarService';
|
||||
import ViewportGridService from './ViewportGridService';
|
||||
import CineService from './CineService';
|
||||
import HangingProtocolService from './HangingProtocolService';
|
||||
import pubSubServiceInterface, {
|
||||
PubSubService,
|
||||
} from './_shared/pubSubServiceInterface';
|
||||
import pubSubServiceInterface, { PubSubService } from './_shared/pubSubServiceInterface';
|
||||
import UserAuthenticationService from './UserAuthenticationService';
|
||||
import CustomizationService from './CustomizationService';
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
function isObject(subject) {
|
||||
return (
|
||||
subject instanceof Object ||
|
||||
(typeof subject === 'object' && subject !== null)
|
||||
);
|
||||
return subject instanceof Object || (typeof subject === 'object' && subject !== null);
|
||||
}
|
||||
|
||||
function isString(subject) {
|
||||
|
||||
@@ -298,10 +298,7 @@ export type Protocol = {
|
||||
* to the GUI when this is used, and it can be expensive to apply.
|
||||
* Alternatives include using the custom attributes where possible.
|
||||
*/
|
||||
export type ProtocolGenerator = ({
|
||||
servicesManager: any,
|
||||
commandsManager: any,
|
||||
}) => {
|
||||
export type ProtocolGenerator = ({ servicesManager: any, commandsManager: any }) => {
|
||||
protocol: Protocol;
|
||||
};
|
||||
|
||||
|
||||
@@ -2,10 +2,7 @@ import Consumer from './Consumer';
|
||||
|
||||
export default interface IPubSub {
|
||||
subscribe: (eventName: string, callback: Consumer) => void;
|
||||
_broadcastEvent: (
|
||||
eventName: string,
|
||||
callbackProps: Record<string, unknown>
|
||||
) => void;
|
||||
_broadcastEvent: (eventName: string, callbackProps: Record<string, unknown>) => void;
|
||||
_unsubscribe: (eventName: string, listenerId: string) => void;
|
||||
_isValidEvent: (eventName: string) => boolean;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PubSubService } from "../services";
|
||||
import { PubSubService } from '../services';
|
||||
|
||||
type Panel = {
|
||||
id?: string;
|
||||
@@ -11,8 +11,8 @@ type Panel = {
|
||||
|
||||
type ActivatePanelTriggers = {
|
||||
sourcePubSubService: PubSubService;
|
||||
sourceEvents: string[]
|
||||
}
|
||||
sourceEvents: string[];
|
||||
};
|
||||
|
||||
interface PanelEvent {
|
||||
panelId: string;
|
||||
@@ -22,9 +22,4 @@ interface ActivatePanelEvent extends PanelEvent {
|
||||
forceActive: boolean;
|
||||
}
|
||||
|
||||
export type {
|
||||
ActivatePanelEvent,
|
||||
ActivatePanelTriggers,
|
||||
Panel,
|
||||
PanelEvent,
|
||||
};
|
||||
export type { ActivatePanelEvent, ActivatePanelTriggers, Panel, PanelEvent };
|
||||
@@ -13,9 +13,7 @@ describe('absoluteUrl', () => {
|
||||
writable: true,
|
||||
});
|
||||
const absoluteUrlOutput = absoluteUrl('/path_3/path_to_destination');
|
||||
expect(absoluteUrlOutput).toEqual(
|
||||
'/path_1/path_2/path_3/path_to_destination'
|
||||
);
|
||||
expect(absoluteUrlOutput).toEqual('/path_1/path_2/path_3/path_to_destination');
|
||||
});
|
||||
|
||||
test('should return / when the path is not defined', () => {
|
||||
|
||||
@@ -9,24 +9,21 @@
|
||||
* 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 } =
|
||||
instance;
|
||||
|
||||
if (PerFrameFunctionalGroupsSequence || NumberOfFrames > 1) {
|
||||
const frameNumber = Number.parseInt(frame || 1);
|
||||
const shared = (SharedFunctionalGroupsSequence
|
||||
? Object.values(SharedFunctionalGroupsSequence[0])
|
||||
: []
|
||||
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])
|
||||
: []
|
||||
const perFrame = (
|
||||
PerFrameFunctionalGroupsSequence
|
||||
? Object.values(PerFrameFunctionalGroupsSequence[frameNumber - 1])
|
||||
: []
|
||||
)
|
||||
.filter(it => !!it)
|
||||
.map(it => it[0])
|
||||
@@ -34,19 +31,12 @@ const combineFrameInstance = (frame, instance) => {
|
||||
|
||||
// this is to fix NM multiframe datasets with position and orientation
|
||||
// information inside DetectorInformationSequence
|
||||
if (
|
||||
!instance.ImageOrientationPatient &&
|
||||
instance.DetectorInformationSequence
|
||||
) {
|
||||
if (!instance.ImageOrientationPatient && instance.DetectorInformationSequence) {
|
||||
instance.ImageOrientationPatient =
|
||||
instance.DetectorInformationSequence[0].ImageOrientationPatient;
|
||||
}
|
||||
if (
|
||||
!instance.ImagePositionPatient &&
|
||||
instance.DetectorInformationSequence
|
||||
) {
|
||||
instance.ImagePositionPatient =
|
||||
instance.DetectorInformationSequence[0].ImagePositionPatient;
|
||||
if (!instance.ImagePositionPatient && instance.DetectorInformationSequence) {
|
||||
instance.ImagePositionPatient = instance.DetectorInformationSequence[0].ImagePositionPatient;
|
||||
}
|
||||
|
||||
const newInstance = Object.assign(instance, { frameNumber: frameNumber });
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
// leading edge, instead of the trailing.
|
||||
function debounce(func, wait, immediate) {
|
||||
var timeout;
|
||||
return function() {
|
||||
return function () {
|
||||
var context = this,
|
||||
args = arguments;
|
||||
var later = function() {
|
||||
var later = function () {
|
||||
timeout = null;
|
||||
if (!immediate) {
|
||||
func.apply(context, args);
|
||||
|
||||
@@ -17,22 +17,14 @@ export default function downloadCSVReport(measurementData) {
|
||||
|
||||
const reportMap = {};
|
||||
measurementData.forEach(measurement => {
|
||||
const {
|
||||
referenceStudyUID,
|
||||
referenceSeriesUID,
|
||||
getReport,
|
||||
uid,
|
||||
} = measurement;
|
||||
const { referenceStudyUID, referenceSeriesUID, getReport, uid } = measurement;
|
||||
|
||||
if (!getReport) {
|
||||
console.warn('Measurement does not have a getReport function');
|
||||
return;
|
||||
}
|
||||
|
||||
const seriesMetadata = DicomMetadataStore.getSeries(
|
||||
referenceStudyUID,
|
||||
referenceSeriesUID
|
||||
);
|
||||
const seriesMetadata = DicomMetadataStore.getSeries(referenceStudyUID, referenceSeriesUID);
|
||||
|
||||
const commonRowItems = _getCommonRowItems(measurement, seriesMetadata);
|
||||
const report = getReport(measurement);
|
||||
@@ -57,9 +49,7 @@ export default function downloadCSVReport(measurementData) {
|
||||
|
||||
const results = _mapReportsToRowArray(reportMap, columns);
|
||||
|
||||
let csvContent =
|
||||
'data:text/csv;charset=utf-8,' +
|
||||
results.map(res => res.join(',')).join('\n');
|
||||
let csvContent = 'data:text/csv;charset=utf-8,' + results.map(res => res.join(',')).join('\n');
|
||||
|
||||
_createAndDownloadFile(csvContent);
|
||||
}
|
||||
|
||||
@@ -25,8 +25,7 @@ const generateAcceptHeader = (
|
||||
return quotedParam;
|
||||
}
|
||||
if (mime.startsWith('transfer-syntax=')) {
|
||||
const quotedParam =
|
||||
'transfer-syntax="' + mime.substring(16, mime.length) + '"';
|
||||
const quotedParam = 'transfer-syntax="' + mime.substring(16, mime.length) + '"';
|
||||
return quotedParam;
|
||||
} else {
|
||||
return mime;
|
||||
|
||||
@@ -38,11 +38,7 @@ export default function getImageId(instance, frame, thumbnail = false) {
|
||||
|
||||
const renderingAttr = thumbnail ? 'thumbnailRendering' : 'imageRendering';
|
||||
|
||||
if (
|
||||
!instance[renderingAttr] ||
|
||||
instance[renderingAttr] === 'wadouri' ||
|
||||
!instance.wadorsuri
|
||||
) {
|
||||
if (!instance[renderingAttr] || instance[renderingAttr] === 'wadouri' || !instance.wadorsuri) {
|
||||
let imageId = 'dicomweb:' + instance.wadouri;
|
||||
if (frame !== undefined) {
|
||||
imageId += '&frame=' + frame;
|
||||
|
||||
@@ -103,7 +103,7 @@ function print(list) {
|
||||
let text = '';
|
||||
if (Array.isArray(list)) {
|
||||
let prev = [];
|
||||
forEachValue(list, function(...args) {
|
||||
forEachValue(list, function (...args) {
|
||||
let prevLen = prev.length;
|
||||
for (let i = 0, l = args.length; i < l; ++i) {
|
||||
if (i < prevLen && args[i] === prev[i]) {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { addToList, forEach, getItem, print } from './hierarchicalListUtils';
|
||||
|
||||
describe('hierarchicalListUtils', function() {
|
||||
describe('hierarchicalListUtils', function () {
|
||||
let sharedList;
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
sharedList = [
|
||||
['1.2.3.1', ['1.2.3.1.1', '1.2.3.1.2']],
|
||||
'1.2.3.2',
|
||||
@@ -11,14 +11,14 @@ describe('hierarchicalListUtils', function() {
|
||||
];
|
||||
});
|
||||
|
||||
describe('getItem', function() {
|
||||
it('should retrieve elements from a list by index', function() {
|
||||
describe('getItem', function () {
|
||||
it('should retrieve elements from a list by index', function () {
|
||||
expect(getItem(sharedList, 0)).toBe('1.2.3.1');
|
||||
expect(getItem(sharedList, 1)).toBe('1.2.3.2');
|
||||
expect(getItem(sharedList, 2)).toBe('1.2.3.3');
|
||||
expect(getItem(sharedList, 3)).toBeUndefined();
|
||||
});
|
||||
it('should retrieve elements from a list by path', function() {
|
||||
it('should retrieve elements from a list by path', function () {
|
||||
expect(getItem(sharedList, '0')).toBe('1.2.3.1');
|
||||
expect(getItem(sharedList, '0/0')).toBe('1.2.3.1.1');
|
||||
expect(getItem(sharedList, '0/1')).toBe('1.2.3.1.2');
|
||||
@@ -35,8 +35,8 @@ describe('hierarchicalListUtils', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('addToList', function() {
|
||||
it('should support adding elements to a list hierarchically', function() {
|
||||
describe('addToList', function () {
|
||||
it('should support adding elements to a list hierarchically', function () {
|
||||
const list = [];
|
||||
addToList(list, '1.2.3.1', '1.2.3.1.1');
|
||||
addToList(list, '1.2.3.1', '1.2.3.1.2');
|
||||
@@ -46,7 +46,7 @@ describe('hierarchicalListUtils', function() {
|
||||
addToList(list, '1.2.3.3', '1.2.3.3.2', '1.2.3.3.2.2');
|
||||
expect(list).toStrictEqual(sharedList);
|
||||
});
|
||||
it('should change leaf nodes into non-leaf nodes', function() {
|
||||
it('should change leaf nodes into non-leaf nodes', function () {
|
||||
const listw = [];
|
||||
const listx = [['x.1', ['x.1.1', 'x.1.2']], 'x.2'];
|
||||
const listy = [
|
||||
@@ -64,8 +64,8 @@ describe('hierarchicalListUtils', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('forEach', function() {
|
||||
it('should iterate through all leaf nodes of the tree', function() {
|
||||
describe('forEach', function () {
|
||||
it('should iterate through all leaf nodes of the tree', function () {
|
||||
const fn = jest.fn();
|
||||
forEach(sharedList, fn);
|
||||
expect(fn).toHaveBeenCalledTimes(6);
|
||||
@@ -78,8 +78,8 @@ describe('hierarchicalListUtils', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('print', function() {
|
||||
it('should pretty-print the hierarchical list', function() {
|
||||
describe('print', function () {
|
||||
it('should pretty-print the hierarchical list', function () {
|
||||
expect(print(sharedList)).toBe(
|
||||
'1.2.3.1\n' +
|
||||
' 1.2.3.1.1\n' +
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
export default function pausePlugin(Mousetrap) {
|
||||
var _originalStopCallback = Mousetrap.prototype.stopCallback;
|
||||
|
||||
Mousetrap.prototype.stopCallback = function(e, element, combo) {
|
||||
Mousetrap.prototype.stopCallback = function (e, element, combo) {
|
||||
var self = this;
|
||||
|
||||
if (self.paused) {
|
||||
@@ -18,12 +18,12 @@ export default function pausePlugin(Mousetrap) {
|
||||
return _originalStopCallback.call(self, e, element, combo);
|
||||
};
|
||||
|
||||
Mousetrap.prototype.pause = function() {
|
||||
Mousetrap.prototype.pause = function () {
|
||||
var self = this;
|
||||
self.paused = true;
|
||||
};
|
||||
|
||||
Mousetrap.prototype.unpause = function() {
|
||||
Mousetrap.prototype.unpause = function () {
|
||||
var self = this;
|
||||
self.paused = false;
|
||||
};
|
||||
|
||||
@@ -122,7 +122,7 @@ export default function recordPlugin(Mousetrap, options = { timeout: 100 }) {
|
||||
*/
|
||||
function _normalizeSequence(sequence) {
|
||||
for (let i = 0; i < sequence.length; ++i) {
|
||||
sequence[i].sort(function(x, y) {
|
||||
sequence[i].sort(function (x, y) {
|
||||
// modifier keys always come first, in alphabetical order
|
||||
if (x.length > 1 && y.length === 1) {
|
||||
return -1;
|
||||
@@ -177,10 +177,10 @@ export default function recordPlugin(Mousetrap, options = { timeout: 100 }) {
|
||||
* @param {Function} callback
|
||||
* @returns void
|
||||
*/
|
||||
Mousetrap.prototype.record = function(callback) {
|
||||
Mousetrap.prototype.record = function (callback) {
|
||||
var self = this;
|
||||
self.recording = true;
|
||||
_recordedSequenceCallback = function() {
|
||||
_recordedSequenceCallback = function () {
|
||||
self.recording = false;
|
||||
callback.apply(self, arguments);
|
||||
};
|
||||
@@ -192,7 +192,7 @@ export default function recordPlugin(Mousetrap, options = { timeout: 100 }) {
|
||||
* @param {Function} callback
|
||||
* @returns void
|
||||
*/
|
||||
Mousetrap.prototype.stopRecord = function() {
|
||||
Mousetrap.prototype.stopRecord = function () {
|
||||
var self = this;
|
||||
self.recording = false;
|
||||
};
|
||||
@@ -203,11 +203,11 @@ export default function recordPlugin(Mousetrap, options = { timeout: 100 }) {
|
||||
* @param {Function} callback
|
||||
* @returns void
|
||||
*/
|
||||
Mousetrap.prototype.startRecording = function() {
|
||||
Mousetrap.prototype.startRecording = function () {
|
||||
var self = this;
|
||||
self.recording = true;
|
||||
};
|
||||
Mousetrap.prototype.handleKey = function() {
|
||||
Mousetrap.prototype.handleKey = function () {
|
||||
var self = this;
|
||||
_handleKey.apply(self, arguments);
|
||||
};
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import isDicomUid from './isDicomUid';
|
||||
|
||||
describe('isDicomUid', function() {
|
||||
it('should return true for valid DICOM UIDs', function() {
|
||||
describe('isDicomUid', function () {
|
||||
it('should return true for valid DICOM UIDs', function () {
|
||||
expect(isDicomUid('1')).toBe(true);
|
||||
expect(isDicomUid('1.2')).toBe(true);
|
||||
expect(isDicomUid('1.2.3')).toBe(true);
|
||||
expect(isDicomUid('1.2.3.4')).toBe(true);
|
||||
});
|
||||
it('should return false for invalid DICOM UIDs', function() {
|
||||
it('should return false for invalid DICOM UIDs', function () {
|
||||
expect(isDicomUid('x')).toBe(false);
|
||||
expect(isDicomUid('1.')).toBe(false);
|
||||
expect(isDicomUid('1. 2')).toBe(false);
|
||||
|
||||
@@ -30,23 +30,17 @@ export default function isDisplaySetReconstructable(instances) {
|
||||
}
|
||||
|
||||
// Can't reconstruct if all instances don't have the ImagePositionPatient.
|
||||
if (
|
||||
!isMultiframe &&
|
||||
!instances.every(instance => instance.ImagePositionPatient)
|
||||
) {
|
||||
if (!isMultiframe && !instances.every(instance => instance.ImagePositionPatient)) {
|
||||
return { value: false };
|
||||
}
|
||||
|
||||
const sortedInstances = sortInstancesByPosition(instances);
|
||||
|
||||
return isMultiframe
|
||||
? processMultiframe(sortedInstances[0])
|
||||
: processSingleframe(sortedInstances);
|
||||
return isMultiframe ? processMultiframe(sortedInstances[0]) : processSingleframe(sortedInstances);
|
||||
}
|
||||
|
||||
function hasPixelMeasurements(multiFrameInstance) {
|
||||
const perFrameSequence =
|
||||
multiFrameInstance.PerFrameFunctionalGroupsSequence?.[0];
|
||||
const perFrameSequence = multiFrameInstance.PerFrameFunctionalGroupsSequence?.[0];
|
||||
const sharedSequence = multiFrameInstance.SharedFunctionalGroupsSequence;
|
||||
|
||||
return (
|
||||
@@ -54,39 +48,34 @@ function hasPixelMeasurements(multiFrameInstance) {
|
||||
Boolean(sharedSequence?.PixelMeasuresSequence) ||
|
||||
Boolean(
|
||||
multiFrameInstance.PixelSpacing &&
|
||||
(multiFrameInstance.SliceThickness ||
|
||||
multiFrameInstance.SpacingBetweenFrames)
|
||||
(multiFrameInstance.SliceThickness || multiFrameInstance.SpacingBetweenFrames)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function hasOrientation(multiFrameInstance) {
|
||||
const sharedSequence = multiFrameInstance.SharedFunctionalGroupsSequence;
|
||||
const perFrameSequence =
|
||||
multiFrameInstance.PerFrameFunctionalGroupsSequence?.[0];
|
||||
const perFrameSequence = multiFrameInstance.PerFrameFunctionalGroupsSequence?.[0];
|
||||
|
||||
return (
|
||||
Boolean(sharedSequence?.PlaneOrientationSequence) ||
|
||||
Boolean(perFrameSequence?.PlaneOrientationSequence) ||
|
||||
Boolean(
|
||||
multiFrameInstance.ImageOrientationPatient ||
|
||||
multiFrameInstance.DetectorInformationSequence?.[0]
|
||||
?.ImageOrientationPatient
|
||||
multiFrameInstance.DetectorInformationSequence?.[0]?.ImageOrientationPatient
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function hasPosition(multiFrameInstance) {
|
||||
const perFrameSequence =
|
||||
multiFrameInstance.PerFrameFunctionalGroupsSequence?.[0];
|
||||
const perFrameSequence = multiFrameInstance.PerFrameFunctionalGroupsSequence?.[0];
|
||||
|
||||
return (
|
||||
Boolean(perFrameSequence?.PlanePositionSequence) ||
|
||||
Boolean(perFrameSequence?.CTPositionSequence) ||
|
||||
Boolean(
|
||||
multiFrameInstance.ImagePositionPatient ||
|
||||
multiFrameInstance.DetectorInformationSequence?.[0]
|
||||
?.ImagePositionPatient
|
||||
multiFrameInstance.DetectorInformationSequence?.[0]?.ImagePositionPatient
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -114,10 +103,7 @@ function processMultiframe(multiFrameInstance) {
|
||||
return { value: false };
|
||||
}
|
||||
|
||||
if (
|
||||
multiFrameInstance.Modality.includes('NM') &&
|
||||
!isNMReconstructable(multiFrameInstance)
|
||||
) {
|
||||
if (multiFrameInstance.Modality.includes('NM') && !isNMReconstructable(multiFrameInstance)) {
|
||||
return { value: false };
|
||||
}
|
||||
|
||||
@@ -130,9 +116,7 @@ function processSingleframe(instances) {
|
||||
const firstImageRows = toNumber(firstImage.Rows);
|
||||
const firstImageColumns = toNumber(firstImage.Columns);
|
||||
const firstImageSamplesPerPixel = toNumber(firstImage.SamplesPerPixel);
|
||||
const firstImageOrientationPatient = toNumber(
|
||||
firstImage.ImageOrientationPatient
|
||||
);
|
||||
const firstImageOrientationPatient = toNumber(firstImage.ImageOrientationPatient);
|
||||
const firstImagePositionPatient = toNumber(firstImage.ImagePositionPatient);
|
||||
|
||||
// Can't reconstruct if we:
|
||||
@@ -141,12 +125,7 @@ function processSingleframe(instances) {
|
||||
// -- Have different orientations within a displaySet.
|
||||
for (let i = 1; i < instances.length; i++) {
|
||||
const instance = instances[i];
|
||||
const {
|
||||
Rows,
|
||||
Columns,
|
||||
SamplesPerPixel,
|
||||
ImageOrientationPatient,
|
||||
} = instance;
|
||||
const { Rows, Columns, SamplesPerPixel, ImageOrientationPatient } = instance;
|
||||
|
||||
const imageOrientationPatient = toNumber(ImageOrientationPatient);
|
||||
|
||||
@@ -167,9 +146,7 @@ function processSingleframe(instances) {
|
||||
// If spacing is on a uniform grid but we are missing frames,
|
||||
// Allow reconstruction, but pass back the number of missing frames.
|
||||
if (instances.length > 2) {
|
||||
const lastIpp = toNumber(
|
||||
instances[instances.length - 1].ImagePositionPatient
|
||||
);
|
||||
const lastIpp = toNumber(instances[instances.length - 1].ImagePositionPatient);
|
||||
|
||||
// We can't reconstruct if we are missing ImagePositionPatient values
|
||||
if (!firstImagePositionPatient || !lastIpp) {
|
||||
@@ -177,8 +154,7 @@ function processSingleframe(instances) {
|
||||
}
|
||||
|
||||
averageSpacingBetweenFrames =
|
||||
_getPerpendicularDistance(firstImagePositionPatient, lastIpp) /
|
||||
(instances.length - 1);
|
||||
_getPerpendicularDistance(firstImagePositionPatient, lastIpp) / (instances.length - 1);
|
||||
|
||||
let previousImagePositionPatient = firstImagePositionPatient;
|
||||
|
||||
@@ -191,10 +167,7 @@ function processSingleframe(instances) {
|
||||
imagePositionPatient,
|
||||
previousImagePositionPatient
|
||||
);
|
||||
const spacingIssue = _getSpacingIssue(
|
||||
spacingBetweenFrames,
|
||||
averageSpacingBetweenFrames
|
||||
);
|
||||
const spacingIssue = _getSpacingIssue(spacingBetweenFrames, averageSpacingBetweenFrames);
|
||||
|
||||
if (spacingIssue) {
|
||||
const issue = spacingIssue.issue;
|
||||
@@ -262,11 +235,7 @@ function _getSpacingIssue(spacing, averageSpacing) {
|
||||
}
|
||||
|
||||
function _getPerpendicularDistance(a, b) {
|
||||
return Math.sqrt(
|
||||
Math.pow(a[0] - b[0], 2) +
|
||||
Math.pow(a[1] - b[1], 2) +
|
||||
Math.pow(a[2] - b[2], 2)
|
||||
);
|
||||
return Math.sqrt(Math.pow(a[0] - b[0], 2) + Math.pow(a[1] - b[1], 2) + Math.pow(a[2] - b[2], 2));
|
||||
}
|
||||
|
||||
const constructableModalities = ['MR', 'CT', 'PT', 'NM'];
|
||||
|
||||
@@ -3,23 +3,17 @@ import { isImage } from './isImage';
|
||||
|
||||
describe('isImage', () => {
|
||||
test('should return true when the image is of type sopClassDictionary.ComputedRadiographyImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.ComputedRadiographyImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.ComputedRadiographyImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.DigitalXRayImageStorageForPresentation', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.DigitalXRayImageStorageForPresentation
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.DigitalXRayImageStorageForPresentation);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.DigitalXRayImageStorageForProcessing', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.DigitalXRayImageStorageForProcessing
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.DigitalXRayImageStorageForProcessing);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
@@ -45,9 +39,7 @@ describe('isImage', () => {
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.DigitalIntraOralXRayImageStorageForProcessing', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.DigitalIntraOralXRayImageStorageForProcessing
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.DigitalIntraOralXRayImageStorageForProcessing);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
@@ -62,16 +54,12 @@ describe('isImage', () => {
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.LegacyConvertedEnhancedCTImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.LegacyConvertedEnhancedCTImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.LegacyConvertedEnhancedCTImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.UltrasoundMultiframeImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.UltrasoundMultiframeImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.UltrasoundMultiframeImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
@@ -86,16 +74,12 @@ describe('isImage', () => {
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.EnhancedMRColorImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.EnhancedMRColorImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.EnhancedMRColorImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.LegacyConvertedEnhancedMRImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.LegacyConvertedEnhancedMRImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.LegacyConvertedEnhancedMRImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
@@ -105,9 +89,7 @@ describe('isImage', () => {
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.SecondaryCaptureImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.SecondaryCaptureImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.SecondaryCaptureImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
@@ -140,9 +122,7 @@ describe('isImage', () => {
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.XRayAngiographicImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.XRayAngiographicImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.XRayAngiographicImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
@@ -152,9 +132,7 @@ describe('isImage', () => {
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.XRayRadiofluoroscopicImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.XRayRadiofluoroscopicImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.XRayRadiofluoroscopicImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
@@ -164,23 +142,17 @@ describe('isImage', () => {
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.XRay3DAngiographicImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.XRay3DAngiographicImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.XRay3DAngiographicImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.XRay3DCraniofacialImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.XRay3DCraniofacialImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.XRay3DCraniofacialImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.BreastTomosynthesisImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.BreastTomosynthesisImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.BreastTomosynthesisImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
@@ -192,9 +164,7 @@ describe('isImage', () => {
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.BreastProjectionXRayImageStorageForProcessing', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.BreastProjectionXRayImageStorageForProcessing
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.BreastProjectionXRayImageStorageForProcessing);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
@@ -213,9 +183,7 @@ describe('isImage', () => {
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.NuclearMedicineImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.NuclearMedicineImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.NuclearMedicineImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
@@ -225,9 +193,7 @@ describe('isImage', () => {
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.VideoEndoscopicImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.VideoEndoscopicImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.VideoEndoscopicImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
@@ -237,65 +203,47 @@ describe('isImage', () => {
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.VideoMicroscopicImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.VideoMicroscopicImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.VideoMicroscopicImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.VLSlideCoordinatesMicroscopicImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.VLSlideCoordinatesMicroscopicImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.VLSlideCoordinatesMicroscopicImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.VLPhotographicImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.VLPhotographicImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.VLPhotographicImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.VideoPhotographicImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.VideoPhotographicImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.VideoPhotographicImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.OphthalmicPhotography8BitImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.OphthalmicPhotography8BitImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.OphthalmicPhotography8BitImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.OphthalmicPhotography16BitImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.OphthalmicPhotography16BitImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.OphthalmicPhotography16BitImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.OphthalmicTomographyImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.OphthalmicTomographyImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.OphthalmicTomographyImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.VLWholeSlideMicroscopyImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.VLWholeSlideMicroscopyImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.VLWholeSlideMicroscopyImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.PositronEmissionTomographyImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.PositronEmissionTomographyImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.PositronEmissionTomographyImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
@@ -305,9 +253,7 @@ describe('isImage', () => {
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.LegacyConvertedEnhancedPETImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.LegacyConvertedEnhancedPETImageStorage
|
||||
);
|
||||
const isImageStatus = isImage(sopClassDictionary.LegacyConvertedEnhancedPETImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
const LOW_PRIORITY_MODALITIES = Object.freeze([
|
||||
'SEG',
|
||||
'KO',
|
||||
'PR',
|
||||
'SR',
|
||||
'RTSTRUCT',
|
||||
]);
|
||||
const LOW_PRIORITY_MODALITIES = Object.freeze(['SEG', 'KO', 'PR', 'SR', 'RTSTRUCT']);
|
||||
|
||||
export default function isLowPriorityModality(Modality) {
|
||||
return LOW_PRIORITY_MODALITIES.includes(Modality);
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
const LOW_PRIORITY_MODALITIES = Object.freeze([
|
||||
'SEG',
|
||||
'KO',
|
||||
'PR',
|
||||
'SR',
|
||||
'RTSTRUCT',
|
||||
]);
|
||||
const LOW_PRIORITY_MODALITIES = Object.freeze(['SEG', 'KO', 'PR', 'SR', 'RTSTRUCT']);
|
||||
|
||||
export default function isLowPriorityModality(Modality) {
|
||||
return LOW_PRIORITY_MODALITIES.includes(Modality);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
export default function makeCancelable(thenable) {
|
||||
let isCanceled = false;
|
||||
const promise = Promise.resolve(thenable).then(
|
||||
function(result) {
|
||||
function (result) {
|
||||
if (isCanceled) {
|
||||
throw Object.freeze({ isCanceled });
|
||||
}
|
||||
return result;
|
||||
},
|
||||
function(error) {
|
||||
function (error) {
|
||||
if (isCanceled) {
|
||||
throw Object.freeze({ isCanceled, error });
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export default function makeDeferred() {
|
||||
let reject,
|
||||
resolve,
|
||||
promise = new Promise(function(res, rej) {
|
||||
promise = new Promise(function (res, rej) {
|
||||
resolve = res;
|
||||
reject = rej;
|
||||
});
|
||||
|
||||
@@ -11,11 +11,7 @@
|
||||
* @returns Array view containing the palette data, or a promise to return one.
|
||||
* Returns undefined if the palette data is absent.
|
||||
*/
|
||||
export default function fetchPaletteColorLookupTableData(
|
||||
item,
|
||||
tag,
|
||||
descriptorTag
|
||||
) {
|
||||
export default function fetchPaletteColorLookupTableData(item, tag, descriptorTag) {
|
||||
const { PaletteColorLookupTableUID } = item;
|
||||
const paletteData = item[tag];
|
||||
if (paletteData === undefined && PaletteColorLookupTableUID === undefined) {
|
||||
@@ -55,19 +51,12 @@ function _getPaletteColor(paletteColorLookupTableData, lutDescriptor) {
|
||||
|
||||
if (paletteColorLookupTableData.InlineBinary) {
|
||||
try {
|
||||
const arraybuffer = Uint8Array.from(
|
||||
atob(paletteColorLookupTableData.InlineBinary),
|
||||
c => c.charCodeAt(0)
|
||||
const arraybuffer = Uint8Array.from(atob(paletteColorLookupTableData.InlineBinary), c =>
|
||||
c.charCodeAt(0)
|
||||
);
|
||||
return (paletteColorLookupTableData.palette = arrayBufferToPaletteColorLUT(
|
||||
arraybuffer
|
||||
));
|
||||
return (paletteColorLookupTableData.palette = arrayBufferToPaletteColorLUT(arraybuffer));
|
||||
} catch (e) {
|
||||
console.log(
|
||||
"Couldn't decode",
|
||||
paletteColorLookupTableData.InlineBinary,
|
||||
e
|
||||
);
|
||||
console.log("Couldn't decode", paletteColorLookupTableData.InlineBinary, e);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
@@ -75,12 +64,7 @@ function _getPaletteColor(paletteColorLookupTableData, lutDescriptor) {
|
||||
if (paletteColorLookupTableData.retrieveBulkData) {
|
||||
return paletteColorLookupTableData
|
||||
.retrieveBulkData()
|
||||
.then(
|
||||
val =>
|
||||
(paletteColorLookupTableData.palette = arrayBufferToPaletteColorLUT(
|
||||
val
|
||||
))
|
||||
);
|
||||
.then(val => (paletteColorLookupTableData.palette = arrayBufferToPaletteColorLUT(val)));
|
||||
}
|
||||
|
||||
console.error(`No data found for ${paletteColorLookupTableData} palette`);
|
||||
|
||||
@@ -48,11 +48,7 @@ export default function getPixelSpacingInformation(instance) {
|
||||
type: TYPES.UNKNOWN,
|
||||
isProjection,
|
||||
};
|
||||
} else if (
|
||||
PixelSpacing &&
|
||||
ImagerPixelSpacing &&
|
||||
PixelSpacing === ImagerPixelSpacing
|
||||
) {
|
||||
} else if (PixelSpacing && ImagerPixelSpacing && PixelSpacing === ImagerPixelSpacing) {
|
||||
// If Imager Pixel Spacing and Pixel Spacing are present and they have the same values,
|
||||
// then the user should be informed that the measurements are at the detector plane
|
||||
return {
|
||||
@@ -60,11 +56,7 @@ export default function getPixelSpacingInformation(instance) {
|
||||
type: TYPES.DETECTOR,
|
||||
isProjection,
|
||||
};
|
||||
} else if (
|
||||
PixelSpacing &&
|
||||
ImagerPixelSpacing &&
|
||||
PixelSpacing !== ImagerPixelSpacing
|
||||
) {
|
||||
} else if (PixelSpacing && ImagerPixelSpacing && PixelSpacing !== ImagerPixelSpacing) {
|
||||
// If Imager Pixel Spacing and Pixel Spacing are present and they have different values,
|
||||
// then the user should be informed that these are "calibrated"
|
||||
// (in some unknown manner if Pixel Spacing Calibration Type and/or
|
||||
@@ -95,10 +87,7 @@ export default function getPixelSpacingInformation(instance) {
|
||||
PixelSpacing: CorrectedImagerPixelSpacing,
|
||||
isProjection,
|
||||
};
|
||||
} else if (
|
||||
SequenceOfUltrasoundRegions &&
|
||||
typeof SequenceOfUltrasoundRegions === 'object'
|
||||
) {
|
||||
} else if (SequenceOfUltrasoundRegions && typeof SequenceOfUltrasoundRegions === 'object') {
|
||||
const { PhysicalDeltaX, PhysicalDeltaY } = SequenceOfUltrasoundRegions;
|
||||
const USPixelSpacing = [PhysicalDeltaX * 10, PhysicalDeltaY * 10];
|
||||
|
||||
|
||||
@@ -5,8 +5,7 @@ export default function unpackOverlay(arrayBuffer) {
|
||||
for (let byteIndex = 0; byteIndex < byteArray.length; byteIndex++) {
|
||||
const bitIndex = byteIndex % 8;
|
||||
const bitByteIndex = Math.floor(byteIndex / 8);
|
||||
byteArray[byteIndex] =
|
||||
1 * ((bitArray[bitByteIndex] & (1 << bitIndex)) >> bitIndex);
|
||||
byteArray[byteIndex] = 1 * ((bitArray[bitByteIndex] & (1 << bitIndex)) >> bitIndex);
|
||||
}
|
||||
|
||||
return byteArray;
|
||||
|
||||
@@ -85,9 +85,7 @@ export class ObjectPath {
|
||||
* @return {Boolean} Returns "true" if the object is a real Object instance and "false" otherwise.
|
||||
*/
|
||||
static isValidObject(object) {
|
||||
return (
|
||||
typeof object === 'object' && object !== null && object instanceof Object
|
||||
);
|
||||
return typeof object === 'object' && object !== null && object instanceof Object;
|
||||
}
|
||||
|
||||
static getPathComponents(path) {
|
||||
|
||||
@@ -149,10 +149,10 @@ function waitOn(list, thenable) {
|
||||
const task = increaseList(list);
|
||||
if (isTask(task)) {
|
||||
task.awaiting = Promise.resolve(thenable).then(
|
||||
function() {
|
||||
function () {
|
||||
finish(task);
|
||||
},
|
||||
function() {
|
||||
function () {
|
||||
task.failed = true;
|
||||
finish(task);
|
||||
}
|
||||
@@ -226,11 +226,7 @@ function getTaskByName(list, name) {
|
||||
* @returns {boolean} Returns true on success and false otherewise
|
||||
*/
|
||||
function addObserver(list, observer) {
|
||||
if (
|
||||
isList(list) &&
|
||||
Array.isArray(list.observers) &&
|
||||
typeof observer === 'function'
|
||||
) {
|
||||
if (isList(list) && Array.isArray(list.observers) && typeof observer === 'function') {
|
||||
list.observers.push(observer);
|
||||
return true;
|
||||
}
|
||||
@@ -244,11 +240,7 @@ function addObserver(list, observer) {
|
||||
* @returns {boolean} Returns true on success and false otherewise
|
||||
*/
|
||||
function removeObserver(list, observer) {
|
||||
if (
|
||||
isList(list) &&
|
||||
Array.isArray(list.observers) &&
|
||||
list.observers.length > 0
|
||||
) {
|
||||
if (isList(list) && Array.isArray(list.observers) && list.observers.length > 0) {
|
||||
const index = list.observers.indexOf(observer);
|
||||
if (index >= 0) {
|
||||
list.observers.splice(index, 1);
|
||||
@@ -276,9 +268,7 @@ function objectWithType(type, object) {
|
||||
}
|
||||
|
||||
function isOfType(type, subject) {
|
||||
return (
|
||||
subject !== null && typeof subject === 'object' && subject[TYPE] === type
|
||||
);
|
||||
return subject !== null && typeof subject === 'object' && subject[TYPE] === type;
|
||||
}
|
||||
|
||||
function isValidProgress(value) {
|
||||
@@ -299,12 +289,8 @@ function contains(list, task) {
|
||||
}
|
||||
|
||||
function notify(list, data) {
|
||||
if (
|
||||
isList(list) &&
|
||||
Array.isArray(list.observers) &&
|
||||
list.observers.length > 0
|
||||
) {
|
||||
list.observers.slice().forEach(function(observer) {
|
||||
if (isList(list) && Array.isArray(list.observers) && list.observers.length > 0) {
|
||||
list.observers.slice().forEach(function (observer) {
|
||||
if (typeof observer === 'function') {
|
||||
try {
|
||||
observer(data, list);
|
||||
|
||||
@@ -40,11 +40,7 @@ describe('progressTrackingUtils', () => {
|
||||
|
||||
it('should call observer twice for each task', () => {
|
||||
const { list, observer } = context;
|
||||
const promises = [
|
||||
Promise.resolve('A'),
|
||||
Promise.resolve('B'),
|
||||
Promise.resolve('C'),
|
||||
];
|
||||
const promises = [Promise.resolve('A'), Promise.resolve('B'), Promise.resolve('C')];
|
||||
promises.forEach(promise => void utils.waitOn(list, promise));
|
||||
return Promise.all(promises).then(() => {
|
||||
expect(observer).toBeCalledTimes(6);
|
||||
|
||||
@@ -10,8 +10,6 @@ export default function resolveObjectPath(root, path, defaultValue) {
|
||||
);
|
||||
}
|
||||
value = root[path];
|
||||
return value === undefined && defaultValue !== undefined
|
||||
? defaultValue
|
||||
: value;
|
||||
return value === undefined && defaultValue !== undefined ? defaultValue : value;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import resolveObjectPath from './resolveObjectPath';
|
||||
|
||||
describe('resolveObjectPath', function() {
|
||||
describe('resolveObjectPath', function () {
|
||||
let config;
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(function () {
|
||||
config = {
|
||||
active: {
|
||||
user: {
|
||||
@@ -21,13 +21,13 @@ describe('resolveObjectPath', function() {
|
||||
};
|
||||
});
|
||||
|
||||
it('should safely return deeply nested values from an object', function() {
|
||||
it('should safely return deeply nested values from an object', function () {
|
||||
expect(resolveObjectPath(config, 'active.user.name.first')).toBe('John');
|
||||
expect(resolveObjectPath(config, 'active.user.name.last')).toBe('Doe');
|
||||
expect(resolveObjectPath(config, 'active.servers.0.ipv4')).toBe('10.0.0.1');
|
||||
});
|
||||
|
||||
it('should silently return undefined when intermediate values are not valid objects', function() {
|
||||
it('should silently return undefined when intermediate values are not valid objects', function () {
|
||||
expect(resolveObjectPath(config, 'active.usr.name.first')).toBeUndefined();
|
||||
expect(resolveObjectPath(config, 'active.name.last')).toBeUndefined();
|
||||
expect(resolveObjectPath(config, 'active.servers.7.ipv4')).toBeUndefined();
|
||||
|
||||
@@ -3,14 +3,10 @@ export const sopClassDictionary = {
|
||||
ComputedRadiographyImageStorage: '1.2.840.10008.5.1.4.1.1.1',
|
||||
DigitalXRayImageStorageForPresentation: '1.2.840.10008.5.1.4.1.1.1.1',
|
||||
DigitalXRayImageStorageForProcessing: '1.2.840.10008.5.1.4.1.1.1.1.1',
|
||||
DigitalMammographyXRayImageStorageForPresentation:
|
||||
'1.2.840.10008.5.1.4.1.1.1.2',
|
||||
DigitalMammographyXRayImageStorageForProcessing:
|
||||
'1.2.840.10008.5.1.4.1.1.1.2.1',
|
||||
DigitalIntraOralXRayImageStorageForPresentation:
|
||||
'1.2.840.10008.5.1.4.1.1.1.3',
|
||||
DigitalIntraOralXRayImageStorageForProcessing:
|
||||
'1.2.840.10008.5.1.4.1.1.1.3.1',
|
||||
DigitalMammographyXRayImageStorageForPresentation: '1.2.840.10008.5.1.4.1.1.1.2',
|
||||
DigitalMammographyXRayImageStorageForProcessing: '1.2.840.10008.5.1.4.1.1.1.2.1',
|
||||
DigitalIntraOralXRayImageStorageForPresentation: '1.2.840.10008.5.1.4.1.1.1.3',
|
||||
DigitalIntraOralXRayImageStorageForProcessing: '1.2.840.10008.5.1.4.1.1.1.3.1',
|
||||
CTImageStorage: '1.2.840.10008.5.1.4.1.1.2',
|
||||
EnhancedCTImageStorage: '1.2.840.10008.5.1.4.1.1.2.1',
|
||||
LegacyConvertedEnhancedCTImageStorage: '1.2.840.10008.5.1.4.1.1.2.2',
|
||||
@@ -23,14 +19,10 @@ export const sopClassDictionary = {
|
||||
UltrasoundImageStorage: '1.2.840.10008.5.1.4.1.1.6.1',
|
||||
EnhancedUSVolumeStorage: '1.2.840.10008.5.1.4.1.1.6.2',
|
||||
SecondaryCaptureImageStorage: '1.2.840.10008.5.1.4.1.1.7',
|
||||
MultiframeSingleBitSecondaryCaptureImageStorage:
|
||||
'1.2.840.10008.5.1.4.1.1.7.1',
|
||||
MultiframeGrayscaleByteSecondaryCaptureImageStorage:
|
||||
'1.2.840.10008.5.1.4.1.1.7.2',
|
||||
MultiframeGrayscaleWordSecondaryCaptureImageStorage:
|
||||
'1.2.840.10008.5.1.4.1.1.7.3',
|
||||
MultiframeTrueColorSecondaryCaptureImageStorage:
|
||||
'1.2.840.10008.5.1.4.1.1.7.4',
|
||||
MultiframeSingleBitSecondaryCaptureImageStorage: '1.2.840.10008.5.1.4.1.1.7.1',
|
||||
MultiframeGrayscaleByteSecondaryCaptureImageStorage: '1.2.840.10008.5.1.4.1.1.7.2',
|
||||
MultiframeGrayscaleWordSecondaryCaptureImageStorage: '1.2.840.10008.5.1.4.1.1.7.3',
|
||||
MultiframeTrueColorSecondaryCaptureImageStorage: '1.2.840.10008.5.1.4.1.1.7.4',
|
||||
Sop12LeadECGWaveformStorage: '1.2.840.10008.5.1.4.1.1.9.1.1',
|
||||
GeneralECGWaveformStorage: '1.2.840.10008.5.1.4.1.1.9.1.2',
|
||||
AmbulatoryECGWaveformStorage: '1.2.840.10008.5.1.4.1.1.9.1.3',
|
||||
@@ -44,8 +36,7 @@ export const sopClassDictionary = {
|
||||
ColorSoftcopyPresentationStateStorage: '1.2.840.10008.5.1.4.1.1.11.2',
|
||||
PseudoColorSoftcopyPresentationStateStorage: '1.2.840.10008.5.1.4.1.1.11.3',
|
||||
BlendingSoftcopyPresentationStateStorage: '1.2.840.10008.5.1.4.1.1.11.4',
|
||||
XAXRFGrayscaleSoftcopyPresentationStateStorage:
|
||||
'1.2.840.10008.5.1.4.1.1.11.5',
|
||||
XAXRFGrayscaleSoftcopyPresentationStateStorage: '1.2.840.10008.5.1.4.1.1.11.5',
|
||||
XRayAngiographicImageStorage: '1.2.840.10008.5.1.4.1.1.12.1',
|
||||
EnhancedXAImageStorage: '1.2.840.10008.5.1.4.1.1.12.1.1',
|
||||
XRayRadiofluoroscopicImageStorage: '1.2.840.10008.5.1.4.1.1.12.2',
|
||||
@@ -53,14 +44,11 @@ export const sopClassDictionary = {
|
||||
XRay3DAngiographicImageStorage: '1.2.840.10008.5.1.4.1.1.13.1.1',
|
||||
XRay3DCraniofacialImageStorage: '1.2.840.10008.5.1.4.1.1.13.1.2',
|
||||
BreastTomosynthesisImageStorage: '1.2.840.10008.5.1.4.1.1.13.1.3',
|
||||
BreastProjectionXRayImageStorageForPresentation:
|
||||
'1.2.840.10008.5.1.4.1.1.13.1.4',
|
||||
BreastProjectionXRayImageStorageForProcessing:
|
||||
'1.2.840.10008.5.1.4.1.1.13.1.5',
|
||||
BreastProjectionXRayImageStorageForPresentation: '1.2.840.10008.5.1.4.1.1.13.1.4',
|
||||
BreastProjectionXRayImageStorageForProcessing: '1.2.840.10008.5.1.4.1.1.13.1.5',
|
||||
IntravascularOpticalCoherenceTomographyImageStorageForPresentation:
|
||||
'1.2.840.10008.5.1.4.1.1.14.1',
|
||||
IntravascularOpticalCoherenceTomographyImageStorageForProcessing:
|
||||
'1.2.840.10008.5.1.4.1.1.14.2',
|
||||
IntravascularOpticalCoherenceTomographyImageStorageForProcessing: '1.2.840.10008.5.1.4.1.1.14.2',
|
||||
NuclearMedicineImageStorage: '1.2.840.10008.5.1.4.1.1.20',
|
||||
RawDataStorage: '1.2.840.10008.5.1.4.1.1.66',
|
||||
SpatialRegistrationStorage: '1.2.840.10008.5.1.4.1.1.66.1',
|
||||
@@ -92,8 +80,7 @@ export const sopClassDictionary = {
|
||||
OphthalmicAxialMeasurementsStorage: '1.2.840.10008.5.1.4.1.1.78.7',
|
||||
IntraocularLensCalculationsStorage: '1.2.840.10008.5.1.4.1.1.78.8',
|
||||
MacularGridThicknessandVolumeReport: '1.2.840.10008.5.1.4.1.1.79.1',
|
||||
OphthalmicVisualFieldStaticPerimetryMeasurementsStorage:
|
||||
'1.2.840.10008.5.1.4.1.1.80.1',
|
||||
OphthalmicVisualFieldStaticPerimetryMeasurementsStorage: '1.2.840.10008.5.1.4.1.1.80.1',
|
||||
OphthalmicThicknessMapStorage: '1.2.840.10008.5.1.4.1.1.81.1',
|
||||
CornealTopographyMapStorage: '1.2.840.10008.5.1.4.1.1.82.1',
|
||||
BasicTextSR: '1.2.840.10008.5.1.4.1.1.88.11',
|
||||
|
||||
@@ -3,7 +3,7 @@ export default function sortBy() {
|
||||
var fields = [].slice.call(arguments),
|
||||
n_fields = fields.length;
|
||||
|
||||
return function(A, B) {
|
||||
return function (A, B) {
|
||||
var a, b, field, key, reverse, result, i;
|
||||
|
||||
for (i = 0; i < n_fields; i++) {
|
||||
|
||||
@@ -15,10 +15,8 @@ export default function sortInstances(instances: Array<any>) {
|
||||
return instances;
|
||||
}
|
||||
|
||||
const {
|
||||
ImagePositionPatient: referenceImagePositionPatient,
|
||||
ImageOrientationPatient,
|
||||
} = instances[Math.floor(instances.length / 2)]; // this prevents getting scout image as test image
|
||||
const { ImagePositionPatient: referenceImagePositionPatient, ImageOrientationPatient } =
|
||||
instances[Math.floor(instances.length / 2)]; // this prevents getting scout image as test image
|
||||
|
||||
if (!referenceImagePositionPatient || !ImageOrientationPatient) {
|
||||
return instances;
|
||||
@@ -49,11 +47,7 @@ export default function sortInstances(instances: Array<any>) {
|
||||
|
||||
const positionVector = vec3.create();
|
||||
|
||||
vec3.sub(
|
||||
positionVector,
|
||||
referenceImagePositionPatient,
|
||||
imagePositionPatient
|
||||
);
|
||||
vec3.sub(positionVector, referenceImagePositionPatient, imagePositionPatient);
|
||||
|
||||
const distance = vec3.dot(positionVector, scanAxisNormal);
|
||||
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
import isLowPriorityModality from './isLowPriorityModality';
|
||||
|
||||
const compareSeriesDateTime = (a, b) => {
|
||||
const seriesDateA = Date.parse(
|
||||
`${a.seriesDate ?? a.SeriesDate} ${a.seriesTime ?? a.SeriesTime}`
|
||||
);
|
||||
const seriesDateB = Date.parse(
|
||||
`${a.seriesDate ?? a.SeriesDate} ${a.seriesTime ?? a.SeriesTime}`
|
||||
);
|
||||
const seriesDateA = Date.parse(`${a.seriesDate ?? a.SeriesDate} ${a.seriesTime ?? a.SeriesTime}`);
|
||||
const seriesDateB = Date.parse(`${a.seriesDate ?? a.SeriesDate} ${a.seriesTime ?? a.SeriesTime}`);
|
||||
return seriesDateA - seriesDateB;
|
||||
};
|
||||
|
||||
@@ -26,12 +22,8 @@ const defaultSeriesSort = (a, b) => {
|
||||
* @param {Object} secondSeries
|
||||
*/
|
||||
function seriesInfoSortingCriteria(firstSeries, secondSeries) {
|
||||
const aLowPriority = isLowPriorityModality(
|
||||
firstSeries.Modality ?? firstSeries.modality
|
||||
);
|
||||
const bLowPriority = isLowPriorityModality(
|
||||
secondSeries.Modality ?? secondSeries.modality
|
||||
);
|
||||
const aLowPriority = isLowPriorityModality(firstSeries.Modality ?? firstSeries.modality);
|
||||
const bLowPriority = isLowPriorityModality(secondSeries.Modality ?? secondSeries.modality);
|
||||
|
||||
if (aLowPriority) {
|
||||
return bLowPriority ? defaultSeriesSort(secondSeries, firstSeries) : 1;
|
||||
@@ -122,10 +114,4 @@ export default function sortStudy(
|
||||
return study;
|
||||
}
|
||||
|
||||
export {
|
||||
sortStudy,
|
||||
sortStudySeries,
|
||||
sortStudyInstances,
|
||||
sortingCriteria,
|
||||
seriesSortCriteria,
|
||||
};
|
||||
export { sortStudy, sortStudySeries, sortStudyInstances, sortingCriteria, seriesSortCriteria };
|
||||
@@ -23,9 +23,7 @@ const getSplitParam = (
|
||||
lowerCaseKey: string,
|
||||
params = new URLSearchParams(window.location.search)
|
||||
): string[] => {
|
||||
const sourceKey = [...params.keys()].find(
|
||||
it => it.toLowerCase() === lowerCaseKey
|
||||
);
|
||||
const sourceKey = [...params.keys()].find(it => it.toLowerCase() === lowerCaseKey);
|
||||
if (!sourceKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -20,10 +20,7 @@ function subscribeToNextViewportGridChange(
|
||||
};
|
||||
|
||||
const subscriptions = [
|
||||
viewportGridService.subscribe(
|
||||
viewportGridService.EVENTS.LAYOUT_CHANGED,
|
||||
callback
|
||||
),
|
||||
viewportGridService.subscribe(viewportGridService.EVENTS.LAYOUT_CHANGED, callback),
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user