commit
6f4f098671
19
.babelrc
Normal file
19
.babelrc
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"targets": {
|
||||
"ie": "11"
|
||||
}
|
||||
}
|
||||
],
|
||||
"@babel/preset-react"
|
||||
],
|
||||
"plugins": [
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
"@babel/plugin-syntax-dynamic-import",
|
||||
"@babel/plugin-transform-regenerator",
|
||||
"@babel/plugin-transform-runtime"
|
||||
]
|
||||
}
|
||||
98
.circleci/config.yml
Normal file
98
.circleci/config.yml
Normal file
@ -0,0 +1,98 @@
|
||||
version: 2
|
||||
|
||||
### ABOUT
|
||||
#
|
||||
# This configuration powers our Circleci.io integration
|
||||
#
|
||||
# Note:
|
||||
# Netlify works independently from this configuration to
|
||||
# create pull request previews and to update `https://docs.ohif.org`
|
||||
###
|
||||
|
||||
defaults: &defaults
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: circleci/node:10.15.1
|
||||
|
||||
jobs:
|
||||
build_and_test:
|
||||
<<: *defaults
|
||||
steps:
|
||||
# Download and cache dependencies
|
||||
- checkout
|
||||
- restore_cache:
|
||||
name: Restore Yarn Package Cache
|
||||
keys:
|
||||
# when lock file changes, use increasingly general patterns to restore cache
|
||||
- yarn-packages-v1-{{ .Branch }}-{{ checksum "yarn.lock" }}
|
||||
- yarn-packages-v1-{{ .Branch }}-
|
||||
- yarn-packages-v1-
|
||||
- run:
|
||||
name: Install Dependencies
|
||||
command: yarn install --frozen-lockfile
|
||||
- save_cache:
|
||||
name: Save Yarn Package Cache
|
||||
paths:
|
||||
- ~/.cache/yarn
|
||||
key: yarn-packages-v1-{{ .Branch }}-{{ checksum "yarn.lock" }}
|
||||
|
||||
# Build & Test
|
||||
- run: yarn build:package:ci
|
||||
# https://www.viget.com/articles/using-junit-on-circleci-2-0-with-jest-and-eslint/
|
||||
- run:
|
||||
name: 'JavaScript Test Suite'
|
||||
command: yarn test:ci
|
||||
environment:
|
||||
JEST_JUNIT_OUTPUT: 'reports/junit/js-test-results.xml'
|
||||
|
||||
# Store result
|
||||
- store_test_results:
|
||||
path: reports/junit
|
||||
- store_artifacts:
|
||||
path: reports/junit
|
||||
|
||||
# Persist :+1:
|
||||
- persist_to_workspace:
|
||||
root: ~/repo
|
||||
paths: .
|
||||
|
||||
npm_publish:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/repo
|
||||
- run:
|
||||
name: Avoid hosts unknown for github
|
||||
command:
|
||||
mkdir ~/.ssh/ && echo -e "Host github.com\n\tStrictHostKeyChecking
|
||||
no\n" > ~/.ssh/config
|
||||
# --no-ci argument is not ideal; however, semantic-rlease thinks we're
|
||||
# attempting to run it from a `pr`, which is not the case
|
||||
- run:
|
||||
name: Publish using Semantic Release
|
||||
command: npx semantic-release --debug --dry-run
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
|
||||
# PULL REQUESTS
|
||||
pull_requests:
|
||||
jobs:
|
||||
- build_and_test:
|
||||
filters:
|
||||
branches:
|
||||
ignore:
|
||||
- master
|
||||
- feature/*
|
||||
- hotfix/*
|
||||
|
||||
# MERGE TO MASTER
|
||||
cut_release:
|
||||
jobs:
|
||||
- build_and_test:
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
||||
- npm_publish:
|
||||
requires:
|
||||
- build_and_test
|
||||
@ -1,17 +1,16 @@
|
||||
.idea/
|
||||
.meteor/local
|
||||
.meteor/meteorite
|
||||
.meteor/dev_bundle
|
||||
*/.meteor/dev_bundle
|
||||
node_modules
|
||||
.npm
|
||||
npm-debug.log
|
||||
Packages/active-entry/helloworld/
|
||||
LesionTracker/tests/nightwatch/reports/
|
||||
package-lock.json
|
||||
docs/_book
|
||||
docs/
|
||||
img/
|
||||
test/
|
||||
LesionTracker/
|
||||
StandaloneViewer/
|
||||
# Output
|
||||
dist/
|
||||
|
||||
# Dependencies
|
||||
node_modules/
|
||||
|
||||
# Root
|
||||
README.md
|
||||
Dockerfile
|
||||
|
||||
# Misc. Config
|
||||
.git
|
||||
.DS_Store
|
||||
.gitignore
|
||||
.vscode
|
||||
.circleci
|
||||
|
||||
14
.env
Normal file
14
.env
Normal file
@ -0,0 +1,14 @@
|
||||
##
|
||||
# Environment: Default
|
||||
#
|
||||
# We're using this to set variables for development.
|
||||
# Please feel free to delete or modify this file for your own setup.
|
||||
# Be careful not to commit anything sensitive to source control.
|
||||
#
|
||||
|
||||
PUBLIC_URL=/
|
||||
|
||||
#
|
||||
# Most vars require REACT_APP_* naming
|
||||
#
|
||||
REACT_APP_CONFIG=config/default.js
|
||||
13
.env.example
Normal file
13
.env.example
Normal file
@ -0,0 +1,13 @@
|
||||
##
|
||||
# EXAMPLE
|
||||
#
|
||||
# Read more about .env files when using create-react-app here:
|
||||
# https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-development-environment-variables-in-env
|
||||
#
|
||||
|
||||
PUBLIC_URL=/demo
|
||||
|
||||
#
|
||||
# Most vars require REACT_APP_* naming
|
||||
#
|
||||
REACT_APP_CONFIG=config/netlify.js
|
||||
@ -1,4 +1,3 @@
|
||||
config/**
|
||||
docs/**
|
||||
img/**
|
||||
StandaloneViewer/**
|
||||
|
||||
16
.eslintrc
Normal file
16
.eslintrc
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": [
|
||||
"react-app",
|
||||
"eslint:recommended",
|
||||
"plugin:react/recommended"
|
||||
],
|
||||
"parser": "babel-eslint",
|
||||
"env": {
|
||||
"jest": true
|
||||
},
|
||||
"settings": {
|
||||
"react": {
|
||||
"version": "detect",
|
||||
},
|
||||
},
|
||||
}
|
||||
16
.eslintrc.js
16
.eslintrc.js
@ -1,16 +0,0 @@
|
||||
module.exports = {
|
||||
'env': {
|
||||
'browser': true,
|
||||
'es6': true,
|
||||
'jquery': true,
|
||||
'node': true,
|
||||
'mocha': true
|
||||
},
|
||||
'extends': 'eslint:recommended',
|
||||
'parserOptions': {
|
||||
'sourceType': 'module'
|
||||
},
|
||||
'rules': {
|
||||
'no-undef': 'error',
|
||||
}
|
||||
};
|
||||
33
.gitignore
vendored
33
.gitignore
vendored
@ -1,12 +1,27 @@
|
||||
.idea/
|
||||
.vscode/
|
||||
.meteor/local
|
||||
.meteor/meteorite
|
||||
.meteor/dev_bundle
|
||||
*/.meteor/dev_bundle
|
||||
# Packages
|
||||
node_modules
|
||||
|
||||
# Output
|
||||
build
|
||||
dist
|
||||
docs/_book
|
||||
src/version.js
|
||||
junit.xml
|
||||
coverage/
|
||||
|
||||
# YALC (for Erik)
|
||||
.yalc
|
||||
yalc.lock
|
||||
|
||||
# Logging, System files, misc.
|
||||
.idea/
|
||||
.npm
|
||||
npm-debug.log
|
||||
Packages/active-entry/helloworld/
|
||||
LesionTracker/tests/nightwatch/reports/
|
||||
docs/_book
|
||||
package-lock.json
|
||||
yarn-error.log
|
||||
.DS_Store
|
||||
|
||||
# Common Example Data Directories
|
||||
sampledata/
|
||||
example/deps/
|
||||
docker/dcm4che/dcm4che-arc
|
||||
|
||||
9
.prettierrc
Normal file
9
.prettierrc
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"trailingComma": "es5",
|
||||
"printWidth": 80,
|
||||
"proseWrap": "always",
|
||||
"tabWidth": 2,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"endOfLine": "lf"
|
||||
}
|
||||
127
.travis.yml
127
.travis.yml
@ -1,127 +0,0 @@
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- "lts/*"
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
before_script:
|
||||
- export PATH=$HOME/.meteor:$PATH
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- ~/.meteor
|
||||
- node_modules
|
||||
- OHIFViewer/node_modules
|
||||
|
||||
env:
|
||||
global:
|
||||
- METEOR_PACKAGE_DIRS=../Packages
|
||||
- secure: "ZhIMR4geQP/BXdXrQkcARPCSPnyry2aTgszo+Jg+lZfRHWil2FmAweCiWyOC/5rRxrYYSik/ZyEMAX54v9N9sNjYsPlA9UFqovMirEQhXCYmIG+DNBsU58zgnrDWQoolF1xD4f/IFtLjUGG9WQNR7SavHeL/2VmWK9Nis8TChnyTdmlL8IaWEeKjznseLqyVKZSMb490bG34I4ztdumaYHWWt01uhNFZ/XA048NVd/E8LhO7yLIqwtmCt7Cr1Z61TfSzgyajJaCiuTLvrNDU8W/f/j4wlhybGJruvvOH9qDPRRp2aw3surgAB33irZftYFgG1h/6NjjKeRrBvqocW9sZdAeXWcqw4xiNyi4AbbSGk5aPrFuYMswJWP0/i9MkSF5N0eRcFoWl/DvTeaG4bkzTQquT29pdYE/Ef3KXDgKevwUKH0OBU79v8VSLjIT9Tr0ps/FOvNXjeGHjI6FoqCkLt2XYgDMteltRC7rjtmxTGBRpQQFoRksa/11jwr6t5YNxYootzM11g8EFA/uX56aJHkTjZBpSzMsImDPsWjpqu/MTttVmdtq6iFEkA9NBwZYIZEJBmiy/wfNXhNgCe2lDuaSdK6MMF8PHXWIjvcW2/+h6u355ktr+LRXeolVuYDIAaN3SDSJBsDkJg4duYWuCeq8ptJ4bzeRjZtPchew=" # DOCKER_USER
|
||||
- secure: "PrUMwM360a1KMLhfIPmx7qp9+Ry2cMDJpW4WspE28UQTrqcSZdhUYFCs5Q2DISZXrZWGI1/utHK+JYeqCAt3xOf3qRsLqupzJIPqzMPyb2AKtyR1JbJZGyBv7y4s6HMrXZ9pNfRBoR7hHFtiZfmTBo8avpMne8gBN1JGGXM0GTqbZwY6JGAG+vQ0Nt+DculhEraDAzFdNF5vBO+lg8wTmvh2qp+espa+4i9JzjTeRk8O09+33jkqRFugZtJOcgIi9iBvZjKUPedmFA1w/hU3lHLUuofi7tTmpAOyqaQyB8Grfj1JsgaCfbOZQs7kPHtsQ1Ai0zw2MbJtTKoA8kHcU9XWDU4Kxa1K1qXyp+ZdofTXYYnHkN4pgS+EU2it/OlKnpJV4I73JK28aF7A+fe8zheWkpJV8rFBiI04xXdILr+jxQKfdM4TOWos/XShp4bJru4VJuIfnveKuR+1EPIpuOhJ2jj4HB7g6AbIAbGsjICbFq98jSiXENeGaYmx1qIBSIlFn+lLJxp40fx/OsGKC0y5orfDgyUcPUkseckEk/H7zc90DGdCLCFmJVVgrKGWnfq8ifFI8GPVTomUVy41PLGv1LTCIYyrjM02mxLIEMIKrKboy4MSbaOidasaobjYFtwjABR3GLnUK5ETLANhO0LLC4Z4w6KFvARFfZ6JPec=" # DOCKER_PASS
|
||||
- secure: "G5qjTBS6CuCCtueEqCRAEUhznycGz2kRXB7nChUK/ftKbAMW6F487sj8uujDEO0CXTv9aWnKyrPoXPnhlB5APQ5PtmC8F8DJEqWGW29J/oBv1giJq2K2Elcz6a0a7ys8pTgGKJyDT+mEvFF9boxVKI/eZQ+4ACI0EkGHBakpzey7Y1YSMsymtG6eM3ic1Fgrxna8FynzazKS0YdoE5Aj6yPDVpfj/7vSucz3wR3r2JxMtq95hiWKWYPdc/iir0dcDnedU+MF9aaAUv+ReHpM6FPScnan4mqOhrYKK5sBx27p0C/IxJhtaB4RVzU2F0kYLynK1vgUOBFc+9H/G2P+wl6TfO5dGjMmGU6kF2eWtTzRqT7JELRdqu9v/QGOlKpKmhmA3diGfkY0E2keEUyIRchHZAZKYQfLUhUObYcve2/4skmg9qhcxSMuh2qjkfTyFj/M4mcfkTZZWB9izgkHO2O3MxQm1d5DJDtoSfNQZOZiLjckyxmghWF3TEKNp3OhDOt+JikrDboZBts3F9+ocAVjLyg3upmWnlE6rFfkmVtWCXmI6Rto+laHtV/ng83Z3M4wL3VcvoOlPXLb0moqCGN4HGvpfolBqryFksGbUybaIqbQ7hQHhQuThzQ9UHq0AQN44rwzxEuKbxY7bTuyb4vSEAkrvjeLFbz4MSHQgno=" # AWS_ACCESS_KEY_ID
|
||||
- secure: "ngqtUAXc8sR84CZTzOtRmg+Di/UFXCASV5bLHBmbgmXrvidIisHGW8O7TTx54ZU4UXlbY+Rg/8K6iIyy+uuCLhRcVRDW4sxacdQTNnoDPDNczqwrbBrOCLU7aW0imNBcIDqEvza+1fXsBrFV/iejtOFYVPn4l/yAb/j9MVo65hTGaKwQ4371lNMbRQp9p9DTEGGmkABo/EOtvbNR2H4qVgTuzeR8XdHC8GJUN0bujwQoK3EPTgkaMO6M7XevSNieO35opmy/Ip0GKYNTt4smKPQrUIokokwApCrjn2URdcGLoHENTTHtjLWMM0QMOV47qRBD+FeVaTUe0I4MB1toEZEIck+Vdy7PTCQ/f1HZtlI+bbDLlDPFwB/EMr7J1EKbudu7NnRopN6/zWupmDnL9VWxZy9boCDXCF47OxL1Kba9qqPYigiaS4vQEXygrceQgr+22axowtgTYYyhcsIbXQPq8COlLS/Ls/OgJMKIcQjMhTlKw01B/a08yZ0WxfVD9HJJbDA4EJiztOT7IZCyJvSv1mxJ8uI5hHC4TUBMWIKM6hVVZb0bjvtJjq7kFP9T4gCe/+OKxLIsSqWwY8AZoot6bY5lreZvb0epmyeM4fmf6qQxjIUviaGgj2o4eU7awDQzevwS8hNTsXPdFGItVUrjtKyLFHPkCMiZcTskSZo=" # AWS_SECRET_ACCESS_KEY
|
||||
- secure: "TfbqhcBGGRbvmJ5KevU60dyCczRbiX7Pt1N36Bgy8Ozj6Cv79jC1K+AaB98j+Q1e0A7PaL7sbuOy7hIV/OqePhGEk0D2mowYj8/ORp14UXQ89FpIL7exUCXSwSPhCIwUaGdY4S5yT0DL1rkb5qeSS8L9KEEEVPvVY1F2vGE/lzzgS1MCLCdk7ajs+3c9HP9N4J2PjYRg3WFkgWmfGNitEjGApSJ91NIJW4Sw9pqLhweWqKO8sAbpsADlE+NhfoDd0kzDTkecxWzSf3siO6yfGKAeh3bf8WE4qZReuLXYDWL3XjJ3LTfK018P1J8Cx9PlMb3M+nHU0B3T6mC1t+XtLrUE/fr1LF89diyDCSRB+ZW2H/l8SNQNVIqgTrXzoBcwqGNeZOPJwd2qcq1vLDAkxgC5QFsoRfyxJmzNff70ESClSmBQy/mNd/pXQZ9JZRMoa097j4pXGZlLGarotiCYUdtlPSZmN/eMsIhLtvxNQ8ryk1ASij5sN7WOdg0r+gZcDAY8AwuuDpmktEu9pHd7iEVFw78DIJmD1N5OgKYdVT6o0WTJnVySBf/+luYK9J/rd6vwvlB4C2LLzhEkWlAGp6n7rl/1V18akM+HPVUPWuDRH69ZYWRPq4TIZwfEPTEG4jYizlTjkn55R+CNi3AWoxL2kr1Qv+zUJSruIvixWvc=" # GITHUB_TOKEN
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: build production docker image
|
||||
before_script:
|
||||
- set -e
|
||||
- if [ -z "${DOCKER_PASS}" ]; then echo "Build triggered by external PR. Skipping build production docker image stage" && exit 0; fi
|
||||
- export REPO=ohif/viewer
|
||||
- export COMMIT=${TRAVIS_COMMIT::8}
|
||||
- export BRANCH=$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then echo $TRAVIS_BRANCH; else echo $TRAVIS_PULL_REQUEST_BRANCH; fi)
|
||||
- echo "TRAVIS_BRANCH=$TRAVIS_BRANCH, PR=$PR, BRANCH=$BRANCH"
|
||||
- export TAG=`if [ "$BRANCH" == "master" ]; then echo "latest"; else echo $BRANCH ; fi`
|
||||
- echo "TAG=$TAG, COMMIT=$COMMIT"
|
||||
- docker pull $REPO:latest
|
||||
- docker --version
|
||||
script:
|
||||
- docker build -t $REPO:$COMMIT . --cache-from $REPO:latest
|
||||
after_success:
|
||||
- docker tag $REPO:$COMMIT $REPO:$TAG
|
||||
- docker tag $REPO:$COMMIT $REPO:travis-$TRAVIS_BUILD_NUMBER
|
||||
- docker images
|
||||
- docker login -u $DOCKER_USER -p $DOCKER_PASS
|
||||
- docker push $REPO:$TAG
|
||||
- docker push $REPO:travis-$TRAVIS_BUILD_NUMBER
|
||||
- docker push $REPO:$COMMIT
|
||||
|
||||
- stage: build development docker image
|
||||
before_script:
|
||||
- set -e
|
||||
- if [ -z "${DOCKER_PASS}" ]; then echo "Build triggered by external PR. Skipping build production docker image stage" && exit 0; fi
|
||||
- export REPO=ohif/viewer-dev
|
||||
- export COMMIT=${TRAVIS_COMMIT::8}
|
||||
- export BRANCH=$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then echo $TRAVIS_BRANCH; else echo $TRAVIS_PULL_REQUEST_BRANCH; fi)
|
||||
- echo "TRAVIS_BRANCH=$TRAVIS_BRANCH, PR=$PR, BRANCH=$BRANCH"
|
||||
- export TAG=`if [ "$TRAVIS_BRANCH" == "master" ]; then echo "latest"; else echo $TRAVIS_BRANCH ; fi`
|
||||
- echo "TAG=$TAG, COMMIT=$COMMIT"
|
||||
- docker pull $REPO:latest
|
||||
- docker --version
|
||||
script:
|
||||
- docker build -f development.Dockerfile -t $REPO:$COMMIT . --cache-from $REPO:latest
|
||||
after_success:
|
||||
- docker tag $REPO:$COMMIT $REPO:$TAG
|
||||
- docker tag $REPO:$COMMIT $REPO:travis-$TRAVIS_BUILD_NUMBER
|
||||
- docker images
|
||||
- docker login -u $DOCKER_USER -p $DOCKER_PASS
|
||||
- docker push $REPO:$TAG
|
||||
- docker push $REPO:travis-$TRAVIS_BUILD_NUMBER
|
||||
- docker push $REPO:$COMMIT
|
||||
|
||||
- stage: build standalone viewer
|
||||
if: branch = master
|
||||
before_script:
|
||||
- export ROOT_URL=http://ohif-viewer.s3-website.eu-central-1.amazonaws.com
|
||||
- export METEOR_PACKAGE_DIRS="../../Packages"
|
||||
- cd StandaloneViewer
|
||||
- mkdir buildDirectory
|
||||
- cd StandaloneViewer
|
||||
- npm install -g meteor-build-client-fixed2@0.4.3-b
|
||||
- meteor-build-client-fixed2 --version
|
||||
- curl https://install.meteor.com | /bin/sh
|
||||
- meteor npm install
|
||||
script:
|
||||
- meteor-build-client-fixed2 ~/standaloneViewerBuild -u $ROOT_URL --legacy
|
||||
after_success:
|
||||
- ls ~/standaloneViewerBuild
|
||||
- ls /home/travis
|
||||
- ls /home/travis/build
|
||||
- ls /home/travis/build/Viewers/StandaloneViewer
|
||||
deploy:
|
||||
provider: s3
|
||||
access_key_id: $AWS_ACCESS_KEY_ID
|
||||
secret_access_key: $AWS_SECRET_ACCESS_KEY
|
||||
bucket: ohif-viewer
|
||||
region: eu-central-1
|
||||
skip_cleanup: true
|
||||
local_dir: /home/travis/standaloneViewerBuild
|
||||
acl: public_read
|
||||
on:
|
||||
branch: master
|
||||
|
||||
- stage: build documentation
|
||||
if: branch = master
|
||||
before_script:
|
||||
- cd docs
|
||||
- rm -rf _book
|
||||
- npm install
|
||||
- npm install -g gitbook-cli
|
||||
- gitbook install
|
||||
script:
|
||||
- gitbook build
|
||||
after_success:
|
||||
- cp assets/CNAME _book/CNAME
|
||||
deploy:
|
||||
provider: pages
|
||||
skip-cleanup: true
|
||||
local-dir: docs/_book
|
||||
github-token: $GITHUB_TOKEN
|
||||
keep-history: true
|
||||
fqdn: docs.ohif.org
|
||||
verbose: true
|
||||
on:
|
||||
branch: master
|
||||
8
.vscode/extensions.json
vendored
Normal file
8
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"esbenp.prettier-vscode",
|
||||
"sysoev.language-stylus",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"mikestead.dotenv"
|
||||
]
|
||||
}
|
||||
30
.vscode/settings.json
vendored
Normal file
30
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"editor.rulers": [80, 120],
|
||||
|
||||
// ===
|
||||
// Spacing
|
||||
// ===
|
||||
|
||||
"editor.insertSpaces": true,
|
||||
"editor.tabSize": 2,
|
||||
"editor.trimAutoWhitespace": true,
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"files.eol": "\n",
|
||||
"files.insertFinalNewline": true,
|
||||
"files.trimFinalNewlines": true,
|
||||
|
||||
// ===
|
||||
// Event Triggers
|
||||
// ===
|
||||
|
||||
"editor.formatOnSave": true,
|
||||
"eslint.autoFixOnSave": true,
|
||||
"eslint.run": "onSave",
|
||||
"eslint.validate": [
|
||||
{ "language": "javascript", "autoFix": true },
|
||||
{ "language": "javascriptreact", "autoFix": true }
|
||||
],
|
||||
"prettier.disableLanguages": [],
|
||||
"prettier.endOfLine": "lf"
|
||||
}
|
||||
|
||||
1
LICENSE
1
LICENSE
@ -19,4 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
@ -1,47 +0,0 @@
|
||||
{
|
||||
"parser": "babel-eslint",
|
||||
"parserOptions": {
|
||||
"allowImportExportEverywhere": true
|
||||
},
|
||||
"plugins": [
|
||||
"meteor"
|
||||
],
|
||||
"env": {
|
||||
/* Allows global vars from the Meteor environment to pass and enables certain rules */
|
||||
"meteor": true,
|
||||
"node": true,
|
||||
"browser": true
|
||||
},
|
||||
"extends": [
|
||||
"airbnb",
|
||||
"plugin:meteor/recommended"
|
||||
],
|
||||
"settings": {
|
||||
"import/resolver": "meteor"
|
||||
},
|
||||
"rules": {
|
||||
"meteor/no-session": 0, // We are actually using Session for now...
|
||||
"meteor/eventmap-params": [2, {"eventParamName": "event"}],
|
||||
"meteor/eventmap-params": [2, {"templateInstanceParamName": "instance"}],
|
||||
"import/no-extraneous-dependencies": 0,
|
||||
"import/no-unresolved": 0, // There are a bunch of ESLint problems with Meteor's resolver
|
||||
"import/no-duplicates": 0, // So we are disabling these for now
|
||||
"import/extensions": 0,
|
||||
"import/no-absolute-path": 0,
|
||||
"no-console": 0, // For development
|
||||
"no-plusplus": ["error", { "allowForLoopAfterthoughts": true }],
|
||||
"indent": ["error", 4],
|
||||
"new-cap": 0, // Until Match has an exception
|
||||
"func-names": 0, // This is a bit of an annoying rule
|
||||
"no-underscore-dangle": 0, // Doesn't seem to mesh with _id for MongoDB Ids (or SimpleSchema)
|
||||
"max-len": 0, // TODO: re-enable the rules below and fix all of the errors
|
||||
"consistent-return": 0,
|
||||
"no-param-reassign": 0,
|
||||
"no-mixed-operators": 0,
|
||||
"arrow-body-style": 0,
|
||||
"valid-typeof": 0,
|
||||
"import/prefer-default-export": 0
|
||||
"no-undef": 0
|
||||
},
|
||||
"globals": {}
|
||||
}
|
||||
@ -1,19 +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
|
||||
1.4.3-split-account-service-packages
|
||||
1.5-add-dynamic-import-package
|
||||
1.7-split-underscore-from-meteor-base
|
||||
2
LesionTracker/.meteor/.gitignore
vendored
2
LesionTracker/.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,65 +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.3
|
||||
|
||||
meteor-base@1.4.0 # Packages every Meteor app needs to have
|
||||
mobile-experience@1.0.5 # Packages for a great mobile UX
|
||||
mongo@1.5.0 # The database Meteor supports right now
|
||||
blaze-html-templates@1.0.4 # Compile .html files into Meteor Blaze views
|
||||
session@1.1.7 # Client-side reactive dictionary for your app
|
||||
jquery@1.11.10 # Helpful client-side library
|
||||
tracker@1.2.0 # Meteor's client-side reactive programming library
|
||||
standard-minifier-css@1.4.1
|
||||
standard-minifier-js@2.3.4
|
||||
http@1.4.1
|
||||
promise@0.11.1
|
||||
stylus@2.513.13
|
||||
random@1.1.0
|
||||
reactive-var@1.0.11
|
||||
reactive-dict@1.2.0
|
||||
check@1.3.1
|
||||
email@1.2.3
|
||||
ecmascript@0.11.1 # Enable ECMAScript2015+ syntax in app code
|
||||
|
||||
clinical:active-entry
|
||||
clinical:theming
|
||||
clinical:fonts
|
||||
clinical:hipaa-audit-log
|
||||
clinical:hipaa-logger
|
||||
|
||||
# OHIF Packages
|
||||
ohif:polyfill
|
||||
ohif:design
|
||||
ohif:core
|
||||
ohif:header
|
||||
ohif:cornerstone
|
||||
ohif:cornerstone-settings
|
||||
ohif:viewerbase
|
||||
ohif:studies
|
||||
ohif:study-list
|
||||
ohif:hanging-protocols
|
||||
ohif:metadata
|
||||
|
||||
# Necessary for Lesion Trakcer
|
||||
ohif:lesiontracker
|
||||
ohif:user-management
|
||||
ohif:user-meteor-accounts
|
||||
ohif:select-tree
|
||||
|
||||
accounts-base@1.4.2
|
||||
accounts-password@1.5.1
|
||||
|
||||
fortawesome:fontawesome
|
||||
momentjs:moment@2.15.1
|
||||
aldeed:simple-schema # Third party package to deal with schemas
|
||||
aldeed:template-extension@4.0.0
|
||||
aldeed:collection2
|
||||
zuuk:stale-session
|
||||
johdirr:meteor-git-rev
|
||||
cultofcoders:persistent-session@0.4.4
|
||||
shell-server@0.3.1
|
||||
underscore
|
||||
@ -1,2 +0,0 @@
|
||||
server
|
||||
browser
|
||||
@ -1 +0,0 @@
|
||||
METEOR@1.7.0.3
|
||||
@ -1,146 +0,0 @@
|
||||
accounts-base@1.4.2
|
||||
accounts-password@1.5.1
|
||||
aldeed:collection2@2.10.0
|
||||
aldeed:collection2-core@1.2.0
|
||||
aldeed:schema-deny@1.1.0
|
||||
aldeed:schema-index@1.1.1
|
||||
aldeed:simple-schema@1.5.4
|
||||
aldeed:template-extension@4.1.0
|
||||
allow-deny@1.1.0
|
||||
amplify@1.0.0
|
||||
autoupdate@1.4.1
|
||||
babel-compiler@7.1.1
|
||||
babel-runtime@1.2.2
|
||||
base64@1.0.11
|
||||
binary-heap@1.0.10
|
||||
blaze@2.3.2
|
||||
blaze-html-templates@1.1.2
|
||||
blaze-tools@1.0.10
|
||||
boilerplate-generator@1.5.0
|
||||
caching-compiler@1.1.12
|
||||
caching-html-compiler@1.1.3
|
||||
callback-hook@1.1.0
|
||||
check@1.3.1
|
||||
clinical:active-entry@1.5.16
|
||||
clinical:auto-resizing@0.2.0
|
||||
clinical:fonts@1.1.6
|
||||
clinical:hipaa-audit-log@2.4.2
|
||||
clinical:hipaa-logger@1.3.0
|
||||
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
|
||||
cultofcoders:persistent-session@0.4.5
|
||||
ddp@1.4.0
|
||||
ddp-client@2.3.3
|
||||
ddp-common@1.4.0
|
||||
ddp-rate-limiter@1.0.7
|
||||
ddp-server@2.2.0
|
||||
deps@1.0.12
|
||||
diff-sequence@1.1.0
|
||||
dynamic-import@0.4.1
|
||||
ecmascript@0.11.1
|
||||
ecmascript-runtime@0.7.0
|
||||
ecmascript-runtime-client@0.7.1
|
||||
ecmascript-runtime-server@0.7.0
|
||||
ejson@1.1.0
|
||||
email@1.2.3
|
||||
es5-shim@4.8.0
|
||||
fastclick@1.0.13
|
||||
fortawesome:fontawesome@4.7.0
|
||||
geojson-utils@1.0.10
|
||||
grove:less@0.2.0
|
||||
hot-code-push@1.0.4
|
||||
html-tools@1.0.11
|
||||
htmljs@1.0.11
|
||||
http@1.4.1
|
||||
id-map@1.1.0
|
||||
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.11
|
||||
launch-screen@1.1.1
|
||||
livedata@1.0.18
|
||||
localstorage@1.2.0
|
||||
logging@1.1.20
|
||||
mdg:validation-error@0.5.1
|
||||
meteor@1.9.2
|
||||
meteor-base@1.4.0
|
||||
meteor-platform@1.2.6
|
||||
minifier-css@1.3.1
|
||||
minifier-js@2.3.5
|
||||
minimongo@1.4.4
|
||||
mobile-experience@1.0.5
|
||||
mobile-status-bar@1.0.14
|
||||
modern-browsers@0.1.2
|
||||
modules@0.12.2
|
||||
modules-runtime@0.10.2
|
||||
momentjs:moment@2.22.2
|
||||
mongo@1.5.1
|
||||
mongo-dev-server@1.1.0
|
||||
mongo-id@1.0.7
|
||||
mrt:moment@2.8.1
|
||||
natestrauser:select2@4.0.3
|
||||
npm-bcrypt@0.9.3
|
||||
npm-mongo@3.0.7
|
||||
observe-sequence@1.0.16
|
||||
ohif:commands@0.0.1
|
||||
ohif:core@0.0.1
|
||||
ohif:cornerstone@0.0.1
|
||||
ohif:cornerstone-settings@0.0.1
|
||||
ohif:design@0.0.1
|
||||
ohif:hanging-protocols@0.0.1
|
||||
ohif:header@0.0.1
|
||||
ohif:hotkeys@0.0.1
|
||||
ohif:lesiontracker@0.0.1
|
||||
ohif:log@0.0.1
|
||||
ohif:measurements@0.0.1
|
||||
ohif:metadata@0.0.1
|
||||
ohif:polyfill@0.0.1
|
||||
ohif:select-tree@0.0.1
|
||||
ohif:servers@0.0.1
|
||||
ohif:studies@0.0.1
|
||||
ohif:study-list@0.0.1
|
||||
ohif:themes@0.0.1
|
||||
ohif:themes-common@0.0.1
|
||||
ohif:user-management@0.0.1
|
||||
ohif:user-meteor-accounts@0.0.1
|
||||
ohif:viewerbase@0.0.1
|
||||
ohif:wadoproxy@0.0.1
|
||||
ordered-dict@1.1.0
|
||||
promise@0.11.1
|
||||
raix:eventemitter@0.1.3
|
||||
random@1.1.0
|
||||
rate-limit@1.0.9
|
||||
reactive-dict@1.2.0
|
||||
reactive-var@1.0.11
|
||||
reload@1.2.0
|
||||
retry@1.1.0
|
||||
routepolicy@1.0.13
|
||||
service-configuration@1.0.11
|
||||
session@1.1.7
|
||||
sha@1.0.9
|
||||
shell-server@0.3.1
|
||||
silentcicero:jszip@0.0.4
|
||||
socket-stream-client@0.2.2
|
||||
spacebars@1.0.15
|
||||
spacebars-compiler@1.1.3
|
||||
srp@1.0.10
|
||||
standard-app-packages@1.0.9
|
||||
standard-minifier-css@1.4.1
|
||||
standard-minifier-js@2.3.4
|
||||
stylus@2.513.14
|
||||
templating@1.3.2
|
||||
templating-compiler@1.3.3
|
||||
templating-runtime@1.3.2
|
||||
templating-tools@1.1.2
|
||||
tracker@1.2.0
|
||||
ui@1.0.13
|
||||
underscore@1.0.10
|
||||
url@1.2.0
|
||||
webapp@1.6.2
|
||||
webapp-hashing@1.0.9
|
||||
zuuk:stale-session@1.0.8
|
||||
@ -1,8 +0,0 @@
|
||||
# LesionTracker
|
||||
LesionTracker is an open source, zero-footprint image viewer focused on oncology clinical trial workflows. It is built using Meteor platform which enables modularity with a set of packages of the OHIF framework.
|
||||
|
||||
|
||||
### Why LesionTracker?
|
||||
LesionTracker brings an user experience for the basic tumor metrics through web browser. It provides a DICOM server for storing and streaming images to the viewer, tools for measuring and following lesions over time, and a database for measurements of overlay data. A web-based system for image assessments rather than a workstation-based installed application will improve workflow efficiency, enhance accessibility, and promote collaborative image review for the radiologists at cooperating cancer centers.
|
||||
|
||||
To get started, checkout [LesionTracker Documentation](https://github.com/OHIF/Viewers/wiki/LesionTracker)
|
||||
@ -1,58 +0,0 @@
|
||||
import { Session } from 'meteor/session';
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Session.set('ThemeConfig', {
|
||||
palette: {
|
||||
colorA: "",
|
||||
colorB: "",
|
||||
colorC: "",
|
||||
colorD: "",
|
||||
colorE: ""
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
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 @@
|
||||
set METEOR_PACKAGE_DIRS=..\Packages
|
||||
meteor --settings ../config/medkenOrthanc.json
|
||||
@ -1 +0,0 @@
|
||||
METEOR_PACKAGE_DIRS="../Packages" meteor --settings ../config/medkenOrthanc.json
|
||||
@ -1,13 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
declare config='../config/orthancDICOMWeb.json'
|
||||
|
||||
if [ $# -gt 0 ]; then
|
||||
if [ "$1" = '--dimse' ]; then
|
||||
config="${config%/*}/orthancDIMSE.json"
|
||||
[ -f "$config" ] && echo "DIMSE config file selected: $config"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo 'Starting Meteor server...'
|
||||
METEOR_PACKAGE_DIRS="../Packages" meteor --settings "$config"
|
||||
@ -1,2 +0,0 @@
|
||||
set METEOR_PACKAGE_DIRS=..\Packages
|
||||
meteor --settings ../config/orthancDICOMWeb.json
|
||||
@ -1,2 +0,0 @@
|
||||
echo "Starting Meteor server..."
|
||||
METEOR_PACKAGE_DIRS="../Packages" meteor --settings ../config/orthancDICOMWeb.json
|
||||
@ -1,3 +0,0 @@
|
||||
<body>
|
||||
<div id="notificationArea" class="notification-area"></div>
|
||||
</body>
|
||||
@ -1,2 +0,0 @@
|
||||
body
|
||||
background-color: black
|
||||
@ -1,29 +0,0 @@
|
||||
<template name="app">
|
||||
{{#header brandHref='http://ohif.org' headerClasses=instance.headerClasses}}
|
||||
{{#section 'brand'}}
|
||||
<svg class="logo-image">
|
||||
<use xlink:href={{absoluteUrl "packages/ohif_viewerbase/assets/icons.svg#icon-ohif-logo"}}></use>
|
||||
</svg>
|
||||
<div class="logo-text">Open Health Imaging Foundation</div>
|
||||
{{/section}}
|
||||
{{#section 'headerAfterBrand'}}
|
||||
{{#if studyListToggleText}}
|
||||
<a href="#" class="btn studyListLinkSection pull-left js-toggle-studyList" id="{{dasherize studyListToggleText}}-btn">
|
||||
{{studyListToggleText}}
|
||||
</a>
|
||||
{{/if}}
|
||||
{{/section}}
|
||||
{{#section 'headerMenu'}}
|
||||
<span class="research-use pull-left m-r-1">
|
||||
INVESTIGATIONAL USE ONLY
|
||||
</span>
|
||||
<span class="user-name pull-left m-r-1">{{userName}}</span>
|
||||
<div class="menu-toggle pull-right">
|
||||
<i class="fa fa-cog"></i>
|
||||
<span class="caret-down"></span>
|
||||
</div>
|
||||
{{/section}}
|
||||
{{/header}}
|
||||
|
||||
{{>Template.dynamic template=(choose this.template 'studylist') data=this}}
|
||||
</template>
|
||||
@ -1,125 +0,0 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
import { Session } from 'meteor/session';
|
||||
import { Router } from 'meteor/clinical:router';
|
||||
import { ReactiveVar } from 'meteor/reactive-var';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
Template.app.onCreated(() => {
|
||||
const instance = Template.instance();
|
||||
instance.headerClasses = new ReactiveVar('');
|
||||
|
||||
OHIF.header.dropdown.setItems([{
|
||||
action: OHIF.user.audit,
|
||||
text: 'View Audit Log',
|
||||
iconClasses: 'log',
|
||||
iconSvgUse: 'packages/ohif_viewerbase/assets/icons.svg#log',
|
||||
separatorAfter: true
|
||||
}, {
|
||||
action: () => OHIF.ui.showDialog('themeSelectorModal'),
|
||||
text: 'Themes',
|
||||
iconClasses: 'theme',
|
||||
iconSvgUse: 'packages/ohif_viewerbase/assets/icons.svg#theme',
|
||||
separatorAfter: true
|
||||
}, {
|
||||
action: () => OHIF.ui.showDialog('serverInformationModal'),
|
||||
text: 'Server Information',
|
||||
iconClasses: 'server',
|
||||
iconSvgUse: 'packages/ohif_viewerbase/assets/icons.svg#server',
|
||||
separatorAfter: true
|
||||
}, {
|
||||
action: () => OHIF.ui.showDialog('userPreferencesDialog'),
|
||||
text: 'Preferences',
|
||||
icon: 'fa fa-user',
|
||||
separatorAfter: true
|
||||
}, {
|
||||
action: OHIF.user.changePassword,
|
||||
text: 'Change Password',
|
||||
iconClasses: 'password',
|
||||
iconSvgUse: 'packages/ohif_viewerbase/assets/icons.svg#password'
|
||||
}, {
|
||||
action: OHIF.user.logout,
|
||||
text: 'Logout',
|
||||
iconClasses: 'logout',
|
||||
iconSvgUse: 'packages/ohif_viewerbase/assets/icons.svg#logout'
|
||||
}]);
|
||||
|
||||
instance.autorun(() => {
|
||||
const currentRoute = Router.current();
|
||||
if (!currentRoute) return;
|
||||
const routeName = currentRoute.route.getName();
|
||||
const isViewer = routeName.indexOf('viewer') === 0;
|
||||
|
||||
// Add or remove the strech class from body
|
||||
$(document.body)[isViewer ? 'addClass' : 'removeClass']('stretch');
|
||||
|
||||
// Set the header on its bigger version if the viewer is not opened
|
||||
instance.headerClasses.set(isViewer ? '' : 'header-big');
|
||||
|
||||
// Set the viewer open state on session
|
||||
Session.set('ViewerOpened', isViewer);
|
||||
});
|
||||
});
|
||||
|
||||
Template.app.events({
|
||||
'click .js-toggle-studyList'(event, instance) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const isViewer = Session.get('ViewerOpened');
|
||||
|
||||
if (!isViewer) {
|
||||
const timepointId = OHIF.viewer.data.currentTimepointId;
|
||||
if (timepointId) {
|
||||
Router.go('viewerTimepoint', { timepointId });
|
||||
} else {
|
||||
const { studyInstanceUids } = OHIF.viewer.data;
|
||||
Router.go('viewerStudies', { studyInstanceUids });
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
OHIF.ui.unsavedChanges.presentProactiveDialog('viewer.*', (hasChanges, userChoice) => {
|
||||
if (!hasChanges) {
|
||||
return Router.go('studylist');
|
||||
}
|
||||
|
||||
switch (userChoice) {
|
||||
case 'abort-action':
|
||||
return;
|
||||
case 'save-changes':
|
||||
OHIF.ui.unsavedChanges.trigger('viewer', 'save', false);
|
||||
OHIF.ui.unsavedChanges.clear('viewer.*');
|
||||
break;
|
||||
case 'abandon-changes':
|
||||
OHIF.ui.unsavedChanges.clear('viewer.*');
|
||||
break;
|
||||
}
|
||||
|
||||
Router.go('studylist');
|
||||
}, {
|
||||
position: {
|
||||
x: event.clientX + 15,
|
||||
y: event.clientY + 15
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Template.app.helpers({
|
||||
userName: OHIF.user.getName,
|
||||
|
||||
studyListToggleText() {
|
||||
const isViewer = Session.get('ViewerOpened');
|
||||
|
||||
// Return empty if viewer was not opened yet
|
||||
if (!OHIF.utils.ObjectPath.get(OHIF, 'viewer.data.studyInstanceUids')) return;
|
||||
|
||||
return isViewer ? 'Study list' : 'Back to viewer';
|
||||
},
|
||||
|
||||
dasherize(text) {
|
||||
return text.replace(/ /g, '-').toLowerCase();
|
||||
}
|
||||
});
|
||||
|
||||
Session.set('defaultSignInMessage', 'Tumor tracking in your browser.');
|
||||
@ -1,88 +0,0 @@
|
||||
@require "{ohif:design}/app"
|
||||
|
||||
body>.header
|
||||
|
||||
.brand
|
||||
height: 30px
|
||||
display: inline-block
|
||||
text-decoration: none
|
||||
|
||||
.logo-image
|
||||
display: inline-block
|
||||
fill: transparent
|
||||
float: left
|
||||
height: 100%
|
||||
margin: 0 8px 0 0
|
||||
width: 30px
|
||||
|
||||
.logo-text
|
||||
display: inline-block
|
||||
font-family: $logoFontFamily
|
||||
font-size: 14px
|
||||
font-weight: $logoFontWeight
|
||||
theme('color', '$textPrimaryColor')
|
||||
line-height: 30px
|
||||
|
||||
.header-menu
|
||||
.user-name
|
||||
font-size: 13px
|
||||
|
||||
.menu-toggle
|
||||
theme('border-left', 'solid 1px $defaultColor')
|
||||
display: inline-block
|
||||
height: 18px
|
||||
padding: 0 8px
|
||||
|
||||
.fa
|
||||
theme('color', '$defaultColor')
|
||||
font-size: 17px
|
||||
line-height: 18px
|
||||
|
||||
.caret-down
|
||||
theme('color', '$uiGrayLight')
|
||||
margin: 0 4px 4px 2px
|
||||
|
||||
.btn
|
||||
theme('color', '$textSecondaryColor')
|
||||
cursor: pointer
|
||||
font-size: 13px
|
||||
font-weight: 500
|
||||
line-height: 26px
|
||||
|
||||
&:hover
|
||||
theme('color', '$hoverColor')
|
||||
|
||||
&:active
|
||||
theme('color', '$activeColor')
|
||||
|
||||
.studyListLinkSection
|
||||
theme('border-left', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
margin: 3px 0 0 10px
|
||||
padding: 0 0 0 10px
|
||||
|
||||
&#back-to-viewer-btn
|
||||
border-left: 0
|
||||
|
||||
&.header-big
|
||||
padding-left: $studyListPadding
|
||||
padding-right: $studyListPadding
|
||||
|
||||
.brand
|
||||
height: 100%
|
||||
width: 80%
|
||||
line-height: $topBarExpandedHeight - 10px
|
||||
|
||||
.logo-image
|
||||
margin: 0 20px 0 0
|
||||
width: 50px
|
||||
|
||||
.logo-text
|
||||
font-size: 30px
|
||||
|
||||
.studyListLinkSection
|
||||
border: none
|
||||
left: 0
|
||||
margin: 0
|
||||
padding: 0
|
||||
position: absolute
|
||||
top: 0
|
||||
@ -1,37 +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}}
|
||||
|
||||
<div class="pull-right m-t-1 rm-x-1">
|
||||
{{#form (extend api=instance.api)}}
|
||||
{{#button class='btn p-x-2' action='save' disabled=(isFinishDisabled)}}Save{{/button}}
|
||||
{{/form}}
|
||||
</div>
|
||||
|
||||
<div id="toggleMeasurements" 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={{absoluteUrl "packages/ohif_viewerbase/assets/icons.svg#icon-hud"}}></use>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="buttonLabel">HUD</div>
|
||||
</div>
|
||||
<div id="toggleTrial" class="toolbarSectionButton pull-right rp-x-1 m-t-1 rm-r-1">
|
||||
<div class="svgContainer">
|
||||
<svg>
|
||||
<use xlink:href={{absoluteUrl "packages/ohif_viewerbase/assets/icons.svg#icon-trial-info"}}></use>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="buttonLabel">Trial</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -1,319 +0,0 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
import { Session } from 'meteor/session';
|
||||
import { Tracker } from 'meteor/tracker';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { Viewerbase } from 'meteor/ohif:viewerbase';
|
||||
|
||||
Template.toolbarSection.helpers({
|
||||
isFinishDisabled() {
|
||||
const instance = Template.instance();
|
||||
|
||||
// Run this computation on save or every time any measurement / timepoint suffer changes
|
||||
OHIF.ui.unsavedChanges.depend();
|
||||
instance.saveObserver.depend();
|
||||
Session.get('LayoutManagerUpdated');
|
||||
|
||||
return OHIF.ui.unsavedChanges.probe('viewer.*') === 0;
|
||||
},
|
||||
|
||||
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 targetSubTools = [];
|
||||
|
||||
targetSubTools.push({
|
||||
id: 'bidirectional',
|
||||
title: 'Bidirectional',
|
||||
classes: 'imageViewerTool rm-l-3',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-measure-target',
|
||||
disabled: isToolDisabled
|
||||
});
|
||||
|
||||
targetSubTools.push({
|
||||
id: 'targetCR',
|
||||
title: 'CR Target',
|
||||
classes: 'imageViewerTool',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-measure-target-cr',
|
||||
disabled: isToolDisabled
|
||||
});
|
||||
|
||||
targetSubTools.push({
|
||||
id: 'targetUN',
|
||||
title: 'UN Target',
|
||||
classes: 'imageViewerTool',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-measure-target-un',
|
||||
disabled: isToolDisabled
|
||||
});
|
||||
|
||||
const extraTools = [];
|
||||
|
||||
extraTools.push({
|
||||
id: 'stackScroll',
|
||||
title: 'Stack Scroll',
|
||||
classes: 'imageViewerTool',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-stack-scroll'
|
||||
});
|
||||
|
||||
extraTools.push({
|
||||
id: 'resetViewport',
|
||||
title: 'Reset',
|
||||
classes: 'imageViewerCommand',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-reset'
|
||||
});
|
||||
|
||||
extraTools.push({
|
||||
id: 'rotateR',
|
||||
title: 'Rotate Right',
|
||||
classes: 'imageViewerCommand',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-rotate-right'
|
||||
});
|
||||
|
||||
extraTools.push({
|
||||
id: 'flipH',
|
||||
title: 'Flip H',
|
||||
classes: 'imageViewerCommand',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-flip-horizontal'
|
||||
});
|
||||
|
||||
extraTools.push({
|
||||
id: 'flipV',
|
||||
title: 'Flip V',
|
||||
classes: 'imageViewerCommand',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-flip-vertical'
|
||||
});
|
||||
|
||||
extraTools.push({
|
||||
id: 'invert',
|
||||
title: 'Invert',
|
||||
classes: 'imageViewerCommand',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-invert'
|
||||
});
|
||||
|
||||
extraTools.push({
|
||||
id: 'magnify',
|
||||
title: 'Magnify',
|
||||
classes: 'imageViewerTool',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-magnify'
|
||||
});
|
||||
|
||||
extraTools.push({
|
||||
id: 'ellipticalRoi',
|
||||
title: 'Ellipse',
|
||||
classes: 'imageViewerTool',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-elliptical-roi'
|
||||
});
|
||||
|
||||
extraTools.push({
|
||||
id: 'toggleDownloadDialog',
|
||||
title: 'Download',
|
||||
classes: 'imageViewerCommand',
|
||||
iconClasses: 'fa fa-camera',
|
||||
active: () => $('#imageDownloadDialog').is(':visible')
|
||||
});
|
||||
|
||||
extraTools.push({
|
||||
id: 'toggleCineDialog',
|
||||
title: 'CINE',
|
||||
classes: 'imageViewerCommand',
|
||||
iconClasses: 'fa fa-youtube-play',
|
||||
active: () => $('#cineDialog').is(':visible')
|
||||
});
|
||||
|
||||
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: 'linkStackScroll',
|
||||
title: 'Link',
|
||||
classes: 'imageViewerCommand toolbarSectionButton nonAutoDisableState',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-link',
|
||||
disableFunction: Viewerbase.viewportUtils.isStackScrollLinkingDisabled
|
||||
});
|
||||
|
||||
buttonData.push({
|
||||
id: 'toggleTarget',
|
||||
title: 'Target',
|
||||
classes: 'rm-l-3',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-measure-target',
|
||||
disabled: isToolDisabled,
|
||||
subTools: targetSubTools
|
||||
});
|
||||
|
||||
buttonData.push({
|
||||
id: 'nonTarget',
|
||||
title: 'Non-Target',
|
||||
classes: 'imageViewerTool',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-measure-non-target',
|
||||
disabled: isToolDisabled
|
||||
});
|
||||
|
||||
buttonData.push({
|
||||
id: 'length',
|
||||
title: 'Temp',
|
||||
classes: 'imageViewerTool',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-measure-temp'
|
||||
});
|
||||
|
||||
buttonData.push({
|
||||
id: 'toggleMore',
|
||||
title: 'More',
|
||||
classes: 'rp-x-1 rm-l-3',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-more',
|
||||
disabled: isToolDisabled,
|
||||
subTools: extraTools
|
||||
});
|
||||
|
||||
return buttonData;
|
||||
}
|
||||
});
|
||||
|
||||
Template.toolbarSection.events({
|
||||
'click #toggleTarget'(event, instance) {
|
||||
const $target = $(event.currentTarget);
|
||||
if (!$target.hasClass('active') && $target.hasClass('expanded')) {
|
||||
Viewerbase.toolManager.setActiveTool('bidirectional');
|
||||
}
|
||||
},
|
||||
|
||||
'click #toggleHUD'(event) {
|
||||
const $this = $(event.currentTarget);
|
||||
|
||||
// Stop here if the tool is disabled
|
||||
if ($this.hasClass('disabled')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const state = Session.get('measurementTableHudOpen');
|
||||
Session.set('measurementTableHudOpen', !state);
|
||||
},
|
||||
|
||||
'click #toggleTrial'(event) {
|
||||
if (!$(event.currentTarget).hasClass('disabled')) {
|
||||
OHIF.ui.showDialog('trialOptionsModal');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Template.toolbarSection.onCreated( function() {
|
||||
const instance = Template.instance();
|
||||
|
||||
instance.path = 'viewer.studyViewer.measurements';
|
||||
instance.saveObserver = new Tracker.Dependency();
|
||||
instance.api = {
|
||||
save() {
|
||||
// Clear signaled unsaved changes...
|
||||
const successHandler = () => {
|
||||
OHIF.ui.unsavedChanges.clear(`${instance.path}.*`);
|
||||
instance.saveObserver.changed();
|
||||
};
|
||||
|
||||
// Display the error messages
|
||||
const errorHandler = data => {
|
||||
OHIF.ui.showDialog('dialogInfo', Object.assign({ class: 'themed' }, data));
|
||||
};
|
||||
|
||||
const promise = instance.data.measurementApi.storeMeasurements();
|
||||
promise.then(successHandler).catch(errorHandler);
|
||||
OHIF.ui.showDialog('dialogLoading', {
|
||||
promise,
|
||||
text: 'Saving measurement data'
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
};
|
||||
|
||||
instance.unsavedChangesHandler = () => {
|
||||
const isNotDisabled = !instance.$('.js-finish-case').hasClass('disabled');
|
||||
if (isNotDisabled && instance.progressPercent.get() === 100) {
|
||||
instance.api.save();
|
||||
}
|
||||
};
|
||||
|
||||
// Attach handler for unsaved changes dialog...
|
||||
OHIF.ui.unsavedChanges.attachHandler(instance.path, 'save', instance.unsavedChangesHandler);
|
||||
});
|
||||
|
||||
Template.toolbarSection.onRendered(function() {
|
||||
// Set disabled/enabled tool buttons that are set in toolManager
|
||||
const states = Viewerbase.toolManager.getToolDefaultStates();
|
||||
const disabledToolButtons = states.disabledToolButtons;
|
||||
const allToolbarButtons = $('.toolbarSection').find('.toolbarSectionButton:not(.nonAutoDisableState)');
|
||||
|
||||
// Additional toolbar buttons whose classes are not toolbarSectionButton
|
||||
allToolbarButtons.push($('#toolbarSectionEntry')[0]);
|
||||
allToolbarButtons.push($('#toggleMeasurements')[0]);
|
||||
|
||||
if (disabledToolButtons && disabledToolButtons.length > 0) {
|
||||
for (let i = 0; i < allToolbarButtons.length; i++) {
|
||||
const toolbarButton = allToolbarButtons[i];
|
||||
const index = disabledToolButtons.indexOf($(toolbarButton).attr('id'));
|
||||
if (index !== -1) {
|
||||
$(toolbarButton).addClass('disabled');
|
||||
$(toolbarButton).find('*').addClass('disabled');
|
||||
} else {
|
||||
$(toolbarButton).removeClass('disabled');
|
||||
$(toolbarButton).find('*').removeClass('disabled');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Template.caseProgress.onDestroyed(() => {
|
||||
const instance = Template.instance();
|
||||
// Remove unsaved changes handler after this view has been destroyed...
|
||||
OHIF.ui.unsavedChanges.removeHandler(instance.path, 'save', instance.unsavedChangesHandler);
|
||||
});
|
||||
@ -1,27 +0,0 @@
|
||||
@import "{ohif:design}/app"
|
||||
|
||||
.toolbarSection
|
||||
theme('border-bottom', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
flex: 0 0 auto
|
||||
height: $toolbarHeight
|
||||
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
|
||||
|
||||
.saveMeasurements
|
||||
display: inline-block
|
||||
margin-left: 22px
|
||||
@ -1,17 +0,0 @@
|
||||
<template name="viewer">
|
||||
<div class="viewerDialogs">
|
||||
{{#if and Template.subscriptionsReady dataSourcesReady}}
|
||||
{{>confirmDeleteDialog}}
|
||||
{{>measurementTableHUD (clone this)}}
|
||||
{{>cineDialog}}
|
||||
{{/if}}
|
||||
</div>
|
||||
<div id="viewer">
|
||||
{{#if and Template.subscriptionsReady dataSourcesReady}}
|
||||
{{>toolbarSection (clone this state=state)}}
|
||||
{{>viewerSection (clone this state=state)}}
|
||||
{{else}}
|
||||
{{>loadingText}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</template>
|
||||
@ -1,388 +0,0 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { Template } from 'meteor/templating';
|
||||
import { Tracker } from 'meteor/tracker';
|
||||
import { Session } from 'meteor/session';
|
||||
import { ReactiveDict } from 'meteor/reactive-dict';
|
||||
import { _ } from 'meteor/underscore';
|
||||
import { $ } from 'meteor/jquery';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
import 'meteor/ohif:cornerstone';
|
||||
import 'meteor/ohif:viewerbase';
|
||||
import 'meteor/ohif:metadata';
|
||||
|
||||
Meteor.startup(() => {
|
||||
Session.set('TimepointsReady', false);
|
||||
Session.set('MeasurementsReady', false);
|
||||
|
||||
OHIF.viewer.displaySeriesQuickSwitch = true;
|
||||
OHIF.viewer.stackImagePositionOffsetSynchronizer = new OHIF.viewerbase.StackImagePositionOffsetSynchronizer();
|
||||
|
||||
// Create the synchronizer used to update reference lines
|
||||
OHIF.viewer.updateImageSynchronizer = new cornerstoneTools.Synchronizer('cornerstonenewimage', cornerstoneTools.updateImageSynchronizer);
|
||||
|
||||
OHIF.viewer.metadataProvider = new OHIF.cornerstone.MetadataProvider();
|
||||
|
||||
// Metadata configuration
|
||||
const metadataProvider = OHIF.viewer.metadataProvider;
|
||||
cornerstone.metaData.addProvider(metadataProvider.getProvider());
|
||||
|
||||
// Target tools configuration
|
||||
OHIF.lesiontracker.configureTargetToolsHandles();
|
||||
});
|
||||
|
||||
Template.viewer.onCreated(() => {
|
||||
Session.set('ViewerReady', false);
|
||||
|
||||
const instance = Template.instance();
|
||||
|
||||
// Define the OHIF.viewer.data global object
|
||||
OHIF.viewer.data = OHIF.viewer.data || Session.get('ViewerData') || {};
|
||||
|
||||
const { TimepointApi, MeasurementApi, ConformanceCriteria } = OHIF.measurements;
|
||||
|
||||
const currentTimepointId = OHIF.viewer.data.currentTimepointId;
|
||||
const timepointApi = new TimepointApi(currentTimepointId);
|
||||
const measurementApi = new MeasurementApi(timepointApi);
|
||||
const conformanceCriteria = new ConformanceCriteria(measurementApi, timepointApi);
|
||||
const apis = {
|
||||
timepointApi,
|
||||
measurementApi,
|
||||
conformanceCriteria
|
||||
};
|
||||
|
||||
Object.assign(OHIF.viewer, apis);
|
||||
Object.assign(instance.data, apis);
|
||||
|
||||
instance.state = new ReactiveDict();
|
||||
instance.state.set('leftSidebar', Session.get('leftSidebar'));
|
||||
instance.state.set('rightSidebar', Session.get('rightSidebar'));
|
||||
|
||||
const viewportUtils = OHIF.viewerbase.viewportUtils;
|
||||
|
||||
OHIF.viewer.functionList = $.extend(OHIF.viewer.functionList, {
|
||||
toggleLesionTrackerTools: OHIF.lesiontracker.toggleLesionTrackerTools,
|
||||
bidirectional: () => {
|
||||
// Used for hotkeys
|
||||
OHIF.viewerbase.toolManager.setActiveTool('bidirectional');
|
||||
},
|
||||
nonTarget: () => {
|
||||
// Used for hotkeys
|
||||
OHIF.viewerbase.toolManager.setActiveTool('nonTarget');
|
||||
},
|
||||
// Viewport functions
|
||||
toggleCineDialog: viewportUtils.toggleCineDialog,
|
||||
clearTools: viewportUtils.clearTools,
|
||||
resetViewport: viewportUtils.resetViewport,
|
||||
invert: viewportUtils.invert,
|
||||
flipV: viewportUtils.flipV,
|
||||
flipH: viewportUtils.flipH,
|
||||
rotateL: viewportUtils.rotateL,
|
||||
rotateR: viewportUtils.rotateR,
|
||||
linkStackScroll: viewportUtils.linkStackScroll
|
||||
});
|
||||
|
||||
if (OHIF.viewer.data.loadedSeriesData) {
|
||||
OHIF.log.info('Reloading previous loadedSeriesData');
|
||||
OHIF.viewer.loadedSeriesData = OHIF.viewer.data.loadedSeriesData;
|
||||
} else {
|
||||
OHIF.log.info('Setting default viewer data');
|
||||
OHIF.viewer.loadedSeriesData = {};
|
||||
OHIF.viewer.data.loadedSeriesData = {};
|
||||
}
|
||||
|
||||
// Store the viewer data in session for further user
|
||||
Session.setPersistent('ViewerData', OHIF.viewer.data);
|
||||
|
||||
Session.set('activeViewport', OHIF.viewer.data.activeViewport || false);
|
||||
|
||||
// Set lesion tool buttons as disabled if pixel spacing is not available for active element
|
||||
instance.autorun(OHIF.lesiontracker.pixelSpacingAutorunCheck);
|
||||
|
||||
// @TypeSafeStudies
|
||||
// Clears OHIF.viewer.Studies collection
|
||||
OHIF.viewer.Studies.removeAll();
|
||||
|
||||
// @TypeSafeStudies
|
||||
// Clears OHIF.viewer.StudyMetadataList collection
|
||||
OHIF.viewer.StudyMetadataList.removeAll();
|
||||
|
||||
instance.data.studies.forEach(study => {
|
||||
const studyMetadata = new OHIF.metadata.StudyMetadata(study, study.studyInstanceUid);
|
||||
let displaySets = study.displaySets;
|
||||
|
||||
if (!study.displaySets) {
|
||||
displaySets = OHIF.viewerbase.sortingManager.getDisplaySets(studyMetadata);
|
||||
study.displaySets = displaySets;
|
||||
}
|
||||
|
||||
studyMetadata.setDisplaySets(displaySets);
|
||||
|
||||
study.selected = true;
|
||||
OHIF.viewer.Studies.insert(study);
|
||||
OHIF.viewer.StudyMetadataList.insert(studyMetadata);
|
||||
});
|
||||
|
||||
const patientId = instance.data.studies[0].patientId;
|
||||
|
||||
// LT-382: Preventing HP to keep identifying studies in timepoints that might be removed
|
||||
instance.data.studies.forEach(study => (delete study.timepointType));
|
||||
|
||||
// TODO: Consider combining the retrieval calls into one?
|
||||
const timepointsPromise = timepointApi.retrieveTimepoints({ patientId });
|
||||
timepointsPromise.then(() => {
|
||||
const timepoints = timepointApi.all();
|
||||
|
||||
// Set timepointType in studies to be used in hanging protocol engine
|
||||
timepoints.forEach(timepoint => {
|
||||
timepoint.studyInstanceUids.forEach(studyInstanceUid => {
|
||||
const study = _.find(instance.data.studies, element => {
|
||||
return element.studyInstanceUid === studyInstanceUid;
|
||||
});
|
||||
if (!study) {
|
||||
return;
|
||||
}
|
||||
|
||||
// @TODO: Maybe this should be a setCustomAttribute?
|
||||
study.timepointType = timepoint.timepointType;
|
||||
});
|
||||
});
|
||||
|
||||
Session.set('TimepointsReady', true);
|
||||
|
||||
const timepointIds = timepoints.map(t => t.timepointId);
|
||||
|
||||
const measurementsPromise = measurementApi.retrieveMeasurements(patientId, timepointIds);
|
||||
measurementsPromise.then(() => {
|
||||
Session.set('MeasurementsReady', true);
|
||||
|
||||
measurementApi.syncMeasurementsAndToolData();
|
||||
});
|
||||
});
|
||||
|
||||
// Provide the necessary data to the Measurement API and Timepoint API
|
||||
const prior = timepointApi.prior();
|
||||
if (prior) {
|
||||
measurementApi.priorTimepointId = prior.timepointId;
|
||||
}
|
||||
|
||||
// Enable/Disable Lesion Tracker Tools if the opened study is associated or not
|
||||
OHIF.lesiontracker.toggleLesionTrackerToolsButtons(!!currentTimepointId);
|
||||
|
||||
let firstMeasurementActivated = false;
|
||||
instance.autorun(() => {
|
||||
if (!Session.get('TimepointsReady') ||
|
||||
!Session.get('MeasurementsReady') ||
|
||||
!Session.get('ViewerReady') ||
|
||||
firstMeasurementActivated) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find and activate the first measurement by Lesion Number
|
||||
// NOTE: This is inefficient, we should be using a hanging protocol
|
||||
// to hang the first measurement's imageId immediately, rather
|
||||
// than changing images after initial loading...
|
||||
const config = OHIF.measurements.MeasurementApi.getConfiguration();
|
||||
const tools = config.measurementTools[0].childTools;
|
||||
const firstTool = tools[Object.keys(tools)[0]];
|
||||
const measurementTypeId = firstTool.id;
|
||||
|
||||
const collection = measurementApi.tools[measurementTypeId];
|
||||
const sorting = {
|
||||
sort: {
|
||||
measurementNumber: -1
|
||||
}
|
||||
};
|
||||
|
||||
const data = collection.find({}, sorting).fetch();
|
||||
|
||||
const current = timepointApi.current();
|
||||
if (!current) {
|
||||
return;
|
||||
}
|
||||
|
||||
let timepoints = [current];
|
||||
const prior = timepointApi.prior();
|
||||
if (prior) {
|
||||
timepoints.push(prior);
|
||||
}
|
||||
|
||||
// TODO: Clean this up, it's probably an inefficient way to get what we need
|
||||
const groupObject = _.groupBy(data, m => m.measurementNumber);
|
||||
|
||||
// Reformat the data
|
||||
const rows = Object.keys(groupObject).map(key => ({
|
||||
measurementTypeId: measurementTypeId,
|
||||
measurementNumber: key,
|
||||
entries: groupObject[key]
|
||||
}));
|
||||
|
||||
const rowItem = rows[0];
|
||||
|
||||
// Activate the first lesion
|
||||
if (rowItem) {
|
||||
OHIF.measurements.jumpToRowItem(rowItem, timepoints);
|
||||
}
|
||||
|
||||
firstMeasurementActivated = true;
|
||||
});
|
||||
|
||||
instance.measurementModifiedHandler = _.throttle((event, instance) => {
|
||||
OHIF.measurements.MeasurementHandlers.onModified(event, instance);
|
||||
}, 300);
|
||||
});
|
||||
|
||||
/**
|
||||
* Sets sidebar configuration and active tool based on viewer template instance
|
||||
* @param {Object} instance Template instance for viewer template
|
||||
*/
|
||||
const setActiveToolAndSidebar = () => {
|
||||
const instance = Template.instance();
|
||||
const { studies, currentTimepointId, measurementApi, timepointIds } = instance.data;
|
||||
|
||||
// Default actions for Associated Studies
|
||||
if (currentTimepointId) {
|
||||
// Follow-up studies: same as the first measurement in the table
|
||||
// Baseline studies: target-tool
|
||||
if (studies[0]) {
|
||||
let activeTool;
|
||||
// In follow-ups, get the baseline timepointId
|
||||
const timepointId = timepointIds.find(id => id !== currentTimepointId);
|
||||
|
||||
// Follow-up studies
|
||||
if (studies[0].timepointType === 'followup' && timepointId) {
|
||||
const measurementTools = OHIF.measurements.MeasurementApi.getConfiguration().measurementTools;
|
||||
|
||||
// Create list of measurement tools
|
||||
const measurementTypes = measurementTools.map(
|
||||
tool => {
|
||||
const { id, cornerstoneToolType } = tool;
|
||||
return {
|
||||
id,
|
||||
cornerstoneToolType
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// Iterate over each measurement tool to find the first baseline
|
||||
// measurement. If so, stops the loop and prevent fetching from all
|
||||
// collections
|
||||
measurementTypes.every(({ id, cornerstoneToolType }) => {
|
||||
// Get measurement
|
||||
if (measurementApi[id]) {
|
||||
const measurement = measurementApi[id].findOne({ timepointId });
|
||||
|
||||
// Found a measurement, save tool and stop loop
|
||||
if (measurement) {
|
||||
const isArray = Array.isArray(cornerstoneToolType);
|
||||
activeTool = isArray ? cornerstoneToolType[0] : cornerstoneToolType;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
// If not set, for associated studies default is target-tool
|
||||
OHIF.viewerbase.toolManager.setActiveTool(activeTool || 'bidirectional');
|
||||
}
|
||||
|
||||
// Toggle Measurement Table
|
||||
if (instance.state) {
|
||||
instance.state.set('rightSidebar', 'measurements');
|
||||
}
|
||||
}
|
||||
// Hide as default for single study
|
||||
else {
|
||||
if (instance.state) {
|
||||
instance.state.set('rightSidebar', null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Inits OHIF Hanging Protocol's onReady.
|
||||
* It waits for OHIF Hanging Protocol to be ready to instantiate the ProtocolEngine
|
||||
* Hanging Protocol will use OHIF LayoutManager to render viewports properly
|
||||
*/
|
||||
|
||||
const initHangingProtocol = () => {
|
||||
// When Hanging Protocol is ready
|
||||
HP.ProtocolStore.onReady(() => {
|
||||
|
||||
setActiveToolAndSidebar();
|
||||
|
||||
// Gets all StudyMetadata objects: necessary for Hanging Protocol to access study metadata
|
||||
const studyMetadataList = OHIF.viewer.StudyMetadataList.all();
|
||||
|
||||
// Caches Layout Manager: Hanging Protocol uses it for layout management according to current protocol
|
||||
const layoutManager = OHIF.viewerbase.layoutManager;
|
||||
|
||||
// Instantiate StudyMetadataSource: necessary for Hanging Protocol to get study metadata
|
||||
const studyMetadataSource = new OHIF.studies.classes.OHIFStudyMetadataSource();
|
||||
|
||||
// Creates Protocol Engine object with required arguments
|
||||
const ProtocolEngine = new HP.ProtocolEngine(layoutManager, studyMetadataList, [], studyMetadataSource);
|
||||
|
||||
// Sets up Hanging Protocol engine
|
||||
HP.setEngine(ProtocolEngine);
|
||||
|
||||
Session.set('ViewerReady', true);
|
||||
|
||||
Session.set('activeViewport', 0);
|
||||
});
|
||||
};
|
||||
|
||||
Template.viewer.onRendered(function() {
|
||||
this.autorun(() => {
|
||||
// To make sure ohif viewerMain is rendered before initializing Hanging Protocols
|
||||
const isOHIFViewerMainRendered = Session.get('OHIFViewerMainRendered');
|
||||
|
||||
// To avoid first run
|
||||
if (isOHIFViewerMainRendered) {
|
||||
// To run only when ViewerMainRendered dependency has changed.
|
||||
// because initHangingProtocol can have other reactive components
|
||||
Tracker.nonreactive(initHangingProtocol);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Template.viewer.helpers({
|
||||
dataSourcesReady() {
|
||||
// TODO: Find a better way to do this
|
||||
const ready = Session.get('TimepointsReady') && Session.get('MeasurementsReady');
|
||||
OHIF.log.info('dataSourcesReady? : ' + ready);
|
||||
return ready;
|
||||
},
|
||||
|
||||
state() {
|
||||
return Template.instance().state;
|
||||
}
|
||||
});
|
||||
|
||||
Template.viewer.events({
|
||||
'cornerstonetoolsmeasurementadded .imageViewerViewport'(event, instance) {
|
||||
const originalEvent = event.originalEvent;
|
||||
OHIF.measurements.MeasurementHandlers.onAdded(originalEvent, instance);
|
||||
},
|
||||
|
||||
'cornerstonetoolsmeasurementmodified .imageViewerViewport'(event, instance) {
|
||||
const originalEvent = event.originalEvent;
|
||||
instance.measurementModifiedHandler(originalEvent, instance);
|
||||
},
|
||||
|
||||
'cornerstonemeasurementremoved .imageViewerViewport'(event, instance) {
|
||||
const originalEvent = event.originalEvent;
|
||||
OHIF.measurements.MeasurementHandlers.onRemoved(originalEvent, instance);
|
||||
}
|
||||
});
|
||||
|
||||
Template.viewer.onDestroyed(() => {
|
||||
Session.set('ViewerMainReady', false);
|
||||
Session.set('TimepointsReady', false);
|
||||
Session.set('MeasurementsReady', false);
|
||||
|
||||
OHIF.viewer.stackImagePositionOffsetSynchronizer.deactivate();
|
||||
});
|
||||
@ -1,55 +0,0 @@
|
||||
@import "{ohif:design}/app"
|
||||
|
||||
#viewer
|
||||
background-color: black
|
||||
height: 100%
|
||||
width: 100%
|
||||
|
||||
#imageViewerViewports
|
||||
.viewportContainer
|
||||
border: none !important
|
||||
outline: 0 !important // Prevent blue outline in Chrome
|
||||
position: relative
|
||||
|
||||
&:hover
|
||||
&.active
|
||||
&:hover.active
|
||||
border: none !important
|
||||
outline: 0 !important // Prevent blue outline in Chrome
|
||||
|
||||
.removable
|
||||
.imageViewerViewport
|
||||
theme('border-bottom', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
|
||||
canvas
|
||||
border-color: transparent
|
||||
border-style: solid
|
||||
border-width: 1px
|
||||
|
||||
&:not(:last-child)
|
||||
.removable
|
||||
.imageViewerViewport
|
||||
theme('border-right', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
|
||||
&:first-child
|
||||
.removable
|
||||
.imageViewerViewport
|
||||
theme('border-left', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
|
||||
&.active
|
||||
.removable
|
||||
.imageViewerViewport
|
||||
border-right: none !important
|
||||
|
||||
canvas
|
||||
theme('border-color', '$uiBorderColorActive')
|
||||
|
||||
|
||||
.sidebar-left-open
|
||||
#layoutManagerTarget
|
||||
#imageViewerViewports
|
||||
.viewportContainer
|
||||
&:first-child
|
||||
.removable
|
||||
.imageViewerViewport
|
||||
border-left: none
|
||||
@ -1,21 +0,0 @@
|
||||
<template name="viewerSection">
|
||||
<div class="viewerSection">
|
||||
<div class="sidebarMenu sidebar-left {{#if leftSidebarOpen}}sidebar-open{{/if}}">
|
||||
{{#if isTimepointBrowser}}
|
||||
{{>timepointBrowserSidebar (clone this)}}
|
||||
{{else}}
|
||||
{{#if instance.loading.get}}
|
||||
{{>loadingText}}
|
||||
{{else}}
|
||||
{{>studyBrowserSidebar (clone this studiesInformation=instance.studiesInformation.get)}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</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,72 +0,0 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
import { ReactiveVar } from 'meteor/reactive-var';
|
||||
import { $ } from 'meteor/jquery';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
Template.viewerSection.onCreated(() => {
|
||||
const instance = Template.instance();
|
||||
|
||||
instance.isTimepointBrowser = () => !!OHIF.viewer.data.currentTimepointId;
|
||||
|
||||
OHIF.viewer.quickSwitchStudyBrowserTemplate = 'timepointBrowserQuickSwitch';
|
||||
if (!instance.isTimepointBrowser()) {
|
||||
OHIF.viewer.quickSwitchStudyBrowserTemplate = 'studyBrowserQuickSwitch';
|
||||
instance.loading = new ReactiveVar(true);
|
||||
instance.studiesInformation = new ReactiveVar([]);
|
||||
const filter = { studyInstanceUid: OHIF.viewer.data.studyInstanceUids };
|
||||
OHIF.studies.searchStudies(filter).then(studiesData => {
|
||||
instance.loading.set(false);
|
||||
instance.studiesInformation.set(studiesData);
|
||||
}).catch(error => {
|
||||
instance.loading.set(false);
|
||||
const text = 'An error has occurred while retrieving studies information';
|
||||
OHIF.ui.notifications.danger({ text });
|
||||
OHIF.log.error(error);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Template.viewerSection.events({
|
||||
'transitionend .sidebarMenu'(event) {
|
||||
if (!event.target.classList.contains('sidebarMenu')) return;
|
||||
window.ResizeViewportManager.handleResize();
|
||||
},
|
||||
|
||||
'ohif.measurements.timepoint.changeViewType .timepoint-browser-list'(event, instance, viewType) {
|
||||
const $browserList = $(event.currentTarget);
|
||||
const $allBrowserItems = $browserList.find('.timepoint-browser-item');
|
||||
|
||||
// Removes all active classes to collapse the timepoints and studies
|
||||
$allBrowserItems.removeClass('active');
|
||||
|
||||
if (viewType === 'key') {
|
||||
const { timepointIds, currentTimepointId } = OHIF.viewer.data;
|
||||
timepointIds.forEach(timepointId => {
|
||||
const $browserItem = $allBrowserItems.filter(`[data-id=${timepointId}]`);
|
||||
$browserItem.find('.timepoint-item').trigger('ohif.measurements.timepoint.load');
|
||||
});
|
||||
|
||||
// Show only current timepoint expanded on key timepoints tab
|
||||
const $browserItem = $allBrowserItems.filter(`[data-id=${currentTimepointId}]`);
|
||||
$browserItem.find('.timepoint-item').trigger('click');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Template.viewerSection.helpers({
|
||||
leftSidebarOpen() {
|
||||
return Template.instance().data.state.get('leftSidebar');
|
||||
},
|
||||
|
||||
rightSidebarOpen() {
|
||||
return Template.instance().data.state.get('rightSidebar');
|
||||
},
|
||||
|
||||
isTimepointBrowser() {
|
||||
return Template.instance().isTimepointBrowser();
|
||||
},
|
||||
|
||||
studiesInformation() {
|
||||
return Template.instance().studiesInformation.get();
|
||||
}
|
||||
});
|
||||
@ -1,81 +0,0 @@
|
||||
@require '{ohif:design}/app'
|
||||
|
||||
.viewerSection
|
||||
display: flex
|
||||
flex: 1
|
||||
flex-flow: row nowrap
|
||||
align-items: stretch
|
||||
height: 'calc(100% - %s)' % ($toolbarHeight + $topBarHeight)
|
||||
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%
|
||||
max-width: inherit
|
||||
position: absolute
|
||||
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
|
||||
visibility: hidden
|
||||
|
||||
&.sidebar-open
|
||||
margin-left: 0
|
||||
visibility: visible
|
||||
|
||||
.loadingTextDiv
|
||||
theme('color', '$textSecondaryColor')
|
||||
font-size: 32px
|
||||
|
||||
.mainContent
|
||||
flex: 1
|
||||
height: 100%
|
||||
order: 2
|
||||
overflow: visible
|
||||
position: relative
|
||||
transition($sidebarTransition)
|
||||
width: 100%
|
||||
|
||||
.viewerMain
|
||||
left: 0
|
||||
position: absolute
|
||||
top: 0
|
||||
|
||||
.sidebar-right
|
||||
flex: 1
|
||||
margin-right: - $rightSidebarMenuWidth
|
||||
max-width: $rightSidebarMenuWidth
|
||||
order: 3
|
||||
position: relative
|
||||
visibility: hidden
|
||||
|
||||
&[data-timepoints="3"]
|
||||
margin-right: - ($rightSidebarMenuWidth + 135.5px)
|
||||
max-width: $rightSidebarMenuWidth + 135.5px
|
||||
|
||||
&[data-timepoints="4"]
|
||||
margin-right: - ($rightSidebarMenuWidth + 270px)
|
||||
max-width: $rightSidebarMenuWidth + 270px
|
||||
|
||||
&.sidebar-open
|
||||
margin-right: 0
|
||||
visibility: visible
|
||||
|
||||
.studiesListedChanger
|
||||
theme('border-bottom', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
padding: 20px 10px
|
||||
text-align: center
|
||||
@ -1,34 +0,0 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { Accounts } from 'meteor/accounts-base';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { cornerstoneWADOImageLoader } from 'meteor/ohif:cornerstone';
|
||||
|
||||
Meteor.startup(function() {
|
||||
const maxWebWorkers = Math.max(navigator.hardwareConcurrency - 1, 1);
|
||||
const config = {
|
||||
maxWebWorkers: maxWebWorkers,
|
||||
startWebWorkersOnDemand: true,
|
||||
webWorkerPath : OHIF.utils.absoluteUrl('packages/ohif_cornerstone/public/js/cornerstoneWADOImageLoaderWebWorker.es5.js'),
|
||||
taskConfiguration: {
|
||||
'decodeTask' : {
|
||||
loadCodecsOnStartup : true,
|
||||
initializeCodecsOnStartup: false,
|
||||
codecsPath: OHIF.utils.absoluteUrl('packages/ohif_cornerstone/public/js/cornerstoneWADOImageLoaderCodecs.es5.js'),
|
||||
usePDFJS: false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cornerstoneWADOImageLoader.webWorkerManager.initialize(config);
|
||||
|
||||
cornerstoneWADOImageLoader.configure({
|
||||
beforeSend: function(xhr) {
|
||||
const userId = Meteor.userId();
|
||||
const loginToken = Accounts._storedLoginToken();
|
||||
if (userId && loginToken) {
|
||||
xhr.setRequestHeader("x-user-id", userId);
|
||||
xhr.setRequestHeader("x-auth-token", loginToken);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -1,17 +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">
|
||||
</head>
|
||||
@ -1,111 +0,0 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
|
||||
Meteor.startup(() => {
|
||||
console.log('Adding Lesion Tracker Hanging Protocols');
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Define Baseline protocol
|
||||
const proto = new HP.Protocol('LT_Baseline');
|
||||
proto.locked = true;
|
||||
|
||||
const isBaseline = new HP.ProtocolMatchingRule();
|
||||
isBaseline.required = true;
|
||||
isBaseline.weight = 1;
|
||||
isBaseline.attribute = 'timepointType';
|
||||
isBaseline.constraint = {
|
||||
equals: {
|
||||
value: 'baseline'
|
||||
}
|
||||
};
|
||||
|
||||
proto.addProtocolMatchingRule(isBaseline);
|
||||
|
||||
const oneByOne = new HP.ViewportStructure('grid', {
|
||||
rows: 1,
|
||||
columns: 1
|
||||
});
|
||||
|
||||
// Stage 1
|
||||
const single = new HP.Viewport();
|
||||
|
||||
const baseline = new HP.StudyMatchingRule(true);
|
||||
baseline.required = true;
|
||||
baseline.attribute = 'timepointType';
|
||||
baseline.constraint = {
|
||||
equals: {
|
||||
value: 'baseline'
|
||||
}
|
||||
};
|
||||
|
||||
single.studyMatchingRules.push(baseline);
|
||||
|
||||
const first = new HP.Stage(oneByOne, 'oneByOne');
|
||||
first.viewports.push(single);
|
||||
|
||||
proto.addStage(first);
|
||||
|
||||
HP.lesionTrackerBaselineProtocol = proto;
|
||||
HP.lesionTrackerBaselineProtocol.id = 'lesionTrackerBaselineProtocol';
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Define Followup Protocol
|
||||
const protoFollowup = new HP.Protocol('LT_BaselineFollowup');
|
||||
protoFollowup.locked = true;
|
||||
|
||||
const isFollowup = new HP.ProtocolMatchingRule();
|
||||
isFollowup.required = true;
|
||||
isFollowup.weight = 2;
|
||||
isFollowup.attribute = 'timepointType';
|
||||
isFollowup.constraint = {
|
||||
equals: {
|
||||
value: 'followup'
|
||||
}
|
||||
};
|
||||
|
||||
protoFollowup.addProtocolMatchingRule(isFollowup);
|
||||
|
||||
const oneByTwo = new HP.ViewportStructure('grid', {
|
||||
rows: 1,
|
||||
columns: 2
|
||||
});
|
||||
|
||||
// Stage 1
|
||||
const left = new HP.Viewport();
|
||||
const right = new HP.Viewport();
|
||||
|
||||
const baseline2 = new HP.StudyMatchingRule(true);
|
||||
baseline2.required = true;
|
||||
baseline2.attribute = 'timepointType';
|
||||
baseline2.constraint = {
|
||||
equals: {
|
||||
value: 'baseline'
|
||||
}
|
||||
};
|
||||
|
||||
const followup = new HP.StudyMatchingRule();
|
||||
followup.required = true;
|
||||
followup.attribute = 'timepointType';
|
||||
followup.constraint = {
|
||||
equals: {
|
||||
value: 'followup'
|
||||
}
|
||||
};
|
||||
|
||||
left.studyMatchingRules.push(followup);
|
||||
right.studyMatchingRules.push(baseline2);
|
||||
|
||||
const first2 = new HP.Stage(oneByTwo, 'oneByTwo');
|
||||
first2.viewports.push(left);
|
||||
first2.viewports.push(right);
|
||||
|
||||
protoFollowup.addStage(first2);
|
||||
|
||||
HP.lesionTrackerFollowupProtocol = protoFollowup;
|
||||
HP.lesionTrackerFollowupProtocol.id = 'lesionTrackerFollowupProtocol';
|
||||
|
||||
HP.ProtocolStore.onReady(() => {
|
||||
console.log('Inserting lesion tracker protocols');
|
||||
HP.ProtocolStore.addProtocol(HP.lesionTrackerBaselineProtocol);
|
||||
HP.ProtocolStore.addProtocol(HP.lesionTrackerFollowupProtocol);
|
||||
});
|
||||
});
|
||||
@ -1,53 +0,0 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { _ } from 'meteor/underscore';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
Meteor.startup(() => {
|
||||
const { toolManager } = OHIF.viewerbase;
|
||||
const contextName = 'viewer';
|
||||
|
||||
// Enable the custom tools
|
||||
const customTools = [{
|
||||
id: 'bidirectional',
|
||||
name: 'Target'
|
||||
}, {
|
||||
id: 'nonTarget',
|
||||
name: 'Non-Target'
|
||||
}, {
|
||||
id: 'targetCR',
|
||||
name: 'CR Target'
|
||||
}, {
|
||||
id: 'targetUN',
|
||||
name: 'UN Target'
|
||||
}];
|
||||
customTools.forEach(tool => {
|
||||
_.defaults(OHIF.hotkeys.defaults[contextName], { [tool.id]: '' });
|
||||
OHIF.commands.register(contextName, tool.id, {
|
||||
name: tool.name,
|
||||
action: tool.action || (() => toolManager.setActiveTool(tool.id))
|
||||
});
|
||||
});
|
||||
|
||||
// Enable the custom commands
|
||||
const customCommands = [{
|
||||
id: 'linkStackScroll',
|
||||
name: 'Link',
|
||||
action: OHIF.viewerbase.viewportUtils.linkStackScroll
|
||||
}, {
|
||||
id: 'saveMeasurements',
|
||||
name: 'Save measurements',
|
||||
hotkey: 'CTRL+S',
|
||||
action() {
|
||||
const activeTimepoint = OHIF.measurements.getActiveTimepoint();
|
||||
if (!activeTimepoint) return;
|
||||
OHIF.measurements.saveMeasurements(OHIF.viewer.measurementApi, activeTimepoint.timepointId);
|
||||
}
|
||||
}];
|
||||
customCommands.forEach(command => {
|
||||
_.defaults(OHIF.hotkeys.defaults[contextName], { [command.id]: command.hotkey || '' });
|
||||
OHIF.commands.register(contextName, command.id, {
|
||||
name: command.name,
|
||||
action: command.action || (() => toolManager.setActiveTool(command.id))
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,3 +0,0 @@
|
||||
import loglevel from 'loglevel';
|
||||
log = loglevel.getLogger('OHIFViewer');
|
||||
log.setLevel('info');
|
||||
@ -1,78 +0,0 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { Router } from 'meteor/clinical:router';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
Router.configure({
|
||||
loadingTemplate: 'loading'
|
||||
});
|
||||
|
||||
// If we are running a disconnected client similar to the StandaloneViewer
|
||||
// (see https://docs.ohif.org/standalone-viewer/usage.html) we don't want
|
||||
// our routes to get stuck while waiting for Pub / Sub.
|
||||
//
|
||||
// In this case, the developer is required to add Servers and specify
|
||||
// a CurrentServer with some other approach (e.g. a separate script).
|
||||
if (Meteor.settings &&
|
||||
Meteor.settings.public &&
|
||||
Meteor.settings.public.clientOnly !== true) {
|
||||
Router.waitOn(function() {
|
||||
return [
|
||||
Meteor.subscribe('servers'),
|
||||
Meteor.subscribe('currentServer')
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
Router.onBeforeAction('loading');
|
||||
|
||||
Router.onBeforeAction(function() {
|
||||
// verifyEmail controls whether emailVerification template will be rendered or not
|
||||
const publicSettings = Meteor.settings && Meteor.settings.public;
|
||||
const verifyEmail = publicSettings && publicSettings.verifyEmail || false;
|
||||
|
||||
// Check if user is signed in or needs an email verification
|
||||
if (!Meteor.userId() && !Meteor.loggingIn()) {
|
||||
this.render('entrySignIn');
|
||||
} else if (verifyEmail && Meteor.user().emails && !Meteor.user().emails[0].verified) {
|
||||
this.render('emailVerification');
|
||||
} else {
|
||||
this.next();
|
||||
}
|
||||
}, {
|
||||
except: ['entrySignIn', 'entrySignUp', 'forgotPassword', 'resetPassword', 'emailVerification']
|
||||
});
|
||||
|
||||
Router.route('/', function() {
|
||||
Router.go('studylist', {}, { replaceState: true });
|
||||
}, { name: 'home' });
|
||||
|
||||
Router.route('/studylist', {
|
||||
name: 'studylist',
|
||||
onBeforeAction: function() {
|
||||
const next = this.next;
|
||||
|
||||
// Retrieve the timepoints data to display in studylist
|
||||
const promise = OHIF.studylist.timepointApi.retrieveTimepoints({});
|
||||
promise.then(() => next());
|
||||
},
|
||||
action: function() {
|
||||
this.render('app', { data: { template: 'studylist' } });
|
||||
}
|
||||
});
|
||||
|
||||
Router.route('/viewer/timepoints/:timepointId', function() {
|
||||
const timepointId = this.params.timepointId;
|
||||
OHIF.viewerbase.renderViewer(this, { timepointId });
|
||||
}, { name: 'viewerTimepoint' });
|
||||
|
||||
Router.route('/viewer/studies/:studyInstanceUids', function() {
|
||||
const studyInstanceUids = this.params.studyInstanceUids.split(';');
|
||||
OHIF.viewerbase.renderViewer(this, { studyInstanceUids });
|
||||
}, { name: 'viewerStudies' });
|
||||
|
||||
// OHIF #98 Show specific series of study
|
||||
Router.route('/study/:studyInstanceUid/series/:seriesInstanceUids', function () {
|
||||
const studyInstanceUid = this.params.studyInstanceUid;
|
||||
const seriesInstanceUids = this.params.seriesInstanceUids.split(';');
|
||||
OHIF.viewerbase.renderViewer(this, { studyInstanceUids: [studyInstanceUid], seriesInstanceUids });
|
||||
}, { name: 'viewerSeries' });
|
||||
2284
LesionTracker/package-lock.json
generated
2284
LesionTracker/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,38 +0,0 @@
|
||||
{
|
||||
"name": "LesionTracker",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"fix": "eslint --fix .",
|
||||
"pretest": "npm run lint --silent"
|
||||
},
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.0.0-beta.51",
|
||||
"bcrypt": "^3.0.1",
|
||||
"loglevel": "^1.6.1",
|
||||
"url": "^0.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-eslint": "^10.0.1",
|
||||
"eslint": "^5.6.0",
|
||||
"eslint-config-airbnb": "^17.1.0",
|
||||
"eslint-import-resolver-meteor": "^0.4.0",
|
||||
"eslint-plugin-import": "^2.14.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.1.1",
|
||||
"eslint-plugin-meteor": "^5.1.0",
|
||||
"eslint-plugin-react": "^7.11.1"
|
||||
},
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/OHIF/Viewers.git"
|
||||
},
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/OHIF/Viewers/issues"
|
||||
},
|
||||
"homepage": "https://github.com/OHIF/Viewers"
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB |
@ -1,52 +0,0 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
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 OHIF.utils.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
|
||||
});
|
||||
}
|
||||
});
|
||||
4
OHIFViewer/.gitignore
vendored
4
OHIFViewer/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
.idea
|
||||
.meteor/local
|
||||
.meteor/meteorite
|
||||
node_modules
|
||||
@ -1,19 +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
|
||||
1.4.3-split-account-service-packages
|
||||
1.5-add-dynamic-import-package
|
||||
1.7-split-underscore-from-meteor-base
|
||||
2
OHIFViewer/.meteor/.gitignore
vendored
2
OHIFViewer/.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
|
||||
|
||||
1jfkhvr1ljfqodmpn32m
|
||||
@ -1,55 +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.
|
||||
|
||||
http@1.4.1
|
||||
promise@0.11.1
|
||||
stylus@2.513.13
|
||||
meteor-base@1.4.0
|
||||
mobile-experience@1.0.5
|
||||
mongo@1.5.0
|
||||
blaze-html-templates@1.0.4
|
||||
session@1.1.7
|
||||
jquery@1.11.10
|
||||
tracker@1.2.0
|
||||
logging@1.1.20
|
||||
reload@1.2.0
|
||||
random@1.1.0
|
||||
ejson@1.1.0
|
||||
spacebars@1.0.12
|
||||
check@1.3.1
|
||||
ecmascript@0.11.1
|
||||
reactive-var@1.0.11
|
||||
reactive-dict@1.2.0
|
||||
standard-minifier-css@1.4.1
|
||||
standard-minifier-js@2.3.4
|
||||
|
||||
# OHIF Packages
|
||||
ohif:polyfill
|
||||
ohif:design
|
||||
ohif:core
|
||||
ohif:commands
|
||||
ohif:hotkeys
|
||||
ohif:header
|
||||
ohif:cornerstone
|
||||
ohif:cornerstone-settings
|
||||
ohif:viewerbase
|
||||
ohif:study-list
|
||||
ohif:hanging-protocols
|
||||
ohif:metadata
|
||||
ohif:google-cloud
|
||||
ohif:demo-mode
|
||||
ohif:user-oidc
|
||||
ohif:measurement-table
|
||||
|
||||
fortawesome:fontawesome
|
||||
momentjs:moment@2.15.1
|
||||
aldeed:simple-schema # Third party package to deal with schemas
|
||||
aldeed:template-extension
|
||||
johdirr:meteor-git-rev
|
||||
cultofcoders:persistent-session
|
||||
shell-server@0.3.1
|
||||
underscore
|
||||
meteortesting:mocha
|
||||
@ -1,2 +0,0 @@
|
||||
server
|
||||
browser
|
||||
@ -1 +0,0 @@
|
||||
METEOR@1.7.0.3
|
||||
@ -1,133 +0,0 @@
|
||||
aldeed:collection2@2.10.0
|
||||
aldeed:collection2-core@1.2.0
|
||||
aldeed:schema-deny@1.1.0
|
||||
aldeed:schema-index@1.1.1
|
||||
aldeed:simple-schema@1.5.4
|
||||
aldeed:template-extension@4.1.0
|
||||
allow-deny@1.1.0
|
||||
amplify@1.0.0
|
||||
autoupdate@1.4.1
|
||||
babel-compiler@7.1.1
|
||||
babel-runtime@1.2.2
|
||||
base64@1.0.11
|
||||
binary-heap@1.0.10
|
||||
blaze@2.3.2
|
||||
blaze-html-templates@1.1.2
|
||||
blaze-tools@1.0.10
|
||||
boilerplate-generator@1.5.0
|
||||
caching-compiler@1.1.12
|
||||
caching-html-compiler@1.1.3
|
||||
callback-hook@1.1.0
|
||||
check@1.3.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
|
||||
cultofcoders:persistent-session@0.4.5
|
||||
ddp@1.4.0
|
||||
ddp-client@2.3.3
|
||||
ddp-common@1.4.0
|
||||
ddp-server@2.2.0
|
||||
deps@1.0.12
|
||||
diff-sequence@1.1.0
|
||||
dynamic-import@0.4.1
|
||||
ecmascript@0.11.1
|
||||
ecmascript-runtime@0.7.0
|
||||
ecmascript-runtime-client@0.7.1
|
||||
ecmascript-runtime-server@0.7.0
|
||||
ejson@1.1.0
|
||||
es5-shim@4.8.0
|
||||
fastclick@1.0.13
|
||||
fortawesome:fontawesome@4.7.0
|
||||
geojson-utils@1.0.10
|
||||
hot-code-push@1.0.4
|
||||
html-tools@1.0.11
|
||||
htmljs@1.0.11
|
||||
http@1.4.1
|
||||
id-map@1.1.0
|
||||
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.11
|
||||
launch-screen@1.1.1
|
||||
livedata@1.0.18
|
||||
lmieulet:meteor-coverage@1.1.4
|
||||
logging@1.1.20
|
||||
mdg:validation-error@0.5.1
|
||||
meteor@1.9.2
|
||||
meteor-base@1.4.0
|
||||
meteor-platform@1.2.6
|
||||
meteorhacks:picker@1.0.3
|
||||
meteortesting:browser-tests@1.0.0
|
||||
meteortesting:mocha@1.0.0
|
||||
minifier-css@1.3.1
|
||||
minifier-js@2.3.5
|
||||
minimongo@1.4.4
|
||||
mobile-experience@1.0.5
|
||||
mobile-status-bar@1.0.14
|
||||
modern-browsers@0.1.2
|
||||
modules@0.12.2
|
||||
modules-runtime@0.10.2
|
||||
momentjs:moment@2.22.2
|
||||
mongo@1.5.1
|
||||
mongo-dev-server@1.1.0
|
||||
mongo-id@1.0.7
|
||||
natestrauser:select2@4.0.3
|
||||
npm-mongo@3.0.7
|
||||
observe-sequence@1.0.16
|
||||
ohif:commands@0.0.1
|
||||
ohif:core@0.0.1
|
||||
ohif:cornerstone@0.0.1
|
||||
ohif:cornerstone-settings@0.0.1
|
||||
ohif:demo-mode@0.0.1
|
||||
ohif:design@0.0.1
|
||||
ohif:google-cloud@0.0.1
|
||||
ohif:hanging-protocols@0.0.1
|
||||
ohif:header@0.0.1
|
||||
ohif:hotkeys@0.0.1
|
||||
ohif:log@0.0.1
|
||||
ohif:measurement-table@0.0.1
|
||||
ohif:measurements@0.0.1
|
||||
ohif:metadata@0.0.1
|
||||
ohif:polyfill@0.0.1
|
||||
ohif:select-tree@0.0.1
|
||||
ohif:servers@0.0.1
|
||||
ohif:studies@0.0.1
|
||||
ohif:study-list@0.0.1
|
||||
ohif:themes@0.0.1
|
||||
ohif:themes-common@0.0.1
|
||||
ohif:user-oidc@0.0.1
|
||||
ohif:viewerbase@0.0.1
|
||||
ohif:wadoproxy@0.0.1
|
||||
ordered-dict@1.1.0
|
||||
practicalmeteor:mocha-core@1.0.1
|
||||
promise@0.11.1
|
||||
raix:eventemitter@0.1.3
|
||||
random@1.1.0
|
||||
reactive-dict@1.2.0
|
||||
reactive-var@1.0.11
|
||||
reload@1.2.0
|
||||
retry@1.1.0
|
||||
routepolicy@1.0.13
|
||||
session@1.1.7
|
||||
shell-server@0.3.1
|
||||
silentcicero:jszip@0.0.4
|
||||
socket-stream-client@0.2.2
|
||||
spacebars@1.0.15
|
||||
spacebars-compiler@1.1.3
|
||||
standard-app-packages@1.0.9
|
||||
standard-minifier-css@1.4.1
|
||||
standard-minifier-js@2.3.4
|
||||
stylus@2.513.14
|
||||
templating@1.3.2
|
||||
templating-compiler@1.3.3
|
||||
templating-runtime@1.3.2
|
||||
templating-tools@1.1.2
|
||||
tracker@1.2.0
|
||||
ui@1.0.13
|
||||
underscore@1.0.10
|
||||
url@1.2.0
|
||||
webapp@1.6.2
|
||||
webapp-hashing@1.0.9
|
||||
@ -1,2 +0,0 @@
|
||||
set METEOR_PACKAGE_DIRS=..\Packages
|
||||
meteor --settings ../config/medkenOrthanc.json
|
||||
@ -1 +0,0 @@
|
||||
METEOR_PACKAGE_DIRS="../Packages" meteor --settings ../config/medkenOrthanc.json
|
||||
@ -1,13 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
declare config='../config/orthancDICOMWeb.json'
|
||||
|
||||
if [ $# -gt 0 ]; then
|
||||
if [ "$1" = '--dimse' ]; then
|
||||
config="${config%/*}/orthancDIMSE.json"
|
||||
[ -f "$config" ] && echo "DIMSE config file selected: $config"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo 'Starting Meteor server...'
|
||||
METEOR_PACKAGE_DIRS="../Packages" meteor --settings "$config"
|
||||
@ -1,2 +0,0 @@
|
||||
set METEOR_PACKAGE_DIRS=..\Packages
|
||||
meteor --settings ../config/orthancDICOMWeb.json
|
||||
@ -1,2 +0,0 @@
|
||||
echo "Starting Meteor server..."
|
||||
METEOR_PACKAGE_DIRS="../Packages" meteor --settings ../config/orthancDICOMWeb.json
|
||||
@ -1,2 +0,0 @@
|
||||
echo "Starting Meteor server..."
|
||||
METEOR_PACKAGE_DIRS="../Packages" meteor --settings ../config/orthancDIMSE.json
|
||||
@ -1,2 +0,0 @@
|
||||
echo "Starting Meteor server..."
|
||||
METEOR_PACKAGE_DIRS="../Packages" meteor --settings ../config/publicOrthancDICOMWeb.json
|
||||
@ -1,40 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
##################################################
|
||||
# Runs the packages tests
|
||||
##################################################
|
||||
|
||||
# check execution arguments
|
||||
while [ "$1" != "" ]; do
|
||||
PARAM=`echo $1 | awk -F= '{print $1}'`
|
||||
case $PARAM in
|
||||
-c | --coverage)
|
||||
export RUN_COVERAGE=1
|
||||
;;
|
||||
-v | --verbose)
|
||||
export COVERAGE_VERBOSE=1
|
||||
;;
|
||||
-s | --spacejam)
|
||||
export RUN_SPACEJAM=1
|
||||
;;
|
||||
*)
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ "$RUN_COVERAGE" == 1 ];
|
||||
then
|
||||
# Setting coverage variables
|
||||
app_folder=$(pwd)
|
||||
app_folder+="/packages/ohif-viewerbase/"
|
||||
export COVERAGE_APP_FOLDER=$app_folder
|
||||
export COVERAGE=1
|
||||
echo 'Running meteor-coverage'
|
||||
fi
|
||||
|
||||
if [ "$RUN_SPACEJAM" == 1 ];
|
||||
then
|
||||
spacejam-mocha ./packages/ohif-viewerbase/
|
||||
else
|
||||
meteor test-packages --driver-package='cultofcoders:mocha' ./packages/ohif-viewerbase/
|
||||
fi
|
||||
@ -1,3 +0,0 @@
|
||||
<body>
|
||||
<div id="notificationArea" class="notification-area"></div>
|
||||
</body>
|
||||
@ -1,2 +0,0 @@
|
||||
body
|
||||
background-color: black
|
||||
@ -1,13 +0,0 @@
|
||||
<template name="flexboxLayout">
|
||||
<div class="viewerSection">
|
||||
<div class="sidebarMenu sidebar-left {{#if leftSidebarOpen}}sidebar-open{{/if}}">
|
||||
{{> studyBrowser (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}}">
|
||||
{{> measurementLightTable (clone this)}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -1,19 +0,0 @@
|
||||
Template.flexboxLayout.events({
|
||||
'transitionend .sidebarMenu'(event) {
|
||||
if (!event.target.classList.contains('sidebarMenu')) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.ResizeViewportManager.handleResize();
|
||||
}
|
||||
});
|
||||
|
||||
Template.flexboxLayout.helpers({
|
||||
leftSidebarOpen() {
|
||||
return Template.instance().data.state.get('leftSidebar');
|
||||
},
|
||||
|
||||
rightSidebarOpen() {
|
||||
return Template.instance().data.state.get('rightSidebar');
|
||||
}
|
||||
});
|
||||
@ -1,67 +0,0 @@
|
||||
@require '{ohif:design}/app'
|
||||
|
||||
.viewerSection
|
||||
display: flex
|
||||
flex: 1
|
||||
flex-flow: row nowrap
|
||||
align-items: stretch
|
||||
height: 'calc(100% - %s)' % ($toolbarHeight + $topBarHeight)
|
||||
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%
|
||||
max-width: inherit
|
||||
position: absolute
|
||||
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
|
||||
height: 100%
|
||||
order: 2
|
||||
overflow: hidden
|
||||
transition($sidebarTransition)
|
||||
width: 100%
|
||||
|
||||
.sidebar-right
|
||||
flex: 1
|
||||
margin-right: - $rightSidebarMenuWidth
|
||||
max-width: $rightSidebarMenuWidth
|
||||
order: 3
|
||||
position: relative
|
||||
|
||||
&[data-timepoints="3"]
|
||||
margin-right: - ($rightSidebarMenuWidth + 135.5px)
|
||||
max-width: $rightSidebarMenuWidth + 135.5px
|
||||
|
||||
&[data-timepoints="4"]
|
||||
margin-right: - ($rightSidebarMenuWidth + 270px)
|
||||
max-width: $rightSidebarMenuWidth + 270px
|
||||
|
||||
&.sidebar-open
|
||||
margin-right: 0
|
||||
|
||||
.studiesListedChanger
|
||||
theme('border-bottom', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
padding: 20px 10px
|
||||
text-align: center
|
||||
@ -1,30 +0,0 @@
|
||||
<template name="ohifViewer">
|
||||
{{#header brandHref='http://ohif.org' headerClasses=instance.headerClasses}}
|
||||
{{#section 'brand'}}
|
||||
<svg class="logo-image">
|
||||
<use xlink:href={{absoluteUrl "packages/ohif_viewerbase/assets/icons.svg#icon-ohif-logo"}}></use>
|
||||
</svg>
|
||||
<div class="logo-text">Open Health Imaging Foundation</div>
|
||||
{{/section}}
|
||||
{{#section 'headerAfterBrand'}}
|
||||
{{#if studyListToggleText}}
|
||||
<a href="#" class="btn studyListLinkSection pull-left js-toggle-studyList">
|
||||
{{studyListToggleText}}
|
||||
</a>
|
||||
{{/if}}
|
||||
{{/section}}
|
||||
{{#section 'headerMenu'}}
|
||||
<span class="research-use pull-left m-r-1">
|
||||
INVESTIGATIONAL USE ONLY
|
||||
</span>
|
||||
<span class="header-options pull-left m-r-1">Options</span>
|
||||
<div class="menu-toggle pull-right">
|
||||
<span class="caret-down"></span>
|
||||
</div>
|
||||
{{/section}}
|
||||
{{/header}}
|
||||
|
||||
{{#if isStudyListReady}}
|
||||
{{>Template.dynamic template=(choose this.template 'studylist') data=this}}
|
||||
{{/if}}
|
||||
</template>
|
||||
@ -1,116 +0,0 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { Template } from 'meteor/templating';
|
||||
import { Session } from 'meteor/session';
|
||||
import { Router } from 'meteor/clinical:router';
|
||||
import { ReactiveVar } from 'meteor/reactive-var';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
Template.ohifViewer.onCreated(() => {
|
||||
const instance = Template.instance();
|
||||
instance.headerClasses = new ReactiveVar('');
|
||||
Session.set("IsStudyListReady", true);;
|
||||
|
||||
const headerItems = [{
|
||||
action: () => OHIF.ui.showDialog('serverInformationModal'),
|
||||
text: 'Server Information',
|
||||
icon: 'fa fa-server fa-lg',
|
||||
separatorAfter: true
|
||||
}, {
|
||||
action: () => OHIF.ui.showDialog('themeSelectorModal'),
|
||||
text: 'Themes',
|
||||
iconClasses: 'theme',
|
||||
iconSvgUse: 'packages/ohif_viewerbase/assets/icons.svg#theme',
|
||||
separatorAfter: false
|
||||
}, {
|
||||
action: () => OHIF.ui.showDialog('userPreferencesDialog'),
|
||||
text: 'Preferences',
|
||||
icon: 'fa fa-user',
|
||||
separatorAfter: true
|
||||
}, {
|
||||
action: () => OHIF.ui.showDialog('aboutModal'),
|
||||
text: 'About',
|
||||
icon: 'fa fa-info'
|
||||
}];
|
||||
|
||||
const isUserLoggedIn = OHIF.user.userLoggedIn();
|
||||
const isDemoUserLoggedIn = OHIF.demoMode && OHIF.demoMode.userLoggedIn();
|
||||
if (isUserLoggedIn || isDemoUserLoggedIn) {
|
||||
headerItems.push({
|
||||
action: isDemoUserLoggedIn ? OHIF.demoMode.logout : OHIF.user.logout,
|
||||
text: 'Logout',
|
||||
iconClasses: 'logout',
|
||||
iconSvgUse: 'packages/ohif_viewerbase/assets/user-menu-icons.svg#logout'
|
||||
});
|
||||
}
|
||||
|
||||
OHIF.header.dropdown.setItems(headerItems);
|
||||
|
||||
instance.autorun(() => {
|
||||
const currentRoute = Router.current();
|
||||
if (!currentRoute) return;
|
||||
const routeName = currentRoute.route.getName();
|
||||
const isViewer = routeName.indexOf('viewer') === 0;
|
||||
|
||||
// Add or remove the strech class from body
|
||||
$(document.body)[isViewer ? 'addClass' : 'removeClass']('stretch');
|
||||
|
||||
// Set the header on its bigger version if the viewer is not opened
|
||||
instance.headerClasses.set(isViewer ? '' : 'header-big');
|
||||
|
||||
// Set the viewer open state on session
|
||||
Session.set('ViewerOpened', isViewer);
|
||||
});
|
||||
|
||||
if (OHIF.demoMode && OHIF.demoMode.userLoggedIn()) {
|
||||
OHIF.demoMode.setDemoServerConfig();
|
||||
} else if (OHIF.gcloud && OHIF.gcloud.isEnabled()) {
|
||||
const server = OHIF.servers.getCurrentServer();
|
||||
|
||||
if (!server || !server.isCloud) {
|
||||
Session.set("IsStudyListReady", false);
|
||||
OHIF.gcloud.showDicomStorePicker({canClose: OHIF.demoMode}).then(config => {
|
||||
if (!config) {
|
||||
if (OHIF.demoMode)
|
||||
Router.go('/demo-signin');
|
||||
return;
|
||||
}
|
||||
OHIF.servers.applyCloudServerConfig(config);
|
||||
Session.set("IsStudyListReady", true);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Template.ohifViewer.events({
|
||||
'click .js-toggle-studyList'(event, instance) {
|
||||
event.preventDefault();
|
||||
const isViewer = Session.get('ViewerOpened');
|
||||
|
||||
if (isViewer) {
|
||||
Router.go('studylist');
|
||||
} else {
|
||||
const { studyInstanceUids } = OHIF.viewer.data;
|
||||
if (studyInstanceUids) {
|
||||
Router.go('viewerStudies', { studyInstanceUids });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
Template.ohifViewer.helpers({
|
||||
studyListToggleText() {
|
||||
const instance = Template.instance();
|
||||
const isViewer = Session.get('ViewerOpened');
|
||||
|
||||
if (isViewer) {
|
||||
instance.hasViewerData = true;
|
||||
return 'Study list';
|
||||
}
|
||||
|
||||
return instance.hasViewerData ? 'Back to viewer' : '';
|
||||
},
|
||||
isStudyListReady() {
|
||||
return !!Session.get('IsStudyListReady');
|
||||
}
|
||||
});
|
||||
@ -1,80 +0,0 @@
|
||||
@import "{ohif:design}/app"
|
||||
|
||||
body>.header
|
||||
|
||||
.brand
|
||||
height: 30px
|
||||
display: inline-block
|
||||
text-decoration: none
|
||||
|
||||
.logo-image
|
||||
display: inline-block
|
||||
fill: transparent
|
||||
float: left
|
||||
height: 100%
|
||||
margin: 0 8px 0 0
|
||||
width: 30px
|
||||
|
||||
.logo-text
|
||||
display: inline-block
|
||||
font-family: $logoFontFamily
|
||||
font-size: 14px
|
||||
font-weight: $logoFontWeight
|
||||
theme('color', '$textPrimaryColor')
|
||||
line-height: 30px
|
||||
|
||||
a.header-menu
|
||||
theme('color', '$textPrimaryColor')
|
||||
|
||||
.header-options
|
||||
font-size: 13px
|
||||
|
||||
.menu-toggle
|
||||
display: inline-block
|
||||
height: 18px
|
||||
|
||||
.research-use
|
||||
font-size: 13px
|
||||
theme('color', '$textSecondaryColor')
|
||||
font-weight: bold
|
||||
|
||||
.btn
|
||||
theme('color', '$textSecondaryColor')
|
||||
cursor: pointer
|
||||
font-size: 13px
|
||||
font-weight: 500
|
||||
line-height: 26px
|
||||
|
||||
&:hover
|
||||
theme('color', '$hoverColor')
|
||||
|
||||
&:active
|
||||
theme('color', '$activeColor')
|
||||
|
||||
.studyListLinkSection
|
||||
theme('border-left', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
margin: 3px 0 0 10px
|
||||
padding: 0 0 0 10px
|
||||
|
||||
&.header-big
|
||||
padding-left: $studyListPadding
|
||||
padding-right: $studyListPadding
|
||||
|
||||
.brand
|
||||
height: 100%
|
||||
line-height: $topBarExpandedHeight - 10px
|
||||
|
||||
.logo-image
|
||||
margin: 0 20px 0 0
|
||||
width: 50px
|
||||
|
||||
.logo-text
|
||||
font-size: 30px
|
||||
|
||||
.studyListLinkSection
|
||||
border: none
|
||||
left: 0
|
||||
margin: 0
|
||||
padding: 0
|
||||
position: absolute
|
||||
top: 0
|
||||
@ -1,11 +0,0 @@
|
||||
<template name="structuredReportModal">
|
||||
{{#dialogForm (extend this
|
||||
id='structuredReportModal'
|
||||
dialogClass='themed modal-lg'
|
||||
title='Structured report'
|
||||
hideCancel=true
|
||||
hideConfirm=true
|
||||
)}}
|
||||
<div id="root"></div>
|
||||
{{/dialogForm}}
|
||||
</template>
|
||||
@ -1,91 +0,0 @@
|
||||
import { $ } from 'meteor/jquery';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
Template.structuredReportModal.onRendered(() => {
|
||||
const structuredReport = getStructureReport();
|
||||
|
||||
render(structuredReport);
|
||||
});
|
||||
|
||||
// FIXME: we use just 1st SR for current study for now
|
||||
function getStructureReport() {
|
||||
let structuredReport;
|
||||
|
||||
OHIF.viewer.StudyMetadataList.find(studyMetadata => {
|
||||
|
||||
structuredReport = studyMetadata.findInstance(instance => instance.getData().modality === 'SR');
|
||||
|
||||
// If SR is found stop the search
|
||||
return !!structuredReport;
|
||||
});
|
||||
|
||||
return structuredReport;
|
||||
}
|
||||
|
||||
function render(structureReport) {
|
||||
const root = $('#root');
|
||||
|
||||
if (structureReport) {
|
||||
renderStructuredReport(root, structureReport.getData());
|
||||
} else {
|
||||
renderNoData(root);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function renderStructuredReport(root, data) {
|
||||
root.append(getMainDataHtml(data));
|
||||
root.append(getContentSequenceHtml(data.contentSequence));
|
||||
}
|
||||
|
||||
function renderNoData(root) {
|
||||
root.append('<div>No structured report found</div>');
|
||||
}
|
||||
|
||||
function getMainDataHtml(data) {
|
||||
const root = $('<div></div>');
|
||||
|
||||
const { completionFlag, verificationFlag, manufacturer, contentDateTime } = data;
|
||||
|
||||
if (completionFlag) {
|
||||
root.append(getMainDataItemHtml('Completion flag', completionFlag));
|
||||
}
|
||||
|
||||
if (verificationFlag) {
|
||||
root.append(getMainDataItemHtml('Verification flag', verificationFlag));
|
||||
}
|
||||
|
||||
if (manufacturer) {
|
||||
root.append(getMainDataItemHtml('Manufacturer', manufacturer));
|
||||
}
|
||||
|
||||
if (contentDateTime) {
|
||||
root.append(getMainDataItemHtml('Content Date/Time', contentDateTime));
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
const getContentSequenceHtml = (data, level = 1) => {
|
||||
const root = $('<div></div>');
|
||||
const header = data.header;
|
||||
const items = data.items || [];
|
||||
|
||||
if (header) {
|
||||
root.append(`<h${level}>${header}</h${level}>`);
|
||||
}
|
||||
|
||||
items.forEach(item => {
|
||||
root.append(
|
||||
item instanceof Object
|
||||
? getContentSequenceHtml(item, level + 1)
|
||||
: `<div>${item}</div>`
|
||||
);
|
||||
});
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
function getMainDataItemHtml(key, value) {
|
||||
return $(`<div><b>${key}</b>: ${value}</div>`);
|
||||
}
|
||||
@ -1,13 +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}}
|
||||
<div class="pull-right m-t-1 rm-x-1">
|
||||
{{>roundedButtonGroup rightSidebarToggleButtonData}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -1,328 +0,0 @@
|
||||
import { Template } from 'meteor/templating';
|
||||
import { $ } from 'meteor/jquery';
|
||||
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import 'meteor/ohif:viewerbase';
|
||||
|
||||
function isThereSeries(studies) {
|
||||
if (studies.length === 1) {
|
||||
const study = studies[0];
|
||||
|
||||
if (study.seriesList && study.seriesList.length > 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (study.displaySets && study.displaySets.length > 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Template.toolbarSection.onCreated(() => {
|
||||
const instance = Template.instance();
|
||||
|
||||
if (OHIF.uiSettings.leftSidebarOpen && isThereSeries(instance.data.studies)) {
|
||||
instance.data.state.set('leftSidebar', 'studies');
|
||||
}
|
||||
});
|
||||
|
||||
Template.toolbarSection.helpers({
|
||||
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: 'Series'
|
||||
}]
|
||||
};
|
||||
},
|
||||
|
||||
rightSidebarToggleButtonData() {
|
||||
const instance = Template.instance();
|
||||
|
||||
// TODO: Figured out a way to handle both right panel contents
|
||||
// return {
|
||||
// toggleable: true,
|
||||
// key: 'rightSidebar',
|
||||
// value: instance.data.state,
|
||||
// options: [{
|
||||
// value: 'hangingprotocols',
|
||||
// iconClasses: 'fa fa-cog',
|
||||
// bottomLabel: 'Hanging'
|
||||
// }]
|
||||
// };
|
||||
|
||||
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() {
|
||||
const extraTools = [];
|
||||
|
||||
extraTools.push({
|
||||
id: 'crosshairs',
|
||||
title: 'Crosshairs',
|
||||
classes: 'imageViewerTool',
|
||||
iconClasses: 'fa fa-crosshairs'
|
||||
});
|
||||
|
||||
extraTools.push({
|
||||
id: 'magnify',
|
||||
title: 'Magnify',
|
||||
classes: 'imageViewerTool toolbarSectionButton',
|
||||
iconClasses: 'fa fa-circle'
|
||||
});
|
||||
|
||||
extraTools.push({
|
||||
id: 'wwwcRegion',
|
||||
title: 'ROI Window',
|
||||
classes: 'imageViewerTool',
|
||||
iconClasses: 'fa fa-square'
|
||||
});
|
||||
|
||||
extraTools.push({
|
||||
id: 'dragProbe',
|
||||
title: 'Probe',
|
||||
classes: 'imageViewerTool',
|
||||
iconClasses: 'fa fa-dot-circle-o'
|
||||
});
|
||||
|
||||
extraTools.push({
|
||||
id: 'ellipticalRoi',
|
||||
title: 'Ellipse',
|
||||
classes: 'imageViewerTool',
|
||||
iconClasses: 'fa fa-circle-o'
|
||||
});
|
||||
|
||||
extraTools.push({
|
||||
id: 'rectangleRoi',
|
||||
title: 'Rectangle',
|
||||
classes: 'imageViewerTool',
|
||||
iconClasses: 'fa fa-square-o'
|
||||
});
|
||||
|
||||
extraTools.push({
|
||||
id: 'toggleDownloadDialog',
|
||||
title: 'Download',
|
||||
classes: 'imageViewerCommand',
|
||||
iconClasses: 'fa fa-camera',
|
||||
active: () => $('#downloadDialog').is(':visible')
|
||||
});
|
||||
|
||||
extraTools.push({
|
||||
id: 'invert',
|
||||
title: 'Invert',
|
||||
classes: 'imageViewerCommand',
|
||||
iconClasses: 'fa fa-adjust'
|
||||
});
|
||||
|
||||
extraTools.push({
|
||||
id: 'rotateR',
|
||||
title: 'Rotate Right',
|
||||
classes: 'imageViewerCommand',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-rotate-right'
|
||||
});
|
||||
|
||||
extraTools.push({
|
||||
id: 'flipH',
|
||||
title: 'Flip H',
|
||||
classes: 'imageViewerCommand',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-flip-horizontal'
|
||||
});
|
||||
|
||||
extraTools.push({
|
||||
id: 'flipV',
|
||||
title: 'Flip V',
|
||||
classes: 'imageViewerCommand',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-flip-vertical'
|
||||
});
|
||||
|
||||
extraTools.push({
|
||||
id: 'clearTools',
|
||||
title: 'Clear',
|
||||
classes: 'imageViewerCommand',
|
||||
iconClasses: 'fa fa-trash'
|
||||
});
|
||||
|
||||
const buttonData = [];
|
||||
|
||||
buttonData.push({
|
||||
id: 'stackScroll',
|
||||
title: 'Stack Scroll',
|
||||
classes: 'imageViewerTool',
|
||||
iconClasses: 'fa fa-bars'
|
||||
});
|
||||
|
||||
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: 'length',
|
||||
title: 'Length',
|
||||
classes: 'imageViewerTool toolbarSectionButton',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-measure-temp'
|
||||
});
|
||||
|
||||
buttonData.push({
|
||||
id: 'annotate',
|
||||
title: 'Annotate',
|
||||
classes: 'imageViewerTool',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-measure-non-target'
|
||||
});
|
||||
|
||||
buttonData.push({
|
||||
id: 'angle',
|
||||
title: 'Angle',
|
||||
classes: 'imageViewerTool',
|
||||
iconClasses: 'fa fa-angle-left'
|
||||
});
|
||||
|
||||
buttonData.push({
|
||||
id: 'resetViewport',
|
||||
title: 'Reset',
|
||||
classes: 'imageViewerCommand',
|
||||
iconClasses: 'fa fa-undo'
|
||||
});
|
||||
|
||||
if (!OHIF.uiSettings.displayEchoUltrasoundWorkflow) {
|
||||
|
||||
buttonData.push({
|
||||
id: 'previousDisplaySet',
|
||||
title: 'Previous',
|
||||
classes: 'imageViewerCommand',
|
||||
iconClasses: 'fa fa-toggle-up fa-fw'
|
||||
});
|
||||
|
||||
buttonData.push({
|
||||
id: 'nextDisplaySet',
|
||||
title: 'Next',
|
||||
classes: 'imageViewerCommand',
|
||||
iconClasses: 'fa fa-toggle-down fa-fw'
|
||||
});
|
||||
|
||||
const { isPlaying } = OHIF.viewerbase.viewportUtils;
|
||||
buttonData.push({
|
||||
id: 'toggleCinePlay',
|
||||
title: () => isPlaying() ? 'Stop' : 'Play',
|
||||
classes: 'imageViewerCommand',
|
||||
iconClasses: () => ('fa fa-fw ' + (isPlaying() ? 'fa-stop' : 'fa-play')),
|
||||
active: isPlaying
|
||||
});
|
||||
|
||||
buttonData.push({
|
||||
id: 'toggleCineDialog',
|
||||
title: 'CINE',
|
||||
classes: 'imageViewerCommand',
|
||||
iconClasses: 'fa fa-youtube-play',
|
||||
active: () => $('#cineDialog').is(':visible')
|
||||
});
|
||||
}
|
||||
|
||||
buttonData.push({
|
||||
id: 'layout',
|
||||
title: 'Layout',
|
||||
iconClasses: 'fa fa-th-large',
|
||||
buttonTemplateName: 'layoutButton'
|
||||
});
|
||||
|
||||
buttonData.push({
|
||||
id: 'sr',
|
||||
title: 'SR',
|
||||
classes: 'imageViewerTool',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-sr'
|
||||
});
|
||||
|
||||
buttonData.push({
|
||||
id: 'toggleMore',
|
||||
title: 'More',
|
||||
classes: 'rp-x-1 rm-l-3',
|
||||
svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-more',
|
||||
subTools: extraTools
|
||||
});
|
||||
|
||||
return buttonData;
|
||||
},
|
||||
|
||||
hangingProtocolButtons() {
|
||||
let buttonData = [];
|
||||
|
||||
buttonData.push({
|
||||
id: 'previousPresentationGroup',
|
||||
title: 'Prev. Stage',
|
||||
iconClasses: 'fa fa-step-backward',
|
||||
buttonTemplateName: 'previousPresentationGroupButton'
|
||||
});
|
||||
|
||||
buttonData.push({
|
||||
id: 'nextPresentationGroup',
|
||||
title: 'Next Stage',
|
||||
iconClasses: 'fa fa-step-forward',
|
||||
buttonTemplateName: 'nextPresentationGroupButton'
|
||||
});
|
||||
|
||||
return buttonData;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Template.toolbarSection.onRendered(function() {
|
||||
const instance = Template.instance();
|
||||
|
||||
instance.$('#layout').dropdown();
|
||||
|
||||
if (OHIF.uiSettings.displayEchoUltrasoundWorkflow) {
|
||||
OHIF.viewerbase.viewportUtils.toggleCineDialog();
|
||||
}
|
||||
|
||||
// Set disabled/enabled tool buttons that are set in toolManager
|
||||
const states = OHIF.viewerbase.toolManager.getToolDefaultStates();
|
||||
const disabledToolButtons = states.disabledToolButtons;
|
||||
const allToolbarButtons = $('#toolbar').find('button');
|
||||
if (disabledToolButtons && disabledToolButtons.length > 0) {
|
||||
for (let 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,13 +0,0 @@
|
||||
@require '{ohif:design}/app'
|
||||
|
||||
.toolbarSection
|
||||
theme('border-bottom', '%s solid $uiBorderColor' % $uiBorderThickness)
|
||||
flex: 0 0 auto
|
||||
height: $toolbarHeight
|
||||
padding-top: 6px
|
||||
position: relative
|
||||
transition(height 300ms ease)
|
||||
width: 100%
|
||||
|
||||
&.expanded
|
||||
height: $toolbarHeight + $toolbarDrawerHeight
|
||||
@ -1,20 +0,0 @@
|
||||
<template name="viewer">
|
||||
{{#if and Template.subscriptionsReady}}
|
||||
<div class="viewerDialogs">
|
||||
{{>cineDialog}}
|
||||
{{>layoutChooser}}
|
||||
{{>annotationDialogs}}
|
||||
|
||||
<!-- Hanging Protocol dialogs -->
|
||||
{{>ruleEntryDialog}}
|
||||
{{>settingEntryDialog}}
|
||||
{{>textEntryDialog}}
|
||||
</div>
|
||||
<div id="viewer">
|
||||
{{>toolbarSection (clone this state=state)}}
|
||||
{{>flexboxLayout (clone this state=state)}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{>loadingText}}
|
||||
{{/if}}
|
||||
</template>
|
||||
@ -1,184 +0,0 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { Session } from 'meteor/session';
|
||||
import { Template } from 'meteor/templating';
|
||||
import { ReactiveDict } from 'meteor/reactive-dict';
|
||||
import { Tracker } from 'meteor/tracker';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { MeasurementTable } from 'meteor/ohif:measurement-table';
|
||||
|
||||
import 'meteor/ohif:cornerstone';
|
||||
import 'meteor/ohif:viewerbase';
|
||||
import 'meteor/ohif:metadata';
|
||||
|
||||
/**
|
||||
* Inits OHIF Hanging Protocol's onReady.
|
||||
* It waits for OHIF Hanging Protocol to be ready to instantiate the ProtocolEngine
|
||||
* Hanging Protocol will use OHIF LayoutManager to render viewports properly
|
||||
*/
|
||||
const initHangingProtocol = () => {
|
||||
// When Hanging Protocol is ready
|
||||
HP.ProtocolStore.onReady(() => {
|
||||
|
||||
// Gets all StudyMetadata objects: necessary for Hanging Protocol to access study metadata
|
||||
const studyMetadataList = OHIF.viewer.StudyMetadataList.all();
|
||||
|
||||
// Caches Layout Manager: Hanging Protocol uses it for layout management according to current protocol
|
||||
const layoutManager = OHIF.viewerbase.layoutManager;
|
||||
|
||||
// Instantiate StudyMetadataSource: necessary for Hanging Protocol to get study metadata
|
||||
const studyMetadataSource = new OHIF.studies.classes.OHIFStudyMetadataSource();
|
||||
|
||||
// Get prior studies map
|
||||
const studyPriorsMap = OHIF.studylist.functions.getStudyPriorsMap(studyMetadataList);
|
||||
|
||||
// Creates Protocol Engine object with required arguments
|
||||
const ProtocolEngine = new HP.ProtocolEngine(layoutManager, studyMetadataList, studyPriorsMap, studyMetadataSource);
|
||||
|
||||
// Sets up Hanging Protocol engine
|
||||
HP.setEngine(ProtocolEngine);
|
||||
|
||||
Session.set('ViewerReady', true);
|
||||
|
||||
Session.set('activeViewport', 0);
|
||||
});
|
||||
};
|
||||
|
||||
Meteor.startup(() => {
|
||||
Session.setDefault('activeViewport', false);
|
||||
Session.setDefault('leftSidebar', false);
|
||||
Session.setDefault('rightSidebar', false);
|
||||
|
||||
OHIF.viewer.defaultTool = 'wwwc';
|
||||
OHIF.viewer.refLinesEnabled = true;
|
||||
OHIF.viewer.cine = {
|
||||
framesPerSecond: 24,
|
||||
loop: true
|
||||
};
|
||||
|
||||
const viewportUtils = OHIF.viewerbase.viewportUtils;
|
||||
|
||||
OHIF.viewer.functionList = {
|
||||
toggleCineDialog: viewportUtils.toggleCineDialog,
|
||||
toggleCinePlay: viewportUtils.toggleCinePlay,
|
||||
clearTools: viewportUtils.clearTools,
|
||||
resetViewport: viewportUtils.resetViewport,
|
||||
invert: viewportUtils.invert
|
||||
};
|
||||
|
||||
// Create the synchronizer used to update reference lines
|
||||
OHIF.viewer.updateImageSynchronizer = new cornerstoneTools.Synchronizer('cornerstonenewimage', cornerstoneTools.updateImageSynchronizer);
|
||||
|
||||
OHIF.viewer.metadataProvider = new OHIF.cornerstone.MetadataProvider();
|
||||
|
||||
// Metadata configuration
|
||||
const metadataProvider = OHIF.viewer.metadataProvider;
|
||||
cornerstone.metaData.addProvider(metadataProvider.provider.bind(metadataProvider));
|
||||
|
||||
// Instanciate viewer plugins
|
||||
OHIF.viewer.measurementTable = new MeasurementTable();
|
||||
});
|
||||
|
||||
Template.viewer.onCreated(() => {
|
||||
Session.set('ViewerReady', false);
|
||||
|
||||
const instance = Template.instance();
|
||||
|
||||
// Define the OHIF.viewer.data global object
|
||||
OHIF.viewer.data = OHIF.viewer.data || Session.get('ViewerData') || {};
|
||||
|
||||
instance.state = new ReactiveDict();
|
||||
instance.state.set('leftSidebar', Session.get('leftSidebar'));
|
||||
instance.state.set('rightSidebar', Session.get('rightSidebar'));
|
||||
|
||||
if (OHIF.viewer.data && OHIF.viewer.data.loadedSeriesData) {
|
||||
OHIF.log.info('Reloading previous loadedSeriesData');
|
||||
OHIF.viewer.loadedSeriesData = OHIF.viewer.data.loadedSeriesData;
|
||||
} else {
|
||||
OHIF.log.info('Setting default viewer data');
|
||||
OHIF.viewer.loadedSeriesData = {};
|
||||
OHIF.viewer.data.loadedSeriesData = OHIF.viewer.loadedSeriesData;
|
||||
|
||||
// Update the viewer data object
|
||||
OHIF.viewer.data.viewportColumns = 1;
|
||||
OHIF.viewer.data.viewportRows = 1;
|
||||
OHIF.viewer.data.activeViewport = 0;
|
||||
}
|
||||
|
||||
// Store the viewer data in session for further user
|
||||
Session.setPersistent('ViewerData', OHIF.viewer.data);
|
||||
|
||||
Session.set('activeViewport', OHIF.viewer.data.activeViewport || 0);
|
||||
|
||||
// @TypeSafeStudies
|
||||
// Clears OHIF.viewer.Studies collection
|
||||
OHIF.viewer.Studies.removeAll();
|
||||
|
||||
// @TypeSafeStudies
|
||||
// Clears OHIF.viewer.StudyMetadataList collection
|
||||
OHIF.viewer.StudyMetadataList.removeAll();
|
||||
|
||||
OHIF.viewer.data.studyInstanceUids = [];
|
||||
instance.data.studies.forEach(study => {
|
||||
const studyMetadata = new OHIF.metadata.StudyMetadata(study, study.studyInstanceUid);
|
||||
let displaySets = study.displaySets;
|
||||
|
||||
if (!study.displaySets) {
|
||||
displaySets = OHIF.viewerbase.sortingManager.getDisplaySets(studyMetadata);
|
||||
study.displaySets = displaySets;
|
||||
}
|
||||
|
||||
studyMetadata.setDisplaySets(displaySets);
|
||||
|
||||
study.selected = true;
|
||||
OHIF.viewer.Studies.insert(study);
|
||||
OHIF.viewer.StudyMetadataList.insert(studyMetadata);
|
||||
OHIF.viewer.data.studyInstanceUids.push(study.studyInstanceUid);
|
||||
|
||||
// Updates WADO-RS metaDataManager
|
||||
OHIF.viewerbase.updateMetaDataManager(study);
|
||||
});
|
||||
|
||||
// Call Viewer plugins onCreated functions
|
||||
if(typeof OHIF.viewer.measurementTable.onCreated === 'function') {
|
||||
OHIF.viewer.measurementTable.onCreated(instance);
|
||||
}
|
||||
});
|
||||
|
||||
Template.viewer.onRendered(function() {
|
||||
const instance = Template.instance();
|
||||
this.autorun(function() {
|
||||
// To make sure ohif viewerMain is rendered before initializing Hanging Protocols
|
||||
const isOHIFViewerMainRendered = Session.get('OHIFViewerMainRendered');
|
||||
|
||||
// To avoid first run
|
||||
if (isOHIFViewerMainRendered) {
|
||||
// To run only when OHIFViewerMainRendered dependency has changed.
|
||||
// because initHangingProtocol can have other reactive components
|
||||
Tracker.nonreactive(initHangingProtocol);
|
||||
}
|
||||
});
|
||||
|
||||
// Call Viewer plugins onRendered functions
|
||||
if(typeof OHIF.viewer.measurementTable.onRendered === 'function') {
|
||||
OHIF.viewer.measurementTable.onRendered(instance);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Template.viewer.events( Object.assign({
|
||||
// Viewer Events
|
||||
},
|
||||
MeasurementTable.measurementEvents
|
||||
));
|
||||
|
||||
Template.viewer.onDestroyed(function() {
|
||||
if(typeof OHIF.viewer.measurementTable.onDestroyed === 'function') {
|
||||
OHIF.viewer.measurementTable.onDestroyed();
|
||||
}
|
||||
});
|
||||
|
||||
Template.viewer.helpers({
|
||||
state() {
|
||||
return Template.instance().state;
|
||||
}
|
||||
});
|
||||
@ -1,13 +0,0 @@
|
||||
@import "{ohif:design}/app"
|
||||
|
||||
body
|
||||
background-color: black
|
||||
|
||||
#viewer
|
||||
background-color: black
|
||||
height: 100%
|
||||
width: 100%
|
||||
|
||||
.loadingTextDiv
|
||||
theme('color', '$textSecondaryColor')
|
||||
font-size: 30px
|
||||
@ -1,38 +0,0 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { cornerstoneWADOImageLoader } from 'meteor/ohif:cornerstone';
|
||||
|
||||
Meteor.startup(function() {
|
||||
const maxWebWorkers = Math.max(navigator.hardwareConcurrency - 1, 1);
|
||||
const config = {
|
||||
maxWebWorkers: maxWebWorkers,
|
||||
startWebWorkersOnDemand: true,
|
||||
webWorkerPath: OHIF.utils.absoluteUrl('packages/ohif_cornerstone/public/js/cornerstoneWADOImageLoaderWebWorker.es5.js'),
|
||||
taskConfiguration: {
|
||||
decodeTask: {
|
||||
loadCodecsOnStartup: true,
|
||||
initializeCodecsOnStartup: false,
|
||||
codecsPath: OHIF.utils.absoluteUrl('packages/ohif_cornerstone/public/js/cornerstoneWADOImageLoaderCodecs.es5.js'),
|
||||
usePDFJS: false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cornerstoneWADOImageLoader.webWorkerManager.initialize(config);
|
||||
|
||||
cornerstoneWADOImageLoader.configure({
|
||||
beforeSend: function(xhr) {
|
||||
const headers = OHIF.DICOMWeb.getAuthorizationHeader();
|
||||
|
||||
if (headers.Authorization) {
|
||||
xhr.setRequestHeader("Authorization", headers.Authorization);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (Meteor.settings &&
|
||||
Meteor.settings.public &&
|
||||
Meteor.settings.public.clientOnly === true) {
|
||||
Meteor.disconnect();
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
import loglevel from 'loglevel';
|
||||
log = loglevel.getLogger('OHIFViewer');
|
||||
log.setLevel('info');
|
||||
@ -1,69 +0,0 @@
|
||||
import { Meteor } from "meteor/meteor";
|
||||
import { Router } from 'meteor/clinical:router';
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
|
||||
Router.configure({
|
||||
layoutTemplate: 'layout',
|
||||
});
|
||||
|
||||
|
||||
// If we are running a disconnected client similar to the StandaloneViewer
|
||||
// (see https://docs.ohif.org/standalone-viewer/usage.html) we don't want
|
||||
// our routes to get stuck while waiting for Pub / Sub.
|
||||
//
|
||||
// In this case, the developer is required to add Servers and specify
|
||||
// a CurrentServer with some other approach (e.g. a separate script).
|
||||
if (Meteor.settings &&
|
||||
Meteor.settings.public &&
|
||||
Meteor.settings.public.clientOnly !== true) {
|
||||
Router.waitOn(function() {
|
||||
return [
|
||||
Meteor.subscribe('servers'),
|
||||
Meteor.subscribe('currentServer')
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
Router.onBeforeAction('loading');
|
||||
|
||||
Router.route('/', function() {
|
||||
Router.go('studylist', {}, { replaceState: true });
|
||||
}, { name: 'home' });
|
||||
|
||||
Router.route('/studylist', function() {
|
||||
this.render('ohifViewer', { data: { template: 'studylist' } });
|
||||
}, { name: 'studylist' });
|
||||
|
||||
Router.route('/viewer/:studyInstanceUids', function() {
|
||||
const studyInstanceUids = this.params.studyInstanceUids.split(';');
|
||||
OHIF.viewerbase.renderViewer(this, { studyInstanceUids }, 'ohifViewer');
|
||||
}, { name: 'viewerStudies' });
|
||||
|
||||
// OHIF #98 Show specific series of study
|
||||
Router.route('/study/:studyInstanceUid/series/:seriesInstanceUids', function () {
|
||||
const studyInstanceUid = this.params.studyInstanceUid;
|
||||
const seriesInstanceUids = this.params.seriesInstanceUids.split(';');
|
||||
OHIF.viewerbase.renderViewer(this, { studyInstanceUids: [studyInstanceUid], seriesInstanceUids }, 'ohifViewer');
|
||||
}, { name: 'viewerSeries' });
|
||||
|
||||
Router.route('/IHEInvokeImageDisplay', function() {
|
||||
const requestType = this.params.query.requestType;
|
||||
|
||||
if (requestType === "STUDY") {
|
||||
const studyInstanceUids = this.params.query.studyUID.split(';');
|
||||
|
||||
OHIF.viewerbase.renderViewer(this, {studyInstanceUids}, 'ohifViewer');
|
||||
} else if (requestType === "STUDYBASE64") {
|
||||
const uids = this.params.query.studyUID;
|
||||
const decodedData = window.atob(uids);
|
||||
const studyInstanceUids = decodedData.split(';');
|
||||
|
||||
OHIF.viewerbase.renderViewer(this, {studyInstanceUids}, 'ohifViewer');
|
||||
} else if (requestType === "PATIENT") {
|
||||
const patientUids = this.params.query.patientID.split(';');
|
||||
|
||||
Router.go('studylist', {}, {replaceState: true});
|
||||
} else {
|
||||
Router.go('studylist', {}, {replaceState: true});
|
||||
}
|
||||
});
|
||||
367
OHIFViewer/package-lock.json
generated
367
OHIFViewer/package-lock.json
generated
@ -1,367 +0,0 @@
|
||||
{
|
||||
"name": "ohifviewer",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": {
|
||||
"version": "7.0.0-beta.51",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0-beta.51.tgz",
|
||||
"integrity": "sha1-SLjtGDBwNMZiD2Q1FGUMoszAFlo=",
|
||||
"requires": {
|
||||
"core-js": "^2.5.7",
|
||||
"regenerator-runtime": "^0.11.1"
|
||||
}
|
||||
},
|
||||
"agent-base": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz",
|
||||
"integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"es6-promisify": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"async-limiter": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
|
||||
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==",
|
||||
"dev": true
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
||||
"dev": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"buffer-from": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz",
|
||||
"integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==",
|
||||
"dev": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||
"dev": true
|
||||
},
|
||||
"concat-stream": {
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
|
||||
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^2.2.2",
|
||||
"typedarray": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"core-js": {
|
||||
"version": "2.5.7",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
|
||||
"integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw=="
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
||||
"dev": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"es6-promise": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz",
|
||||
"integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==",
|
||||
"dev": true
|
||||
},
|
||||
"es6-promisify": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
|
||||
"integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"es6-promise": "^4.0.3"
|
||||
}
|
||||
},
|
||||
"extract-zip": {
|
||||
"version": "1.6.7",
|
||||
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz",
|
||||
"integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"concat-stream": "1.6.2",
|
||||
"debug": "2.6.9",
|
||||
"mkdirp": "0.5.1",
|
||||
"yauzl": "2.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"fd-slicer": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
|
||||
"integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pend": "~1.2.0"
|
||||
}
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
||||
"dev": true
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
|
||||
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"https-proxy-agent": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz",
|
||||
"integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"agent-base": "^4.1.0",
|
||||
"debug": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
|
||||
"dev": true
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
|
||||
"dev": true
|
||||
},
|
||||
"loglevel": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz",
|
||||
"integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po="
|
||||
},
|
||||
"mime": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-2.3.1.tgz",
|
||||
"integrity": "sha512-OEUllcVoydBHGN1z84yfQDimn58pZNNNXgZlHXSboxMlFvgI6MXSWpWKpFRra7H1HxpVhHTkrghfRW49k6yjeg==",
|
||||
"dev": true
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
|
||||
"dev": true
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
||||
"dev": true
|
||||
},
|
||||
"pend": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
|
||||
"integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
|
||||
"dev": true
|
||||
},
|
||||
"process-nextick-args": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
|
||||
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
|
||||
"dev": true
|
||||
},
|
||||
"progress": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz",
|
||||
"integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=",
|
||||
"dev": true
|
||||
},
|
||||
"proxy-from-env": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz",
|
||||
"integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=",
|
||||
"dev": true
|
||||
},
|
||||
"puppeteer": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.5.0.tgz",
|
||||
"integrity": "sha512-eELwFtFxL+uhmg4jPZOZXzSrPEYy4CaYQNbcchBbfxY+KjMpnv6XGf/aYWaQG49OTpfi2/DMziXtDM8XuJgoUA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^3.1.0",
|
||||
"extract-zip": "^1.6.6",
|
||||
"https-proxy-agent": "^2.2.1",
|
||||
"mime": "^2.0.3",
|
||||
"progress": "^2.0.0",
|
||||
"proxy-from-env": "^1.0.0",
|
||||
"rimraf": "^2.6.1",
|
||||
"ws": "^5.1.1"
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.11.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
|
||||
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
|
||||
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"glob": "^7.0.5"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"dev": true
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"typedarray": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
||||
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
|
||||
"dev": true
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
|
||||
"dev": true
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"dev": true
|
||||
},
|
||||
"ws": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
|
||||
"integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"async-limiter": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"yauzl": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
|
||||
"integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fd-slicer": "~1.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
{
|
||||
"name": "ohifviewer",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.0.0-beta.51",
|
||||
"loglevel": "^1.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"puppeteer": "^1.5.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT"
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB |
@ -1,7 +0,0 @@
|
||||
active-entry
|
||||
hipaa-audit-log
|
||||
meteor-stale-session
|
||||
orthanc-remote
|
||||
ohif-cornerstone
|
||||
ohif-viewerbase/client/compatibility
|
||||
ohif-core/client/lib/third-party/
|
||||
@ -1,47 +0,0 @@
|
||||
{
|
||||
"parser": "babel-eslint",
|
||||
"parserOptions": {
|
||||
"allowImportExportEverywhere": true
|
||||
},
|
||||
"plugins": [
|
||||
"meteor"
|
||||
],
|
||||
"env": {
|
||||
/* Allows global vars from the Meteor environment to pass and enables certain rules */
|
||||
"meteor": true,
|
||||
"node": true,
|
||||
"browser": true
|
||||
},
|
||||
"extends": [
|
||||
"airbnb",
|
||||
"plugin:meteor/recommended"
|
||||
],
|
||||
"settings": {
|
||||
"import/resolver": "meteor"
|
||||
},
|
||||
"rules": {
|
||||
"meteor/no-session": 0, // We are actually using Session for now...
|
||||
"meteor/eventmap-params": [2, {"eventParamName": "event"}],
|
||||
"meteor/eventmap-params": [2, {"templateInstanceParamName": "instance"}],
|
||||
"import/no-extraneous-dependencies": 0,
|
||||
"import/no-unresolved": 0, // There are a bunch of ESLint problems with Meteor's resolver
|
||||
"import/no-duplicates": 0, // So we are disabling these for now
|
||||
"import/extensions": 0,
|
||||
"import/no-absolute-path": 0,
|
||||
"no-console": 0, // For development
|
||||
"no-plusplus": ["error", { "allowForLoopAfterthoughts": true }],
|
||||
"indent": ["error", 4],
|
||||
"new-cap": 0, // Until Match has an exception
|
||||
"func-names": 0, // This is a bit of an annoying rule
|
||||
"no-underscore-dangle": 0, // Doesn't seem to mesh with _id for MongoDB Ids (or SimpleSchema)
|
||||
"max-len": 0, // TODO: re-enable the rules below and fix all of the errors
|
||||
"consistent-return": 0,
|
||||
"no-param-reassign": 0,
|
||||
"no-mixed-operators": 0,
|
||||
"arrow-body-style": 0,
|
||||
"valid-typeof": 0,
|
||||
"import/prefer-default-export": 0
|
||||
//"no-undef": 0
|
||||
},
|
||||
"globals": {}
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.10"
|
||||
#sudo: required
|
||||
|
||||
sudo: required
|
||||
|
||||
env:
|
||||
global:
|
||||
- METEOR_ENV=development
|
||||
|
||||
before_install:
|
||||
- "curl -L http://git.io/ejPSng | /bin/sh"
|
||||
@ -1,34 +0,0 @@
|
||||
## Contributing
|
||||
|
||||
**Submit your Pull Request on a Feature Branch**
|
||||
|
||||
- To ensure your pull-request has the greatest chance of getting merged in, please submit it on a feature branch rather than directly to master.
|
||||
- Please see [A successful Git branching model](http://nvie.com/posts/a-successful-git-branching-model/) for more details.
|
||||
|
||||
**Quality Assurance**
|
||||
- Pull Requests will be generally accepted as long as the QA tests pass on [Circle CI](https://circleci.com/gh/clinical-meteor/clinical-active-entry).
|
||||
- Begin a Pull Request by logging an Issue for discussion.
|
||||
- Next, clone the package into a project for local development.
|
||||
- Use ``git checkout -b newfeature`` to create a new branch.
|
||||
- Run the package verification tests to ensure that the test runner works.
|
||||
- Add an it() clause at the bottom of the [activeEntryTests.js](https://github.com/clinical-meteor/clinical-active-entry/blob/master/tests/gagarin/activeEntryTests.js) file for each new feature you wish to implement.
|
||||
- Sketch out a test script for a feature.
|
||||
- Run the verification tests, and confirm that the new test fails.
|
||||
- Update the package with the new feature until the new test passes.
|
||||
- Push the package to the repo on GitHub.
|
||||
- Submit a pull-request.
|
||||
- If the PR passes tests on Circle CI, we'll merge it in!
|
||||
|
||||
**Reference Implementation**
|
||||
- Please see the [ChecklistManifest](http://checklist-manifesto.meteor.com/) and it's [source code](https://github.com/clinical-meteor/checklist-manifesto) for a reference implementation of the ActiveEntry package. It's being built as a workqueue, and is being designed to be FDA, HIPAA, and HL7 FHIR compliant.
|
||||
|
||||
**Feature Toggling**
|
||||
- In general, it's a best practice to implement features that can be enabled/disabled. Some people will want a feature; others will not. The best way to toggle features is adding them to a config file, which is what the [ActiveEntry](https://github.com/clinical-meteor/clinical-active-entry/blob/master/lib/ActiveEntry.js) object is for.
|
||||
- It's recommended that fields be added to the ActiveEntryConfig object that can be used to enabled/disable the feature you are implementing.
|
||||
- The ActiveEntryConfig object can be roughly considered as analogous to the ``props`` field that is passed into React templates.
|
||||
|
||||
**Theming and Styling**
|
||||
- Different apps require different presentation/style layers, so Clinical Meteor has implemented a [Theme](https://github.com/clinical-meteor/clinical-theming/blob/master/objects/Theme.js) object which manages theming. Generally speaking, we're trying to avoid the inclusion of third-party component libraries, UI widgets, and CSS frameworks, and keeping the Clinical Meteor packages as close to the default HTML that Blaze produces as possible (while using line styles for animation effects).
|
||||
- Generally speaking, Bootstrap HTML structure in acceptable in designing pages, but avoid including global CSS files, and keep any CSS locally scoped using LESS nested classes. This approach allows people to add the Bootstrap library if they want it, prevents cascading leaks, and allows more fine-grained control over CSS to implement animation effects.
|
||||
- Pull requests that include visual integration with other projects are acceptable, but please submit an issue for discussion before submitting PRs with wholesale changes that include Jade, Material UI, React, etc.
|
||||
- The ActiveEntry pages are designed to be used in an IronRouter Layout template. As such, no height/width constraints are provided. It's assumed that the layout template will take care of such things. But basic padding/margin is provided.
|
||||
@ -1,130 +0,0 @@
|
||||
## clinical:active-entry
|
||||
|
||||
This package provides the SignIn, SignUp, and ForgotPassword pages.
|
||||
|
||||
[](https://circleci.com/gh/clinical-meteor/active-entry/tree/master)
|
||||
|
||||
===============================
|
||||
#### Installation
|
||||
|
||||
````
|
||||
meteor add clinical:active-entry
|
||||
````
|
||||
|
||||
===============================
|
||||
#### Entry Flowchart
|
||||
|
||||
The following diagram represents the entry workflow that is being implemented in this package. This package is under active development, and is about half completed. Pull requests which help implement the following workflow will be fast-tracked and accepted into the package.
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
===============================
|
||||
#### Routing API
|
||||
|
||||
````
|
||||
/entrySignIn
|
||||
/entrySignUp
|
||||
/forgotPassword
|
||||
````
|
||||
|
||||
===============================
|
||||
#### Component API
|
||||
|
||||
````
|
||||
{{> entrySignIn }}
|
||||
{{> entrySignUp }}
|
||||
{{> forgotPassword }}
|
||||
````
|
||||
|
||||
|
||||
===============================
|
||||
#### ActiveEntry Configuration
|
||||
|
||||
````js
|
||||
|
||||
if(Meteor.isClient){
|
||||
ActiveEntry.configure({
|
||||
logo: {
|
||||
url: "/mini-circles.png",
|
||||
displayed: true
|
||||
},
|
||||
signIn: {
|
||||
displayFullName: true,
|
||||
destination: "/table/users"
|
||||
},
|
||||
signUp: {
|
||||
destination: "/table/users"
|
||||
},
|
||||
themeColors: {
|
||||
primary: ""
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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';
|
||||
})
|
||||
}
|
||||
````
|
||||
Alternatively, you may want to set the ``MAIL_URL`` via an external environment variable, particularly if you're using a SaaS hosting provider.
|
||||
|
||||
````sh
|
||||
MAIL_URL = 'smtp://sandboxid.mailgun.org:mypassword@smtp.mailgun.org:587' meteor
|
||||
````
|
||||
|
||||
===============================
|
||||
#### Local Development
|
||||
|
||||
Simply clone the repository into your ``/packages`` directory. You can also specify the packages you want to develop locally in your ``.git-packages.json`` file, and use starrynight to fetch them.
|
||||
|
||||
````bash
|
||||
# clone a single package into your application
|
||||
git clone http://github.com/clinical-meteor/clinical-active-entry packages/active-entry
|
||||
|
||||
# fetch all the packages listed in git-packages.json
|
||||
starrynight fetch
|
||||
````
|
||||
|
||||
===============================
|
||||
#### Quality Assurance Testing
|
||||
|
||||
There are two types of quality assurance tests you can run: verification and validation tests. Verification tests are similar to unit or integration tests; and can run either at the application or package level. Validation tests are application-wide, but often require commands exposed in packages. So you'll need to run the ``autoconfig`` command to scan the filesystem for validation commands. See [http://starrynight.meteor.com/](http://starrynight.meteor.com/) for more details.
|
||||
|
||||
````bash
|
||||
# install the testing utility
|
||||
npm install -g starrynight
|
||||
|
||||
# verification testing (a.k.a. package-level unit/integration testing)
|
||||
starrynight run-tests --type package-verification
|
||||
|
||||
#to run validation tests, you'll need an ``.initializeUsers()`` function
|
||||
meteor add clinical:accounts-housemd
|
||||
|
||||
#validation testing (a.k.a. application acceptance/end-to-end testing)
|
||||
starrynight autoscan
|
||||
starrynight run-tests --type validation
|
||||
````
|
||||
|
||||
===============================
|
||||
#### Contributing
|
||||
|
||||
See our [notes on contributing](https://github.com/clinical-meteor/clinical-active-entry/blob/master/Contributing.md).
|
||||
|
||||
===============================
|
||||
#### Licensing
|
||||
|
||||

|
||||
@ -1,84 +0,0 @@
|
||||
## Customize the test machine
|
||||
machine:
|
||||
node:
|
||||
version: 0.10.33
|
||||
|
||||
# Timezone
|
||||
timezone:
|
||||
America/Los_Angeles # Set the timezone
|
||||
|
||||
# Add some environment variables
|
||||
environment:
|
||||
CIRCLE_ENV: test
|
||||
CXX: g++-4.8
|
||||
DISPLAY: :99.0
|
||||
NPM_PREFIX: /home/ubuntu/nvm/v0.10.33
|
||||
|
||||
|
||||
## Customize checkout
|
||||
checkout:
|
||||
post:
|
||||
#- git submodule sync
|
||||
#- git submodule update --init --recursive # use submodules
|
||||
|
||||
#general:
|
||||
# build_dir: helloworld
|
||||
|
||||
## Customize dependencies
|
||||
dependencies:
|
||||
cache_directories:
|
||||
- ~/.meteor # relative to the user's home directory
|
||||
- ~/nvm/v0.10.33/lib/node_modules/starrynight
|
||||
- ~/nvm/v0.10.33/bin/starrynight
|
||||
|
||||
pre:
|
||||
# Install Starrynight unless it is cached
|
||||
- if [ ! -e ~/nvm/v0.10.33/bin/starrynight ]; then npm install -g starrynight; else echo "Starrynight seems to be cached"; fi;
|
||||
# Install Meteor
|
||||
- mkdir -p ${HOME}/.meteor
|
||||
# If Meteor is already cached, do not need to build it again.
|
||||
- if [ ! -e ${HOME}/.meteor/meteor ]; then curl https://install.meteor.com | /bin/sh; else echo "Meteor seems to be cached"; fi;
|
||||
# Link the meteor executable into /usr/bin
|
||||
- sudo ln -s $HOME/.meteor/meteor /usr/bin/meteor
|
||||
# Check if the helloworld directory already exists, if it doesn't, create the helloworld app
|
||||
# The following doesn't work, because it should be checking ${HOME}/active-entry/helloworld
|
||||
# - if [ ! -e ${HOME}/helloworld ]; then meteor create --release METEOR@1.1.0.3 helloworld; else echo "helloworld app seems to be cached"; fi;
|
||||
|
||||
override:
|
||||
- cd ${HOME} && meteor create --release METEOR@1.1.0.3 helloworld
|
||||
- cd ${HOME}/helloworld
|
||||
- cd ${HOME}/helloworld && ls -la
|
||||
- cd ${HOME}/helloworld && rm helloworld.*
|
||||
- cd ${HOME}/helloworld && mkdir packages && mkdir packages/active-entry
|
||||
- cp -R * ${HOME}/helloworld/packages/active-entry
|
||||
- cd ${HOME}/helloworld && meteor add anti:gagarin@0.4.11 accounts-base accounts-password session meteor-platform clinical:user-model clinical:active-entry
|
||||
- cd ${HOME}/helloworld && starrynight autoconfig
|
||||
- cd ${HOME}/helloworld && meteor list
|
||||
- cat tests/gagarin/activeEntryTests.js
|
||||
- ls -la
|
||||
- cd ~ && ls -la
|
||||
- cd ${HOME} && pwd
|
||||
- cd ${HOME} && ls -la
|
||||
- cd ${HOME}/helloworld && ls -la
|
||||
|
||||
## Customize test commands
|
||||
test:
|
||||
pre:
|
||||
- cd helloworld && meteor:
|
||||
background: true
|
||||
- sleep 30
|
||||
override:
|
||||
- cd ${HOME}/helloworld && starrynight run-tests --type package-verification
|
||||
|
||||
## Customize deployment commands
|
||||
#deployment:
|
||||
# production:
|
||||
# branch: master
|
||||
# commands:
|
||||
# - printf "<Meteor username>\n<Meteor password>\n" | meteor deploy circlecivelocity.meteor.com
|
||||
|
||||
## Custom notifications
|
||||
#notify:
|
||||
#webhooks:
|
||||
# A list of hashes representing hooks. Only the url field is supported.
|
||||
#- url: https://someurl.com/hooks/circle
|
||||
@ -1,48 +0,0 @@
|
||||
<template name="changePassword">
|
||||
<div id="changePassword" class="page entryPage" style="{{getOpacityWithCorner}}">
|
||||
<div class="content-scrollable">
|
||||
<div class="wrapper-auth">
|
||||
<div class="entryLogo" style="background-image: url('{{getLogoUrl}}')"></div>
|
||||
|
||||
<h1 id="changePasswordPageTitle" class="title-auth">Change Password</h1>
|
||||
<div id="changePasswordPageMessage" class="subtitle-auth" style="{{getChangePasswordMessageColor}}">{{getChangePasswordMessage}}</div>
|
||||
|
||||
<form>
|
||||
{{#if changePasswordErrorMessages}}
|
||||
<div id="errorMessages" class="list-errors">
|
||||
{{#each changePasswordErrorMessages}}
|
||||
<div class="alert alert-danger list-item">{{this}}</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="input-symbol">
|
||||
<input id="changePasswordPageOldPasswordInput" type="password" name="oldPassword" placeholder="Old Password" style="{{getPasswordStyling}}" />
|
||||
<span class="fa fa-lock" title="Password"></span>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<div class="input-symbol">
|
||||
<input id="changePasswordPagePasswordInput" type="password" name="password" placeholder="Password" style="{{getPasswordStyling}}" />
|
||||
<span class="fa fa-lock" title="Password"></span>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<div class="input-symbol">
|
||||
<input id="changePasswordPagePasswordConfirmInput" type="password" name="confirm" placeholder="Confirm Password" style="{{getConfirmPasswordStyling}}" />
|
||||
<span class="fa fa-lock" title="Confirm Password"></span>
|
||||
</div>
|
||||
|
||||
<br><br>
|
||||
|
||||
<button id="changePasswordButton" type="submit" class="btn-gray btn-main btn-large" style="{{getButtonColor}}">Change Password</button>
|
||||
<br><br>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -1,100 +0,0 @@
|
||||
//==========================================
|
||||
|
||||
Router.route('/changePassword', {
|
||||
name: "changePassword",
|
||||
template: "changePassword"
|
||||
});
|
||||
|
||||
|
||||
Template.changePassword.helpers({
|
||||
getChangePasswordMessageColor: function (){
|
||||
if (ActiveEntry.errorMessages.get('changePasswordError')) {
|
||||
return "color: #a94442; background-color: #f2dede; border-color: #ebccd1;"
|
||||
} else {
|
||||
return "color: black;"
|
||||
}
|
||||
},
|
||||
getChangePasswordMessage: function (){
|
||||
if (ActiveEntry.errorMessages.get('changePasswordError')) {
|
||||
return ActiveEntry.errorMessages.get('changePasswordError');
|
||||
} else {
|
||||
return Session.get('defaultSignInMessage');
|
||||
}
|
||||
},
|
||||
getPasswordStyling: function () {
|
||||
if (ActiveEntry.errorMessages.equals('password', "Password is required")) {
|
||||
return "border: 1px solid #a94442";
|
||||
} else if (ActiveEntry.errorMessages.equals('password', "Password is weak")) {
|
||||
return "border: 1px solid #f2dede";
|
||||
} else if (ActiveEntry.errorMessages.equals('password', "Password present")) {
|
||||
return "border: 1px solid green";
|
||||
} else {
|
||||
return "border: 1px solid gray";
|
||||
}
|
||||
},
|
||||
getConfirmPasswordStyling: function () {
|
||||
if (ActiveEntry.errorMessages.equals('confirm', "Password is required")) {
|
||||
return "border: 1px solid #a94442";
|
||||
} else if (ActiveEntry.errorMessages.equals('confirm', "Passwords do not match")) {
|
||||
return "border: 1px solid #a94442";
|
||||
} else if (ActiveEntry.errorMessages.equals('confirm', "Password is weak")) {
|
||||
return "border: 1px solid #f2dede";
|
||||
} else if (ActiveEntry.errorMessages.equals('confirm', "Passwords match")) {
|
||||
return "border: 1px solid green";
|
||||
} else {
|
||||
return "border: 1px solid gray";
|
||||
}
|
||||
},
|
||||
|
||||
changePasswordErrorMessages: function() {
|
||||
var allErrorMessages = Object.keys(ActiveEntry.errorMessages.all()).filter(function(key) {
|
||||
return (key === "password" || key === "confirm") && ActiveEntry.errorMessages.get(key);
|
||||
});
|
||||
|
||||
if (allErrorMessages.length > 0) {
|
||||
var errorMessage = ActiveEntry.errorMessages.get(allErrorMessages[0]);
|
||||
if (errorMessage) {
|
||||
return [errorMessage];
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Template.changePassword.events({
|
||||
'change, keyup #changePasswordPagePasswordInput': function (event, template) {
|
||||
var password = $('[name="password"]').val();
|
||||
var confirmPassword = $('[name="confirm"]').val();
|
||||
|
||||
ActiveEntry.verifyPassword(password);
|
||||
ActiveEntry.errorMessages.set('changePasswordError', null);
|
||||
},
|
||||
'change, keyup #changePasswordPagePasswordConfirmInput': function (event, template) {
|
||||
var password = $('[name="password"]').val();
|
||||
var confirmPassword = $('[name="confirm"]').val();
|
||||
|
||||
ActiveEntry.verifyConfirmPassword(password, confirmPassword);
|
||||
ActiveEntry.errorMessages.set('changePasswordError', null);
|
||||
},
|
||||
"submit": function (event, template) {
|
||||
event.preventDefault();
|
||||
|
||||
var oldPassword = $('[name="oldPassword"]').val();
|
||||
|
||||
var password = $('[name="password"]').val();
|
||||
var confirmPassword = $('[name="confirm"]').val();
|
||||
|
||||
ActiveEntry.verifyConfirmPassword(password, confirmPassword);
|
||||
ActiveEntry.errorMessages.set('changePasswordError', null);
|
||||
|
||||
|
||||
if (ActiveEntry.errorMessages.get('password') || ActiveEntry.errorMessages.get('confirm') || !oldPassword) {
|
||||
return;
|
||||
}
|
||||
|
||||
ActiveEntry.changePassword(oldPassword, password);
|
||||
|
||||
}
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user