reorganize packages, start converting overall app to react (very broken at the moment)

This commit is contained in:
Erik Ziegler committed 2018-12-12 18:06:25 +01:00
1 parent 024fe1a448
commit 5f30f7bd35
479 files changed
+5364 -11611

No files matched your search

@@ -0,0 +1,243 @@
import { Meteor } from 'meteor/meteor';
import { OHIF } from 'meteor/ohif:core';
// Local imports
import { removeFromArray } from '../lib/removeFromArray';
/**
* This class represents a Hanging Protocol at the highest level
*
* @type {Protocol}
*/
HP.Protocol = class Protocol {
/**
* The Constructor for the Class to create a Protocol with the bare
* minimum information
*
* @param name The desired name for the Protocol
*/
constructor(name) {
// Create a new UUID for this Protocol
this.id = OHIF.utils.guid();
// Store a value which determines whether or not a Protocol is locked
// This is probably temporary, since we will eventually have role / user
// checks for editing. For now we just need it to prevent changes to the
// default protocols.
this.locked = false;
// Boolean value to indicate if the protocol has updated priors information
// it's set in "updateNumberOfPriorsReferenced" function
this.hasUpdatedPriorsInformation = false;
// Apply the desired name
this.name = name;
// Set the created and modified dates to Now
this.createdDate = new Date();
this.modifiedDate = new Date();
// If we are logged in while creating this Protocol,
// store this information as well
if (OHIF.user && OHIF.user.userLoggedIn && OHIF.user.userLoggedIn()) {
this.createdBy = OHIF.user.getUserId();
this.modifiedBy = OHIF.user.getUserId();
}
// Create two empty Sets specifying which roles
// have read and write access to this Protocol
this.availableTo = new Set();
this.editableBy = new Set();
// Define empty arrays for the Protocol matching rules
// and Stages
this.protocolMatchingRules = [];
this.stages = [];
// Define auxiliary values for priors
this.numberOfPriorsReferenced = -1;
}
getNumberOfPriorsReferenced(skipCache = false) {
let numberOfPriorsReferenced = skipCache !== true ? this.numberOfPriorsReferenced : -1;
// Check if information is cached already
if (numberOfPriorsReferenced > -1) {
return numberOfPriorsReferenced;
}
numberOfPriorsReferenced = 0;
// Search each study matching rule for prior rules
// Each stage can have many viewports that can have
// multiple study matching rules.
this.stages.forEach(stage => {
if (!stage.viewports) {
return;
}
stage.viewports.forEach(viewport => {
if (!viewport.studyMatchingRules) {
return;
}
viewport.studyMatchingRules.forEach(rule => {
// If the current rule is not a priors rule, it will return -1 then numberOfPriorsReferenced will continue to be 0
const priorsReferenced = rule.getNumberOfPriorsReferenced();
if (priorsReferenced > numberOfPriorsReferenced) {
numberOfPriorsReferenced = priorsReferenced;
}
});
});
});
this.numberOfPriorsReferenced = numberOfPriorsReferenced;
return numberOfPriorsReferenced
}
updateNumberOfPriorsReferenced() {
this.getNumberOfPriorsReferenced(true);
}
/**
* Method to update the modifiedDate when the Protocol
* has been changed
*/
protocolWasModified() {
// If we are logged in while modifying this Protocol,
// store this information as well
if (OHIF.user && OHIF.user.userLoggedIn && OHIF.user.userLoggedIn()) {
this.modifiedBy = OHIF.user.getUserId();
}
// Protocol has been modified, so mark priors information
// as "outdated"
this.hasUpdatedPriorsInformation = false;
// Update number of priors referenced info
this.updateNumberOfPriorsReferenced();
// Update the modifiedDate with the current Date/Time
this.modifiedDate = new Date();
}
/**
* Occasionally the Protocol class needs to be instantiated from a JavaScript Object
* containing the Protocol data. This function fills in a Protocol with the Object
* data.
*
* @param input A Protocol as a JavaScript Object, e.g. retrieved from MongoDB or JSON
*/
fromObject(input) {
// Check if the input already has an ID
// If so, keep it. It not, create a new UUID
this.id = input.id || OHIF.utils.guid();
// Assign the input name to the Protocol
this.name = input.name;
// Retrieve locked status, use !! to make it truthy
// so that undefined values will be set to false
this.locked = !!input.locked;
// TODO: Check how to regenerate Set from Object
//this.availableTo = new Set(input.availableTo);
//this.editableBy = new Set(input.editableBy);
// If the input contains Protocol matching rules
if (input.protocolMatchingRules) {
input.protocolMatchingRules.forEach(ruleObject => {
// Create new Rules from the stored data
var rule = new HP.ProtocolMatchingRule();
rule.fromObject(ruleObject);
// Add them to the Protocol
this.protocolMatchingRules.push(rule);
});
}
// If the input contains data for various Stages in the
// display set sequence
if (input.stages) {
input.stages.forEach(stageObject => {
// Create Stages from the stored data
var stage = new HP.Stage();
stage.fromObject(stageObject);
// Add them to the Protocol
this.stages.push(stage);
});
}
}
/**
* Creates a clone of the current Protocol with a new name
*
* @param name
* @returns {Protocol|*}
*/
createClone(name) {
// Create a new JavaScript independent of the current Protocol
var currentProtocol = Object.assign({}, this);
// Create a new Protocol to return
var clonedProtocol = new HP.Protocol();
// Apply the desired properties
currentProtocol.id = clonedProtocol.id;
clonedProtocol.fromObject(currentProtocol);
// If we have specified a name, assign it
if (name) {
clonedProtocol.name = name;
}
// Unlock the clone
clonedProtocol.locked = false;
// Return the cloned Protocol
return clonedProtocol;
}
/**
* Adds a Stage to this Protocol's display set sequence
*
* @param stage
*/
addStage(stage) {
this.stages.push(stage);
// Update the modifiedDate and User that last
// modified this Protocol
this.protocolWasModified();
}
/**
* Adds a Rule to this Protocol's array of matching rules
*
* @param rule
*/
addProtocolMatchingRule(rule) {
this.protocolMatchingRules.push(rule);
// Update the modifiedDate and User that last
// modified this Protocol
this.protocolWasModified();
}
/**
* Removes a Rule from this Protocol's array of matching rules
*
* @param rule
*/
removeProtocolMatchingRule(rule) {
var wasRemoved = removeFromArray(this.protocolMatchingRules, rule);
// Update the modifiedDate and User that last
// modified this Protocol
if (wasRemoved) {
this.protocolWasModified();
}
}
};
@@ -0,0 +1,172 @@
import { OHIF } from 'meteor/ohif:core';
import { comparators } from '../lib/comparators';
const EQUALS_REGEXP = /^equals$/;
/**
* This Class represents a Rule to be evaluated given a set of attributes
* Rules have:
* - An attribute (e.g. 'seriesDescription')
* - A constraint Object, in the form required by Validate.js:
*
* rule.constraint = {
* contains: {
* value: 'T-1'
* }
* };
*
* Note: In this example we use the 'contains' Validator, which is a custom Validator defined in Viewerbase
*
* - A value for whether or not they are Required to be matched (default: False)
* - A value for their relative weighting during Protocol or Image matching (default: 1)
*/
export class Rule {
/**
* The Constructor for the Class to create a Rule with the bare
* minimum information
*
* @param name The desired name for the Rule
*/
constructor(attribute, constraint, required, weight) {
// Create a new UUID for this Rule
this.id = OHIF.utils.guid();
// Set the Rule's weight (defaults to 1)
this.weight = weight || 1;
// If an attribute is specified, assign it
if (attribute) {
this.attribute = attribute;
}
// If a constraint is specified, assign it
if (constraint) {
this.constraint = constraint;
}
// If a value for 'required' is specified, assign it
if (required === undefined) {
// If no value was specified, default to False
this.required = false;
} else {
this.required = required;
}
// Cache for constraint info object
this._constraintInfo = void 0;
// Cache for validator and value object
this._validatorAndValue = void 0;
}
/**
* Occasionally the Rule class needs to be instantiated from a JavaScript Object.
* This function fills in a Protocol with the Object data.
*
* @param input A Rule as a JavaScript Object, e.g. retrieved from MongoDB or JSON
*/
fromObject(input) {
// Check if the input already has an ID
// If so, keep it. It not, create a new UUID
this.id = input.id || OHIF.utils.guid();
// Assign the specified input data to the Rule
this.required = input.required;
this.weight = input.weight;
this.attribute = input.attribute;
this.constraint = input.constraint;
}
/**
* Get the constraint info object for the current constraint
* @return {Object\undefined} Constraint object or undefined if current constraint
* is not valid or not found in comparators list
*/
getConstraintInfo() {
let constraintInfo = this._constraintInfo;
// Check if info is cached already
if (constraintInfo !== void 0) {
return constraintInfo;
}
const ruleConstraint = Object.keys(this.constraint)[0];
if (ruleConstraint !== void 0) {
constraintInfo = comparators.find(comparator => ruleConstraint === comparator.id)
}
// Cache this information for later use
this._constraintInfo = constraintInfo;
return constraintInfo;
}
/**
* Check if current rule is related to priors
* @return {Boolean} True if a rule is related to priors or false otherwise
*/
isRuleForPrior() {
// @TODO: Should we check this too? this.attribute === 'relativeTime'
return this.attribute === 'abstractPriorValue';
}
/**
* If the current rule is a rule for priors, returns the number of referenced priors. Otherwise, returns -1.
* @return {Number} The number of referenced priors or -1 if not applicable. Returns zero if the actual value could not be determined.
*/
getNumberOfPriorsReferenced() {
if (!this.isRuleForPrior()) {
return -1;
}
// Get rule's validator and value
const ruleValidatorAndValue = this.getConstraintValidatorAndValue();
const { value, validator } = ruleValidatorAndValue;
const intValue = parseInt(value, 10) || 0; // avoid possible NaN
// "Equal to" validators
if (EQUALS_REGEXP.test(validator)) {
// In this case, -1 (the oldest prior) indicates that at least one study is used
return intValue < 0 ? 1 : intValue;
}
// Default cases return value
return 0;
}
/**
* Get the constraint validator and value
* @return {Object|undefined} Returns an object containing the validator and it's value or undefined
*/
getConstraintValidatorAndValue() {
let validatorAndValue = this._validatorAndValue;
// Check if validator and value are cached already
if (validatorAndValue !== void 0) {
return validatorAndValue;
}
// Get the constraint info object
const constraintInfo = this.getConstraintInfo();
// Constraint info object exists and is valid
if (constraintInfo !== void 0) {
const validator = constraintInfo.validator;
const currentValidator = this.constraint[validator];
if (currentValidator) {
const constraintValidator = constraintInfo.validatorOption;
const constraintValue = currentValidator[constraintValidator];
validatorAndValue = {
value: constraintValue,
validator: constraintInfo.id
};
this._validatorAndValue = validatorAndValue;
}
}
return validatorAndValue;
}
}
@@ -0,0 +1,87 @@
import { OHIF } from 'meteor/ohif:core';
/**
* A Stage is one step in the Display Set Sequence for a Hanging Protocol
*
* Stages are defined as a ViewportStructure and an array of Viewports
*
* @type {Stage}
*/
HP.Stage = class Stage {
constructor(ViewportStructure, name) {
// Create a new UUID for this Stage
this.id = OHIF.utils.guid();
// Assign the name and ViewportStructure provided
this.name = name;
this.viewportStructure = ViewportStructure;
// Create an empty array for the Viewports
this.viewports = [];
// Set the created date to Now
this.createdDate = new Date();
}
/**
* Creates a clone of the current Stage with a new name
*
* Note! This method absolutely cannot be renamed 'clone', because
* Minimongo's insert method uses 'clone' internally and this
* somehow causes very bizarre behaviour
*
* @param name
* @returns {Stage|*}
*/
createClone(name) {
// Create a new JavaScript independent of the current Protocol
var currentStage = Object.assign({}, this);
// Create a new Stage to return
var clonedStage = new HP.Stage();
// Assign the desired properties
currentStage.id = clonedStage.id;
clonedStage.fromObject(currentStage);
// If we have specified a name, assign it
if (name) {
clonedStage.name = name;
}
// Return the cloned Stage
return clonedStage;
}
/**
* Occasionally the Stage class needs to be instantiated from a JavaScript Object.
* This function fills in a Protocol with the Object data.
*
* @param input A Stage as a JavaScript Object, e.g. retrieved from MongoDB or JSON
*/
fromObject(input) {
// Check if the input already has an ID
// If so, keep it. It not, create a new UUID
this.id = input.id || OHIF.utils.guid();
// Assign the input name to the Stage
this.name = input.name;
// If a ViewportStructure is present in the input, add it from the
// input data
this.viewportStructure = new HP.ViewportStructure();
this.viewportStructure.fromObject(input.viewportStructure);
// If any viewports are present in the input object
if (input.viewports) {
input.viewports.forEach(viewportObject => {
// Create a new Viewport with their data
var viewport = new HP.Viewport();
viewport.fromObject(viewportObject);
// Add it to the viewports array
this.viewports.push(viewport);
});
}
}
};
@@ -0,0 +1,81 @@
// Local imports
import { removeFromArray } from '../lib/removeFromArray';
/**
* This Class defines a Viewport in the Hanging Protocol Stage. A Viewport contains
* arrays of Rules that are matched in the ProtocolEngine in order to determine which
* images should be hung.
*
* @type {Viewport}
*/
HP.Viewport = class Viewport {
constructor() {
this.viewportSettings = {};
this.imageMatchingRules = [];
this.seriesMatchingRules = [];
this.studyMatchingRules = [];
}
/**
* Occasionally the Viewport class needs to be instantiated from a JavaScript Object.
* This function fills in a Viewport with the Object data.
*
* @param input The Viewport as a JavaScript Object, e.g. retrieved from MongoDB or JSON
*/
fromObject(input) {
// If ImageMatchingRules exist, create them from the Object data
// and add them to the Viewport's imageMatchingRules array
if (input.imageMatchingRules) {
input.imageMatchingRules.forEach(ruleObject => {
var rule = new HP.ImageMatchingRule();
rule.fromObject(ruleObject);
this.imageMatchingRules.push(rule);
});
}
// If SeriesMatchingRules exist, create them from the Object data
// and add them to the Viewport's seriesMatchingRules array
if (input.seriesMatchingRules) {
input.seriesMatchingRules.forEach(ruleObject => {
var rule = new HP.SeriesMatchingRule();
rule.fromObject(ruleObject);
this.seriesMatchingRules.push(rule);
});
}
// If StudyMatchingRules exist, create them from the Object data
// and add them to the Viewport's studyMatchingRules array
if (input.studyMatchingRules) {
input.studyMatchingRules.forEach(ruleObject => {
var rule = new HP.StudyMatchingRule();
rule.fromObject(ruleObject);
this.studyMatchingRules.push(rule);
});
}
// If ViewportSettings exist, add them to the current protocol
if (input.viewportSettings) {
this.viewportSettings = input.viewportSettings;
}
}
/**
* Finds and removes a rule from whichever array it exists in.
* It is not required to specify if it exists in studyMatchingRules,
* seriesMatchingRules, or imageMatchingRules
*
* @param rule
*/
removeRule(rule) {
var array;
if (rule instanceof HP.StudyMatchingRule) {
array = this.studyMatchingRules;
} else if (rule instanceof HP.SeriesMatchingRule) {
array = this.seriesMatchingRules;
} else if (rule instanceof HP.ImageMatchingRule) {
array = this.imageMatchingRules;
}
removeFromArray(array, rule);
}
};
@@ -0,0 +1,53 @@
/**
* The ViewportStructure class represents the layout and layout properties that
* Viewports are displayed in. ViewportStructure has a type, which corresponds to
* a layout template, and a set of properties, which depend on the type.
*
* @type {ViewportStructure}
*/
HP.ViewportStructure = class ViewportStructure {
constructor(type, properties) {
this.type = type;
this.properties = properties;
}
/**
* Occasionally the ViewportStructure class needs to be instantiated from a JavaScript Object.
* This function fills in a ViewportStructure with the Object data.
*
* @param input The ViewportStructure as a JavaScript Object, e.g. retrieved from MongoDB or JSON
*/
fromObject(input) {
this.type = input.type;
this.properties = input.properties;
}
/**
* Retrieve the layout template name based on the layout type
*
* @returns {string}
*/
getLayoutTemplateName() {
// Viewport structure can be updated later when we build more complex display layouts
switch (this.type) {
case 'grid':
return 'gridLayout';
}
}
/**
* Retrieve the number of Viewports required for this layout
* given the layout type and properties
*
* @returns {string}
*/
getNumViewports() {
// Viewport structure can be updated later when we build more complex display layouts
switch (this.type) {
case 'grid':
// For the typical grid layout, we only need to multiply rows by columns to
// obtain the number of viewports
return this.properties.rows * this.properties.columns;
}
}
};
@@ -0,0 +1,9 @@
import { Rule } from '../Rule';
/**
* The ImageMatchingRule class extends the Rule Class.
*
* At present it does not add any new methods or attributes
* @type {ImageMatchingRule}
*/
HP.ImageMatchingRule = class ImageMatchingRule extends Rule {};
@@ -0,0 +1,9 @@
import { Rule } from '../Rule';
/**
* The ProtocolMatchingRule Class extends the Rule Class.
*
* At present it does not add any new methods or attributes
* @type {ProtocolMatchingRule}
*/
HP.ProtocolMatchingRule = class ProtocolMatchingRule extends Rule {};
@@ -0,0 +1,9 @@
import { Rule } from '../Rule';
/**
* The SeriesMatchingRule Class extends the Rule Class.
*
* At present it does not add any new methods or attributes
* @type {SeriesMatchingRule}
*/
HP.SeriesMatchingRule = class SeriesMatchingRule extends Rule {};
@@ -0,0 +1,9 @@
import { Rule } from '../Rule';
/**
* The StudyMatchingRule Class extends the Rule Class.
*
* At present it does not add any new methods or attributes
* @type {StudyMatchingRule}
*/
HP.StudyMatchingRule = class StudyMatchingRule extends Rule {};
@@ -1,9 +1,12 @@
import { Meteor } from 'meteor/meteor';
import { comparators } from '../both/lib/comparators';
import { comparators } from './lib/comparators';
MatchedProtocols = new Meteor.Collection(null);
MatchedProtocols._debugName = 'MatchedProtocols';
HangingProtocols = new Meteor.Collection(null);
HangingProtocols._debugName = 'HangingProtocols';
Comparators = new Meteor.Collection(null);
Comparators._debugName = 'Comparators';
@@ -1,7 +1,7 @@
import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { Session } from 'meteor/session';
import { $ } from 'meteor/jquery';
import $ from 'jquery';
import { OHIF } from 'meteor/ohif:core';
import 'meteor/ohif:viewerbase';
@@ -1,4 +1,4 @@
@import "{ohif:design}/app"
@import "{ohif:viewerbase}/app"
$height = 20px
@@ -1,4 +1,4 @@
import { $ } from 'meteor/jquery';
import $ from 'jquery';
import { Session } from 'meteor/session';
import { ReactiveVar } from 'meteor/reactive-var';
import { Template } from 'meteor/templating';
@@ -1,4 +1,4 @@
@import "{ohif:design}/app"
@import "{ohif:viewerbase}/app"
.ruleEntryDialog
theme('background', '$uiGrayDarkest', 0.95)
@@ -1,4 +1,4 @@
@import "{ohif:design}/app"
@import "{ohif:viewerbase}/app"
table.ruleTable
thead
@@ -24,11 +24,11 @@ table.ruleTable
&:hover, &:active
cursor: pointer
transition(all 0.1s ease)
&:hover
theme('color', '$hoverColor')
&:active
&:active
theme('color', '$activeColor')
td:first-child
@@ -50,9 +50,9 @@ table.ruleTable
.addRule
cursor: pointer
transition(all 0.1s ease)
&:hover
theme('color', '$hoverColor')
&:active
theme('color', '$activeColor')
&:active
theme('color', '$activeColor')
@@ -2,7 +2,7 @@ import { Template } from 'meteor/templating';
import { Session } from 'meteor/session';
import { ReactiveVar } from 'meteor/reactive-var';
import { Blaze } from 'meteor/blaze';
import { $ } from 'meteor/jquery';
import $ from 'jquery';
import { Viewerbase } from 'meteor/ohif:viewerbase';
@@ -1,4 +1,4 @@
@import "{ohif:design}/app"
@import "{ohif:viewerbase}/app"
.settingEntryDialog
theme('border', '1px solid $uiBorderColor', 0.95)
@@ -1,4 +1,4 @@
@import "{ohif:design}/app"
@import "{ohif:viewerbase}/app"
table.settingsTable
thead
@@ -22,13 +22,13 @@ table.settingsTable
.deleteSetting
cursor: pointer
transition(all 0.1s ease)
&:hover
theme('color', '$hoverColor')
&:active
&:active
theme('color', '$activeColor')
td:first-child
text-align: left
@@ -40,9 +40,9 @@ table.settingsTable
.addSetting
cursor: pointer
transition(all 0.1s ease)
&:hover
theme('color', '$hoverColor')
&:active
theme('color', '$activeColor')
&:active
theme('color', '$activeColor')
@@ -1,4 +1,4 @@
@import "{ohif:design}/app"
@import "{ohif:viewerbase}/app"
#stageDetails
overflow-y: auto
@@ -1,4 +1,4 @@
@import "{ohif:design}/app"
@import "{ohif:viewerbase}/app"
#stageSortingContainer
padding: 0 20px
@@ -13,7 +13,7 @@
&:hover
theme('color', '$hoverColor')
&.active
theme('color', '$activeColor')
@@ -38,11 +38,11 @@
cursor: pointer
theme('color', '$defaultColor')
transition(all 0.1s ease)
&:hover
theme('color', '$hoverColor')
&:active
&:active
theme('color', '$activeColor')
.addStage
@@ -52,11 +52,11 @@
#addStage
transition(all 0.1s ease)
&:hover
theme('color', '$hoverColor')
&:active
&:active
theme('color', '$activeColor')
.moveStageButtons
@@ -68,11 +68,11 @@
cursor: pointer
text-decoration: none
transition(all 0.1s ease)
&:hover
theme('color', '$hoverColor')
&:active
&:active
theme('color', '$activeColor')
&[disabled="true"]
@@ -1,5 +1,5 @@
import { Blaze } from 'meteor/blaze';
import { $ } from 'meteor/jquery';
import $ from 'jquery';
import { Template } from 'meteor/templating';
import { Viewerbase } from 'meteor/ohif:viewerbase';
@@ -1,4 +1,4 @@
@import "{ohif:design}/app"
@import "{ohif:viewerbase}/app"
.textEntryDialog
theme('border', '1px solid $uiBorderColor', 0.95)
@@ -0,0 +1,102 @@
HP.attributeDefaults = {
abstractPriorValue: 0
};
HP.displaySettings = {
invert: {
id: 'invert',
text: 'Show Grayscale Inverted',
defaultValue: 'NO',
options: ['YES', 'NO']
}
};
// @TODO Fix abstractPriorValue comparison
HP.studyAttributes = [{
id: 'x00100020',
text: '(x00100020) Patient ID'
}, {
id: 'x0020000d',
text: '(x0020000d) Study Instance UID'
}, {
id: 'x00080020',
text: '(x00080020) Study Date'
}, {
id: 'x00080030',
text: '(x00080030) Study Time'
}, {
id: 'x00081030',
text: '(x00081030) Study Description'
}, {
id: 'abstractPriorValue',
text: 'Abstract Prior Value'
}];
HP.protocolAttributes = [{
id: 'x00100020',
text: '(x00100020) Patient ID'
}, {
id: 'x0020000d',
text: '(x0020000d) Study Instance UID'
}, {
id: 'x00080020',
text: '(x00080020) Study Date'
}, {
id: 'x00080030',
text: '(x00080030) Study Time'
}, {
id: 'x00081030',
text: '(x00081030) Study Description'
}, {
id: 'anatomicRegion',
text: 'Anatomic Region'
}];
HP.seriesAttributes = [{
id: 'x0020000e',
text: '(x0020000e) Series Instance UID'
}, {
id: 'x00080060',
text: '(x00080060) Modality'
}, {
id: 'x00200011',
text: '(x00200011) Series Number'
}, {
id: 'x0008103e',
text: '(x0008103e) Series Description'
}, {
id: 'numImages',
text: 'Number of Images'
}];
HP.instanceAttributes = [{
id: 'x00080016',
text: '(x00080016) SOP Class UID'
}, {
id: 'x00080018',
text: '(x00080018) SOP Instance UID'
}, {
id: 'x00185101',
text: '(x00185101) View Position'
}, {
id: 'x00200013',
text: '(x00200013) Instance Number'
}, {
id: 'x00080008',
text: '(x00080008) Image Type'
}, {
id: 'x00181063',
text: '(x00181063) Frame Time'
}, {
id: 'x00200060',
text: '(x00200060) Laterality'
}, {
id: 'x00541330',
text: '(x00541330) Image Index'
}, {
id: 'x00280004',
text: '(x00280004) Photometric Interpretation'
}, {
id: 'x00180050',
text: '(x00180050) Slice Thickness'
}];
@@ -0,0 +1,84 @@
const comparators = [{
id: 'equals',
name: '= (Equals)',
validator: 'equals',
validatorOption: 'value',
description: 'The attribute must equal this value.'
}, {
id: 'doesNotEqual',
name: '!= (Does not equal)',
validator: 'doesNotEqual',
validatorOption: 'value',
description: 'The attribute must not equal this value.'
}, {
id: 'contains',
name: 'Contains',
validator: 'contains',
validatorOption: 'value',
description: 'The attribute must contain this value.'
}, {
id: 'doesNotContain',
name: 'Does not contain',
validator: 'doesNotContain',
validatorOption: 'value',
description: 'The attribute must not contain this value.'
}, {
id: 'startsWith',
name: 'Starts with',
validator: 'startsWith',
validatorOption: 'value',
description: 'The attribute must start with this value.'
}, {
id: 'endsWith',
name: 'Ends with',
validator: 'endsWith',
validatorOption: 'value',
description: 'The attribute must end with this value.'
}, {
id: 'onlyInteger',
name: 'Only Integers',
validator: 'numericality',
validatorOption: 'onlyInteger',
description: "Real numbers won't be allowed."
}, {
id: 'greaterThan',
name: '> (Greater than)',
validator: 'numericality',
validatorOption: 'greaterThan',
description: 'The attribute has to be greater than this value.'
}, {
id: 'greaterThanOrEqualTo',
name: '>= (Greater than or equal to)',
validator: 'numericality',
validatorOption: 'greaterThanOrEqualTo',
description: 'The attribute has to be at least this value.'
}, {
id: 'lessThanOrEqualTo',
name: '<= (Less than or equal to)',
validator: 'numericality',
validatorOption: 'lessThanOrEqualTo',
description: 'The attribute can be this value at the most.'
}, {
id: 'lessThan',
name: '< (Less than)',
validator: 'numericality',
validatorOption: 'lessThan',
description: 'The attribute has to be less than this value.'
}, {
id: 'odd',
name: 'Odd',
validator: 'numericality',
validatorOption: 'odd',
description: 'The attribute has to be odd.'
}, {
id: 'even',
name: 'Even',
validator: 'numericality',
validatorOption: 'even',
description: 'The attribute has to be even.'
}];
// Immutable object
Object.freeze(comparators);
export { comparators }
@@ -0,0 +1,33 @@
import _ from 'underscore';
/**
* Removes the first instance of an element from an array, if an equal value exists
*
* @param array
* @param input
*
* @returns {boolean} Whether or not the element was found and removed
*/
const removeFromArray = (array, input) => {
// If the array is empty, stop here
if (!array ||
!array.length) {
return false;
}
array.forEach((value, index) => {
if (_.isEqual(value, input)) {
indexToRemove = index;
return false;
}
});
if (indexToRemove === void 0) {
return false;
}
array.splice(indexToRemove, 1);
return true;
};
export { removeFromArray };
@@ -0,0 +1 @@
HP = {};
@@ -1,5 +1,5 @@
import { Meteor } from 'meteor/meteor';
import { _ } from 'meteor/underscore';
import _ from 'underscore';
import { Session } from 'meteor/session';
// OHIF Modules
@@ -1,159 +1,8 @@
import { Meteor } from "meteor/meteor";
import { Mongo } from 'meteor/mongo';
// The ProtocolStore default strategy is used to persist hanging protocols in
// the MongoDB collection 'HangingProtocols' in the application server.
var defaultStrategy = (function () {
var hangingProtocolSubs;
function addDefaultProtocols() {
console.log('Inserting default protocols');
addProtocol(HP.defaultProtocol);
}
function getDatabaseIdByProtocolId(protocolId) {
const filteredProtocol = HangingProtocols.findOne({
id: protocolId
}, {
fields: {
_id: true
}
});
if (!filteredProtocol) {
return;
}
return filteredProtocol._id;
}
/**
* Registers a function to be called when the hangingprotocols collection is subscribed
* The callback is called only one time when the subscription is ready
*
* @param callback The function to be called as a callback
*/
function onReady(callback) {
if (hangingProtocolSubs && hangingProtocolSubs.ready()) {
// It is already ready
callback();
} else {
// Subscribe the hangingprotocols collection
hangingProtocolSubs = Meteor.subscribe('hangingprotocols');
// Wait for the subscription to be ready
Tracker.autorun((computation) => {
if (hangingProtocolSubs.ready()) {
computation.stop();
addDefaultProtocols();
callback();
}
});
}
}
/**
* Gets the hanging protocol by protocolId if defined, otherwise all stored hanging protocols
*
* @param protocolId The protocol ID used to find the hanging protocol
* @returns {object|array} The hanging protocol by protocolId or array of the stored hanging protocols
*/
function getProtocol(protocolId) {
// Return the hanging protocol by protocolId if defined
if (protocolId) {
return HangingProtocols.findOne({
id: protocolId
});
}
// Otherwise, return all protocols
return HangingProtocols.find().fetch();
}
/**
* Stores the hanging protocol
*
* @param protocol The hanging protocol to be stored
*/
function addProtocol(protocol) {
// Collections can only be updated by database ID (_id) on client, so
// get the database ID (_id) by the hanging protocol ID firstly
const databaseId = getDatabaseIdByProtocolId(protocol.id);
// Remove any MongoDB ID the protocol may have had
delete protocol._id;
// Update the protocol with the same id if exists instead of inserting this protocol
if (databaseId) {
// Update the hanging protocol by the database ID
HangingProtocols.update(databaseId, {
$set: protocol
});
return;
}
// Insert the protocol
HangingProtocols.insert(protocol);
}
/**
* Updates the hanging protocol by protocolId
*
* @param protocolId The protocol ID used to find the hanging protocol to update
* @param protocol The updated hanging protocol
*/
function updateProtocol(protocolId, protocol) {
// Collections can only be updated by database ID (_id) on client, so
// get the database ID (_id) by the hanging protocol ID firstly
const databaseId = getDatabaseIdByProtocolId(protocolId);
// Skip if it does not exist in database
if (!databaseId) {
return;
}
// Remove any MongoDB ID the protocol may have had
delete protocol._id;
// Update the hanging protocol by the database ID
HangingProtocols.update(databaseId, {
$set: protocol
});
}
/**
* Removes the hanging protocol
*
* @param protocolId The protocol ID used to remove the hanging protocol
*/
function removeProtocol(protocolId) {
// Collections can only be removed by database ID (_id) on client, so
// get the database ID (_id) by the hanging protocol ID firstly
const databaseId = getDatabaseIdByProtocolId(protocolId);
// Skip if it does not exist in database
if (!databaseId) {
return;
}
// Remove the hanging protocol by the database ID
HangingProtocols.remove(databaseId);
}
// Module Exports
return {
onReady: onReady,
getProtocol: getProtocol,
addProtocol: addProtocol,
updateProtocol: updateProtocol,
removeProtocol: removeProtocol
};
})();
var clientOnlyStrategy = (function () {
const HangingProtocols = new Mongo.Collection(null);
let defaultsAdded = false;
@@ -296,16 +145,5 @@ var clientOnlyStrategy = (function () {
})();
// If we are running a disconnect client similar to the StandaloneViewer
// (see https://docs.ohif.org/standalone-viewer/usage.html) we don't want
// our HangingProtocol strategy to try to use Meteor methods or Pub / Sub
if (Meteor.settings &&
Meteor.settings.public &&
Meteor.settings.public.clientOnly === true) {
HP.ProtocolStore.setStrategy(clientOnlyStrategy);
} else {
HP.ProtocolStore.setStrategy(defaultStrategy);
}
HP.clientOnlyStrategy = clientOnlyStrategy;
HP.ProtocolStore.setStrategy(defaultStrategy);
@@ -0,0 +1,13 @@
// @TODO start using namespace instead
// Base classes
import './classes/Protocol';
import './classes/Stage';
import './classes/Viewport';
import './classes/ViewportStructure';
// Specialized Rule classes
import './classes/rules/ProtocolMatchingRule';
import './classes/rules/StudyMatchingRule';
import './classes/rules/SeriesMatchingRule';
import './classes/rules/ImageMatchingRule';
File diff suppressed because it is too large. Load diff