LT-334: Prevent Lesion Tracker dropping measurements when storing a new case. Removed test PET SUV application since it's unnecessary
This commit is contained in:
parent
d6a3172bb3
commit
3d29a7e299
1
PETSUVMeasurements/.gagarin/.gitignore
vendored
1
PETSUVMeasurements/.gagarin/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
local
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
# This file contains information which helps Meteor properly upgrade your
|
|
||||||
# app when you run 'meteor update'. You should check it into version control
|
|
||||||
# with your project.
|
|
||||||
|
|
||||||
notices-for-0.9.0
|
|
||||||
notices-for-0.9.1
|
|
||||||
0.9.4-platform-file
|
|
||||||
notices-for-facebook-graph-api-2
|
|
||||||
1.2.0-standard-minifiers-package
|
|
||||||
1.2.0-meteor-platform-split
|
|
||||||
1.2.0-cordova-changes
|
|
||||||
1.2.0-breaking-changes
|
|
||||||
1.3.0-split-minifiers-package
|
|
||||||
1.3.5-remove-old-dev-bundle-link
|
|
||||||
1.4.0-remove-old-dev-bundle-link
|
|
||||||
1.4.1-add-shell-server-package
|
|
||||||
2
PETSUVMeasurements/.meteor/.gitignore
vendored
2
PETSUVMeasurements/.meteor/.gitignore
vendored
@ -1,2 +0,0 @@
|
|||||||
dev_bundle
|
|
||||||
local
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
# This file contains a token that is unique to your project.
|
|
||||||
# Check it into your repository along with the rest of this directory.
|
|
||||||
# It can be used for purposes such as:
|
|
||||||
# - ensuring you don't accidentally deploy one app on top of another
|
|
||||||
# - providing package authors with aggregated statistics
|
|
||||||
|
|
||||||
1q3vtk41m2yk4k1rqj08l
|
|
||||||
@ -1,136 +0,0 @@
|
|||||||
{
|
|
||||||
"starrynight": {
|
|
||||||
"version": "3.7.0"
|
|
||||||
},
|
|
||||||
"nightwatch": {
|
|
||||||
"version": "0.8.6"
|
|
||||||
},
|
|
||||||
"src_folders": [
|
|
||||||
"./tests/nightwatch/walkthroughs"
|
|
||||||
],
|
|
||||||
"output_folder": "./tests/nightwatch/reports",
|
|
||||||
"custom_commands_path": [
|
|
||||||
"./tests/nightwatch/commands",
|
|
||||||
"./tests/nightwatch/commands/api/meteor",
|
|
||||||
"./tests/nightwatch/commands/actions",
|
|
||||||
"./tests/nightwatch/commands/components",
|
|
||||||
"./tests/nightwatch/commands/methods"
|
|
||||||
],
|
|
||||||
"custom_assertions_path": [
|
|
||||||
"./tests/nightwatch/assertions"
|
|
||||||
],
|
|
||||||
"globals_path": "./tests/nightwatch/globals.json",
|
|
||||||
"selenium": {
|
|
||||||
"start_process": true,
|
|
||||||
"server_path": "${npm_config_prefix}/lib/node_modules/starrynight/node_modules/selenium-server-standalone-jar/jar/selenium-server-standalone-2.45.0.jar",
|
|
||||||
"log_path": "tests/nightwatch/logs",
|
|
||||||
"host": "127.0.0.1",
|
|
||||||
"port": 4444,
|
|
||||||
"cli_args": {
|
|
||||||
"webdriver.chrome.driver": "${npm_config_prefix}/lib/node_modules/starrynight/node_modules/chromedriver/bin/chromedriver"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"test_settings": {
|
|
||||||
"default": {
|
|
||||||
"launch_url": "http://localhost:5000",
|
|
||||||
"selenium_host": "127.0.0.1",
|
|
||||||
"selenium_port": 4444,
|
|
||||||
"pathname": "/wd/hub",
|
|
||||||
"silent": true,
|
|
||||||
"disable_colors": false,
|
|
||||||
"firefox_profile": false,
|
|
||||||
"ie_driver": "",
|
|
||||||
"screenshots": {
|
|
||||||
"enabled": false,
|
|
||||||
"path": "./tests/nightwatch/screenshots"
|
|
||||||
},
|
|
||||||
"desiredCapabilities": {
|
|
||||||
"browserName": "chrome",
|
|
||||||
"javascriptEnabled": true,
|
|
||||||
"acceptSslCerts": true,
|
|
||||||
"loggingPrefs": {
|
|
||||||
"browser": "ALL"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"exclude": "./tests/nightwatch/unittests/*"
|
|
||||||
},
|
|
||||||
"phantomjs": {
|
|
||||||
"desiredCapabilities": {
|
|
||||||
"browserName": "phantomjs",
|
|
||||||
"javascriptEnabled": true,
|
|
||||||
"databaseEnabled": false,
|
|
||||||
"locationContextEnabled": false,
|
|
||||||
"applicationCacheEnabled": false,
|
|
||||||
"browserConnectionEnabled": false,
|
|
||||||
"webStorageEnabled": false,
|
|
||||||
"acceptSslCerts": true,
|
|
||||||
"rotatable": false,
|
|
||||||
"nativeEvents": false,
|
|
||||||
"phantomjs.binary.path": "${npm_config_prefix}/lib/node_modules/starrynight/node_modules/phantomjs/bin/phantomjs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"travis": {
|
|
||||||
"launch_url": "http://localhost:3000",
|
|
||||||
"selenium_host": "127.0.0.1",
|
|
||||||
"selenium_port": 4444,
|
|
||||||
"pathname": "/wd/hub",
|
|
||||||
"silent": true,
|
|
||||||
"disable_colors": false,
|
|
||||||
"firefox_profile": false,
|
|
||||||
"screenshots": {
|
|
||||||
"enabled": false,
|
|
||||||
"path": "./tests/nightwatch/screenshots"
|
|
||||||
},
|
|
||||||
"desiredCapabilities": {
|
|
||||||
"browserName": "firefox",
|
|
||||||
"javascriptEnabled": true,
|
|
||||||
"databaseEnabled": true,
|
|
||||||
"locationContextEnabled": true,
|
|
||||||
"applicationCacheEnabled": true,
|
|
||||||
"browserConnectionEnabled": true,
|
|
||||||
"webStorageEnabled": true,
|
|
||||||
"acceptSslCerts": true,
|
|
||||||
"rotatable": true,
|
|
||||||
"nativeEvents": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"travischrome": {
|
|
||||||
"launch_url": "http://localhost:3000",
|
|
||||||
"selenium_host": "127.0.0.1",
|
|
||||||
"selenium_port": 4444,
|
|
||||||
"pathname": "/wd/hub",
|
|
||||||
"silent": true,
|
|
||||||
"disable_colors": false,
|
|
||||||
"firefox_profile": false,
|
|
||||||
"screenshots": {
|
|
||||||
"enabled": false,
|
|
||||||
"path": "./tests/nightwatch/screenshots"
|
|
||||||
},
|
|
||||||
"desiredCapabilities": {
|
|
||||||
"browserName": "chrome",
|
|
||||||
"javascriptEnabled": true,
|
|
||||||
"databaseEnabled": true,
|
|
||||||
"locationContextEnabled": true,
|
|
||||||
"applicationCacheEnabled": true,
|
|
||||||
"browserConnectionEnabled": true,
|
|
||||||
"webStorageEnabled": true,
|
|
||||||
"acceptSslCerts": true,
|
|
||||||
"rotatable": true,
|
|
||||||
"nativeEvents": true,
|
|
||||||
"chromeOptions": {
|
|
||||||
"args": [
|
|
||||||
"--no-sandbox"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"unittests": {
|
|
||||||
"selenium": {
|
|
||||||
"start_process": false,
|
|
||||||
"start_session": false
|
|
||||||
},
|
|
||||||
"filter": "./tests/nightwatch/unittests/*",
|
|
||||||
"exclude": ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,74 +0,0 @@
|
|||||||
# Meteor packages used by this project, one per line.
|
|
||||||
# Check this file (and the other files in this directory) into your repository.
|
|
||||||
#
|
|
||||||
# 'meteor add' and 'meteor remove' will edit this file for you,
|
|
||||||
# but you can also edit it by hand.
|
|
||||||
|
|
||||||
npm-bcrypt@0.9.1
|
|
||||||
|
|
||||||
meteor-base@1.0.4 # Packages every Meteor app needs to have
|
|
||||||
mobile-experience@1.0.4 # Packages for a great mobile UX
|
|
||||||
mongo@1.1.12 # The database Meteor supports right now
|
|
||||||
blaze-html-templates@1.0.4 # Compile .html files into Meteor Blaze views
|
|
||||||
session@1.1.6 # Client-side reactive dictionary for your app
|
|
||||||
jquery@1.11.9 # Helpful client-side library
|
|
||||||
tracker@1.1.0 # Meteor's client-side reactive programming library
|
|
||||||
|
|
||||||
es5-shim@4.6.14 # ECMAScript 5 compatibility for older browsers.
|
|
||||||
ecmascript@0.5.8 # Enable ECMAScript2015+ syntax in app code
|
|
||||||
|
|
||||||
insecure
|
|
||||||
|
|
||||||
clinical:router
|
|
||||||
clinical:extended-api
|
|
||||||
clinical:active-entry
|
|
||||||
clinical:error-pages
|
|
||||||
clinical:theming
|
|
||||||
clinical:fonts
|
|
||||||
clinical:hipaa-audit-log
|
|
||||||
clinical:hipaa-logger
|
|
||||||
|
|
||||||
aldeed:simple-schema # Third party package to deal with schemas
|
|
||||||
|
|
||||||
# OHIF Packages
|
|
||||||
design
|
|
||||||
ohif:core
|
|
||||||
ohif:cornerstone
|
|
||||||
ohif:viewerbase
|
|
||||||
ohif:study-list
|
|
||||||
ohif:dicom-services
|
|
||||||
ohif:hanging-protocols
|
|
||||||
ohif:user-management
|
|
||||||
ohif:petsuv
|
|
||||||
|
|
||||||
accounts-base@1.2.11
|
|
||||||
accounts-password@1.3.0
|
|
||||||
|
|
||||||
ian:accounts-ui-bootstrap-3
|
|
||||||
twbs:bootstrap
|
|
||||||
http@1.2.9
|
|
||||||
arsnebula:reactive-promise
|
|
||||||
promise@0.8.4
|
|
||||||
stylus@2.513.5
|
|
||||||
fortawesome:fontawesome
|
|
||||||
random@1.0.10
|
|
||||||
reactive-var@1.0.10
|
|
||||||
reactive-dict@1.1.8
|
|
||||||
practicalmeteor:loglevel
|
|
||||||
momentjs:moment
|
|
||||||
|
|
||||||
anti:gagarin@=0.4.11
|
|
||||||
check@1.2.3
|
|
||||||
aldeed:template-extension@4.0.0
|
|
||||||
zuuk:stale-session
|
|
||||||
gilbertwat:bootstrap3-daterangepicker
|
|
||||||
email@1.1.17
|
|
||||||
peppelg:bootstrap-3-modal
|
|
||||||
simple:reactive-method
|
|
||||||
fastclick@1.0.12
|
|
||||||
standard-minifier-css@1.2.0
|
|
||||||
standard-minifier-js@1.2.0
|
|
||||||
johdirr:meteor-git-rev
|
|
||||||
u2622:persistent-session
|
|
||||||
shell-server
|
|
||||||
aldeed:collection2
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
server
|
|
||||||
browser
|
|
||||||
@ -1 +0,0 @@
|
|||||||
METEOR@1.4.1.1
|
|
||||||
@ -1,143 +0,0 @@
|
|||||||
accounts-base@1.2.11
|
|
||||||
accounts-password@1.3.0
|
|
||||||
aldeed:collection2@2.9.1
|
|
||||||
aldeed:collection2-core@1.1.1
|
|
||||||
aldeed:schema-deny@1.0.1
|
|
||||||
aldeed:schema-index@1.0.1
|
|
||||||
aldeed:simple-schema@1.5.3
|
|
||||||
aldeed:template-extension@4.0.0
|
|
||||||
allow-deny@1.0.5
|
|
||||||
amplify@1.0.0
|
|
||||||
anti:gagarin@0.4.11
|
|
||||||
anti:i18n@0.4.3
|
|
||||||
arsnebula:reactive-promise@0.9.1
|
|
||||||
autoupdate@1.3.11
|
|
||||||
babel-compiler@6.9.1
|
|
||||||
babel-runtime@0.1.11
|
|
||||||
base64@1.0.9
|
|
||||||
binary-heap@1.0.9
|
|
||||||
blaze@2.1.8
|
|
||||||
blaze-html-templates@1.0.4
|
|
||||||
blaze-tools@1.0.9
|
|
||||||
boilerplate-generator@1.0.9
|
|
||||||
caching-compiler@1.1.7
|
|
||||||
caching-html-compiler@1.0.6
|
|
||||||
callback-hook@1.0.9
|
|
||||||
check@1.2.3
|
|
||||||
clinical:active-entry@1.5.16
|
|
||||||
clinical:auto-resizing@0.2.0
|
|
||||||
clinical:error-pages@0.2.0
|
|
||||||
clinical:extended-api@2.2.4
|
|
||||||
clinical:fonts@1.1.1
|
|
||||||
clinical:hipaa-audit-log@2.4.2
|
|
||||||
clinical:hipaa-logger@1.0.1
|
|
||||||
clinical:router@2.0.19
|
|
||||||
clinical:router-location@2.1.0
|
|
||||||
clinical:router-middleware-stack@2.1.2
|
|
||||||
clinical:router-url@2.1.0
|
|
||||||
clinical:theming@0.4.10
|
|
||||||
coffeescript@1.2.4_1
|
|
||||||
ddp@1.2.5
|
|
||||||
ddp-client@1.3.1
|
|
||||||
ddp-common@1.2.6
|
|
||||||
ddp-rate-limiter@1.0.5
|
|
||||||
ddp-server@1.3.10
|
|
||||||
deps@1.0.12
|
|
||||||
design@0.0.1
|
|
||||||
diff-sequence@1.0.6
|
|
||||||
ecmascript@0.5.8
|
|
||||||
ecmascript-runtime@0.3.14
|
|
||||||
ejson@1.0.12
|
|
||||||
email@1.1.17
|
|
||||||
es5-shim@4.6.14
|
|
||||||
fastclick@1.0.12
|
|
||||||
fortawesome:fontawesome@4.5.0
|
|
||||||
geojson-utils@1.0.9
|
|
||||||
gilbertwat:bootstrap3-daterangepicker@1.3.21_1
|
|
||||||
grove:less@0.2.0
|
|
||||||
hot-code-push@1.0.4
|
|
||||||
html-tools@1.0.10
|
|
||||||
htmljs@1.0.10
|
|
||||||
http@1.2.9
|
|
||||||
ian:accounts-ui-bootstrap-3@1.2.89
|
|
||||||
id-map@1.0.8
|
|
||||||
insecure@1.0.7
|
|
||||||
iron:controller@1.0.12
|
|
||||||
iron:core@1.0.11
|
|
||||||
iron:dynamic-template@1.0.12
|
|
||||||
iron:layout@1.0.12
|
|
||||||
johdirr:meteor-git-rev@0.0.4
|
|
||||||
jquery@1.11.9
|
|
||||||
launch-screen@1.0.12
|
|
||||||
livedata@1.0.18
|
|
||||||
localstorage@1.0.11
|
|
||||||
logging@1.1.15
|
|
||||||
mdg:validation-error@0.5.1
|
|
||||||
meteor@1.2.17
|
|
||||||
meteor-base@1.0.4
|
|
||||||
meteor-platform@1.2.6
|
|
||||||
minifier-css@1.2.14
|
|
||||||
minifier-js@1.2.14
|
|
||||||
minimongo@1.0.17
|
|
||||||
mobile-experience@1.0.4
|
|
||||||
mobile-status-bar@1.0.12
|
|
||||||
modules@0.7.6
|
|
||||||
modules-runtime@0.7.6
|
|
||||||
momentjs:moment@2.14.4
|
|
||||||
mongo@1.1.12
|
|
||||||
mongo-id@1.0.5
|
|
||||||
mrt:moment@2.8.1
|
|
||||||
natestrauser:select2@4.0.3
|
|
||||||
npm-bcrypt@0.9.1
|
|
||||||
npm-mongo@1.5.49
|
|
||||||
observe-sequence@1.0.12
|
|
||||||
ohif:core@0.0.1
|
|
||||||
ohif:cornerstone@0.0.1
|
|
||||||
ohif:dicom-services@0.0.1
|
|
||||||
ohif:hanging-protocols@0.0.1
|
|
||||||
ohif:measurements@0.0.1
|
|
||||||
ohif:petsuv@0.0.1
|
|
||||||
ohif:study-list@0.0.1
|
|
||||||
ohif:user-management@0.0.1
|
|
||||||
ohif:viewerbase@0.0.1
|
|
||||||
ohif:wadoproxy@0.0.1
|
|
||||||
ordered-dict@1.0.8
|
|
||||||
peppelg:bootstrap-3-modal@1.0.4
|
|
||||||
practicalmeteor:chai@2.1.0_1
|
|
||||||
practicalmeteor:loglevel@1.2.0_2
|
|
||||||
promise@0.8.4
|
|
||||||
raix:eventemitter@0.1.3
|
|
||||||
random@1.0.10
|
|
||||||
rate-limit@1.0.5
|
|
||||||
reactive-dict@1.1.8
|
|
||||||
reactive-var@1.0.10
|
|
||||||
reload@1.1.10
|
|
||||||
retry@1.0.8
|
|
||||||
routepolicy@1.0.11
|
|
||||||
service-configuration@1.0.10
|
|
||||||
session@1.1.6
|
|
||||||
sha@1.0.8
|
|
||||||
shell-server@0.2.1
|
|
||||||
silentcicero:jszip@0.0.4
|
|
||||||
simple:reactive-method@1.0.2
|
|
||||||
spacebars@1.0.12
|
|
||||||
spacebars-compiler@1.0.12
|
|
||||||
srp@1.0.9
|
|
||||||
standard-app-packages@1.0.9
|
|
||||||
standard-minifier-css@1.2.0
|
|
||||||
standard-minifier-js@1.2.0
|
|
||||||
stylus@2.513.5
|
|
||||||
templating@1.2.14
|
|
||||||
templating-tools@1.0.4
|
|
||||||
tracker@1.1.0
|
|
||||||
twbs:bootstrap@3.3.6
|
|
||||||
typ:accounts-ldap@1.0.1
|
|
||||||
typ:ldapjs@0.7.3
|
|
||||||
u2622:persistent-session@0.4.4
|
|
||||||
ui@1.0.11
|
|
||||||
underscore@1.0.9
|
|
||||||
url@1.0.10
|
|
||||||
validatejs@0.0.1
|
|
||||||
webapp@1.3.11
|
|
||||||
webapp-hashing@1.0.9
|
|
||||||
zuuk:stale-session@1.0.8
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
if (Meteor.isClient){
|
|
||||||
ActiveEntry.configure({
|
|
||||||
logo: {
|
|
||||||
url: '/mini-circles.png',
|
|
||||||
displayed: true
|
|
||||||
},
|
|
||||||
signIn: {
|
|
||||||
displayFullName: true,
|
|
||||||
destination: '/studylist'
|
|
||||||
},
|
|
||||||
signUp: {
|
|
||||||
destination: '/studylist'
|
|
||||||
},
|
|
||||||
themeColors: {
|
|
||||||
primary: ""
|
|
||||||
},
|
|
||||||
passwordOptions: {
|
|
||||||
showPasswordStrengthIndicator: false,
|
|
||||||
requireRegexValidation: true,
|
|
||||||
//requireStrongPasswords: false
|
|
||||||
passwordHistoryCount: 6,
|
|
||||||
failedAttemptsLimit: 5
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
if (Meteor.isServer){
|
|
||||||
Accounts.emailTemplates.siteName = 'AwesomeSite';
|
|
||||||
Accounts.emailTemplates.from = 'AwesomeSite Admin <accounts@example.com>';
|
|
||||||
Accounts.emailTemplates.enrollAccount.subject = function(user) {
|
|
||||||
return 'Welcome to Awesome Town, ' + user.profile.name;
|
|
||||||
};
|
|
||||||
|
|
||||||
Accounts.emailTemplates.enrollAccount.text = function(user, url) {
|
|
||||||
return 'You have been selected to participate in building a better future!'
|
|
||||||
+ ' To activate your account, simply click the link below:\n\n'
|
|
||||||
+ url;
|
|
||||||
};
|
|
||||||
|
|
||||||
Meteor.startup(function() {
|
|
||||||
//process.env.MAIL_URL = 'smtp://sandboxid.mailgun.org:mypassword@smtp.mailgun.org:587';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
body
|
|
||||||
background-color: black
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
<template name="app">
|
|
||||||
<div class="topBar noselect {{#if onStudyList}}studyList{{/if}}">
|
|
||||||
<div class="clearfix">
|
|
||||||
<a target='_blank'
|
|
||||||
class="brandSection pull-left"
|
|
||||||
href="http://ohif.org">
|
|
||||||
<svg class="logoImage">
|
|
||||||
<use xlink:href="/packages/ohif_viewerbase/assets/icons.svg#icon-ohif-logo"></use>
|
|
||||||
</svg>
|
|
||||||
<div class="logoText">
|
|
||||||
Open Health Imaging Foundation
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
{{ #if studyListToggleText }}
|
|
||||||
<a class="btn studyListLinkSection pull-left js-toggle-studyList">
|
|
||||||
{{studyListToggleText}}
|
|
||||||
</a>
|
|
||||||
{{ /if }}
|
|
||||||
<div class="userAccountSection pull-right">
|
|
||||||
{{>userAccountMenu}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{ >timeoutCountdownDialog }}
|
|
||||||
<div id="studylistTabs" class="tab-content">
|
|
||||||
<div class="tab-pane active" id="studylistTab">
|
|
||||||
<div class="studylistContainer">
|
|
||||||
{{> studylistResult }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="tab-pane" id="viewerTab">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{ >serverInformationModal }}
|
|
||||||
{{ >lastLoginModal }}
|
|
||||||
{{ >progressDialog }}
|
|
||||||
{{ >viewSeriesDetailsModal }}
|
|
||||||
</template>
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
const studylistContentId = 'studylistTab';
|
|
||||||
const viewerContentId = 'viewerTab';
|
|
||||||
|
|
||||||
// Define the ViewerData global object
|
|
||||||
// If there is currently any Session data for this object,
|
|
||||||
// use this to repopulate the variable
|
|
||||||
Template.app.onCreated(() => {
|
|
||||||
ViewerData = Session.get('ViewerData') || {};
|
|
||||||
});
|
|
||||||
|
|
||||||
Template.app.events({
|
|
||||||
'click .js-toggle-studyList'() {
|
|
||||||
const contentId = Session.get('activeContentId');
|
|
||||||
|
|
||||||
if (contentId !== studylistContentId) {
|
|
||||||
switchToTab(studylistContentId);
|
|
||||||
} else {
|
|
||||||
switchToTab(viewerContentId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Template.app.helpers({
|
|
||||||
studyListToggleText() {
|
|
||||||
const contentId = Session.get('activeContentId');
|
|
||||||
|
|
||||||
// If the Viewer has not been opened yet, 'Back to viewer' should
|
|
||||||
// not be displayed
|
|
||||||
const viewerContentExists = !!Object.keys(ViewerData).length;
|
|
||||||
if (!viewerContentExists) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (contentId === studylistContentId) {
|
|
||||||
return 'Back to viewer';
|
|
||||||
} else if (contentId === viewerContentId) {
|
|
||||||
return 'Study list';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onStudyList() {
|
|
||||||
return (Session.get('activeContentId') === 'studylistTab');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Session.set('defaultSignInMessage', 'Tumor tracking in your browser.');
|
|
||||||
@ -1,87 +0,0 @@
|
|||||||
@import "{design}/app"
|
|
||||||
|
|
||||||
$expandedHeight = 160px
|
|
||||||
|
|
||||||
.logoImage
|
|
||||||
display: inline-block
|
|
||||||
height: 100%
|
|
||||||
float: left
|
|
||||||
|
|
||||||
.topBar
|
|
||||||
height: $topBarHeight
|
|
||||||
padding: 10px 10px 0
|
|
||||||
theme('color', '$textPrimaryColor')
|
|
||||||
theme('background-color', '$primaryBackgroundColor')
|
|
||||||
transition(all 0.5s ease)
|
|
||||||
|
|
||||||
&>.clearfix
|
|
||||||
position: relative
|
|
||||||
|
|
||||||
.brandSection
|
|
||||||
height: 30px
|
|
||||||
display: inline-block
|
|
||||||
text-decoration: none
|
|
||||||
|
|
||||||
.logoImage
|
|
||||||
margin: 0 8px 0 0
|
|
||||||
width: 30px
|
|
||||||
|
|
||||||
.logoText
|
|
||||||
display: inline-block
|
|
||||||
font-family: $logoFontFamily
|
|
||||||
font-weight: $logoFontWeight
|
|
||||||
theme('color', '$textPrimaryColor')
|
|
||||||
line-height: 30px
|
|
||||||
|
|
||||||
.studyListLinkSection
|
|
||||||
theme('border-left', '%s solid $uiBorderColor' % $uiBorderThickness)
|
|
||||||
margin: 3px 0 0 10px
|
|
||||||
padding: 0 0 0 10px
|
|
||||||
|
|
||||||
.btn
|
|
||||||
theme('color', '$textSecondaryColor')
|
|
||||||
cursor: pointer
|
|
||||||
font-size: 13px
|
|
||||||
font-weight: 500
|
|
||||||
line-height: 26px
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
theme('color', '$hoverColor')
|
|
||||||
|
|
||||||
&:active
|
|
||||||
theme('color', '$activeColor')
|
|
||||||
|
|
||||||
&.studyList
|
|
||||||
background-color: rgba(21, 25, 30, 0.7)
|
|
||||||
height: $expandedHeight
|
|
||||||
padding-left: $studyListPadding
|
|
||||||
padding-right: $studyListPadding
|
|
||||||
|
|
||||||
.brandSection
|
|
||||||
height: 100%
|
|
||||||
width: 80%
|
|
||||||
line-height: $expandedHeight - 10px
|
|
||||||
|
|
||||||
.logoImage
|
|
||||||
width: 50px
|
|
||||||
margin: 0 20px 0 0
|
|
||||||
|
|
||||||
.logoText
|
|
||||||
font-size: 30px
|
|
||||||
|
|
||||||
.studyListLinkSection
|
|
||||||
border: none
|
|
||||||
left: 0
|
|
||||||
margin: 0
|
|
||||||
padding: 0
|
|
||||||
position: absolute
|
|
||||||
top: 0
|
|
||||||
|
|
||||||
#studylistTabs
|
|
||||||
height: "calc(100% - %s)" % $topBarHeight
|
|
||||||
|
|
||||||
.tab-pane
|
|
||||||
.viewerContainer
|
|
||||||
.loadingTextDiv
|
|
||||||
theme('color', '$textSecondaryColor')
|
|
||||||
font-size: 30px
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
<template name="toolbarSection">
|
|
||||||
<div class="toolbarSection noselect p-x-2">
|
|
||||||
<div class="clearfix">
|
|
||||||
<div class="pull-left m-t-1">
|
|
||||||
{{>roundedButtonGroup leftSidebarToggleButtonData}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{>toolbarSectionTools toolbarButtons=toolbarButtons extraToolbarButtons=extraToolbarButtons}}
|
|
||||||
|
|
||||||
{{#if splitView}}
|
|
||||||
{{>studySeriesQuickSwitch (clone this side="right" viewportIndex=1)}}
|
|
||||||
{{>studySeriesQuickSwitch (clone this side="left" viewportIndex=0)}}
|
|
||||||
{{else}}
|
|
||||||
{{>studySeriesQuickSwitch (clone this side="middle" viewportIndex=0)}}
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<div class="toolbarSectionEntry pull-right rm-l-1 p-x-1">
|
|
||||||
{{>caseProgress}}
|
|
||||||
</div>
|
|
||||||
<div class="pull-right m-t-1 rm-x-1">
|
|
||||||
{{>roundedButtonGroup rightSidebarToggleButtonData}}
|
|
||||||
</div>
|
|
||||||
<div id="toggleHUD" class="toolbarSectionButton pull-right rp-x-1 m-t-1 rm-r-3 {{#if session 'measurementTableHudOpen'}}active{{/if}}">
|
|
||||||
<div class="svgContainer">
|
|
||||||
<svg>
|
|
||||||
<use xlink:href="/packages/ohif_viewerbase/assets/icons.svg#icon-hud"></use>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<div class="buttonLabel">HUD</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
@ -1,143 +0,0 @@
|
|||||||
import { OHIF } from 'meteor/ohif:core';
|
|
||||||
|
|
||||||
Template.toolbarSection.helpers({
|
|
||||||
// Returns true if the view shall be split in two viewports
|
|
||||||
splitView() {
|
|
||||||
// Run this computation every time the viewports are updated
|
|
||||||
Session.get('LayoutManagerUpdated');
|
|
||||||
|
|
||||||
// Stops here if layout manager is not defined yet
|
|
||||||
if (!window.layoutManager) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return window.layoutManager.viewportData.length > 1;
|
|
||||||
},
|
|
||||||
|
|
||||||
leftSidebarToggleButtonData() {
|
|
||||||
const instance = Template.instance();
|
|
||||||
return {
|
|
||||||
toggleable: true,
|
|
||||||
key: 'leftSidebar',
|
|
||||||
value: instance.data.state,
|
|
||||||
options: [{
|
|
||||||
value: 'studies',
|
|
||||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-studies',
|
|
||||||
svgWidth: 15,
|
|
||||||
svgHeight: 13,
|
|
||||||
bottomLabel: 'Studies'
|
|
||||||
}]
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
rightSidebarToggleButtonData() {
|
|
||||||
const instance = Template.instance();
|
|
||||||
return {
|
|
||||||
toggleable: true,
|
|
||||||
key: 'rightSidebar',
|
|
||||||
value: instance.data.state,
|
|
||||||
options: [{
|
|
||||||
value: 'measurements',
|
|
||||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-measurements-lesions',
|
|
||||||
svgWidth: 18,
|
|
||||||
svgHeight: 10,
|
|
||||||
bottomLabel: 'Measurements'
|
|
||||||
}]
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
toolbarButtons() {
|
|
||||||
// Check if the measure tools shall be disabled
|
|
||||||
const isToolDisabled = false; //!Template.instance().data.timepointApi;
|
|
||||||
|
|
||||||
const buttonData = [];
|
|
||||||
|
|
||||||
buttonData.push({
|
|
||||||
id: 'zoom',
|
|
||||||
title: 'Zoom',
|
|
||||||
classes: 'imageViewerTool',
|
|
||||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-zoom'
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonData.push({
|
|
||||||
id: 'wwwc',
|
|
||||||
title: 'Levels',
|
|
||||||
classes: 'imageViewerTool',
|
|
||||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-levels'
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonData.push({
|
|
||||||
id: 'pan',
|
|
||||||
title: 'Pan',
|
|
||||||
classes: 'imageViewerTool',
|
|
||||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-pan'
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonData.push({
|
|
||||||
id: 'ellipticalRoi',
|
|
||||||
title: 'Ellipse',
|
|
||||||
classes: 'imageViewerTool',
|
|
||||||
iconClasses: 'fa fa-circle-o'
|
|
||||||
});
|
|
||||||
|
|
||||||
return buttonData;
|
|
||||||
},
|
|
||||||
|
|
||||||
extraToolbarButtons() {
|
|
||||||
// Check if the measure tools shall be disabled
|
|
||||||
const isToolDisabled = false; //!Template.instance().data.timepointApi.currentTimepointId;
|
|
||||||
const buttonData = [];
|
|
||||||
|
|
||||||
// TODO: Get real icons for CR / UN / EX
|
|
||||||
buttonData.push({
|
|
||||||
id: 'crTool',
|
|
||||||
title: 'CR Tool',
|
|
||||||
classes: 'imageViewerTool toolbarSectionButton',
|
|
||||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-measure-temp',
|
|
||||||
disabled: isToolDisabled
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonData.push({
|
|
||||||
id: 'unTool',
|
|
||||||
title: 'UN Tool',
|
|
||||||
classes: 'imageViewerTool toolbarSectionButton',
|
|
||||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-measure-temp',
|
|
||||||
disabled: isToolDisabled
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonData.push({
|
|
||||||
id: 'exTool',
|
|
||||||
title: 'EX Tool',
|
|
||||||
classes: 'imageViewerTool toolbarSectionButton',
|
|
||||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-measure-temp',
|
|
||||||
disabled: isToolDisabled
|
|
||||||
});
|
|
||||||
|
|
||||||
return buttonData;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Template.toolbarSection.events({
|
|
||||||
'click #toggleHUD'() {
|
|
||||||
const state = Session.get('measurementTableHudOpen');
|
|
||||||
Session.set('measurementTableHudOpen', !state);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Template.toolbarSection.onRendered(function() {
|
|
||||||
// Set disabled/enabled tool buttons that are set in toolManager
|
|
||||||
const states = toolManager.getToolDefaultStates();
|
|
||||||
const disabledToolButtons = states.disabledToolButtons;
|
|
||||||
const allToolbarButtons = $('#toolbar').find('button');
|
|
||||||
if (disabledToolButtons && disabledToolButtons.length > 0) {
|
|
||||||
for (var i = 0; i < allToolbarButtons.length; i++) {
|
|
||||||
const toolbarButton = allToolbarButtons[i];
|
|
||||||
$(toolbarButton).prop('disabled', false);
|
|
||||||
|
|
||||||
const index = disabledToolButtons.indexOf($(toolbarButton).attr('id'));
|
|
||||||
if (index !== -1) {
|
|
||||||
$(toolbarButton).prop('disabled', true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
@import "{design}/app"
|
|
||||||
|
|
||||||
.toolbarSection
|
|
||||||
theme('border-bottom', '%s solid $uiBorderColor' % $uiBorderThickness)
|
|
||||||
flex: 0 0 auto
|
|
||||||
height: $toolbarHeight
|
|
||||||
overflow: hidden
|
|
||||||
padding-top: 6px
|
|
||||||
position: relative
|
|
||||||
transition(height 300ms ease)
|
|
||||||
width: 100%
|
|
||||||
|
|
||||||
&.expanded
|
|
||||||
height: $toolbarHeight + $toolbarDrawerHeight
|
|
||||||
|
|
||||||
.toolbarSectionEntry
|
|
||||||
theme('color', '$defaultColor')
|
|
||||||
cursor: pointer
|
|
||||||
display: inline-block
|
|
||||||
theme('fill', '$defaultColor')
|
|
||||||
margin-top: 3px
|
|
||||||
min-width: 30px
|
|
||||||
theme('stroke', '$defaultColor')
|
|
||||||
text-align: center
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
<template name="viewer">
|
|
||||||
{{#if Template.subscriptionsReady}}
|
|
||||||
<div class="viewerDialogs">
|
|
||||||
{{>confirmDeleteDialog}}
|
|
||||||
{{>measurementTableHUD (clone this)}}
|
|
||||||
</div>
|
|
||||||
<div id="viewer">
|
|
||||||
{{>toolbarSection (clone this)}}
|
|
||||||
{{>viewerSection (clone this)}}
|
|
||||||
</div>
|
|
||||||
{{else}}
|
|
||||||
{{>loadingText}}
|
|
||||||
{{/if}}
|
|
||||||
</template>
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
import { OHIF } from 'meteor/ohif:core';
|
|
||||||
import { MeasurementsConfiguration } from 'meteor/ohif:measurements/both/configuration/measurements';
|
|
||||||
|
|
||||||
Session.set('MeasurementsReady', false);
|
|
||||||
|
|
||||||
Template.viewer.onCreated(() => {
|
|
||||||
OHIF.viewer = OHIF.viewer || {};
|
|
||||||
|
|
||||||
const instance = Template.instance();
|
|
||||||
|
|
||||||
instance.data.state = new ReactiveDict();
|
|
||||||
instance.data.state.set('leftSidebar', Session.get('leftSidebar'));
|
|
||||||
instance.data.state.set('rightSidebar', Session.get('rightSidebar'));
|
|
||||||
|
|
||||||
const contentId = instance.data.contentId;
|
|
||||||
|
|
||||||
if (ViewerData[contentId].loadedSeriesData) {
|
|
||||||
OHIF.log.info('Reloading previous loadedSeriesData');
|
|
||||||
OHIF.viewer.loadedSeriesData = ViewerData[contentId].loadedSeriesData;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
OHIF.log.info('Setting default ViewerData');
|
|
||||||
OHIF.viewer.loadedSeriesData = {};
|
|
||||||
ViewerData[contentId].loadedSeriesData = {};
|
|
||||||
Session.set('ViewerData', ViewerData);
|
|
||||||
}
|
|
||||||
|
|
||||||
Session.set('activeViewport', ViewerData[contentId].activeViewport || false);
|
|
||||||
|
|
||||||
// Update the ViewerStudies collection with the loaded studies
|
|
||||||
ViewerStudies.remove({});
|
|
||||||
|
|
||||||
instance.data.studies.forEach(study => {
|
|
||||||
study.selected = true;
|
|
||||||
study.displaySets = createStacks(study);
|
|
||||||
ViewerStudies.insert(study);
|
|
||||||
});
|
|
||||||
|
|
||||||
instance.data.measurementApi = new OHIF.measurements.MeasurementApi();
|
|
||||||
const measurementsPromise = instance.data.measurementApi.retrieveMeasurements();
|
|
||||||
measurementsPromise.then(() => {
|
|
||||||
Session.set('MeasurementsReady', true);
|
|
||||||
|
|
||||||
instance.data.measurementApi.syncMeasurementsAndToolData();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
Template.viewer.helpers({
|
|
||||||
dataSourcesReady() {
|
|
||||||
// TODO: Find a better way to do this
|
|
||||||
return Session.get('MeasurementsReady');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Template.viewer.events({
|
|
||||||
'CornerstoneToolsMeasurementAdded .imageViewerViewport'(event, instance, eventData) {
|
|
||||||
OHIF.measurements.MeasurementHandlers.onAdded(event, instance, eventData);
|
|
||||||
},
|
|
||||||
'CornerstoneToolsMeasurementModified .imageViewerViewport'(event, instance, eventData) {
|
|
||||||
OHIF.measurements.MeasurementHandlers.onModified(event, instance, eventData);
|
|
||||||
},
|
|
||||||
'CornerstoneToolsMeasurementRemoved .imageViewerViewport'(event, instance, eventData) {
|
|
||||||
OHIF.measurements.MeasurementHandlers.onRemoved(event, instance, eventData);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
@import "{design}/app"
|
|
||||||
|
|
||||||
#viewer
|
|
||||||
background-color: black
|
|
||||||
height: 100%
|
|
||||||
width: 100%
|
|
||||||
|
|
||||||
#imageViewerViewports
|
|
||||||
.viewportContainer
|
|
||||||
border: none !important
|
|
||||||
outline: 0 !important // Prevent blue outline in Chrome
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
&.active
|
|
||||||
&:hover.active
|
|
||||||
border: none !important
|
|
||||||
outline: 0 !important // Prevent blue outline in Chrome
|
|
||||||
|
|
||||||
&:not(:last-child)
|
|
||||||
.removable
|
|
||||||
.imageViewerViewport
|
|
||||||
theme('border-right', '%s solid $uiBorderColor' % $uiBorderThickness)
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
<template name="viewerSection">
|
|
||||||
<div class="viewerSection">
|
|
||||||
<div class="sidebarMenu sidebar-left {{#if leftSidebarOpen}}sidebar-open{{/if}}">
|
|
||||||
{{>studyTimepointBrowser (clone this)}}
|
|
||||||
</div>
|
|
||||||
<div class="mainContent {{#if leftSidebarOpen}}sidebar-left-open{{/if}} {{#if rightSidebarOpen}}sidebar-right-open{{/if}}">
|
|
||||||
{{>viewerMain (clone this)}}
|
|
||||||
</div>
|
|
||||||
<div class="sidebarMenu sidebar-right {{#if rightSidebarOpen}}sidebar-open{{/if}}">
|
|
||||||
{{>measurementTable (clone this)}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
Template.viewerSection.events({
|
|
||||||
'transitionend .sidebarMenu'(event) {
|
|
||||||
if (!event.target.classList.contains('sidebarMenu')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleResize();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Template.viewerSection.helpers({
|
|
||||||
leftSidebarOpen() {
|
|
||||||
return Template.instance().data.state.get('leftSidebar');
|
|
||||||
},
|
|
||||||
|
|
||||||
rightSidebarOpen() {
|
|
||||||
return Template.instance().data.state.get('rightSidebar');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@ -1,78 +0,0 @@
|
|||||||
@import "{design}/app"
|
|
||||||
|
|
||||||
.viewerSection
|
|
||||||
display: flex
|
|
||||||
flex: 1
|
|
||||||
flex-flow: row nowrap
|
|
||||||
align-items: stretch
|
|
||||||
height: calc(100% - 78px);
|
|
||||||
width: 100%
|
|
||||||
|
|
||||||
.sidebarMenu
|
|
||||||
height: 100%
|
|
||||||
// required transformation to make inner fixed elements relative to this one
|
|
||||||
transform(scale(1))
|
|
||||||
transition($sidebarTransition)
|
|
||||||
|
|
||||||
.sidebar-option
|
|
||||||
height: 100%
|
|
||||||
position: fixed
|
|
||||||
transform(translateX(100%))
|
|
||||||
transition($sidebarTransition)
|
|
||||||
width: 100%
|
|
||||||
|
|
||||||
&.active
|
|
||||||
transform(translateX(0%))
|
|
||||||
|
|
||||||
.sidebar-left
|
|
||||||
theme('border-right', '%s solid $uiBorderColor' % $uiBorderThickness)
|
|
||||||
flex: 1
|
|
||||||
margin-left: - $studiesSidebarMenuWidth
|
|
||||||
max-width: $studiesSidebarMenuWidth
|
|
||||||
order: 1
|
|
||||||
|
|
||||||
&.sidebar-open
|
|
||||||
margin-left: 0
|
|
||||||
|
|
||||||
.mainContent
|
|
||||||
flex: 1
|
|
||||||
order: 2
|
|
||||||
width: 100%
|
|
||||||
height: 100%
|
|
||||||
overflow: hidden
|
|
||||||
transition($sidebarTransition)
|
|
||||||
|
|
||||||
.sidebar-right
|
|
||||||
flex: 1
|
|
||||||
margin-left: -12px
|
|
||||||
margin-right: - $lesionsSidebarMenuWidth
|
|
||||||
max-width: $lesionsSidebarMenuWidth
|
|
||||||
order: 3
|
|
||||||
padding-left: 6px
|
|
||||||
position: relative
|
|
||||||
|
|
||||||
&[data-timepoints="3"]
|
|
||||||
margin-right: - ($lesionsSidebarMenuWidth + 135.5px)
|
|
||||||
max-width: $lesionsSidebarMenuWidth + 135.5px
|
|
||||||
|
|
||||||
&[data-timepoints="4"]
|
|
||||||
margin-right: - ($lesionsSidebarMenuWidth + 270px)
|
|
||||||
max-width: $lesionsSidebarMenuWidth + 270px
|
|
||||||
|
|
||||||
&:before
|
|
||||||
theme('background-color', '$uiBorderColor')
|
|
||||||
content: ''
|
|
||||||
display: block
|
|
||||||
height: 100%
|
|
||||||
left: 5px
|
|
||||||
position: absolute
|
|
||||||
top: 0
|
|
||||||
width: $uiBorderThickness
|
|
||||||
|
|
||||||
&.sidebar-open
|
|
||||||
margin-right: 0
|
|
||||||
|
|
||||||
.studiesListedChanger
|
|
||||||
theme('border-bottom', '%s solid $uiBorderColor' % $uiBorderThickness)
|
|
||||||
padding: 20px 10px
|
|
||||||
text-align: center
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>Lesion Tracker</title>
|
|
||||||
<meta name="description" content="Prototype viewer application for oncology">
|
|
||||||
<!-- Prevents page zooming -->
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
|
||||||
|
|
||||||
<link rel="shortcut icon" type="image/png" href="images/logo.png" sizes="16x16 32x32 64x64">
|
|
||||||
<!--Best display for mobile devices-->
|
|
||||||
<meta http-equiv="cleartype" content="on">
|
|
||||||
<meta name="MobileOptimized" content="320">
|
|
||||||
<meta name="HandheldFriendly" content="True">
|
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
||||||
|
|
||||||
<!-- Make SVG work on IE -->
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
|
|
||||||
<link href='http://fonts.googleapis.com/css?family=Roboto:400,100,100italic,300,300italic,400italic,500,500italic,700,700italic,900,900italic&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
|
|
||||||
<link href='http://fonts.googleapis.com/css?family=Sanchez:400,700&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
|
|
||||||
</head>
|
|
||||||
@ -1,167 +0,0 @@
|
|||||||
// Define Baseline protocol
|
|
||||||
var proto = new HP.Protocol('LT_Baseline');
|
|
||||||
proto.locked = true;
|
|
||||||
|
|
||||||
var studyDescription = new HP.ProtocolMatchingRule();
|
|
||||||
studyDescription.required = true;
|
|
||||||
studyDescription.attribute = 'studyDescription';
|
|
||||||
studyDescription.constraint = {
|
|
||||||
contains: {
|
|
||||||
value: 'CT'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var isBaseline = new HP.ProtocolMatchingRule();
|
|
||||||
isBaseline.required = true;
|
|
||||||
isBaseline.attribute = 'timepointType';
|
|
||||||
isBaseline.constraint = {
|
|
||||||
equals: {
|
|
||||||
value: 'baseline'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
proto.addProtocolMatchingRule(studyDescription);
|
|
||||||
proto.addProtocolMatchingRule(isBaseline);
|
|
||||||
|
|
||||||
var oneByOne = new HP.ViewportStructure('grid', {
|
|
||||||
rows: 1,
|
|
||||||
columns: 1
|
|
||||||
});
|
|
||||||
|
|
||||||
// Stage 1
|
|
||||||
var single = new HP.Viewport();
|
|
||||||
|
|
||||||
var baseline = new HP.StudyMatchingRule(true);
|
|
||||||
baseline.required = true;
|
|
||||||
baseline.attribute = 'timepointType';
|
|
||||||
baseline.constraint = {
|
|
||||||
equals: {
|
|
||||||
value: 'baseline'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var body = new HP.SeriesMatchingRule();
|
|
||||||
body.attribute = 'seriesDescription';
|
|
||||||
body.weight = 5;
|
|
||||||
body.constraint = {
|
|
||||||
contains: {
|
|
||||||
value: 'Body'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var chest = new HP.SeriesMatchingRule();
|
|
||||||
chest.attribute = 'seriesDescription';
|
|
||||||
chest.constraint = {
|
|
||||||
contains: {
|
|
||||||
value: 'CHEST'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
single.studyMatchingRules.push(baseline);
|
|
||||||
single.seriesMatchingRules.push(body);
|
|
||||||
single.seriesMatchingRules.push(chest);
|
|
||||||
|
|
||||||
var first = new HP.Stage(oneByOne, 'oneByOne');
|
|
||||||
first.viewports.push(single);
|
|
||||||
|
|
||||||
proto.addStage(first);
|
|
||||||
|
|
||||||
HP.lesionTrackerBaselineProtocol = proto;
|
|
||||||
HP.lesionTrackerBaselineProtocol.id = 'lesionTrackerBaselineProtocol';
|
|
||||||
|
|
||||||
|
|
||||||
// Define Followup Protocol
|
|
||||||
var proto = new HP.Protocol('LT_BaselineFollowup');
|
|
||||||
proto.locked = true;
|
|
||||||
|
|
||||||
var studyDescription = new HP.ProtocolMatchingRule();
|
|
||||||
studyDescription.required = true;
|
|
||||||
studyDescription.attribute = 'studyDescription';
|
|
||||||
studyDescription.constraint = {
|
|
||||||
contains: {
|
|
||||||
value: 'CT'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var isFollowup = new HP.ProtocolMatchingRule();
|
|
||||||
isFollowup.required = true;
|
|
||||||
isFollowup.attribute = 'timepointType';
|
|
||||||
isFollowup.constraint = {
|
|
||||||
equals: {
|
|
||||||
value: 'followup'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
proto.addProtocolMatchingRule(studyDescription);
|
|
||||||
proto.addProtocolMatchingRule(isFollowup);
|
|
||||||
|
|
||||||
var oneByTwo = new HP.ViewportStructure('grid', {
|
|
||||||
rows: 1,
|
|
||||||
columns: 2
|
|
||||||
});
|
|
||||||
|
|
||||||
// Stage 1
|
|
||||||
var left = new HP.Viewport();
|
|
||||||
var right = new HP.Viewport();
|
|
||||||
|
|
||||||
var baseline = new HP.StudyMatchingRule(true);
|
|
||||||
baseline.required = true;
|
|
||||||
baseline.attribute = 'timepointType';
|
|
||||||
baseline.constraint = {
|
|
||||||
equals: {
|
|
||||||
value: 'baseline'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var followup = new HP.StudyMatchingRule();
|
|
||||||
followup.required = true;
|
|
||||||
followup.attribute = 'timepointType';
|
|
||||||
followup.constraint = {
|
|
||||||
equals: {
|
|
||||||
value: 'followup'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var body = new HP.SeriesMatchingRule();
|
|
||||||
body.attribute = 'seriesDescription';
|
|
||||||
body.weight = 5;
|
|
||||||
body.constraint = {
|
|
||||||
contains: {
|
|
||||||
value: 'Body'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var chest = new HP.SeriesMatchingRule();
|
|
||||||
chest.attribute = 'seriesDescription';
|
|
||||||
chest.constraint = {
|
|
||||||
contains: {
|
|
||||||
value: 'CHEST'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
left.studyMatchingRules.push(baseline);
|
|
||||||
//left.seriesMatchingRules.push(body);
|
|
||||||
//left.seriesMatchingRules.push(chest);
|
|
||||||
|
|
||||||
right.studyMatchingRules.push(followup);
|
|
||||||
//right.seriesMatchingRules.push(body);
|
|
||||||
//right.seriesMatchingRules.push(chest);
|
|
||||||
|
|
||||||
var first = new HP.Stage(oneByTwo, 'oneByTwo');
|
|
||||||
first.viewports.push(left);
|
|
||||||
first.viewports.push(right);
|
|
||||||
|
|
||||||
proto.addStage(first);
|
|
||||||
|
|
||||||
HP.lesionTrackerFollowupProtocol = proto;
|
|
||||||
HP.lesionTrackerFollowupProtocol.id = 'lesionTrackerFollowupProtocol';
|
|
||||||
|
|
||||||
Meteor.call('removeHangingProtocolByID', HP.lesionTrackerBaselineProtocol.id, function() {
|
|
||||||
HangingProtocols.insert(HP.lesionTrackerBaselineProtocol);
|
|
||||||
});
|
|
||||||
|
|
||||||
Meteor.call('removeHangingProtocolByID', HP.lesionTrackerFollowupProtocol.id, function() {
|
|
||||||
HangingProtocols.insert(HP.lesionTrackerFollowupProtocol);
|
|
||||||
});
|
|
||||||
|
|
||||||
HangingProtocols.insert(HP.defaultProtocol);
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
// Create application logger using loglevel
|
|
||||||
// https://atmospherejs.com/spacejamio/loglevel
|
|
||||||
log = loglevel.createAppLogger('PETSUVMeasurements', defaultLevel = 'info');
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
Session.setDefault('ViewerData', {});
|
|
||||||
|
|
||||||
// verifyEmail controls whether emailVerification template will be rendered or not
|
|
||||||
var verifyEmail = Meteor.settings && Meteor.settings.public && Meteor.settings.public.verifyEmail || false;
|
|
||||||
|
|
||||||
Router.configure({
|
|
||||||
layoutTemplate: 'layout',
|
|
||||||
loadingTemplate: 'layout'
|
|
||||||
});
|
|
||||||
|
|
||||||
Router.onBeforeAction('loading');
|
|
||||||
|
|
||||||
var data = {
|
|
||||||
additionalTemplates: []
|
|
||||||
};
|
|
||||||
|
|
||||||
var routerOptions = {
|
|
||||||
data: data
|
|
||||||
};
|
|
||||||
|
|
||||||
Router.route('/', function() {
|
|
||||||
// Check user is logged in
|
|
||||||
if (Meteor.user() && Meteor.userId()) {
|
|
||||||
if (verifyEmail && Meteor.user().emails && !Meteor.user().emails[0].verified) {
|
|
||||||
this.render('emailVerification', routerOptions);
|
|
||||||
} else {
|
|
||||||
Session.set('activeContentId', 'studylistTab');
|
|
||||||
this.render('app', routerOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
this.render('entrySignIn', routerOptions);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Router.route('/viewer/timepoints/:_id', {
|
|
||||||
layoutTemplate: 'layout',
|
|
||||||
name: 'viewer',
|
|
||||||
onBeforeAction: function() {
|
|
||||||
var timepointId = this.params._id;
|
|
||||||
|
|
||||||
this.render('app', routerOptions);
|
|
||||||
OHIF.lesiontracker.openNewTabWithTimepoint(timepointId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Router.onBeforeAction(function() {
|
|
||||||
if (!Meteor.userId() && !Meteor.loggingIn()) {
|
|
||||||
this.render('entrySignIn');
|
|
||||||
} else {
|
|
||||||
this.next();
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
except: ['entrySignIn', 'entrySignUp', 'forgotPassword', 'resetPassword']
|
|
||||||
});
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB |
@ -1,14 +0,0 @@
|
|||||||
// Temporary fix to drop all Collections on server restart
|
|
||||||
// http://stackoverflow.com/questions/23891631/meteor-how-can-i-drop-all-mongo-collections-and-clear-all-data-on-startup
|
|
||||||
Meteor.startup(function() {
|
|
||||||
console.warn('Dropping all Collections!');
|
|
||||||
for (var property in global) {
|
|
||||||
var object = global[property];
|
|
||||||
if (object instanceof Meteor.Collection) {
|
|
||||||
if (!(/^server|currentServer$/).test(object._name)) {
|
|
||||||
console.warn('Dropping: ' + object._debugName);
|
|
||||||
object.remove({});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@ -1,50 +0,0 @@
|
|||||||
Meteor.startup(function () {
|
|
||||||
|
|
||||||
// Mail server settings
|
|
||||||
var username = Meteor.settings && Meteor.settings.mailServerSettings && Meteor.settings.mailServerSettings.username || null;
|
|
||||||
var password = Meteor.settings && Meteor.settings.mailServerSettings && Meteor.settings.mailServerSettings.password || null;
|
|
||||||
var server = Meteor.settings && Meteor.settings.mailServerSettings && Meteor.settings.mailServerSettings.server || null;
|
|
||||||
var port = Meteor.settings && Meteor.settings.mailServerSettings && Meteor.settings.mailServerSettings.port || null;
|
|
||||||
var verifyEmail = Meteor.settings && Meteor.settings.public && Meteor.settings.public.verifyEmail || false;
|
|
||||||
var siteName = Meteor.settings && Meteor.settings.public && Meteor.settings.public.siteName || "Lesion Tracker";
|
|
||||||
|
|
||||||
if (username && password && server && port) {
|
|
||||||
Accounts.emailTemplates.siteName = siteName;
|
|
||||||
Accounts.emailTemplates.from = siteName+' Admin <'+username+'>';
|
|
||||||
|
|
||||||
process.env.MAIL_URL = 'smtp://' +
|
|
||||||
encodeURIComponent(username) + ':' +
|
|
||||||
encodeURIComponent(password) + '@' +
|
|
||||||
encodeURIComponent(server) + ':' + port;
|
|
||||||
|
|
||||||
// Subject line of the email.
|
|
||||||
Accounts.emailTemplates.verifyEmail.subject = function(user) {
|
|
||||||
return 'Confirm Your Email Address for '+siteName;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Email text
|
|
||||||
Accounts.emailTemplates.verifyEmail.text = function(user, url) {
|
|
||||||
return 'Thank you for registering. Please click on the following link to verify your email address: \r\n' + url;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Reset password mail
|
|
||||||
Accounts.emailTemplates.resetPassword.subject = function() {
|
|
||||||
return 'Reset your '+siteName+' password'
|
|
||||||
};
|
|
||||||
|
|
||||||
Accounts.urls.resetPassword = function(token) {
|
|
||||||
return Meteor.absoluteUrl('resetPassword/' + token);
|
|
||||||
};
|
|
||||||
|
|
||||||
Accounts.emailTemplates.resetPassword.text = function(user, url) {
|
|
||||||
return "Hello " + user.profile.fullName + ",\n\n" +
|
|
||||||
"Click the following link to set your new password:\n" +
|
|
||||||
url + "\n\n";
|
|
||||||
};
|
|
||||||
|
|
||||||
// Send email when account is created
|
|
||||||
Accounts.config({
|
|
||||||
sendVerificationEmail: verifyEmail
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@ -20,13 +20,13 @@ export const retrieveMeasurements = (filter) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const storeMeasurements = (measurementData) => {
|
export const storeMeasurements = (measurementData, timepointIds) => {
|
||||||
console.log('storeMeasurements');
|
console.log('storeMeasurements');
|
||||||
|
|
||||||
// Here is where we should do any required data transformation and API calls
|
// Here is where we should do any required data transformation and API calls
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
Meteor.call('storeMeasurements', measurementData, (error, response) => {
|
Meteor.call('storeMeasurements', measurementData, timepointIds, (error, response) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(error);
|
reject(error);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -97,7 +97,7 @@ Meteor.methods({
|
|||||||
return Timepoints.find(filter || {}).fetch();
|
return Timepoints.find(filter || {}).fetch();
|
||||||
},
|
},
|
||||||
|
|
||||||
storeMeasurements(measurementData) {
|
storeMeasurements(measurementData, filter = {}) {
|
||||||
OHIF.log.info('Storing Measurements on the Server');
|
OHIF.log.info('Storing Measurements on the Server');
|
||||||
OHIF.log.info(JSON.stringify(measurementData, null, 2));
|
OHIF.log.info(JSON.stringify(measurementData, null, 2));
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ Meteor.methods({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MeasurementCollections[toolId].remove({});
|
MeasurementCollections[toolId].remove(filter);
|
||||||
|
|
||||||
const measurements = measurementData[toolId];
|
const measurements = measurementData[toolId];
|
||||||
measurements.forEach(measurement => {
|
measurements.forEach(measurement => {
|
||||||
|
|||||||
@ -58,7 +58,7 @@ class MeasurementApi {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
storeMeasurements(timepointId) {
|
storeMeasurements(timepoints) {
|
||||||
const storeFn = configuration.dataExchange.store;
|
const storeFn = configuration.dataExchange.store;
|
||||||
if (!_.isFunction(storeFn)) {
|
if (!_.isFunction(storeFn)) {
|
||||||
return;
|
return;
|
||||||
@ -70,7 +70,16 @@ class MeasurementApi {
|
|||||||
measurementData[measurementTypeId] = this[measurementTypeId].find().fetch();
|
measurementData[measurementTypeId] = this[measurementTypeId].find().fetch();
|
||||||
});
|
});
|
||||||
|
|
||||||
storeFn(measurementData).then(() => {
|
const timepointIds = timepoints.map(t => t.timepointId);
|
||||||
|
const patientId = timepoints[0].patientId;
|
||||||
|
const filter = {
|
||||||
|
patientId,
|
||||||
|
timepointId: {
|
||||||
|
$in: timepointIds
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
storeFn(measurementData, filter).then(() => {
|
||||||
OHIF.log.info('Measurement storage completed');
|
OHIF.log.info('Measurement storage completed');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -124,7 +124,7 @@ Template.caseProgress.helpers({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Template.caseProgress.events({
|
Template.caseProgress.events({
|
||||||
'click .js-finish-case'(event) {
|
'click .js-finish-case'(event, instance) {
|
||||||
const $this = $(event.currentTarget);
|
const $this = $(event.currentTarget);
|
||||||
|
|
||||||
// Stop here if the tool is disabled
|
// Stop here if the tool is disabled
|
||||||
@ -132,8 +132,12 @@ Template.caseProgress.events({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const instance = Template.instance();
|
|
||||||
switchToTab('studylistTab');
|
switchToTab('studylistTab');
|
||||||
instance.data.measurementApi.storeMeasurements();
|
|
||||||
|
const timepointApi = instance.data.timepointApi;
|
||||||
|
const timepoints = timepointApi.all();
|
||||||
|
OHIF.log.info('Saving Measurements for timepoints:')
|
||||||
|
OHIF.log.info(timepoints);
|
||||||
|
instance.data.measurementApi.storeMeasurements(timepoints);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,17 +0,0 @@
|
|||||||
import { OHIF } from 'meteor/ohif:core';
|
|
||||||
|
|
||||||
import { measurementTools } from './measurementTools';
|
|
||||||
import { retrieveMeasurements, storeMeasurements } from './dataExchange';
|
|
||||||
import { validateMeasurements } from './dataValidation';
|
|
||||||
|
|
||||||
console.log('OHIF-PET SUV: Defining Configuration for Measurements');
|
|
||||||
OHIF.measurements.MeasurementApi.setConfiguration({
|
|
||||||
measurementTools: measurementTools,
|
|
||||||
dataExchange: {
|
|
||||||
retrieve: retrieveMeasurements,
|
|
||||||
store: storeMeasurements
|
|
||||||
},
|
|
||||||
dataValidation: {
|
|
||||||
validation: validateMeasurements
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
import { measurementTools } from './measurementTools';
|
|
||||||
|
|
||||||
export const retrieveMeasurements = () => {
|
|
||||||
console.log('retrieveMeasurements');
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
Meteor.call("retrieveMeasurements", (error, response) => {
|
|
||||||
if (error) {
|
|
||||||
reject(error);
|
|
||||||
} else {
|
|
||||||
console.log(response);
|
|
||||||
|
|
||||||
/*measurementTools.forEach(tool => {
|
|
||||||
console.log('Retrieving tool: ' + tool.id);
|
|
||||||
});*/
|
|
||||||
|
|
||||||
resolve(response);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const storeMeasurements = (measurementData) => {
|
|
||||||
console.log('storeMeasurements');
|
|
||||||
|
|
||||||
// Here is where we should do any required data transformation and API calls
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
Meteor.call("storeMeasurements", measurementData, (error, response) => {
|
|
||||||
if (error) {
|
|
||||||
reject(error);
|
|
||||||
} else {
|
|
||||||
resolve(response);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
import { ellipse } from './ellipse';
|
|
||||||
|
|
||||||
export const validateMeasurements = () => {
|
|
||||||
console.log('validateMeasurements');
|
|
||||||
};
|
|
||||||
@ -1,103 +0,0 @@
|
|||||||
import { SimpleSchema } from 'meteor/aldeed:simple-schema';
|
|
||||||
import { MeasurementSchemaTypes } from 'meteor/ohif:measurements/both/schema/measurements';
|
|
||||||
|
|
||||||
const CornerstoneHandleSchema = MeasurementSchemaTypes.CornerstoneHandleSchema;
|
|
||||||
|
|
||||||
const EllipseHandlesSchema = new SimpleSchema({
|
|
||||||
start: {
|
|
||||||
type: CornerstoneHandleSchema,
|
|
||||||
label: 'Start'
|
|
||||||
},
|
|
||||||
end: {
|
|
||||||
type: CornerstoneHandleSchema,
|
|
||||||
label: 'End'
|
|
||||||
},
|
|
||||||
textBox: {
|
|
||||||
type: CornerstoneHandleSchema,
|
|
||||||
label: 'Text Box'
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const MeanStdDevSchema = new SimpleSchema({
|
|
||||||
count: {
|
|
||||||
type: Number,
|
|
||||||
label: 'Count'
|
|
||||||
},
|
|
||||||
mean: {
|
|
||||||
type: Number,
|
|
||||||
label: 'Mean',
|
|
||||||
decimal: true
|
|
||||||
},
|
|
||||||
variance: {
|
|
||||||
type: Number,
|
|
||||||
label: 'Variance',
|
|
||||||
decimal: true
|
|
||||||
},
|
|
||||||
stdDev: {
|
|
||||||
type: Number,
|
|
||||||
label: 'Variance',
|
|
||||||
decimal: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const MeanStdDevSUVSchema = new SimpleSchema({
|
|
||||||
mean: {
|
|
||||||
type: Number,
|
|
||||||
label: 'Mean SUV',
|
|
||||||
decimal: true
|
|
||||||
},
|
|
||||||
stdDev: {
|
|
||||||
type: Number,
|
|
||||||
label: 'St. Dev SUV',
|
|
||||||
decimal: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const EllipseSchema = new SimpleSchema([MeasurementSchemaTypes.CornerstoneToolMeasurement, {
|
|
||||||
handles: {
|
|
||||||
type: EllipseHandlesSchema,
|
|
||||||
label: 'Handles'
|
|
||||||
},
|
|
||||||
meanStdDev: {
|
|
||||||
type: MeanStdDevSchema,
|
|
||||||
label: 'Mean St.Dev',
|
|
||||||
optional: true
|
|
||||||
},
|
|
||||||
meanStdDevSUV: {
|
|
||||||
type: MeanStdDevSUVSchema,
|
|
||||||
label: 'Mean St.Dev SUV',
|
|
||||||
optional: true
|
|
||||||
},
|
|
||||||
area: {
|
|
||||||
type: Number,
|
|
||||||
decimal: true,
|
|
||||||
optional: true
|
|
||||||
}
|
|
||||||
}]);
|
|
||||||
|
|
||||||
function numberWithCommas(x) {
|
|
||||||
// http://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript
|
|
||||||
var parts = x.toString().split('.');
|
|
||||||
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
|
||||||
return parts.join('.');
|
|
||||||
}
|
|
||||||
|
|
||||||
function displayFunction(data) {
|
|
||||||
if (!data.area ||
|
|
||||||
!data.meanStdDev ||
|
|
||||||
data.meanStdDev.mean === undefined) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return numberWithCommas(data.meanStdDev.mean.toFixed(2));
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ellipse = {
|
|
||||||
id: 'ellipse',
|
|
||||||
name: 'Mean',
|
|
||||||
cornerstoneToolType: 'ellipticalRoi',
|
|
||||||
showInMeasurementTable: true,
|
|
||||||
includeInCaseProgress: true,
|
|
||||||
schema: EllipseSchema,
|
|
||||||
displayFunction: displayFunction
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
import { ellipse } from './ellipse';
|
|
||||||
|
|
||||||
export const measurementTools = [
|
|
||||||
ellipse
|
|
||||||
];
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
Package.describe({
|
|
||||||
name: 'ohif:petsuv',
|
|
||||||
summary: 'OHIF PET SUV Measurement Tools',
|
|
||||||
version: '0.0.1'
|
|
||||||
});
|
|
||||||
|
|
||||||
Package.onUse(function(api) {
|
|
||||||
api.versionsFrom('1.4');
|
|
||||||
|
|
||||||
api.use('ecmascript');
|
|
||||||
api.use('standard-app-packages');
|
|
||||||
api.use('jquery');
|
|
||||||
api.use('stylus');
|
|
||||||
api.use('random');
|
|
||||||
|
|
||||||
api.use('validatejs');
|
|
||||||
|
|
||||||
// Template overriding
|
|
||||||
api.use('aldeed:template-extension@4.0.0');
|
|
||||||
|
|
||||||
// Our custom packages
|
|
||||||
api.use('design');
|
|
||||||
api.use('ohif:core');
|
|
||||||
api.use('ohif:study-list');
|
|
||||||
api.use('ohif:cornerstone');
|
|
||||||
api.use('ohif:measurements');
|
|
||||||
|
|
||||||
api.addFiles('both/configuration/ellipse.js', [ 'client', 'server' ]);
|
|
||||||
api.addFiles('both/configuration/measurementTools.js', [ 'client', 'server' ]);
|
|
||||||
|
|
||||||
api.addFiles('both/configuration/dataExchange.js', [ 'client', 'server' ]);
|
|
||||||
api.addFiles('both/configuration/dataValidation.js', [ 'client', 'server' ]);
|
|
||||||
api.addFiles('both/configuration/configuration.js', [ 'client', 'server' ]);
|
|
||||||
|
|
||||||
api.addFiles('server/methods.js', 'server');
|
|
||||||
});
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
import { Meteor } from 'meteor/meteor';
|
|
||||||
import { Mongo } from 'meteor/mongo';
|
|
||||||
import { measurementTools } from 'meteor/ohif:petsuv/both/configuration/measurementTools';
|
|
||||||
|
|
||||||
let MeasurementCollections = {};
|
|
||||||
measurementTools.forEach(tool => {
|
|
||||||
MeasurementCollections[tool.id] = new Mongo.Collection(tool.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Timepoints = new Mongo.Collection('timepoints');
|
|
||||||
|
|
||||||
// Drop our collections for testing purposes
|
|
||||||
Meteor.startup(() => {
|
|
||||||
Timepoints.remove({});
|
|
||||||
measurementTools.forEach(tool => {
|
|
||||||
MeasurementCollections[tool.id].remove({});
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: Make storage use update instead of clearing the entire collection and
|
|
||||||
// re-inserting everything.
|
|
||||||
Meteor.methods({
|
|
||||||
storeTimepoints(timepoints) {
|
|
||||||
console.log('Storing Timepoints on the Server')
|
|
||||||
console.log(JSON.stringify(timepoints, null, 2));
|
|
||||||
Timepoints.remove({});
|
|
||||||
timepoints.forEach(timepoint => {
|
|
||||||
delete timepoint._id;
|
|
||||||
Timepoints.insert(timepoint);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
retrieveTimepoints() {
|
|
||||||
console.log('Retrieving Timepoints from the Server');
|
|
||||||
return Timepoints.find().fetch();
|
|
||||||
},
|
|
||||||
|
|
||||||
storeMeasurements(measurementData) {
|
|
||||||
console.log('Storing Measurements on the Server')
|
|
||||||
console.log(JSON.stringify(measurementData, null, 2));
|
|
||||||
|
|
||||||
Object.keys(measurementData).forEach(toolId => {
|
|
||||||
MeasurementCollections[toolId].remove({});
|
|
||||||
|
|
||||||
const measurements = measurementData[toolId];
|
|
||||||
measurements.forEach(measurement => {
|
|
||||||
MeasurementCollections[toolId].insert(measurement);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
retrieveMeasurements() {
|
|
||||||
console.log('Retrieving Measurements from the Server');
|
|
||||||
let measurementData = {};
|
|
||||||
|
|
||||||
measurementTools.forEach(tool => {
|
|
||||||
measurementData[tool.id] = MeasurementCollections[tool.id].find().fetch();
|
|
||||||
});
|
|
||||||
|
|
||||||
return measurementData;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Loading…
Reference in New Issue
Block a user