PWV-1: Refactoring ohif:studylist package
This commit is contained in:
1 parent
984ef94403
commit
4d79bf84a8
79 files changed
+450
-551
No files matched your search
@@ -35,7 +35,6 @@
|
|||||||
{{ >serverInformationModal }}
|
{{ >serverInformationModal }}
|
||||||
{{ >confirmRemoveTimepointAssociation }}
|
{{ >confirmRemoveTimepointAssociation }}
|
||||||
{{ >lastLoginModal }}
|
{{ >lastLoginModal }}
|
||||||
{{ >studyContextMenu }}
|
|
||||||
{{ >progressDialog }}
|
{{ >progressDialog }}
|
||||||
{{ >viewSeriesDetailsModal }}
|
{{ >viewSeriesDetailsModal }}
|
||||||
</template>
|
</template>
|
||||||
@@ -33,7 +33,6 @@
|
|||||||
</div>
|
</div>
|
||||||
{{ >serverInformationModal }}
|
{{ >serverInformationModal }}
|
||||||
{{ >lastLoginModal }}
|
{{ >lastLoginModal }}
|
||||||
{{ >studyContextMenu }}
|
|
||||||
{{ >progressDialog }}
|
{{ >progressDialog }}
|
||||||
{{ >viewSeriesDetailsModal }}
|
{{ >viewSeriesDetailsModal }}
|
||||||
</template>
|
</template>
|
||||||
@@ -12,7 +12,7 @@ OHIF.mixins.button = new OHIF.Mixin({
|
|||||||
const component = instance.component;
|
const component = instance.component;
|
||||||
|
|
||||||
// Set the element to be controlled
|
// Set the element to be controlled
|
||||||
component.$element = instance.$('button:first');
|
component.$element = instance.$('button').first();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -54,7 +54,7 @@ OHIF.mixins.form = new OHIF.Mixin({
|
|||||||
const component = instance.component;
|
const component = instance.component;
|
||||||
|
|
||||||
// Set the component main and style elements
|
// Set the component main and style elements
|
||||||
component.$style = component.$element = instance.$('form:first');
|
component.$style = component.$element = instance.$('form').first();
|
||||||
|
|
||||||
// Block page redirecting on submit
|
// Block page redirecting on submit
|
||||||
component.$element[0].onsubmit = () => false;
|
component.$element[0].onsubmit = () => false;
|
||||||
@@ -66,7 +66,7 @@ OHIF.mixins.form = new OHIF.Mixin({
|
|||||||
const targetKey = $(event.currentTarget).attr('data-target');
|
const targetKey = $(event.currentTarget).attr('data-target');
|
||||||
|
|
||||||
// Focus the first input inside the element with error state
|
// Focus the first input inside the element with error state
|
||||||
instance.$(`.state-error[data-key="${targetKey}"] :input:first`).focus();
|
instance.$(`.state-error[data-key="${targetKey}"]`).find(':input:first').focus();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ OHIF.mixins.group = new OHIF.Mixin({
|
|||||||
const component = instance.component;
|
const component = instance.component;
|
||||||
|
|
||||||
// Set the element to be controlled
|
// Set the element to be controlled
|
||||||
component.$element = instance.$('.component-group:first');
|
component.$element = instance.$('.component-group').first();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -12,7 +12,7 @@ OHIF.mixins.input = new OHIF.Mixin({
|
|||||||
const component = instance.component;
|
const component = instance.component;
|
||||||
|
|
||||||
// Set the element to be controlled
|
// Set the element to be controlled
|
||||||
component.$element = instance.$('input:first');
|
component.$element = instance.$('input').first();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -12,7 +12,7 @@ OHIF.mixins.link = new OHIF.Mixin({
|
|||||||
const component = instance.component;
|
const component = instance.component;
|
||||||
|
|
||||||
// Set the element to be controlled
|
// Set the element to be controlled
|
||||||
component.$element = instance.$('a:first');
|
component.$element = instance.$('a').first();
|
||||||
},
|
},
|
||||||
|
|
||||||
events: {
|
events: {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ OHIF.mixins.select = new OHIF.Mixin({
|
|||||||
const component = instance.component;
|
const component = instance.component;
|
||||||
|
|
||||||
// Set the element to be controlled
|
// Set the element to be controlled
|
||||||
component.$element = instance.$('select:first');
|
component.$element = instance.$('select').first();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<template name="dropdownBackdrop">
|
||||||
|
<div class="dropdown-backdrop"></div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<template name="dropdownForm">
|
||||||
|
{{#form class='dropdown' api=this.api hideValidationBox=true}}
|
||||||
|
{{>dropdownBackdrop}}
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
{{>UI.contentBlock}}
|
||||||
|
</ul>
|
||||||
|
{{/form}}
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { Template } from 'meteor/templating';
|
||||||
|
import { Blaze } from 'meteor/blaze';
|
||||||
|
import { _ } from 'meteor/underscore';
|
||||||
|
|
||||||
|
Template.dropdownForm.onRendered(() => {
|
||||||
|
const instance = Template.instance();
|
||||||
|
|
||||||
|
// Show the dropdown
|
||||||
|
instance.$('.dropdown').addClass('open');
|
||||||
|
|
||||||
|
// Destroy the Blaze created view (either created with template calls or with renderWithData)
|
||||||
|
instance.destroyView = () => {
|
||||||
|
if (_.isFunction(instance.data.destroyView)) {
|
||||||
|
instance.data.destroyView();
|
||||||
|
} else {
|
||||||
|
Blaze.remove(instance.view);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.dropdownForm.events({
|
||||||
|
'click .dropdown'(event, instance) {
|
||||||
|
instance.destroyView();
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -3,6 +3,10 @@ import './dialog/form.js';
|
|||||||
import './dialog/login.html';
|
import './dialog/login.html';
|
||||||
import './dialog/login.js';
|
import './dialog/login.js';
|
||||||
|
|
||||||
|
import './dropdown/backdrop.html';
|
||||||
|
import './dropdown/form.html';
|
||||||
|
import './dropdown/form.js';
|
||||||
|
|
||||||
import './form/button.html';
|
import './form/button.html';
|
||||||
import './form/form.html';
|
import './form/form.html';
|
||||||
import './form/group.html';
|
import './form/group.html';
|
||||||
|
|||||||
@@ -36,10 +36,15 @@ class Bounded {
|
|||||||
options(options={}) {
|
options(options={}) {
|
||||||
// Process the given options and store it in the instance
|
// Process the given options and store it in the instance
|
||||||
const { boundingElement, allowResizing } = options;
|
const { boundingElement, allowResizing } = options;
|
||||||
this.boundingElement = boundingElement || window;
|
this.boundingElement = boundingElement;
|
||||||
this.$boundingElement = $(this.boundingElement);
|
this.$boundingElement = $(this.boundingElement);
|
||||||
this.allowResizing = allowResizing;
|
this.allowResizing = allowResizing;
|
||||||
|
|
||||||
|
// Check for fixed positioning
|
||||||
|
if (this.$element.css('position') === 'fixed') {
|
||||||
|
this.boundingElement = window;
|
||||||
|
}
|
||||||
|
|
||||||
// Destroy and initialize again the instance
|
// Destroy and initialize again the instance
|
||||||
this.destroy();
|
this.destroy();
|
||||||
this.init();
|
this.init();
|
||||||
@@ -55,6 +60,9 @@ class Bounded {
|
|||||||
|
|
||||||
// Add the bounded class to the element
|
// Add the bounded class to the element
|
||||||
this.$element.addClass('bounded');
|
this.$element.addClass('bounded');
|
||||||
|
|
||||||
|
// Trigger the bounding check for the first timepoint
|
||||||
|
setTimeout(() => this.$element.trigger('spatialChanged'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy this instance, returning the element to its previous state
|
// Destroy this instance, returning the element to its previous state
|
||||||
@@ -70,12 +78,26 @@ class Bounded {
|
|||||||
// Create the result object
|
// Create the result object
|
||||||
const result = {};
|
const result = {};
|
||||||
|
|
||||||
|
// Check if the element is the window
|
||||||
|
if (element === window) {
|
||||||
|
const $window = $(window);
|
||||||
|
const width = $window.outerWidth();
|
||||||
|
const height = $window.outerHeight();
|
||||||
|
return {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
x0: 0,
|
||||||
|
y0: 0,
|
||||||
|
x1: width,
|
||||||
|
y1: height
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Get the jQuery object for the element
|
// Get the jQuery object for the element
|
||||||
const el = element === window ? window.document.body : element;
|
const $element = $(element);
|
||||||
const $element = $(el);
|
|
||||||
|
|
||||||
// Get the element style
|
// Get the element style
|
||||||
const style = el.style;
|
const style = element.style;
|
||||||
|
|
||||||
// Get the integer numbers for element's width
|
// Get the integer numbers for element's width
|
||||||
if (style.width && style.width.indexOf('px') > -1) {
|
if (style.width && style.width.indexOf('px') > -1) {
|
||||||
@@ -91,10 +113,13 @@ class Bounded {
|
|||||||
result.height = $element.outerHeight();
|
result.height = $element.outerHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the position property based on the element position CSS attribute
|
||||||
|
const positionProperty = $element.css('position') === 'fixed' ? 'position' : 'offset';
|
||||||
|
|
||||||
// Get the element's start position
|
// Get the element's start position
|
||||||
const offset = $element.offset();
|
const position = $element[positionProperty]();
|
||||||
result.x0 = offset.left;
|
result.x0 = position.left;
|
||||||
result.y0 = offset.top;
|
result.y0 = position.top;
|
||||||
|
|
||||||
// Get the element's end position
|
// Get the element's end position
|
||||||
result.x1 = result.x0 + result.width;
|
result.x1 = result.x0 + result.width;
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { Template } from 'meteor/templating';
|
||||||
|
import { Blaze } from 'meteor/blaze';
|
||||||
|
import { _ } from 'meteor/underscore';
|
||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
|
OHIF.ui.showFormDropdown = (templateName, dropdownData) => {
|
||||||
|
// Check if the given template exists
|
||||||
|
const template = Template[templateName];
|
||||||
|
if (!template) {
|
||||||
|
throw {
|
||||||
|
name: 'TEMPLATE_NOT_FOUND',
|
||||||
|
message: `Template ${templateName} not found.`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the method to destroy the view
|
||||||
|
let view;
|
||||||
|
const destroyView = () => Blaze.remove(view);
|
||||||
|
const templateData = _.extend({}, dropdownData, {
|
||||||
|
destroyView
|
||||||
|
});
|
||||||
|
|
||||||
|
// Render the dialog with the given template and data
|
||||||
|
view = Blaze.renderWithData(template, templateData, document.body);
|
||||||
|
|
||||||
|
// Return the dropdown element to enable position manipulation
|
||||||
|
const dropdown = view.firstNode();
|
||||||
|
return dropdown;
|
||||||
|
};
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import './bounded/bounded.js';
|
import './bounded/bounded.js';
|
||||||
import './dialog/form.js';
|
import './dialog/form.js';
|
||||||
import './draggable/draggable.js';
|
import './draggable/draggable.js';
|
||||||
|
import './dropdown/form.js';
|
||||||
import './resizable/resizable.js';
|
import './resizable/resizable.js';
|
||||||
@@ -7,8 +7,7 @@ import { Meteor } from 'meteor/meteor';
|
|||||||
const OHIF = {
|
const OHIF = {
|
||||||
log: {},
|
log: {},
|
||||||
ui: {},
|
ui: {},
|
||||||
viewer: {},
|
viewer: {}
|
||||||
measurements: {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Expose the OHIF object to the client if it is on development mode
|
// Expose the OHIF object to the client if it is on development mode
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
|
OHIF.measurements = {};
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
|
import './base.js';
|
||||||
import './configuration';
|
import './configuration';
|
||||||
import './schema';
|
import './schema';
|
||||||
+25
-35
@@ -1,3 +1,7 @@
|
|||||||
|
import { Template } from 'meteor/templating';
|
||||||
|
import { moment } from 'meteor/momentjs:moment';
|
||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds related studies within defined time window of =/- 14 days of selected studies
|
* Finds related studies within defined time window of =/- 14 days of selected studies
|
||||||
* @param selectedStudies
|
* @param selectedStudies
|
||||||
@@ -14,13 +18,13 @@ function getDateRange(selectedStudies, range) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var earliestStudy = selectedStudies[0];
|
const earliestStudy = selectedStudies[0];
|
||||||
var latestStudy = selectedStudies[selectedStudies.length - 1];
|
const latestStudy = selectedStudies[selectedStudies.length - 1];
|
||||||
|
|
||||||
var earliestDate = moment(earliestStudy.studyDate, 'YYYYMMDD');
|
const earliestDate = moment(earliestStudy.studyDate, 'YYYYMMDD');
|
||||||
earliestDate.subtract(range);
|
earliestDate.subtract(range);
|
||||||
|
|
||||||
var latestDate = moment(latestStudy.studyDate, 'YYYYMMDD');
|
const latestDate = moment(latestStudy.studyDate, 'YYYYMMDD');
|
||||||
latestDate.add(range);
|
latestDate.add(range);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -43,12 +47,12 @@ function autoSelectStudies(selectedStudies) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var range = getDateRange(selectedStudies);
|
const range = getDateRange(selectedStudies);
|
||||||
|
|
||||||
// Fetch autoselected studies based on the date range
|
// Fetch autoselected studies based on the date range
|
||||||
// Note that we used MongoDB's fetch here so we have a mutable array,
|
// Note that we used MongoDB's fetch here so we have a mutable array,
|
||||||
// rather than a Cursor
|
// rather than a Cursor
|
||||||
var autoselected = StudyListStudies.find({
|
const autoselected = StudyListStudies.find({
|
||||||
studyDate: {
|
studyDate: {
|
||||||
$gte: range.earliestDate.format('YYYYMMDD'),
|
$gte: range.earliestDate.format('YYYYMMDD'),
|
||||||
$lte: range.latestDate.format('YYYYMMDD')
|
$lte: range.latestDate.format('YYYYMMDD')
|
||||||
@@ -60,12 +64,10 @@ function autoSelectStudies(selectedStudies) {
|
|||||||
}).fetch();
|
}).fetch();
|
||||||
|
|
||||||
// Make an array of studyInstanceUids in selectedStudies
|
// Make an array of studyInstanceUids in selectedStudies
|
||||||
var studyInstanceUids = selectedStudies.map(function(selectedStudy) {
|
const studyInstanceUids = selectedStudies.map(selectedStudy => selectedStudy.studyInstanceUid);
|
||||||
return selectedStudy.studyInstanceUid;
|
|
||||||
});
|
|
||||||
|
|
||||||
autoselected.forEach(function(study) {
|
autoselected.forEach(study => {
|
||||||
var exists = studyInstanceUids.indexOf(study.studyInstanceUid);
|
const exists = studyInstanceUids.indexOf(study.studyInstanceUid);
|
||||||
if (exists > -1) {
|
if (exists > -1) {
|
||||||
study.autoselected = false;
|
study.autoselected = false;
|
||||||
return;
|
return;
|
||||||
@@ -84,12 +86,8 @@ Template.studyAssociationTable.helpers({
|
|||||||
*
|
*
|
||||||
* @returns {Array.<T>}
|
* @returns {Array.<T>}
|
||||||
*/
|
*/
|
||||||
relevantStudies: function() {
|
relevantStudies() {
|
||||||
var selectedStudies = StudyListSelectedStudies.find({}, {
|
const selectedStudies = OHIF.studylist.getSelectedStudies();
|
||||||
sort: {
|
|
||||||
studyDate: 1
|
|
||||||
}
|
|
||||||
}).fetch() || [];
|
|
||||||
|
|
||||||
return autoSelectStudies(selectedStudies);
|
return autoSelectStudies(selectedStudies);
|
||||||
},
|
},
|
||||||
@@ -98,7 +96,7 @@ Template.studyAssociationTable.helpers({
|
|||||||
*
|
*
|
||||||
* @returns {Array.<T>}
|
* @returns {Array.<T>}
|
||||||
*/
|
*/
|
||||||
timepointOptions: function() {
|
timepointOptions() {
|
||||||
return [{
|
return [{
|
||||||
value: 'baseline',
|
value: 'baseline',
|
||||||
name: 'Baseline',
|
name: 'Baseline',
|
||||||
@@ -109,26 +107,18 @@ Template.studyAssociationTable.helpers({
|
|||||||
checked: false
|
checked: false
|
||||||
}];
|
}];
|
||||||
},
|
},
|
||||||
earliestDate: function() {
|
earliestDate() {
|
||||||
var selectedStudies = StudyListSelectedStudies.find({}, {
|
const selectedStudies = OHIF.studylist.getSelectedStudies();
|
||||||
sort: {
|
|
||||||
studyDate: 1
|
|
||||||
}
|
|
||||||
}).fetch();
|
|
||||||
|
|
||||||
var range = getDateRange(selectedStudies);
|
const range = getDateRange(selectedStudies);
|
||||||
if (range) {
|
if (range) {
|
||||||
return range.earliestDate;
|
return range.earliestDate;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
latestDate: function() {
|
latestDate() {
|
||||||
var selectedStudies = StudyListSelectedStudies.find({}, {
|
const selectedStudies = OHIF.studylist.getSelectedStudies();
|
||||||
sort: {
|
|
||||||
studyDate: 1
|
|
||||||
}
|
|
||||||
}).fetch();
|
|
||||||
|
|
||||||
var range = getDateRange(selectedStudies);
|
const range = getDateRange(selectedStudies);
|
||||||
if (range) {
|
if (range) {
|
||||||
return range.latestDate;
|
return range.latestDate;
|
||||||
}
|
}
|
||||||
@@ -136,9 +126,9 @@ Template.studyAssociationTable.helpers({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Template.studyAssociationTable.events({
|
Template.studyAssociationTable.events({
|
||||||
'change input.includeStudy': function(e) {
|
'change input.includeStudy'(event, instance) {
|
||||||
var checkbox = e.currentTarget;
|
const checkbox = event.currentTarget;
|
||||||
var studyDataCells = $(checkbox).parents('tr').find('td.studyDataCell');
|
const studyDataCells = $(checkbox).parents('tr').find('td.studyDataCell');
|
||||||
if (checkbox.checked === true) {
|
if (checkbox.checked === true) {
|
||||||
studyDataCells.removeClass('disabled');
|
studyDataCells.removeClass('disabled');
|
||||||
studyDataCells.find('input').attr('disabled', false);
|
studyDataCells.find('input').attr('disabled', false);
|
||||||
|
|||||||
+18
-28
@@ -1,30 +1,20 @@
|
|||||||
<template name="longitudinalStudyListContextMenu">
|
<template name="longitudinalStudyListContextMenu">
|
||||||
{{#if uiSettings.studyListFunctionsEnabled}}
|
{{#dropdownForm}}
|
||||||
<div id="studyContextMenu" class="studyContextMenu noselect"
|
<li><a id="viewStudies" type="button" title="View Studies">View</a></li>
|
||||||
oncontextmenu='return false;'
|
<li class="divider" role="separator"></li>
|
||||||
unselectable='on'
|
<!-- {{#link action='associate'}}Associate{{/link}} -->
|
||||||
onselectstart='return false;'>
|
<li><a id="launchStudyAssociation" title="Launch Study Association">Associate</a></li>
|
||||||
<ul>
|
<li><a id="launchRemoveAssociation" type="button" data-toggle="modal"
|
||||||
<li>
|
data-target="#confirmRemoveTimepointAssociation" title="Remove Timepoint Association"
|
||||||
<a id="viewStudies" type="button" title="View Studies">View</a>
|
>Remove Association</a></li>
|
||||||
<hr/>
|
<li class="divider" role="separator"></li>
|
||||||
<!-- {{#link action='associate'}}Associate{{/link}} -->
|
<li><a id="viewSeriesDetails" type="button"
|
||||||
<a id="launchStudyAssociation" title="Launch Study Association">Associate</a>
|
title="View Series Details"
|
||||||
<a id="launchRemoveAssociation" type="button"
|
>View Series Details</a></li>
|
||||||
data-toggle="modal"
|
<li class="disabled"><a class="disabled">Anonymize</a></li>
|
||||||
data-target="#confirmRemoveTimepointAssociation"
|
<li class="disabled"><a class="disabled">Send</a></li>
|
||||||
title="Remove Timepoint Association">Remove Association</a>
|
<li class="divider" role="separator"></li>
|
||||||
<hr/>
|
<li><a id="exportSelectedStudies" title="Export Selected Studies">Export</a></li>
|
||||||
<a id="viewSeriesDetails" type="button"
|
<li class="disabled"><a class="disabled">Delete</a></li>
|
||||||
title="View Series Details">View Series Details</a>
|
{{/dropdownForm}}
|
||||||
<a class="disabled">Anonymize</a>
|
|
||||||
<a class="disabled">Send</a>
|
|
||||||
<hr/>
|
|
||||||
<a id="exportSelectedStudies"
|
|
||||||
title="Export Selected Studies">Export</a>
|
|
||||||
<a class="disabled">Delete</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</template>
|
</template>
|
||||||
+26
-38
@@ -1,3 +1,6 @@
|
|||||||
|
import { Template } from 'meteor/templating';
|
||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import { Random } from 'meteor/random';
|
||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
// Use Aldeed's meteor-template-extension package to replace the
|
// Use Aldeed's meteor-template-extension package to replace the
|
||||||
@@ -7,21 +10,17 @@ const defaultTemplate = 'studyContextMenu';
|
|||||||
|
|
||||||
Template.longitudinalStudyListContextMenu.replaces(defaultTemplate);
|
Template.longitudinalStudyListContextMenu.replaces(defaultTemplate);
|
||||||
|
|
||||||
StudyList.functions['launchStudyAssociation'] = () => OHIF.ui.showFormDialog('dialogStudyAssociation');
|
StudyList.functions.launchStudyAssociation = () => OHIF.ui.showFormDialog('dialogStudyAssociation');
|
||||||
StudyList.functions['removeTimepointAssociations'] = removeTimepointAssociations;
|
StudyList.functions.removeTimepointAssociations = removeTimepointAssociations;
|
||||||
StudyList.functions['exportSelectedStudies'] = exportSelectedStudies;
|
StudyList.functions.exportSelectedStudies = exportSelectedStudies;
|
||||||
StudyList.functions['viewStudies'] = viewStudies;
|
StudyList.functions.viewStudies = viewStudies;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all present study / timepoint associations from the Clinical Trial
|
* Removes all present study / timepoint associations from the Clinical Trial
|
||||||
*/
|
*/
|
||||||
function removeTimepointAssociations() {
|
function removeTimepointAssociations() {
|
||||||
// Get a Cursor pointing to the selected Studies from the StudyList
|
// Get a Cursor pointing to the selected Studies from the StudyList
|
||||||
const selectedStudies = StudyListSelectedStudies.find({}, {
|
const selectedStudies = OHIF.studylist.getSelectedStudies();
|
||||||
sort: {
|
|
||||||
studyDate: 1
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Loop through the Cursor of Selected Studies
|
// Loop through the Cursor of Selected Studies
|
||||||
selectedStudies.forEach(function(selectedStudy) {
|
selectedStudies.forEach(function(selectedStudy) {
|
||||||
@@ -31,14 +30,14 @@ function removeTimepointAssociations() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let timepoint = timepointApi.study(data.study.studyInstanceUid)[0];
|
let timepoint = timepointApi.study(selectedStudy.studyInstanceUid)[0];
|
||||||
if (!timepoint) {
|
if (!timepoint) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the index of the current studyInstanceUid in the array
|
// Find the index of the current studyInstanceUid in the array
|
||||||
// of reference studyInstanceUids
|
// of reference studyInstanceUids
|
||||||
var index = timepoint.studyInstanceUids.indexOf(study.studyInstanceUid);
|
const index = timepoint.studyInstanceUids.indexOf(selectedStudy.studyInstanceUid);
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -57,14 +56,14 @@ function removeTimepointAssociations() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Log
|
// Log
|
||||||
var hipaaEvent = {
|
const hipaaEvent = {
|
||||||
eventType: 'modify',
|
eventType: 'modify',
|
||||||
userId: Meteor.userId(),
|
userId: Meteor.userId(),
|
||||||
userName: Meteor.user().profile.fullName,
|
userName: Meteor.user().profile.fullName,
|
||||||
collectionName: "Timepoints",
|
collectionName: 'Timepoints',
|
||||||
recordId: study.timepointId,
|
recordId: selectedStudy.timepointId,
|
||||||
patientId: study.patientId,
|
patientId: selectedStudy.patientId,
|
||||||
patientName: study.patientName
|
patientName: selectedStudy.patientName
|
||||||
};
|
};
|
||||||
HipaaLogger.logEvent(hipaaEvent);
|
HipaaLogger.logEvent(hipaaEvent);
|
||||||
} else {
|
} else {
|
||||||
@@ -77,14 +76,14 @@ function removeTimepointAssociations() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Log
|
// Log
|
||||||
var hipaaEvent = {
|
const hipaaEvent = {
|
||||||
eventType: 'delete',
|
eventType: 'delete',
|
||||||
userId: Meteor.userId(),
|
userId: Meteor.userId(),
|
||||||
userName: Meteor.user().profile.fullName,
|
userName: Meteor.user().profile.fullName,
|
||||||
collectionName: "Timepoints",
|
collectionName: 'Timepoints',
|
||||||
recordId: study.timepointId,
|
recordId: selectedStudy.timepointId,
|
||||||
patientId: study.patientId,
|
patientId: selectedStudy.patientId,
|
||||||
patientName: study.patientName
|
patientName: selectedStudy.patientName
|
||||||
};
|
};
|
||||||
HipaaLogger.logEvent(hipaaEvent);
|
HipaaLogger.logEvent(hipaaEvent);
|
||||||
});
|
});
|
||||||
@@ -94,43 +93,32 @@ function removeTimepointAssociations() {
|
|||||||
|
|
||||||
// ---------- TODO: Remove these duplicated functions below -------------
|
// ---------- TODO: Remove these duplicated functions below -------------
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exports all selected studies on the studylist
|
* Exports all selected studies on the studylist
|
||||||
*/
|
*/
|
||||||
function exportSelectedStudies() {
|
function exportSelectedStudies() {
|
||||||
const selectedStudies = StudyListSelectedStudies.find({}, {
|
const selectedStudies = OHIF.studylist.getSelectedStudies();
|
||||||
sort: {
|
|
||||||
studyDate: 1
|
|
||||||
}
|
|
||||||
}).fetch();
|
|
||||||
|
|
||||||
if (!selectedStudies || !selectedStudies.length) {
|
if (!selectedStudies || !selectedStudies.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
exportStudies(selectedStudies);
|
OHIF.studylist.exportStudies(selectedStudies);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads multiple unassociated studies in the Viewer
|
* Loads multiple unassociated studies in the Viewer
|
||||||
*/
|
*/
|
||||||
function viewStudies() {
|
function viewStudies() {
|
||||||
console.log('viewStudies');
|
OHIF.log.info('viewStudies');
|
||||||
const selectedStudies = StudyListSelectedStudies.find({}, {
|
const selectedStudies = OHIF.studylist.getSelectedStudies();
|
||||||
sort: {
|
|
||||||
studyDate: 1
|
|
||||||
}
|
|
||||||
}).fetch();
|
|
||||||
|
|
||||||
if (!selectedStudies || !selectedStudies.length) {
|
if (!selectedStudies || !selectedStudies.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var title = selectedStudies[0].patientName;
|
const title = selectedStudies[0].patientName;
|
||||||
var studyInstanceUids = selectedStudies.map(function(study) {
|
const studyInstanceUids = selectedStudies.map(study => study.studyInstanceUid);
|
||||||
return study.studyInstanceUid;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Generate a unique ID to represent this tab
|
// Generate a unique ID to represent this tab
|
||||||
// We can't just use the Mongo entry ID because
|
// We can't just use the Mongo entry ID because
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
import './components';
|
|
||||||
import './lib';
|
import './lib';
|
||||||
import './helpers';
|
import './helpers';
|
||||||
|
import './components';
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
|
OHIF.studylist = {
|
||||||
|
collections: {},
|
||||||
|
actions: {}
|
||||||
|
};
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
import { Mongo } from 'meteor/mongo';
|
import { Mongo } from 'meteor/mongo';
|
||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
import { Servers as ServerSchema } from 'meteor/ohif:study-list/both/schema/servers.js';
|
import { Servers as ServerSchema } from 'meteor/ohif:study-list/both/schema/servers.js';
|
||||||
|
|
||||||
StudyImportStatus = new Mongo.Collection('studyImportStatus');
|
const StudyImportStatus = new Mongo.Collection('studyImportStatus');
|
||||||
StudyImportStatus._debugName = 'StudyImportStatus';
|
StudyImportStatus._debugName = 'StudyImportStatus';
|
||||||
|
OHIF.studylist.collections.StudyImportStatus = StudyImportStatus;
|
||||||
|
|
||||||
// Servers describe the DICOM servers configurations
|
// Servers describe the DICOM servers configurations
|
||||||
Servers = new Mongo.Collection('servers');
|
Servers = new Mongo.Collection('servers');
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import './lib';
|
||||||
|
import './schema';
|
||||||
|
import './base.js';
|
||||||
|
import './collections.js';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
import './getCurrentServer.js';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
import './servers.js';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
import './subscriptions.js';
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import './progressDialog';
|
||||||
|
import './seriesDetailsModal';
|
||||||
|
import './serverInformation';
|
||||||
|
import './studyContextMenu';
|
||||||
|
import './studylist';
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import './progressDialog.html';
|
||||||
|
import './progressDialog.styl';
|
||||||
|
import './progressDialog.js';
|
||||||
@@ -6,14 +6,13 @@
|
|||||||
<div class="dialogContent">
|
<div class="dialogContent">
|
||||||
<div class="progress">
|
<div class="progress">
|
||||||
<div class="progress-bar progress-bar-striped active"
|
<div class="progress-bar progress-bar-striped active"
|
||||||
role="progressbar"
|
role="progressbar"
|
||||||
style="width:{{progressStatus}}">
|
style="width: {{progressStatus}}%"
|
||||||
{{formatNumberPrecision progressStatus 0}}%
|
>{{formatNumberPrecision progressStatus 0}}%</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="message">
|
<div id="message">
|
||||||
{{{progressMessage}}}
|
{{{progressMessage}}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -1,4 +1,28 @@
|
|||||||
progressDialog = {
|
import { Template } from 'meteor/templating';
|
||||||
|
import { Session } from 'meteor/session';
|
||||||
|
import { _ } from 'meteor/underscore';
|
||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
|
const updateProgress = numberOfCompleted => {
|
||||||
|
const progressDialogSettings = Session.get('progressDialogSettings');
|
||||||
|
progressDialogSettings.numberOfCompleted = numberOfCompleted;
|
||||||
|
|
||||||
|
Session.set('progressDialogSettings', progressDialogSettings);
|
||||||
|
|
||||||
|
if (progressDialogSettings.numberOfCompleted === progressDialogSettings.numberOfTotal) {
|
||||||
|
OHIF.studylist.progressDialog.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const setProgressMessage = message => {
|
||||||
|
let progressDialogSettings = Session.get('progressDialogSettings');
|
||||||
|
progressDialogSettings.message = message;
|
||||||
|
Session.set('progressDialogSettings', progressDialogSettings);
|
||||||
|
};
|
||||||
|
|
||||||
|
OHIF.studylist.progressDialog = {
|
||||||
|
update: _.debounce(updateProgress, 100),
|
||||||
|
setMessage: _.debounce(setProgressMessage, 100),
|
||||||
show: function(title, numberOfTotal) {
|
show: function(title, numberOfTotal) {
|
||||||
Session.set('progressDialogSettings', {
|
Session.set('progressDialogSettings', {
|
||||||
title: title,
|
title: title,
|
||||||
@@ -8,16 +32,6 @@ progressDialog = {
|
|||||||
|
|
||||||
$('#progressDialog').css('display', 'block');
|
$('#progressDialog').css('display', 'block');
|
||||||
},
|
},
|
||||||
update: function(numberOfCompleted) {
|
|
||||||
var progressDialogSettings = Session.get('progressDialogSettings');
|
|
||||||
progressDialogSettings.numberOfCompleted = numberOfCompleted;
|
|
||||||
|
|
||||||
Session.set('progressDialogSettings', progressDialogSettings);
|
|
||||||
|
|
||||||
if (progressDialogSettings.numberOfCompleted === progressDialogSettings.numberOfTotal) {
|
|
||||||
progressDialog.close();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
close: function() {
|
close: function() {
|
||||||
Session.set('progressDialogSettings', {
|
Session.set('progressDialogSettings', {
|
||||||
title: '',
|
title: '',
|
||||||
@@ -26,17 +40,12 @@ progressDialog = {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$('#progressDialog').css('display', 'none');
|
$('#progressDialog').css('display', 'none');
|
||||||
},
|
|
||||||
setMessage: function(message) {
|
|
||||||
let progressDialogSettings = Session.get('progressDialogSettings');
|
|
||||||
progressDialogSettings.message = message;
|
|
||||||
Session.set('progressDialogSettings', progressDialogSettings);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Template.progressDialog.helpers({
|
Template.progressDialog.helpers({
|
||||||
progressDialogTitle() {
|
progressDialogTitle() {
|
||||||
var settings = Session.get('progressDialogSettings');
|
const settings = Session.get('progressDialogSettings');
|
||||||
if (!settings) {
|
if (!settings) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -55,11 +64,11 @@ Template.progressDialog.helpers({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return settings.numberOfCompleted / settings.numberOfTotal;
|
return (settings.numberOfCompleted / settings.numberOfTotal) * 100;
|
||||||
},
|
},
|
||||||
|
|
||||||
progressMessage() {
|
progressMessage() {
|
||||||
var settings = Session.get('progressDialogSettings');
|
const settings = Session.get('progressDialogSettings');
|
||||||
if (!settings) {
|
if (!settings) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import './viewSeriesDetailsModal.html';
|
||||||
|
|
||||||
|
import './seriesDetailsTable/seriesDetailsTable.html';
|
||||||
|
import './seriesDetailsTable/seriesDetailsTable.styl';
|
||||||
|
import './seriesDetailsTable/seriesDetailsTable.js';
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,15 @@
|
|||||||
|
import './serverInformationDicomWeb/serverInformationDicomWeb.html';
|
||||||
|
import './serverInformationDicomWeb/serverInformationDicomWeb.js';
|
||||||
|
|
||||||
|
import './serverInformationDimse/serverInformationDimse.html';
|
||||||
|
import './serverInformationDimse/serverInformationDimse.js';
|
||||||
|
|
||||||
|
import './serverInformationForm/serverInformationForm.html';
|
||||||
|
import './serverInformationForm/serverInformationForm.js';
|
||||||
|
|
||||||
|
import './serverInformationList/serverInformationList.html';
|
||||||
|
import './serverInformationList/serverInformationList.js';
|
||||||
|
|
||||||
|
import './serverInformationModal/serverInformationModal.html';
|
||||||
|
import './serverInformationModal/serverInformationModal.styl';
|
||||||
|
import './serverInformationModal/serverInformationModal.js';
|
||||||
-10
@@ -1,10 +0,0 @@
|
|||||||
<template name="serverInformationFormField">
|
|
||||||
<div class="col-lg-6">
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="wrapper">
|
|
||||||
<span>{{this.label}}</span>
|
|
||||||
<input type="text" name="{{this.name}}" class="form-control">
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
import './studyContextMenu.html';
|
||||||
|
import './studyContextMenu.js';
|
||||||
@@ -1,25 +1,12 @@
|
|||||||
<template name="studyContextMenu">
|
<template name="studyContextMenu">
|
||||||
{{#if uiSettings.studyListFunctionsEnabled}}
|
{{#dropdownForm}}
|
||||||
<div id="studyContextMenu" class="studyContextMenu noselect"
|
<li><a id="viewSeriesDetails" type="button"
|
||||||
oncontextmenu='return false;'
|
title="View Series Details"
|
||||||
unselectable='on'
|
>View Series Details</a></li>
|
||||||
onselectstart='return false;'>
|
<li class="disabled"><a class="disabled">Anonymize</a></li>
|
||||||
<ul>
|
<li class="disabled"><a class="disabled">Send</a></li>
|
||||||
<li>
|
<li class="divider" role="separator"></li>
|
||||||
<a id="viewSeriesDetails" type="button"
|
<li class="disabled"><a class="disabled">Delete</a></li>
|
||||||
title="View Series Details">
|
<li><a id="exportSelectedStudies" title="Export Selected Studies">Export</a></li>
|
||||||
View Series Details
|
{{/dropdownForm}}
|
||||||
</a>
|
|
||||||
<a class="disabled">Anonymize</a>
|
|
||||||
<a class="disabled">Send</a>
|
|
||||||
<hr/>
|
|
||||||
<a class="disabled">Delete</a>
|
|
||||||
<a id="exportSelectedStudies"
|
|
||||||
title="Export Selected Studies">
|
|
||||||
Export
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</template>
|
</template>
|
||||||
@@ -1,84 +1,48 @@
|
|||||||
function closeHandler(dialog) {
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
// Hide the dialog
|
|
||||||
$(dialog).css('display', 'none');
|
|
||||||
|
|
||||||
// Remove the backdrop
|
|
||||||
$('.removableBackdrop').remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function is used inside the StudyList package to define a right click callback
|
* This function is used inside the StudyList package to define a right click callback
|
||||||
*
|
*
|
||||||
* @param e
|
* @param event
|
||||||
*/
|
*/
|
||||||
openStudyContextMenu = function(e) {
|
openStudyContextMenu = event => {
|
||||||
StudyList.functions['exportSelectedStudies'] = exportSelectedStudies;
|
if (!OHIF.uiSettings.studyListFunctionsEnabled) {
|
||||||
StudyList.functions['viewSeriesDetails'] = viewSeriesDetails;
|
return;
|
||||||
|
|
||||||
|
|
||||||
Template.studyContextMenu.study = $(e.currentTarget);
|
|
||||||
|
|
||||||
var dialog = $('#studyContextMenu');
|
|
||||||
|
|
||||||
// Show the nonTargetLesion dialog above
|
|
||||||
var dialogProperty = {
|
|
||||||
display: 'block'
|
|
||||||
};
|
|
||||||
|
|
||||||
var pageHeight = $(document).height();
|
|
||||||
dialogProperty.top = Math.max(e.pageY, 0);
|
|
||||||
dialogProperty.top = Math.min(dialogProperty.top, pageHeight - dialog.outerHeight());
|
|
||||||
|
|
||||||
var pageWidth = $(document).width();
|
|
||||||
dialogProperty.left = Math.max(e.pageX, 0);
|
|
||||||
dialogProperty.left = Math.min(dialogProperty.left, pageWidth - dialog.outerWidth());
|
|
||||||
|
|
||||||
// Device is touch device or not
|
|
||||||
// If device is touch device, set position center of screen vertically and horizontally
|
|
||||||
if (isTouchDevice()) {
|
|
||||||
// add dialogMobile class to provide a black, transparent background
|
|
||||||
dialog.addClass('dialogMobile');
|
|
||||||
dialogProperty.top = 0;
|
|
||||||
dialogProperty.left = 0;
|
|
||||||
dialogProperty.right = 0;
|
|
||||||
dialogProperty.bottom = 0;
|
|
||||||
dialogProperty.margin = 'auto';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog.css(dialogProperty);
|
StudyList.functions.exportSelectedStudies = exportSelectedStudies;
|
||||||
dialog.focus();
|
StudyList.functions.viewSeriesDetails = viewSeriesDetails;
|
||||||
|
|
||||||
// Show the backdrop
|
Template.studyContextMenu.$study = $(event.currentTarget);
|
||||||
UI.render(Template.removableBackdrop, document.body);
|
|
||||||
|
|
||||||
// Make sure the context menu is closed when the user clicks away
|
const dropdown = OHIF.ui.showFormDropdown('studyContextMenu');
|
||||||
$('.removableBackdrop').one('mousedown touchstart', function() {
|
const $dropdown = $(dropdown);
|
||||||
closeHandler(dialog);
|
const $dropdownMenu = $dropdown.children('.dropdown-menu');
|
||||||
});
|
|
||||||
|
dropdown.oncontextmenu = () => false;
|
||||||
|
|
||||||
|
$dropdownMenu.css({
|
||||||
|
position: 'fixed',
|
||||||
|
left: `${event.clientX}px`,
|
||||||
|
top: `${event.clientY}px`,
|
||||||
|
'z-index': 10000
|
||||||
|
}).bounded().focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exports all selected studies on the studylist
|
* Exports all selected studies on the studylist
|
||||||
*/
|
*/
|
||||||
function exportSelectedStudies() {
|
function exportSelectedStudies() {
|
||||||
var selectedStudies = StudyListSelectedStudies.find({}, {
|
const selectedStudies = OHIF.studylist.getSelectedStudies();
|
||||||
sort: {
|
|
||||||
studyDate: 1
|
|
||||||
}
|
|
||||||
}).fetch() || [];
|
|
||||||
|
|
||||||
exportStudies(selectedStudies);
|
OHIF.studylist.exportStudies(selectedStudies);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display series details of study in modal
|
* Display series details of study in modal
|
||||||
*/
|
*/
|
||||||
function viewSeriesDetails() {
|
function viewSeriesDetails() {
|
||||||
var selectedStudies = StudyListSelectedStudies.find({}, {
|
const selectedStudies = OHIF.studylist.getSelectedStudies();
|
||||||
sort: {
|
|
||||||
studyDate: 1
|
|
||||||
}
|
|
||||||
}).fetch();
|
|
||||||
|
|
||||||
if (!selectedStudies) {
|
if (!selectedStudies) {
|
||||||
return;
|
return;
|
||||||
@@ -91,7 +55,7 @@ function viewSeriesDetails() {
|
|||||||
|
|
||||||
Template.studyContextMenu.events({
|
Template.studyContextMenu.events({
|
||||||
'click a': function(e) {
|
'click a': function(e) {
|
||||||
var study = Template.studyContextMenu.study;
|
var study = Template.studyContextMenu.$study;
|
||||||
var id = $(e.currentTarget).attr('id');
|
var id = $(e.currentTarget).attr('id');
|
||||||
|
|
||||||
var fn = StudyList.functions[id];
|
var fn = StudyList.functions[id];
|
||||||
@@ -100,6 +64,5 @@ Template.studyContextMenu.events({
|
|||||||
}
|
}
|
||||||
|
|
||||||
var dialog = $('#studyContextMenu');
|
var dialog = $('#studyContextMenu');
|
||||||
closeHandler(dialog);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
@import "{design}/app"
|
|
||||||
|
|
||||||
.studyContextMenu
|
|
||||||
z-index: 10000
|
|
||||||
display: none
|
|
||||||
position: absolute
|
|
||||||
color: #2f2f2f
|
|
||||||
background-color: #f2f2f2
|
|
||||||
|
|
||||||
width: -moz-fit-content
|
|
||||||
width: -webkit-fit-content
|
|
||||||
width: fit-content
|
|
||||||
width: 207px
|
|
||||||
|
|
||||||
height: -moz-fit-content
|
|
||||||
height: -webkit-fit-content
|
|
||||||
height: fit-content
|
|
||||||
|
|
||||||
min-width: 100px
|
|
||||||
font-size: 14px
|
|
||||||
text-align: left
|
|
||||||
-webkit-background-clip: padding-box
|
|
||||||
background-clip: padding-box
|
|
||||||
border: 1px solid rgba(0, 0, 0, .15)
|
|
||||||
border-radius: 3px
|
|
||||||
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175)
|
|
||||||
box-shadow: 0 6px 12px rgba(0, 0, 0, .175)
|
|
||||||
|
|
||||||
hr
|
|
||||||
border-top: solid 1px #d1d1d1
|
|
||||||
margin: 2px
|
|
||||||
|
|
||||||
ul
|
|
||||||
width: 100%
|
|
||||||
margin: 5px 0
|
|
||||||
list-style: none
|
|
||||||
padding: 0
|
|
||||||
|
|
||||||
li
|
|
||||||
clear: both
|
|
||||||
white-space: nowrap
|
|
||||||
|
|
||||||
a
|
|
||||||
padding: 3px 15px
|
|
||||||
display: block
|
|
||||||
text-decoration: none
|
|
||||||
cursor: pointer
|
|
||||||
font-size: 15px
|
|
||||||
line-height: 1.7
|
|
||||||
color: black
|
|
||||||
|
|
||||||
&:not(.disabled):hover
|
|
||||||
theme('color', '$activeColor')
|
|
||||||
text-decoration: none
|
|
||||||
|
|
||||||
&.disabled
|
|
||||||
opacity: 0.4
|
|
||||||
pointer-events: none
|
|
||||||
cursor: default
|
|
||||||
|
|
||||||
.fa-lg
|
|
||||||
width: 40px
|
|
||||||
text-align: center
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import './studylist.html';
|
||||||
|
import './studylist.js';
|
||||||
|
import './studylist.styl';
|
||||||
|
|
||||||
|
import './studylistStudy/studylistStudy.html';
|
||||||
|
import './studylistStudy/studylistStudy.js';
|
||||||
|
import './studylistStudy/studylistStudy.styl';
|
||||||
|
|
||||||
|
import './studylistResult/studylistResult.html';
|
||||||
|
import './studylistResult/studylistResult.js';
|
||||||
|
import './studylistResult/studylistResult.styl';
|
||||||
|
|
||||||
|
import './studylistToolbar/studylistToolbar.html';
|
||||||
|
import './studylistToolbar/studylistToolbar.js';
|
||||||
|
import './studylistToolbar/studylistToolbar.styl';
|
||||||
|
|
||||||
|
import './studylistPagination/studylistPagination.html';
|
||||||
|
import './studylistPagination/studylistPagination.styl';
|
||||||
|
import './studylistPagination/studylistPagination.js';
|
||||||
+1
-2
@@ -14,6 +14,5 @@
|
|||||||
{{#each templateName in additionalTemplates}}
|
{{#each templateName in additionalTemplates}}
|
||||||
{{> UI.dynamic template=templateName}}
|
{{> UI.dynamic template=templateName}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{>studyContextMenu }}
|
|
||||||
{{>progressDialog}}
|
{{>progressDialog}}
|
||||||
</template>
|
</template>
|
||||||
+1
-16
@@ -19,7 +19,7 @@ Session.setDefault('activeContentId', 'studylistTab');
|
|||||||
|
|
||||||
Template.studylist.onCreated(() => {
|
Template.studylist.onCreated(() => {
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
|
|
||||||
if (StudyList.subscriptions) {
|
if (StudyList.subscriptions) {
|
||||||
StudyList.subscriptions.forEach(subscriptionName => {
|
StudyList.subscriptions.forEach(subscriptionName => {
|
||||||
instance.subscribe(subscriptionName);
|
instance.subscribe(subscriptionName);
|
||||||
@@ -44,18 +44,3 @@ Template.studylist.onRendered(() => {
|
|||||||
|
|
||||||
Meteor.subscribe('hangingprotocols');
|
Meteor.subscribe('hangingprotocols');
|
||||||
});
|
});
|
||||||
|
|
||||||
Template.studylist.events({
|
|
||||||
'click #tablist a[data-toggle="tab"]': function(e) {
|
|
||||||
// If this tab is already active, do nothing
|
|
||||||
const tabButton = $(e.currentTarget);
|
|
||||||
const tabTitle = tabButton.parents('.tabTitle');
|
|
||||||
if (tabTitle.hasClass('active')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, switch to the tab
|
|
||||||
const contentId = tabButton.data('target').replace('#', '');
|
|
||||||
switchToTab(contentId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1,8 +0,0 @@
|
|||||||
<template name="tabTitle">
|
|
||||||
<li role="presentation" class="tabTitle">
|
|
||||||
<a data-target="#{{contentid}}" role="tab" data-toggle="tab">
|
|
||||||
{{title}}
|
|
||||||
<button class="close">×</button>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</template>
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
Template.tabTitle.events({
|
|
||||||
/**
|
|
||||||
* Closes a tab when the close button is pressed in the title
|
|
||||||
* The next tab to the left is loaded if the current tab is closed
|
|
||||||
*
|
|
||||||
* @param e The click event used to close the tab
|
|
||||||
*/
|
|
||||||
'click .close': function(e) {
|
|
||||||
console.log('click .close');
|
|
||||||
|
|
||||||
// Identify the tab title DOM node
|
|
||||||
var tab = $(e.currentTarget).parents('a[data-toggle="tab"]').eq(0);
|
|
||||||
|
|
||||||
// Get the relevent contentId that this tab title represents
|
|
||||||
// Replace any hash marks (#) that were required by Bootstrap's tab switching
|
|
||||||
var contentId = tab.data('target').replace('#', '');
|
|
||||||
|
|
||||||
// Check if we are closing the active tab. If we are, prepare to switch
|
|
||||||
// to the next tab to the left.
|
|
||||||
var activeContentId = Session.get('activeContentId');
|
|
||||||
if (activeContentId === contentId) {
|
|
||||||
// Find the index of the tab that is being closed
|
|
||||||
var tabIndex = tab.parent('li').index();
|
|
||||||
|
|
||||||
// Find the index the tab to its left
|
|
||||||
var newActiveTabIndex = Math.max(tabIndex - 1, 0);
|
|
||||||
|
|
||||||
// Find the DOM node of the tab that will be activated
|
|
||||||
var newActiveTab = $('.tabTitle').eq(newActiveTabIndex);
|
|
||||||
|
|
||||||
// Find the content ID of the tab that will be switched to
|
|
||||||
var newActiveTabLink = newActiveTab.find('a[data-toggle=tab]');
|
|
||||||
var newContentId = newActiveTabLink.data('target').replace('#', '');
|
|
||||||
|
|
||||||
// Switch to this tab
|
|
||||||
switchToTab(newContentId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove any stored data related to this tab from the global ViewerData structure
|
|
||||||
delete ViewerData[contentId];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
.tabTitle
|
|
||||||
button.close
|
|
||||||
// Prevent blue glow around button in Chrome
|
|
||||||
outline: none
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import './collections';
|
||||||
|
import './lib';
|
||||||
|
import './components';
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
var exportFailed;
|
import { JSZip } from 'meteor/silentcicero:jszip';
|
||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
|
let exportFailed;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exports requested studies
|
* Exports requested studies
|
||||||
* @param studiesToExport Studies to export
|
* @param studiesToExport Studies to export
|
||||||
*/
|
*/
|
||||||
exportStudies = function(studiesToExport) {
|
OHIF.studylist.exportStudies = studiesToExport => {
|
||||||
if (studiesToExport.length < 1) {
|
if (studiesToExport.length < 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -12,37 +15,45 @@ exportStudies = function(studiesToExport) {
|
|||||||
queryStudies(studiesToExport, exportQueriedStudies);
|
queryStudies(studiesToExport, exportQueriedStudies);
|
||||||
};
|
};
|
||||||
|
|
||||||
function exportQueriedStudies(studiesToExport) {
|
const exportQueriedStudies = studiesToExport => {
|
||||||
var numberOfFilesToExport = 0;
|
let numberOfFilesToExport = 0;
|
||||||
studiesToExport.forEach(function(study) {
|
studiesToExport.forEach(study => {
|
||||||
numberOfFilesToExport += getNumberOfFilesInStudy(study);
|
numberOfFilesToExport += getNumberOfFilesInStudy(study);
|
||||||
});
|
});
|
||||||
|
|
||||||
progressDialog.show("Exporting Studies...", numberOfFilesToExport);
|
OHIF.studylist.progressDialog.show('Exporting Studies...', numberOfFilesToExport);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
exportQueriedStudiesInternal(studiesToExport, numberOfFilesToExport);
|
exportQueriedStudiesInternal(studiesToExport, numberOfFilesToExport);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
progressDialog.close();
|
OHIF.studylist.progressDialog.close();
|
||||||
console.error("Failed to export studies: " + err.message);
|
OHIF.log.error(`Failed to export studies: ${err.message}`);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
function exportQueriedStudiesInternal(studiesToExport, numberOfFilesToExport) {
|
const exportQueriedStudiesInternal = (studiesToExport, numberOfFilesToExport) => {
|
||||||
var zip = new JSZip();
|
const zip = new JSZip();
|
||||||
|
|
||||||
exportFailed = false;
|
exportFailed = false;
|
||||||
var numberOfFilesExported = 0;
|
let numberOfFilesExported = 0;
|
||||||
|
|
||||||
studiesToExport.forEach(function(study) {
|
const onExportFailed = err => {
|
||||||
|
exportFailed = true;
|
||||||
|
OHIF.studylist.progressDialog.close();
|
||||||
|
|
||||||
|
//TODO: Export failed and dialog closed, so let user know
|
||||||
|
OHIF.log.error('Failed to export studies!', err);
|
||||||
|
};
|
||||||
|
|
||||||
|
studiesToExport.forEach(study => {
|
||||||
sortStudy(study);
|
sortStudy(study);
|
||||||
|
|
||||||
var studyFolder = zip.folder(study.studyInstanceUid);
|
const studyFolder = zip.folder(study.studyInstanceUid);
|
||||||
|
|
||||||
study.seriesList.forEach(function(series) {
|
study.seriesList.forEach(series => {
|
||||||
var seriesFolder = studyFolder.folder(series.seriesInstanceUid);
|
const seriesFolder = studyFolder.folder(series.seriesInstanceUid);
|
||||||
|
|
||||||
series.instances.forEach(function(instance) {
|
series.instances.forEach(instance => {
|
||||||
if (!instance.wadouri) {
|
if (!instance.wadouri) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -53,12 +64,12 @@ function exportQueriedStudiesInternal(studiesToExport, numberOfFilesToExport) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Download and Zip the dicom file
|
// Download and Zip the dicom file
|
||||||
var xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
xhr.open("GET", instance.wadouri, true);
|
xhr.open('GET', instance.wadouri, true);
|
||||||
xhr.responseType = "blob";
|
xhr.responseType = 'blob';
|
||||||
|
|
||||||
// Downloaded the dicom file completely
|
// Downloaded the dicom file completely
|
||||||
xhr.onload = function(e) {
|
xhr.onload = () => {
|
||||||
// If failed to download a dicom file, skip others
|
// If failed to download a dicom file, skip others
|
||||||
if (exportFailed) {
|
if (exportFailed) {
|
||||||
return;
|
return;
|
||||||
@@ -66,17 +77,17 @@ function exportQueriedStudiesInternal(studiesToExport, numberOfFilesToExport) {
|
|||||||
|
|
||||||
// Failed to export a file
|
// Failed to export a file
|
||||||
if (xhr.readyState === 4 && xhr.status !== 200) {
|
if (xhr.readyState === 4 && xhr.status !== 200) {
|
||||||
onExportFailed("File not downloaded: " + instance.wadouri);
|
onExportFailed(`File not downloaded: ${instance.wadouri}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var blobFile = new Blob([xhr.response], {type: 'application/dicom'});
|
const blobFile = new Blob([xhr.response], { type: 'application/dicom' });
|
||||||
|
|
||||||
var fileReader = new FileReader();
|
const fileReader = new FileReader();
|
||||||
|
|
||||||
fileReader.onload = function() {
|
fileReader.onload = () => {
|
||||||
try {
|
try {
|
||||||
seriesFolder.file(instance.sopInstanceUid + ".dcm", fileReader.result, { binary: true });
|
seriesFolder.file(`${instance.sopInstanceUid}.dcm`, fileReader.result, { binary: true });
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
onExportFailed(err.message);
|
onExportFailed(err.message);
|
||||||
return;
|
return;
|
||||||
@@ -85,31 +96,21 @@ function exportQueriedStudiesInternal(studiesToExport, numberOfFilesToExport) {
|
|||||||
numberOfFilesExported++;
|
numberOfFilesExported++;
|
||||||
|
|
||||||
if (numberOfFilesExported === numberOfFilesToExport) {
|
if (numberOfFilesExported === numberOfFilesToExport) {
|
||||||
var zipContent = zip.generate({ type: "blob" });
|
const zipContent = zip.generate({ type: 'blob' });
|
||||||
saveAs(zipContent, "studies.zip");
|
saveAs(zipContent, 'studies.zip');
|
||||||
}
|
}
|
||||||
|
|
||||||
progressDialog.update(numberOfFilesExported);
|
OHIF.studylist.progressDialog.update(numberOfFilesExported);
|
||||||
};
|
};
|
||||||
|
|
||||||
fileReader.readAsArrayBuffer(blobFile);
|
fileReader.readAsArrayBuffer(blobFile);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Failed to download the dicom file
|
// Failed to download the dicom file
|
||||||
xhr.onerror = function() {
|
xhr.onerror = () => onExportFailed(`File not downloaded: ${instance.wadouri}`);
|
||||||
onExportFailed("File not downloaded: " + instance.wadouri);
|
|
||||||
};
|
|
||||||
|
|
||||||
xhr.send();
|
xhr.send();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
function onExportFailed(err) {
|
|
||||||
exportFailed = true;
|
|
||||||
progressDialog.close();
|
|
||||||
|
|
||||||
//TODO: Export failed and dialog closed, so let user know
|
|
||||||
console.error("Failed to export studies!", err);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
|
OHIF.studylist.getSelectedStudies = () => {
|
||||||
|
return StudyListSelectedStudies.find({}, {
|
||||||
|
sort: {
|
||||||
|
studyDate: 1
|
||||||
|
}
|
||||||
|
}).fetch() || [];
|
||||||
|
};
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { $ } from 'meteor/jquery';
|
||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,7 +11,7 @@ import { OHIF } from 'meteor/ohif:core';
|
|||||||
* @param doneCallback The callback function to be executed when the study retrieval has finished
|
* @param doneCallback The callback function to be executed when the study retrieval has finished
|
||||||
* @param failCallback The callback function to be executed when the study retrieval has failed
|
* @param failCallback The callback function to be executed when the study retrieval has failed
|
||||||
*/
|
*/
|
||||||
getStudiesMetadata = function(studyInstanceUids, doneCallback, failCallback) {
|
OHIF.studylist.getStudiesMetadata = (studyInstanceUids, doneCallback, failCallback) => {
|
||||||
// Check to make sure studyInstanceUids were actually input
|
// Check to make sure studyInstanceUids were actually input
|
||||||
if (!studyInstanceUids || !studyInstanceUids.length) {
|
if (!studyInstanceUids || !studyInstanceUids.length) {
|
||||||
if (failCallback && typeof failCallback === 'function') {
|
if (failCallback && typeof failCallback === 'function') {
|
||||||
@@ -22,13 +23,13 @@ getStudiesMetadata = function(studyInstanceUids, doneCallback, failCallback) {
|
|||||||
|
|
||||||
// Create an empty array to store the Promises for each metaData
|
// Create an empty array to store the Promises for each metaData
|
||||||
// retrieval call
|
// retrieval call
|
||||||
var promises = [];
|
const promises = [];
|
||||||
|
|
||||||
// Loop through the array of studyInstanceUids
|
// Loop through the array of studyInstanceUids
|
||||||
studyInstanceUids.forEach(function(studyInstanceUid) {
|
studyInstanceUids.forEach(function(studyInstanceUid) {
|
||||||
// Create a new Deferred to monitor the progress of the asynchronous
|
// Create a new Deferred to monitor the progress of the asynchronous
|
||||||
// metaData retrieval
|
// metaData retrieval
|
||||||
var deferred = new $.Deferred();
|
const deferred = new $.Deferred();
|
||||||
|
|
||||||
// Send the call, and attach doneCallbacks and failCallbacks
|
// Send the call, and attach doneCallbacks and failCallbacks
|
||||||
// which can resolve or reject the related promise based on its outcome
|
// which can resolve or reject the related promise based on its outcome
|
||||||
@@ -45,7 +46,7 @@ getStudiesMetadata = function(studyInstanceUids, doneCallback, failCallback) {
|
|||||||
// When all of the promises are complete, this callback runs
|
// When all of the promises are complete, this callback runs
|
||||||
$.when.apply($, promises).done(function() {
|
$.when.apply($, promises).done(function() {
|
||||||
// Convert the Arguments Array-like Object to an actual array
|
// Convert the Arguments Array-like Object to an actual array
|
||||||
var studies = $.makeArray(arguments);
|
const studies = $.makeArray(arguments);
|
||||||
|
|
||||||
// Pass the studies array to the doneCallback, if one exists
|
// Pass the studies array to the doneCallback, if one exists
|
||||||
if (doneCallback && typeof doneCallback === 'function') {
|
if (doneCallback && typeof doneCallback === 'function') {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ importStudies = function(filesToImport, importCallback) {
|
|||||||
};
|
};
|
||||||
var numberOfFilesToUpload = filesToImport.length;
|
var numberOfFilesToUpload = filesToImport.length;
|
||||||
var studiesToImport = [];
|
var studiesToImport = [];
|
||||||
progressDialog.show({
|
OHIF.studylist.progressDialog.show({
|
||||||
title: "Uploading Files...",
|
title: "Uploading Files...",
|
||||||
numberOfCompleted: 0,
|
numberOfCompleted: 0,
|
||||||
numberOfTotal: numberOfFilesToUpload
|
numberOfTotal: numberOfFilesToUpload
|
||||||
@@ -38,7 +38,7 @@ importStudies = function(filesToImport, importCallback) {
|
|||||||
updateFileUploadStatus(fileUploadStatus, true);
|
updateFileUploadStatus(fileUploadStatus, true);
|
||||||
|
|
||||||
var numberOfFilesProcessedToUpload = fileUploadStatus.numberOfFilesUploaded + fileUploadStatus.numberOfFilesFailed;
|
var numberOfFilesProcessedToUpload = fileUploadStatus.numberOfFilesUploaded + fileUploadStatus.numberOfFilesFailed;
|
||||||
progressDialog.update(numberOfFilesProcessedToUpload);
|
OHIF.studylist.progressDialog.update(numberOfFilesProcessedToUpload);
|
||||||
|
|
||||||
if (numberOfFilesToUpload === numberOfFilesProcessedToUpload) {
|
if (numberOfFilesToUpload === numberOfFilesProcessedToUpload) {
|
||||||
// The upload is completed, so import files
|
// The upload is completed, so import files
|
||||||
@@ -74,7 +74,7 @@ function importStudiesInternal(studiesToImport, importCallback) {
|
|||||||
|
|
||||||
var numberOfStudiesToImport = studiesToImport.length;
|
var numberOfStudiesToImport = studiesToImport.length;
|
||||||
|
|
||||||
progressDialog.show({
|
OHIF.studylist.progressDialog.show({
|
||||||
title: "Importing Studies...",
|
title: "Importing Studies...",
|
||||||
numberOfCompleted: 0,
|
numberOfCompleted: 0,
|
||||||
numberOfTotal: numberOfStudiesToImport
|
numberOfTotal: numberOfStudiesToImport
|
||||||
@@ -84,13 +84,13 @@ function importStudiesInternal(studiesToImport, importCallback) {
|
|||||||
Meteor.call("createStudyImportStatus", function(err, studyImportStatusId) {
|
Meteor.call("createStudyImportStatus", function(err, studyImportStatusId) {
|
||||||
if (err) {
|
if (err) {
|
||||||
// Hide dialog
|
// Hide dialog
|
||||||
progressDialog.close();
|
OHIF.studylist.progressDialog.close();
|
||||||
console.log(err.message);
|
console.log(err.message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle when StudyImportStatus collection is updated
|
// Handle when StudyImportStatus collection is updated
|
||||||
StudyImportStatus.find(studyImportStatusId).observe({
|
OHIF.studylist.collections.StudyImportStatus.find(studyImportStatusId).observe({
|
||||||
changed: function(studyImportStatus) {
|
changed: function(studyImportStatus) {
|
||||||
if (!studyImportStatus) {
|
if (!studyImportStatus) {
|
||||||
return;
|
return;
|
||||||
@@ -100,16 +100,16 @@ function importStudiesInternal(studiesToImport, importCallback) {
|
|||||||
|
|
||||||
// Show number of imported files
|
// Show number of imported files
|
||||||
var successMessage = 'Imported '+studyImportStatus.numberOfStudiesImported+' of '+numberOfStudiesToImport;
|
var successMessage = 'Imported '+studyImportStatus.numberOfStudiesImported+' of '+numberOfStudiesToImport;
|
||||||
progressDialog.setMessage({
|
OHIF.studylist.progressDialog.setMessage({
|
||||||
message: successMessage,
|
message: successMessage,
|
||||||
messageType: 'success'
|
messageType: 'success'
|
||||||
});
|
});
|
||||||
progressDialog.update(numberOfStudiesProcessedToImport);
|
OHIF.studylist.progressDialog.update(numberOfStudiesProcessedToImport);
|
||||||
|
|
||||||
// Show number of failed files if there is at least one failed file
|
// Show number of failed files if there is at least one failed file
|
||||||
if (studyImportStatus.numberOfStudiesFailed > 0) {
|
if (studyImportStatus.numberOfStudiesFailed > 0) {
|
||||||
var successMessage = 'Failed '+studyImportStatus.numberOfStudiesFailed+' of '+numberOfStudiesToImport;
|
var successMessage = 'Failed '+studyImportStatus.numberOfStudiesFailed+' of '+numberOfStudiesToImport;
|
||||||
progressDialog.setMessage({
|
OHIF.studylist.progressDialog.setMessage({
|
||||||
message: successMessage,
|
message: successMessage,
|
||||||
messageType: 'warning'
|
messageType: 'warning'
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import './third-party/jquery.twbsPagination.min.js';
|
||||||
|
|
||||||
|
import './exportStudies.js';
|
||||||
|
import './getSelectedStudies.js';
|
||||||
|
import './getStudyMetadata.js';
|
||||||
|
import './getStudiesMetadata.js';
|
||||||
|
import './importStudies.js';
|
||||||
|
import './openNewTab.js';
|
||||||
|
import './queryStudies.js';
|
||||||
|
import './studylist.js';
|
||||||
|
import './switchToTab.js';
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queries requested studies to get their metadata from PACS
|
* Queries requested studies to get their metadata from PACS
|
||||||
* @param studiesToQuery Studies to query
|
* @param studiesToQuery Studies to query
|
||||||
@@ -11,7 +13,7 @@ queryStudies = function(studiesToQuery, doneCallback) {
|
|||||||
var studiesQueried = [];
|
var studiesQueried = [];
|
||||||
var numberOfStudiesToQuery = studiesToQuery.length;
|
var numberOfStudiesToQuery = studiesToQuery.length;
|
||||||
|
|
||||||
progressDialog.show("Querying Studies...", numberOfStudiesToQuery);
|
OHIF.studylist.progressDialog.show("Querying Studies...", numberOfStudiesToQuery);
|
||||||
|
|
||||||
studiesToQuery.forEach(function(studyToQuery) {
|
studiesToQuery.forEach(function(studyToQuery) {
|
||||||
getStudyMetadata(studyToQuery.studyInstanceUid, function(study) {
|
getStudyMetadata(studyToQuery.studyInstanceUid, function(study) {
|
||||||
@@ -19,7 +21,7 @@ queryStudies = function(studiesToQuery, doneCallback) {
|
|||||||
|
|
||||||
var numberOfStudiesQueried = studiesQueried.length;
|
var numberOfStudiesQueried = studiesQueried.length;
|
||||||
|
|
||||||
progressDialog.update(numberOfStudiesQueried);
|
OHIF.studylist.progressDialog.update(numberOfStudiesQueried);
|
||||||
|
|
||||||
if (numberOfStudiesQueried === numberOfStudiesToQuery) {
|
if (numberOfStudiesQueried === numberOfStudiesToQuery) {
|
||||||
doneCallback(studiesQueried);
|
doneCallback(studiesQueried);
|
||||||
@@ -45,4 +47,4 @@ getNumberOfFilesInStudy = function(study) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return numberOFFilesToExport;
|
return numberOFFilesToExport;
|
||||||
};
|
};
|
||||||
@@ -13,9 +13,6 @@ switchToTab = function(contentId) {
|
|||||||
|
|
||||||
OHIF.log.info('Switching to tab: ' + contentId);
|
OHIF.log.info('Switching to tab: ' + contentId);
|
||||||
|
|
||||||
$('.tabTitle').removeClass('active');
|
|
||||||
$('.tabTitle a[data-target="#' + contentId + '"]').addClass('active');
|
|
||||||
|
|
||||||
$('.tab-content .tab-pane').removeClass('active');
|
$('.tab-content .tab-pane').removeClass('active');
|
||||||
if (contentId !== 'studylistTab') {
|
if (contentId !== 'studylistTab') {
|
||||||
$('.tab-content .tab-pane#viewerTab').addClass('active');
|
$('.tab-content .tab-pane#viewerTab').addClass('active');
|
||||||
@@ -71,7 +68,7 @@ switchToTab = function(contentId) {
|
|||||||
var studyInstanceUids = ViewerData[contentId].studyInstanceUids;
|
var studyInstanceUids = ViewerData[contentId].studyInstanceUids;
|
||||||
|
|
||||||
// Attempt to retrieve the meta data (it might be cached)
|
// Attempt to retrieve the meta data (it might be cached)
|
||||||
getStudiesMetadata(studyInstanceUids, function(studies) {
|
OHIF.studylist.getStudiesMetadata(studyInstanceUids, function(studies) {
|
||||||
viewStudiesInTab(contentId, studies);
|
viewStudiesInTab(contentId, studies);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
File renamed without changes.
@@ -1,10 +1,10 @@
|
|||||||
Package.describe({
|
Package.describe({
|
||||||
name: "ohif:study-list",
|
name: 'ohif:study-list',
|
||||||
summary: "Basic study list for web-based DICOM viewers",
|
summary: 'Basic study list for web-based DICOM viewers',
|
||||||
version: '0.0.1'
|
version: '0.0.1'
|
||||||
});
|
});
|
||||||
|
|
||||||
Package.onUse(function (api) {
|
Package.onUse(function(api) {
|
||||||
api.versionsFrom('1.4');
|
api.versionsFrom('1.4');
|
||||||
|
|
||||||
api.use('ecmascript');
|
api.use('ecmascript');
|
||||||
@@ -34,109 +34,14 @@ Package.onUse(function (api) {
|
|||||||
// TODO: Replace with NPM dependency
|
// TODO: Replace with NPM dependency
|
||||||
api.use('ohif:cornerstone'); // Only for HammerJS
|
api.use('ohif:cornerstone'); // Only for HammerJS
|
||||||
|
|
||||||
api.addFiles('both/collections.js', ['client', 'server']);
|
// Client and server imports
|
||||||
api.addFiles('both/schema/servers.js', ['client', 'server']);
|
api.addFiles('both/index.js', [ 'client', 'server' ]);
|
||||||
api.addFiles('both/lib/getCurrentServer.js', ['client', 'server']);
|
|
||||||
|
|
||||||
// Client collections and subscriptions
|
// Server imports
|
||||||
api.addFiles('client/collections/subscriptions.js', 'client');
|
api.addFiles('server/index.js', 'server');
|
||||||
|
|
||||||
// Components
|
// Client imports
|
||||||
api.addFiles('client/components/studylist.html', 'client');
|
api.addFiles('client/index.js', 'client');
|
||||||
api.addFiles('client/components/studylist.js', 'client');
|
|
||||||
api.addFiles('client/components/studylist.styl', 'client');
|
|
||||||
|
|
||||||
api.addFiles('client/components/tabTitle/tabTitle.html', 'client');
|
|
||||||
api.addFiles('client/components/tabTitle/tabTitle.js', 'client');
|
|
||||||
api.addFiles('client/components/tabTitle/tabTitle.styl', 'client');
|
|
||||||
|
|
||||||
api.addFiles('client/components/studylistStudy/studylistStudy.html', 'client');
|
|
||||||
api.addFiles('client/components/studylistStudy/studylistStudy.js', 'client');
|
|
||||||
api.addFiles('client/components/studylistStudy/studylistStudy.styl', 'client');
|
|
||||||
|
|
||||||
api.addFiles('client/components/studylistResult/studylistResult.html', 'client');
|
|
||||||
api.addFiles('client/components/studylistResult/studylistResult.js', 'client');
|
|
||||||
api.addFiles('client/components/studylistResult/studylistResult.styl', 'client');
|
|
||||||
|
|
||||||
api.addFiles('client/components/studyContextMenu/studyContextMenu.html', 'client');
|
|
||||||
api.addFiles('client/components/studyContextMenu/studyContextMenu.js', 'client');
|
|
||||||
api.addFiles('client/components/studyContextMenu/studyContextMenu.styl', 'client');
|
|
||||||
|
|
||||||
api.addFiles('client/components/studylistToolbar/studylistToolbar.html', 'client');
|
|
||||||
api.addFiles('client/components/studylistToolbar/studylistToolbar.js', 'client');
|
|
||||||
api.addFiles('client/components/studylistToolbar/studylistToolbar.styl', 'client');
|
|
||||||
|
|
||||||
api.addFiles('client/components/progressDialog/progressDialog.html', 'client');
|
|
||||||
api.addFiles('client/components/progressDialog/progressDialog.styl', 'client');
|
|
||||||
api.addFiles('client/components/progressDialog/progressDialog.js', 'client');
|
|
||||||
|
|
||||||
api.addFiles('client/components/studylistPagination/studylistPagination.html', 'client');
|
|
||||||
api.addFiles('client/components/studylistPagination/studylistPagination.styl', 'client');
|
|
||||||
api.addFiles('client/components/studylistPagination/studylistPagination.js', 'client');
|
|
||||||
|
|
||||||
api.addFiles('client/components/viewSeriesDetailsModal/viewSeriesDetailsModal.html', 'client');
|
|
||||||
|
|
||||||
api.addFiles('client/components/seriesDetailsTable/seriesDetailsTable.html', 'client');
|
|
||||||
api.addFiles('client/components/seriesDetailsTable/seriesDetailsTable.styl', 'client');
|
|
||||||
api.addFiles('client/components/seriesDetailsTable/seriesDetailsTable.js', 'client');
|
|
||||||
|
|
||||||
api.addFiles('client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.html', 'client');
|
|
||||||
api.addFiles('client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.js', 'client');
|
|
||||||
|
|
||||||
api.addFiles('client/components/serverInformation/serverInformationDimse/serverInformationDimse.html', 'client');
|
|
||||||
api.addFiles('client/components/serverInformation/serverInformationDimse/serverInformationDimse.js', 'client');
|
|
||||||
|
|
||||||
api.addFiles('client/components/serverInformation/serverInformationForm/serverInformationForm.html', 'client');
|
|
||||||
api.addFiles('client/components/serverInformation/serverInformationForm/serverInformationForm.js', 'client');
|
|
||||||
api.addFiles('client/components/serverInformation/serverInformationForm/serverInformationFormField.html', 'client');
|
|
||||||
|
|
||||||
api.addFiles('client/components/serverInformation/serverInformationList/serverInformationList.html', 'client');
|
|
||||||
api.addFiles('client/components/serverInformation/serverInformationList/serverInformationList.js', 'client');
|
|
||||||
|
|
||||||
api.addFiles('client/components/serverInformation/serverInformationModal/serverInformationModal.html', 'client');
|
|
||||||
api.addFiles('client/components/serverInformation/serverInformationModal/serverInformationModal.styl', 'client');
|
|
||||||
api.addFiles('client/components/serverInformation/serverInformationModal/serverInformationModal.js', 'client');
|
|
||||||
|
|
||||||
// Client-side library functions
|
|
||||||
api.addFiles('client/lib/getStudyMetadata.js', 'client');
|
|
||||||
api.addFiles('client/lib/getStudiesMetadata.js', 'client');
|
|
||||||
api.addFiles('client/lib/openNewTab.js', 'client');
|
|
||||||
api.addFiles('client/lib/switchToTab.js', 'client');
|
|
||||||
api.addFiles('client/lib/exportStudies.js', 'client');
|
|
||||||
api.addFiles('client/lib/studylist.js', 'client');
|
|
||||||
api.addFiles('client/lib/queryStudies.js', 'client');
|
|
||||||
api.addFiles('client/lib/importStudies.js', 'client');
|
|
||||||
api.addFiles('client/lib/jquery.twbsPagination/jquery.twbsPagination.min.js', 'client');
|
|
||||||
|
|
||||||
// Server-side functions
|
|
||||||
api.addFiles('server/publications.js', 'server');
|
|
||||||
api.addFiles('server/validateServerConfiguration.js', 'server');
|
|
||||||
api.addFiles('server/servers.js', 'server');
|
|
||||||
api.addFiles('server/lib/remoteGetValue.js', 'server');
|
|
||||||
api.addFiles('server/lib/encodeQueryData.js', 'server');
|
|
||||||
api.addFiles('server/lib/parseFloatArray.js', 'server');
|
|
||||||
|
|
||||||
api.addFiles('server/methods/getStudyMetadata.js', 'server');
|
|
||||||
api.addFiles('server/methods/importStudies.js', 'server');
|
|
||||||
api.addFiles('server/methods/studylistSearch.js', 'server');
|
|
||||||
|
|
||||||
api.addFiles('server/services/namespace.js', 'server');
|
|
||||||
|
|
||||||
// DICOMWeb instance, study, and metadata retrieval
|
|
||||||
api.addFiles('server/services/qido/instances.js', 'server');
|
|
||||||
api.addFiles('server/services/qido/studies.js', 'server');
|
|
||||||
api.addFiles('server/services/wado/retrieveMetadata.js', 'server');
|
|
||||||
|
|
||||||
// DIMSE instance, study, and metadata retrieval
|
|
||||||
api.addFiles('server/services/dimse/instances.js', 'server');
|
|
||||||
api.addFiles('server/services/dimse/studies.js', 'server');
|
|
||||||
api.addFiles('server/services/dimse/retrieveMetadata.js', 'server');
|
|
||||||
api.addFiles('server/services/dimse/setup.js', 'server');
|
|
||||||
|
|
||||||
// Study, instance, and metadata retrieval from remote PACS via Orthanc as a proxy
|
|
||||||
api.addFiles('server/services/remote/instances.js', 'server');
|
|
||||||
api.addFiles('server/services/remote/studies.js', 'server');
|
|
||||||
api.addFiles('server/services/remote/retrieveMetadata.js', 'server');
|
|
||||||
|
|
||||||
// Export Servers and CurrentServer Collections
|
// Export Servers and CurrentServer Collections
|
||||||
api.export('Servers', ['client', 'server']);
|
api.export('Servers', ['client', 'server']);
|
||||||
@@ -149,10 +54,8 @@ Package.onUse(function (api) {
|
|||||||
|
|
||||||
// Export StudyList helper functions for usage in Routes
|
// Export StudyList helper functions for usage in Routes
|
||||||
api.export('getStudyMetadata', 'client');
|
api.export('getStudyMetadata', 'client');
|
||||||
api.export('getStudiesMetadata', 'client');
|
|
||||||
api.export('openNewTab', 'client');
|
api.export('openNewTab', 'client');
|
||||||
api.export('switchToTab', 'client');
|
api.export('switchToTab', 'client');
|
||||||
api.export('progressDialog', 'client');
|
|
||||||
api.export('StudyList');
|
api.export('StudyList');
|
||||||
|
|
||||||
// Export the global ViewerData object
|
// Export the global ViewerData object
|
||||||
@@ -160,5 +63,5 @@ Package.onUse(function (api) {
|
|||||||
|
|
||||||
// Export the Collections
|
// Export the Collections
|
||||||
api.export('StudyListStudies', 'client');
|
api.export('StudyListStudies', 'client');
|
||||||
api.export('StudyListSelectedStudies', 'client')
|
api.export('StudyListSelectedStudies', 'client');
|
||||||
});
|
});
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import './publications.js';
|
||||||
|
import './validateServerConfiguration.js';
|
||||||
|
|
||||||
|
import './lib';
|
||||||
|
import './methods';
|
||||||
|
import './services';
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
import './remoteGetValue.js';
|
||||||
|
import './encodeQueryData.js';
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { StudyImportStatus } from '../../both/collections';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
var fs = Npm.require('fs');
|
var fs = Npm.require('fs');
|
||||||
var fiber = Npm.require('fibers');
|
var fiber = Npm.require('fibers');
|
||||||
@@ -73,14 +73,14 @@ Meteor.methods({
|
|||||||
*/
|
*/
|
||||||
createStudyImportStatus: function() {
|
createStudyImportStatus: function() {
|
||||||
var studyImportStatus = { numberOfStudiesImported: 0, numberOfStudiesFailed: 0 };
|
var studyImportStatus = { numberOfStudiesImported: 0, numberOfStudiesFailed: 0 };
|
||||||
return StudyImportStatus.insert(studyImportStatus);
|
return OHIF.studylist.collections.StudyImportStatus.insert(studyImportStatus);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Remove the study import status item from the collection
|
* Remove the study import status item from the collection
|
||||||
* @param id Collection id of the study import status in the collection
|
* @param id Collection id of the study import status in the collection
|
||||||
*/
|
*/
|
||||||
removeStudyImportStatus: function(id) {
|
removeStudyImportStatus: function(id) {
|
||||||
StudyImportStatus.remove(id);
|
OHIF.studylist.collections.StudyImportStatus.remove(id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -96,16 +96,16 @@ function importStudiesDIMSE(studiesToImport, studyImportStatusId) {
|
|||||||
try {
|
try {
|
||||||
// Update the import status
|
// Update the import status
|
||||||
if (err) {
|
if (err) {
|
||||||
StudyImportStatus.update({_id: studyImportStatusId}, {$inc: {'numberOfStudiesFailed': 1}});
|
OHIF.studylist.collections.StudyImportStatus.update({_id: studyImportStatusId}, {$inc: {'numberOfStudiesFailed': 1}});
|
||||||
console.log("Failed to import study via DIMSE: ", file, err);
|
console.log("Failed to import study via DIMSE: ", file, err);
|
||||||
} else {
|
} else {
|
||||||
StudyImportStatus.update({_id: studyImportStatusId}, {$inc: {'numberOfStudiesImported': 1}});
|
OHIF.studylist.collections.StudyImportStatus.update({_id: studyImportStatusId}, {$inc: {'numberOfStudiesImported': 1}});
|
||||||
console.log("Study successfully imported via DIMSE: ", file);
|
console.log("Study successfully imported via DIMSE: ", file);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
|
|
||||||
StudyImportStatus.update({_id: studyImportStatusId}, {$inc: {'numberOfStudiesFailed': 1}});
|
OHIF.studylist.collections.StudyImportStatus.update({_id: studyImportStatusId}, {$inc: {'numberOfStudiesFailed': 1}});
|
||||||
console.log("Failed to import study via DIMSE: ", file, error);
|
console.log("Failed to import study via DIMSE: ", file, error);
|
||||||
} finally {
|
} finally {
|
||||||
// The import operation of this file is completed, so delete it if still exists
|
// The import operation of this file is completed, so delete it if still exists
|
||||||
@@ -116,7 +116,7 @@ function importStudiesDIMSE(studiesToImport, studyImportStatusId) {
|
|||||||
|
|
||||||
}).run();
|
}).run();
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
StudyImportStatus.update({_id: studyImportStatusId}, {$inc: {'numberOfStudiesFailed': 1}});
|
OHIF.studylist.collections.StudyImportStatus.update({_id: studyImportStatusId}, {$inc: {'numberOfStudiesFailed': 1}});
|
||||||
console.log("Failed to import study via DIMSE: ", file, error);
|
console.log("Failed to import study via DIMSE: ", file, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import './getStudyMetadata.js';
|
||||||
|
import './importStudies.js';
|
||||||
|
import './studylistSearch.js';
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
Meteor.publish('studyImportStatus', () => {
|
Meteor.publish('studyImportStatus', () => {
|
||||||
return StudyImportStatus.find();
|
return OHIF.studylist.collections.StudyImportStatus.find();
|
||||||
});
|
});
|
||||||
|
|
||||||
Meteor.publish('servers', () => {
|
Meteor.publish('servers', () => {
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import './namespace.js';
|
||||||
|
|
||||||
|
// DICOMWeb instance, study, and metadata retrieval
|
||||||
|
import './qido/instances.js';
|
||||||
|
import './qido/studies.js';
|
||||||
|
import './wado/retrieveMetadata.js';
|
||||||
|
|
||||||
|
// DIMSE instance, study, and metadata retrieval
|
||||||
|
import './dimse/instances.js';
|
||||||
|
import './dimse/studies.js';
|
||||||
|
import './dimse/retrieveMetadata.js';
|
||||||
|
|
||||||
|
// Study, instance, and metadata retrieval from remote PACS via Orthanc as a proxy
|
||||||
|
import './remote/instances.js';
|
||||||
|
import './remote/studies.js';
|
||||||
|
import './remote/retrieveMetadata.js';
|
||||||
@@ -183,7 +183,6 @@ Package.onUse(function(api) {
|
|||||||
api.export('updateAllViewports', 'client');
|
api.export('updateAllViewports', 'client');
|
||||||
api.export('queryStudies', 'client');
|
api.export('queryStudies', 'client');
|
||||||
api.export('getNumberOfFilesInStudy', 'client');
|
api.export('getNumberOfFilesInStudy', 'client');
|
||||||
api.export('exportStudies', 'client');
|
|
||||||
api.export('importStudies', 'client');
|
api.export('importStudies', 'client');
|
||||||
api.export('getActiveViewportElement', 'client');
|
api.export('getActiveViewportElement', 'client');
|
||||||
api.export('getInstanceClassDefaultViewport', 'client');
|
api.export('getInstanceClassDefaultViewport', 'client');
|
||||||
|
|||||||
Reference in new issue
Block a user