Compare commits
83
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26da6b0013 | ||
|
|
156b093965 | ||
|
|
54dacbb91b | ||
|
|
6d18e7f1fe | ||
|
|
08ff214ea6 | ||
|
|
cac911f08e | ||
|
|
36952c401a | ||
|
|
b3781ac692 | ||
|
|
2174f4f2fd | ||
|
|
d033bd5995 | ||
|
|
c455253c0e | ||
|
|
ec1946e379 | ||
|
|
ad325fd83f | ||
|
|
a4112c46a5 | ||
|
|
e73d009c21 | ||
|
|
f826341631 | ||
|
|
f8b52d0fee | ||
|
|
0e78836d55 | ||
|
|
40bf1a2efd | ||
|
|
02c732aa15 | ||
|
|
c5f532159b | ||
|
|
b1df019c49 | ||
|
|
54b70e5fa4 | ||
|
|
5802cf18eb | ||
|
|
210c2e8d2c | ||
|
|
da318c9c8c | ||
|
|
903c41d26f | ||
|
|
ba261a0d54 | ||
|
|
3398a894a3 | ||
|
|
5a13194203 | ||
|
|
a2cc477a1a | ||
|
|
2e7a59f7f8 | ||
|
|
83d7d59954 | ||
|
|
163fee8941 | ||
|
|
f547fdf832 | ||
|
|
ac347849d0 | ||
|
|
54e0e32e22 | ||
|
|
690156d4b6 | ||
|
|
3b5fdb678a | ||
|
|
e7604c4418 | ||
|
|
71f11a4856 | ||
|
|
ae5d0587db | ||
|
|
fbc06329e2 | ||
|
|
86732c8186 | ||
|
|
a34d47c850 | ||
|
|
f758741950 | ||
|
|
29a470103a | ||
|
|
104343aad5 | ||
|
|
d8b4a4d4c0 | ||
|
|
2fd60f3109 | ||
|
|
08ce30e69c | ||
|
|
546f6bfe68 | ||
|
|
8e1f15e031 | ||
|
|
0d5d804741 | ||
|
|
ca735fa070 | ||
|
|
3d425f54cc | ||
|
|
7bc9b45853 | ||
|
|
5bd3af0cca | ||
|
|
d4aee36542 | ||
|
|
2a281da19f | ||
|
|
4631218dcb | ||
|
|
8b3e5dffb1 | ||
|
|
ef6819cf40 | ||
|
|
2f104b5e91 | ||
|
|
f256ac5a7d | ||
|
|
3a4ee9e346 | ||
|
|
1a9cfea365 | ||
|
|
9055f19fb5 | ||
|
|
bcbc5e4bbf | ||
|
|
408ba36f4f | ||
|
|
091cab49e0 | ||
|
|
4a09f33446 | ||
|
|
4095629310 | ||
|
|
91d2d31846 | ||
|
|
ff2c1cb2f1 | ||
|
|
727c0d8ba6 | ||
|
|
4b3994e788 | ||
|
|
571dd5848f | ||
|
|
2d48d0aa37 | ||
|
|
562d63fa74 | ||
|
|
1a6246f99b | ||
|
|
ce1a62a961 | ||
|
|
dd6acb2d03 |
No files matched your search
+79
-77
@@ -11,10 +11,13 @@ version: 2.1
|
||||
|
||||
orbs:
|
||||
codecov: codecov/codecov@1.0.5
|
||||
cypress: cypress-io/cypress@1.8.0
|
||||
|
||||
defaults: &defaults
|
||||
docker:
|
||||
- image: circleci/node:10.16.0
|
||||
environment:
|
||||
TERM: xterm # Enable colors in term
|
||||
working_directory: ~/repo
|
||||
|
||||
jobs:
|
||||
@@ -47,12 +50,12 @@ jobs:
|
||||
|
||||
# RUN TESTS
|
||||
- run:
|
||||
name: "JavaScript Test Suite"
|
||||
name: 'JavaScript Test Suite'
|
||||
command: yarn run test:unit:ci
|
||||
|
||||
# PLATFORM/VIEWER
|
||||
- run:
|
||||
name: "VIEWER: Combine report output"
|
||||
name: 'VIEWER: Combine report output'
|
||||
command: |
|
||||
viewerCov="/home/circleci/repo/platform/viewer/coverage"
|
||||
touch "${viewerCov}/reports"
|
||||
@@ -61,12 +64,12 @@ jobs:
|
||||
cat "${viewerCov}/lcov.info" >>"${viewerCov}/reports"
|
||||
echo "\<<\<<\<< EOF" >> "${viewerCov}/reports"
|
||||
- codecov/upload:
|
||||
file: "/home/circleci/repo/platform/viewer/coverage/reports"
|
||||
flags: "viewer"
|
||||
file: '/home/circleci/repo/platform/viewer/coverage/reports'
|
||||
flags: 'viewer'
|
||||
|
||||
# PLATFORM/CORE
|
||||
- run:
|
||||
name: "CORE: Combine report output"
|
||||
name: 'CORE: Combine report output'
|
||||
command: |
|
||||
coreCov="/home/circleci/repo/platform/core/coverage"
|
||||
touch "${coreCov}/reports"
|
||||
@@ -75,8 +78,13 @@ jobs:
|
||||
cat "${coreCov}/lcov.info" >> "${coreCov}/reports"
|
||||
echo "\<<\<<\<< EOF" >> "${coreCov}/reports"
|
||||
- codecov/upload:
|
||||
file: "/home/circleci/repo/platform/core/coverage/reports"
|
||||
flags: "core"
|
||||
file: '/home/circleci/repo/platform/core/coverage/reports'
|
||||
flags: 'core'
|
||||
|
||||
# Persist :+1:
|
||||
- persist_to_workspace:
|
||||
root: ~/repo
|
||||
paths: .
|
||||
|
||||
MERGE_UNIT_TESTS:
|
||||
<<: *defaults
|
||||
@@ -107,12 +115,12 @@ jobs:
|
||||
|
||||
# RUN TESTS
|
||||
- run:
|
||||
name: "JavaScript Test Suite"
|
||||
name: 'JavaScript Test Suite'
|
||||
command: yarn run test:unit:ci
|
||||
|
||||
# PLATFORM/VIEWER
|
||||
- run:
|
||||
name: "VIEWER: Combine report output"
|
||||
name: 'VIEWER: Combine report output'
|
||||
command: |
|
||||
viewerCov="/home/circleci/repo/platform/viewer/coverage"
|
||||
touch "${viewerCov}/reports"
|
||||
@@ -121,12 +129,12 @@ jobs:
|
||||
cat "${viewerCov}/lcov.info" >>"${viewerCov}/reports"
|
||||
echo "\<<\<<\<< EOF" >> "${viewerCov}/reports"
|
||||
- codecov/upload:
|
||||
file: "/home/circleci/repo/platform/viewer/coverage/reports"
|
||||
flags: "viewer"
|
||||
file: '/home/circleci/repo/platform/viewer/coverage/reports'
|
||||
flags: 'viewer'
|
||||
|
||||
# PLATFORM/CORE
|
||||
- run:
|
||||
name: "CORE: Combine report output"
|
||||
name: 'CORE: Combine report output'
|
||||
command: |
|
||||
coreCov="/home/circleci/repo/platform/core/coverage"
|
||||
touch "${coreCov}/reports"
|
||||
@@ -135,37 +143,14 @@ jobs:
|
||||
cat "${coreCov}/lcov.info" >> "${coreCov}/reports"
|
||||
echo "\<<\<<\<< EOF" >> "${coreCov}/reports"
|
||||
- codecov/upload:
|
||||
file: "/home/circleci/repo/platform/core/coverage/reports"
|
||||
flags: "core"
|
||||
file: '/home/circleci/repo/platform/core/coverage/reports'
|
||||
flags: 'core'
|
||||
|
||||
# Persist :+1:
|
||||
- persist_to_workspace:
|
||||
root: ~/repo
|
||||
paths: .
|
||||
|
||||
e2e_test:
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: cypress/base:8
|
||||
environment:
|
||||
## this enables colors in the output
|
||||
TERM: xterm
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/repo
|
||||
- restore_cache:
|
||||
name: Restore Yarn and Cypress 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: $(yarn bin)/cypress run --record
|
||||
# Shouldn't be needed if we're using a package cache that contains Cypress
|
||||
# Could do a check here, if it doesn't exist, install cypress?
|
||||
- run: yarn install
|
||||
- run: yarn run test:e2e:ci
|
||||
|
||||
npm_publish:
|
||||
<<: *defaults
|
||||
steps:
|
||||
@@ -176,11 +161,13 @@ jobs:
|
||||
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: git config --global user.email "danny.ri.brown+ohif-bot@gmail.com"
|
||||
- run: git config --global user.name "ohif-bot"
|
||||
- run:
|
||||
name: Publish using Semantic Release
|
||||
command: npx semantic-release --debug
|
||||
npx lerna version --allow-branch monorepo --conventional-commits
|
||||
--conventional-prerelease=* --create-release github
|
||||
- run: npx lerna publish from-package --canary --dist-tag canary
|
||||
|
||||
# Persist :+1:
|
||||
- persist_to_workspace:
|
||||
root: ~/repo
|
||||
@@ -196,8 +183,8 @@ jobs:
|
||||
command:
|
||||
mkdir ~/.ssh/ && echo -e "Host github.com\n\tStrictHostKeyChecking
|
||||
no\n" > ~/.ssh/config
|
||||
- run: git config --global user.email "gh-pages@localhost"
|
||||
- run: git config --global user.name "npm gh-pages"
|
||||
- run: git config --global user.email "danny.ri.brown+ohif-bot@gmail.com"
|
||||
- run: git config --global user.name "ohif-bot"
|
||||
- run: yarn global add gh-pages
|
||||
- run:
|
||||
name: Generate Docs
|
||||
@@ -235,29 +222,14 @@ jobs:
|
||||
docker push ohif/$IMAGE_NAME:latest
|
||||
fi
|
||||
|
||||
build_demo_site:
|
||||
deploy_demo_site:
|
||||
<<: *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" }}
|
||||
- attach_workspace:
|
||||
at: ~/repo
|
||||
# Build & Test
|
||||
- run:
|
||||
name: "Build Demo Site, Upload SourceMaps, Send Deploy Notification"
|
||||
name: 'Build Demo Site, Upload SourceMaps, Send Deploy Notification'
|
||||
command: |
|
||||
yarn build:demo:ci
|
||||
perl -i -pe 's#</head>#`cat .circleci/rollbar.html` #e' build/index.html
|
||||
@@ -311,6 +283,22 @@ workflows:
|
||||
- master
|
||||
- feature/*
|
||||
- hotfix/*
|
||||
# Cypress job added by `cypress-io` orb
|
||||
- cypress/run:
|
||||
pre-steps:
|
||||
- run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v' # Use yarn latest
|
||||
yarn: true
|
||||
store_artifacts: true
|
||||
start: yarn run dev
|
||||
wait-on: 'http://localhost:3000'
|
||||
no-workspace: true # Don't persist workspace
|
||||
working_directory: platform/viewer
|
||||
cache-key: 'yarn-packages-v1-{{ .Branch }}-{{ checksum "yarn.lock" }}'
|
||||
post-steps:
|
||||
- store_test_results:
|
||||
path: cypress/results
|
||||
requires:
|
||||
- PR_UNIT_TESTS
|
||||
|
||||
# MERGE TO MASTER
|
||||
cut_release:
|
||||
@@ -318,26 +306,40 @@ workflows:
|
||||
- MERGE_UNIT_TESTS:
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
||||
- e2e_test:
|
||||
only: monorepo
|
||||
# only: master
|
||||
# Cypress job added by `cypress-io` orb
|
||||
- cypress/run:
|
||||
pre-steps:
|
||||
- run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v' # Use yarn latest
|
||||
yarn: true
|
||||
record: true
|
||||
store_artifacts: true
|
||||
start: yarn run dev
|
||||
wait-on: 'http://localhost:3000'
|
||||
working_directory: platform/viewer
|
||||
cache-key: 'yarn-packages-v1-{{ .Branch }}-{{ checksum "yarn.lock" }}'
|
||||
post-steps:
|
||||
- store_test_results:
|
||||
path: cypress/results
|
||||
requires:
|
||||
- MERGE_UNIT_TESTS
|
||||
# Update NPM
|
||||
- npm_publish:
|
||||
requires:
|
||||
- e2e_test
|
||||
- cypress/run
|
||||
# Update docs.ohif.org
|
||||
- docs_publish:
|
||||
requires:
|
||||
- e2e_test
|
||||
# - docs_publish:
|
||||
# requires:
|
||||
# - cypress/run
|
||||
# Update hub.docker.org
|
||||
- docker_publish:
|
||||
requires:
|
||||
- npm_publish
|
||||
# - docker_publish:
|
||||
# requires:
|
||||
# - npm_publish
|
||||
# Update viewer.ohif.org
|
||||
- build_demo_site:
|
||||
requires:
|
||||
- e2e_test
|
||||
- demo_site_publish:
|
||||
requires:
|
||||
- build_demo_site
|
||||
# - build_demo_site:
|
||||
# requires:
|
||||
# - cypress/run
|
||||
# - demo_site_publish:
|
||||
# requires:
|
||||
# - build_demo_site
|
||||
File renamed without changes.
@@ -8,6 +8,7 @@ docs/_book
|
||||
src/version.js
|
||||
junit.xml
|
||||
coverage/
|
||||
.docz/
|
||||
|
||||
# YALC (for Erik)
|
||||
.yalc
|
||||
@@ -28,3 +29,6 @@ docker/dcm4che/dcm4che-arc
|
||||
|
||||
# Cypress test results
|
||||
cypress/videos/
|
||||
|
||||
# Locize settings
|
||||
.locize
|
||||
@@ -3,79 +3,28 @@
|
||||
# Set directory to location of this script
|
||||
# https://stackoverflow.com/a/3355423/1867984
|
||||
cd "$(dirname "$0")"
|
||||
cd .. # Up to project root
|
||||
|
||||
# Helpful to verify which versions we're using
|
||||
yarn -v
|
||||
node -v
|
||||
|
||||
# Install GitBook CLI
|
||||
echo 'Installing Gitbook CLI'
|
||||
yarn global add gitbook-cli
|
||||
npm install -g gitbook-cli
|
||||
|
||||
echo 'Running Gitbook installation'
|
||||
# Generate all version's GitBook output
|
||||
# For each directory in /docs ...
|
||||
cd ./../docs/
|
||||
for D in *; do
|
||||
if [ -d "${D}" ]; then
|
||||
|
||||
echo "Generating output for: ${D}"
|
||||
cd "${D}"
|
||||
|
||||
# Clear previous output, generate new
|
||||
rm -rf _book
|
||||
node /opt/buildhome/.nvm/versions/node/v10.16.0/lib/node_modules/gitbook-cli/bin/gitbook.js install
|
||||
node /opt/buildhome/.nvm/versions/node/v10.16.0/lib/node_modules/gitbook-cli/bin/gitbook.js build
|
||||
cd ..
|
||||
|
||||
fi
|
||||
done
|
||||
|
||||
# Move CNAME File into `latest`
|
||||
cp CNAME ./latest/_book/CNAME
|
||||
|
||||
# Create a history folder in our latest version's output
|
||||
mkdir ./latest/_book/history
|
||||
|
||||
# Move each version's files to latest's history folder
|
||||
for D in *; do
|
||||
# If it's a directory
|
||||
if [ -d "${D}" ]; then
|
||||
# If the directory name starts with `v` (v1, v2, etc.)
|
||||
if [ "${D}" == v* ] ; then
|
||||
|
||||
echo "Moving ${D} to the latest version's history folder"
|
||||
|
||||
mkdir "./latest/_book/history/${D}"
|
||||
cp -v -r "./${D}/_book"/* "./latest/_book/history/${D}"
|
||||
|
||||
fi
|
||||
fi
|
||||
done
|
||||
cd ..
|
||||
|
||||
# Build and copy the PWA Viewer into the demo directory
|
||||
mkdir ./docs/latest/_book/demo/
|
||||
|
||||
# Install build deps and all monorepo package dependencies. Yarn Workspaces
|
||||
# should also symlink all projects appropriately
|
||||
yarn install --no-ignore-optional --pure-lockfile
|
||||
|
||||
# Navigate to our Viewer project
|
||||
cd ./platform/viewer/
|
||||
dir
|
||||
ls
|
||||
|
||||
# Create a Versions File
|
||||
# node -p -e '"export default "' + require(\"./../package.json\").version + '";"' > src/version.js
|
||||
yarn run version
|
||||
# Copy over wado-image-loader codecs and worker file
|
||||
cp ./../../node_modules/cornerstone-wado-image-loader/dist/*.min.js* public -v
|
||||
# Build using react-scripts
|
||||
# npx cross-env PUBLIC_URL=/demo REACT_APP_CONFIG=config/netlify.js react-scripts --max_old_space_size=4096 build
|
||||
# Build using WebPack
|
||||
# TODO: consume public/config correctly instead of hardcode
|
||||
npx webpack --config config/webpack.prod.js --mode production --env.production
|
||||
# Copy output to the folder that is our publish target
|
||||
npx cpx "dist/**/*" ./../../docs/latest/_book/demo --verbose
|
||||
# Build && Move PWA Output
|
||||
yarn run build:ci
|
||||
mkdir -p ./.netlify/www/pwa
|
||||
mv platform/viewer/dist/* .netlify/www/pwa -v
|
||||
|
||||
# Build && Move script output
|
||||
# yarn run build:package
|
||||
|
||||
echo 'Nothing left to see here. Go home, folks.'
|
||||
|
||||
# Build using react-scripts
|
||||
# npx cross-env PUBLIC_URL=/demo REACT_APP_CONFIG=config/netlify.js react-scripts --max_old_space_size=4096 build
|
||||
@@ -0,0 +1,14 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>OHIF Viewer: Deploy Preview</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World</h1>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/pwa">PWA</a>
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
+74
-37
@@ -1,53 +1,75 @@
|
||||
const path = require("path");
|
||||
const ExtractCssChunks = require("extract-css-chunks-webpack-plugin");
|
||||
|
||||
const SRC_DIR = path.join(__dirname, "../src");
|
||||
const PUBLIC_DIR = path.join(__dirname, "../public");
|
||||
const DIST_DIR = path.join(__dirname, "../dist");
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const autoprefixer = require('autoprefixer');
|
||||
// const ExtractCssChunks = require('extract-css-chunks-webpack-plugin');
|
||||
|
||||
module.exports = (env, argv, { SRC_DIR, DIST_DIR }) => {
|
||||
return {
|
||||
entry: {
|
||||
app: `${SRC_DIR}/index.js`
|
||||
bundle: `${SRC_DIR}/index.js`,
|
||||
},
|
||||
context: SRC_DIR,
|
||||
module: {
|
||||
rules: [
|
||||
/**
|
||||
* JSX
|
||||
*/
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
exclude: [/node_modules/, /packages\\extension/],
|
||||
loader: "babel-loader",
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
// Find babel.config.js in monorepo root
|
||||
// https://babeljs.io/docs/en/options#rootmode
|
||||
rootMode: "upward",
|
||||
rootMode: 'upward',
|
||||
presets: [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
'@babel/preset-env',
|
||||
{
|
||||
// Do not transform ES6 modules to another format.
|
||||
// Webpack will take care of that.
|
||||
modules: false
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
modules: false,
|
||||
targets: {
|
||||
ie: '11',
|
||||
},
|
||||
// https://babeljs.io/docs/en/babel-preset-env#usebuiltins
|
||||
useBuiltIns: 'usage',
|
||||
// https://babeljs.io/docs/en/babel-preset-env#corejs
|
||||
corejs: 3,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
/**
|
||||
* Stylus to CSS
|
||||
* CSS to CommonJS
|
||||
* Style nodes from JS Strings
|
||||
*/
|
||||
{
|
||||
test: /\.styl$/,
|
||||
use: [
|
||||
{ loader: 'style-loader' },
|
||||
{ loader: 'css-loader' },
|
||||
{ loader: 'stylus-loader' },
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
"style-loader",
|
||||
ExtractCssChunks.loader,
|
||||
{ loader: "css-loader", options: { importLoaders: 1 } },
|
||||
'style-loader',
|
||||
// ExtractCssChunks.loader,
|
||||
{ loader: 'css-loader', options: { importLoaders: 1 } },
|
||||
{
|
||||
loader: "postcss-loader",
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
config: {
|
||||
path: "./postcss.config.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
path: './postcss.config.js',
|
||||
},
|
||||
plugins: () => [autoprefixer('last 2 version', 'ie >= 11')],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
/**
|
||||
* This allows us to include web workers in our bundle, and VTK.js
|
||||
@@ -59,10 +81,10 @@ module.exports = (env, argv, { SRC_DIR, DIST_DIR }) => {
|
||||
include: /vtk\.js[\/\\]Sources/,
|
||||
use: [
|
||||
{
|
||||
loader: "worker-loader",
|
||||
options: { inline: true, fallback: false }
|
||||
}
|
||||
]
|
||||
loader: 'worker-loader',
|
||||
options: { inline: true, fallback: false },
|
||||
},
|
||||
],
|
||||
},
|
||||
/**
|
||||
* This is exclusively used by `vtk.js` to bundle glsl files.
|
||||
@@ -70,21 +92,36 @@ module.exports = (env, argv, { SRC_DIR, DIST_DIR }) => {
|
||||
{
|
||||
test: /\.glsl$/i,
|
||||
include: /vtk\.js[\/\\]Sources/,
|
||||
loader: "shader-loader"
|
||||
}
|
||||
]
|
||||
loader: 'shader-loader',
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
// Which directories to search when resolving modules
|
||||
modules: [
|
||||
path.resolve(__dirname, "../node_modules"),
|
||||
path.resolve(__dirname, "../../../node_modules"),
|
||||
SRC_DIR
|
||||
// Modules specific to this package
|
||||
path.resolve(__dirname, '../node_modules'),
|
||||
// Hoisted Yarn Workspace Modules
|
||||
path.resolve(__dirname, '../../../node_modules'),
|
||||
SRC_DIR,
|
||||
],
|
||||
// Attempt to resolve these extensions in order.
|
||||
extensions: [".js", ".jsx", ".json", "*"],
|
||||
extensions: ['.js', '.jsx', '.json', '*'],
|
||||
// symlinked resources are resolved to their real path, not their symlinked location
|
||||
symlinks: true
|
||||
}
|
||||
symlinks: true,
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
|
||||
'process.env.DEBUG': JSON.stringify(process.env.DEBUG),
|
||||
'process.env.APP_CONFIG': JSON.stringify(process.env.APP_CONFIG || ''),
|
||||
'process.env.PUBLIC_URL': JSON.stringify(process.env.PUBLIC_URL || ''),
|
||||
}),
|
||||
],
|
||||
// Fix: https://github.com/webpack-contrib/css-loader/issues/447#issuecomment-285598881
|
||||
// For issue in cornerstone-wado-image-loader
|
||||
node: {
|
||||
fs: 'empty',
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -124,11 +124,12 @@ These commands are available from the root directory. Each project directory als
|
||||
| -------------------- | ------------------------------------------------------------- |
|
||||
| **Develop** | |
|
||||
| `dev` or `start` | Default development experience for Viewer |
|
||||
| `dev:<package-name>` | Replace with `core`, `ui`, `i18n`, `cornerstone`, `vtk`, etc. |
|
||||
| `dev:project <package-name>` | Replace with `core`, `ui`, `i18n`, `cornerstone`, `vtk`, etc. |
|
||||
| `test:unit` | Jest multi-project test runner; overall coverage |
|
||||
| **Deploy** | |
|
||||
| `build`* | Builds production output for our PWA Viewer |
|
||||
| `build:package`* | Builds commonjs bundles for all projects |
|
||||
| `build:package`* | Builds production `commonjs` output for our Viewer |
|
||||
| `build:package-all`* | Builds commonjs bundles for all projects |
|
||||
|
||||
|
||||
\* - For more information on our different builds, check out our [Deploy Docs][deployment-docs]
|
||||
|
||||
+30
-24
@@ -1,29 +1,35 @@
|
||||
const aliases = require("./aliases.config");
|
||||
const path = require("path");
|
||||
const aliases = require('./aliases.config');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
// https://babeljs.io/docs/en/options#babelrcroots
|
||||
// Also specified in .webpack/webpack.common.js
|
||||
// https://github.com/zloirock/core-js/blob/master/docs/2019-03-19-core-js-3-babel-and-a-look-into-the-future.md
|
||||
presets: [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
'@babel/preset-env',
|
||||
{
|
||||
targets: {
|
||||
ie: "11"
|
||||
}
|
||||
}
|
||||
ie: '11',
|
||||
},
|
||||
// https://babeljs.io/docs/en/babel-preset-env#usebuiltins
|
||||
useBuiltIns: 'usage',
|
||||
// https://babeljs.io/docs/en/babel-preset-env#corejs
|
||||
corejs: 3,
|
||||
},
|
||||
],
|
||||
"@babel/preset-react"
|
||||
'@babel/preset-react',
|
||||
],
|
||||
babelrcRoots: ["./platform/*", "./extensions/*"],
|
||||
// https://babeljs.io/docs/en/options#babelrcroots
|
||||
babelrcRoots: ['./platform/*', './extensions/*'],
|
||||
plugins: [
|
||||
"inline-react-svg",
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
"@babel/plugin-proposal-object-rest-spread",
|
||||
"@babel/plugin-syntax-dynamic-import",
|
||||
"@babel/plugin-transform-regenerator",
|
||||
"@babel/plugin-transform-runtime",
|
||||
'inline-react-svg',
|
||||
'@babel/plugin-proposal-class-properties',
|
||||
'@babel/plugin-proposal-object-rest-spread',
|
||||
'@babel/plugin-syntax-dynamic-import',
|
||||
'@babel/plugin-transform-regenerator',
|
||||
'@babel/plugin-transform-runtime',
|
||||
[
|
||||
"module-resolver",
|
||||
'module-resolver',
|
||||
{
|
||||
// https://github.com/tleunen/babel-plugin-module-resolver/issues/338
|
||||
// There seem to be a bug with module-resolver with a mono-repo setup:
|
||||
@@ -33,18 +39,18 @@ module.exports = {
|
||||
// This will return undefined if aliases has no key for the sourcePath,
|
||||
// in which case module-resolver will fallback on its default behaviour.
|
||||
return aliases[sourcePath];
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
env: {
|
||||
debug: {
|
||||
sourceMaps: "inline",
|
||||
retainLines: true
|
||||
sourceMaps: 'inline',
|
||||
retainLines: true,
|
||||
},
|
||||
build: {
|
||||
ignore: ["**/*.test.jsx", "**/*.test.js", "__snapshots__", "__tests__"]
|
||||
}
|
||||
}
|
||||
ignore: ['**/*.test.jsx', '**/*.test.js', '__snapshots__', '__tests__'],
|
||||
},
|
||||
},
|
||||
// ignore: ["node_modules"]
|
||||
};
|
||||
@@ -1,11 +1,5 @@
|
||||
# Google Cloud Healthcare
|
||||
|
||||
> ATTENTION: The original documentation for this integration lives in the legacy
|
||||
> `version 1` Meteor documentation. You can
|
||||
> [find it here](/history/v1/connecting-to-image-archives/google-cloud-healthcare.html).
|
||||
> These docs will mirror the Meteor documentation until our `React`
|
||||
> implementation has been updated to work with Google Cloud Healthcare.
|
||||
|
||||
> The [Google Cloud Healthcare API](https://cloud.google.com/healthcare/) is a
|
||||
> powerful option for storing medical imaging data in the cloud.
|
||||
|
||||
@@ -16,10 +10,7 @@ store their data in the cloud. It offers an
|
||||
[almost-entirely complete DICOMWeb API](https://cloud.google.com/healthcare/docs/dicom)
|
||||
which requires tokens generated via the
|
||||
[OAuth 2.0 Sign In flow](https://developers.google.com/identity/sign-in/web/sign-in).
|
||||
Images can even be transcoded on the fly if this is desired. The Cloud
|
||||
Healthcare API is a very attractive option because it allows us to avoid
|
||||
deploying the Meteor server entirely. We can just deploy OHIF as a client-only
|
||||
static site application.
|
||||
Images can even be transcoded on the fly if this is desired.
|
||||
|
||||
## Setup a Google Cloud Healthcare Project
|
||||
|
||||
@@ -44,10 +35,10 @@ static site application.
|
||||
- Choose the "Web Application" type
|
||||
- Set up an
|
||||
[OAuth 2.0 Client ID](https://support.google.com/cloud/answer/6158849?hl=en)
|
||||
- Add your domain (e.g. `http://localhost:3000`) to Authorized JavaScript
|
||||
- Add your domain (e.g. `http://localhost:5000`) to Authorized JavaScript
|
||||
origins.
|
||||
- Add your domain, plus `_oauth/google` (e.g.
|
||||
`http://localhost:3000/_oauth/google`) to Authorized Redirect URIs.
|
||||
- Add your domain, plus `callback` (e.g.
|
||||
`http://localhost:5000/callback`) to Authorized Redirect URIs.
|
||||
- Save your Client ID for later.
|
||||
|
||||
- (Optional): Enable Public Datasets that are being hosted by Google:
|
||||
@@ -55,70 +46,26 @@ static site application.
|
||||
|
||||
## Run the viewer with your OAuth Client ID
|
||||
|
||||
1. Open the `config/oidc-googleCloud.json` file and change `YOURCLIENTID` to
|
||||
1. Open the `config/google.js` file and change `YOURCLIENTID` to
|
||||
your Client ID value.
|
||||
1. Run the OHIF Viewer using the oidc-googleCloud.json configuration file
|
||||
1. Run the OHIF Viewer using the config/google.js configuration file
|
||||
|
||||
```bash
|
||||
cd OHIFViewer
|
||||
METEOR_PACKAGE_DIRS="../Packages" meteor npm install
|
||||
METEOR_PACKAGE_DIRS="../Packages" meteor --settings ../config/oidc-googleCloud.json
|
||||
yarn install
|
||||
REACT_APP_CONFIG=config/google.js yarn run dev
|
||||
```
|
||||
|
||||
## Running via Docker
|
||||
|
||||
OHIF is also providing a Docker container which can connect to Google Cloud
|
||||
Healthcare with a Client ID which is provided at runtime. This is a very simple
|
||||
method to get up and running. Internally, the container is running
|
||||
[Nginx](https://nginx.org/) to serve the
|
||||
[Standalone Viewer](../standalone-viewer/usage.md).
|
||||
The OHIF Viewer Docker container can be connected to Google Cloud
|
||||
Healthcare by providing a Client ID at runtime. This is a very simple
|
||||
method to get up and running.
|
||||
|
||||
1. Install Docker (https://www.docker.com/)
|
||||
1. Run the Docker container, providing a Client ID as an environment variable.
|
||||
Client IDs look like `xyz.apps.googleusercontent.com`.
|
||||
|
||||
```bash
|
||||
docker run --env CLIENT_ID=$CLIENT_ID --publish 3000:80 ohif/viewer-google-cloud:latest
|
||||
```
|
||||
|
||||
## Building the ohif/viewer-google-cloud Docker Image
|
||||
|
||||
The
|
||||
[ohif/viewer-google-cloud](https://cloud.docker.com/u/ohif/repository/docker/ohif/viewer-google-cloud)
|
||||
Docker image is built as follows. The Dockerfile and nginx.conf are in the
|
||||
`/dockersupport/viewer-google-cloud` folder.
|
||||
|
||||
1. [Install Meteor](https://www.meteor.com/install)
|
||||
1. Clone the repository
|
||||
|
||||
```bash
|
||||
git clone https://github.com/OHIF/Viewers.git
|
||||
cd Viewers
|
||||
```
|
||||
|
||||
1. Install meteor-build-client-fixed2 so you can build the Standalone Viewer
|
||||
|
||||
```bash
|
||||
npm install -g meteor-build-client-fixed2
|
||||
```
|
||||
|
||||
1. Build the Standalone client-only OHIF Viewer
|
||||
|
||||
```bash
|
||||
cd OHIFViewer/
|
||||
METEOR_PACKAGE_DIRS="../Packages" meteor npm install
|
||||
METEOR_PACKAGE_DIRS="../Packages" meteor-build-client-fixed2 ../dockersupport/viewer-google-cloud/build -s ../config/oidc.json
|
||||
```
|
||||
|
||||
1. Build the Docker image
|
||||
|
||||
```bash
|
||||
cd ../dockersupport/viewer-google-cloud
|
||||
docker build -t ohif/viewer-google-cloud .
|
||||
```
|
||||
|
||||
1. Run the Docker image using an OAuth Client ID
|
||||
|
||||
```bash
|
||||
docker run --env CLIENT_ID={$someID}.apps.googleusercontent.com --publish 3000:80 ohif/viewer-google-cloud
|
||||
docker run --env CLIENT_ID=$CLIENT_ID --publish 5000:80 ohif/viewer:latest
|
||||
```
|
||||
@@ -88,7 +88,6 @@ _/public/config/default.js_
|
||||
```js
|
||||
window.config = {
|
||||
routerBasename: '/',
|
||||
relativeWebWorkerScriptsPath: '',
|
||||
servers: {
|
||||
dicomWeb: [
|
||||
{
|
||||
|
||||
@@ -50,8 +50,6 @@ include tags. Here's how it works:
|
||||
window.config = {
|
||||
// default: '/'
|
||||
routerBasename: '/',
|
||||
// default: ''
|
||||
relativeWebWorkerScriptsPath: '',
|
||||
servers: {
|
||||
dicomWeb: [
|
||||
{
|
||||
|
||||
@@ -24,7 +24,6 @@ _/public/config/default.js_
|
||||
```js
|
||||
window.config = {
|
||||
routerBasename: '/',
|
||||
relativeWebWorkerScriptsPath: '',
|
||||
servers: {
|
||||
dicomWeb: [
|
||||
{
|
||||
|
||||
@@ -104,7 +104,6 @@ like:
|
||||
```js
|
||||
window.config = {
|
||||
routerBasename: '/',
|
||||
relativeWebWorkerScriptsPath: '',
|
||||
servers: {
|
||||
dicomWeb: [
|
||||
{
|
||||
|
||||
@@ -1074,10 +1074,10 @@ gitbook-plugin-sitemap@^1.2.0:
|
||||
dependencies:
|
||||
sitemap "1.5.0"
|
||||
|
||||
gitbook-plugin-theme-cornerstone@^1.1.2:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/gitbook-plugin-theme-cornerstone/-/gitbook-plugin-theme-cornerstone-1.1.3.tgz#320e1d688eaf27dbf8d580f285509b55984437fd"
|
||||
integrity sha512-fURj67XGQ5rZPj8LXbwEviMxLfWgN/s08t9Wnp1dQqffBUJwsLe00R/IeecOjsQHJ3Gvb8GjbXJ6qzIDGu5hPA==
|
||||
gitbook-plugin-theme-cornerstone@^1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/gitbook-plugin-theme-cornerstone/-/gitbook-plugin-theme-cornerstone-1.1.4.tgz#bc21b65acee2ac67e2ddb0986442ec448fe0c7fb"
|
||||
integrity sha512-BADgFyEKhkc0pPSBRwXa5VU2UoYQkd2cRwjrtjHyV6w4h/M7uyeWYFOcsgi2ju3rpHRCwF8lMg/TtDdAV8V1SQ==
|
||||
|
||||
gitbook-plugin-versions@^2.1.4:
|
||||
version "2.1.4"
|
||||
@@ -1608,9 +1608,9 @@ lodash.map@^4.4.0:
|
||||
integrity sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=
|
||||
|
||||
lodash.merge@^4.4.0:
|
||||
version "4.6.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54"
|
||||
integrity sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==
|
||||
version "4.6.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
|
||||
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
|
||||
|
||||
lodash.pad@^4.1.0:
|
||||
version "4.5.1"
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
const path = require('path');
|
||||
const merge = require('webpack-merge');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.common.js');
|
||||
|
||||
//
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR });
|
||||
|
||||
return merge(commonConfig, {
|
||||
// https://webpack.js.org/configuration/mode/#mode-development
|
||||
mode: 'development',
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
const merge = require('webpack-merge');
|
||||
const path = require('path');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.common.js');
|
||||
const pkg = require('./../package.json');
|
||||
|
||||
const ROOT_DIR = path.join(__dirname, './..');
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR });
|
||||
|
||||
return merge(commonConfig, {
|
||||
// https://webpack.js.org/configuration/mode/#mode-production
|
||||
mode: 'production',
|
||||
devtool: 'source-map',
|
||||
stats: {
|
||||
colors: true,
|
||||
hash: true,
|
||||
timings: true,
|
||||
assets: true,
|
||||
chunks: false,
|
||||
chunkModules: false,
|
||||
modules: false,
|
||||
children: false,
|
||||
warnings: true,
|
||||
},
|
||||
optimization: {
|
||||
minimize: true,
|
||||
sideEffects: true,
|
||||
},
|
||||
output: {
|
||||
path: ROOT_DIR,
|
||||
library: 'ohifExtensionCornerstone',
|
||||
libraryTarget: 'umd',
|
||||
filename: pkg.main,
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,5 +1,63 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## 0.0.39-alpha.8 (2019-08-14)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.0.39-alpha.7](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@0.0.39-alpha.6...@ohif/extension-cornerstone@0.0.39-alpha.7) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.0.39-alpha.6](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@0.0.39-alpha.5...@ohif/extension-cornerstone@0.0.39-alpha.6) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.0.39-alpha.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@0.0.39-alpha.4...@ohif/extension-cornerstone@0.0.39-alpha.5) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.0.39-alpha.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@0.0.39-alpha.3...@ohif/extension-cornerstone@0.0.39-alpha.4) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.0.39-alpha.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@0.0.39-alpha.2...@ohif/extension-cornerstone@0.0.39-alpha.3) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-cornerstone
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const ExtractCssChunks = require('extract-css-chunks-webpack-plugin');
|
||||
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
return {
|
||||
entry: {
|
||||
app: `${SRC_DIR}/index.js`,
|
||||
},
|
||||
context: SRC_DIR,
|
||||
resolve: {
|
||||
extensions: ['.js', '.jsx', '.json', '*'],
|
||||
symlinks: true,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(js|jsx)$/,
|
||||
exclude: [/node_modules/],
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
// Find babel.config.js in monorepo root
|
||||
// https://babeljs.io/docs/en/options#rootmode
|
||||
rootMode: 'upward',
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
// Do not transform ES6 modules to another format.
|
||||
// Webpack will take care of that.
|
||||
modules: false,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
'style-loader',
|
||||
ExtractCssChunks.loader,
|
||||
{ loader: 'css-loader', options: { importLoaders: 1 } },
|
||||
{
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
config: {
|
||||
path: './postcss.config.js',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new webpack.EnvironmentPlugin(['NODE_ENV']),
|
||||
new ExtractCssChunks({
|
||||
filename: '[name].css',
|
||||
chunkFilename: '[id].css',
|
||||
// hot: true /* only necessary if hot reloading not function*/
|
||||
}),
|
||||
],
|
||||
};
|
||||
};
|
||||
@@ -1,64 +0,0 @@
|
||||
const merge = require('webpack-merge');
|
||||
const path = require('path');
|
||||
const common = require('./webpack.common');
|
||||
const pkg = require('./../package.json');
|
||||
|
||||
const ROOT_DIR = path.join(__dirname, './..');
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const commonConfig = common(env, argv);
|
||||
|
||||
return merge(commonConfig, {
|
||||
mode: 'production',
|
||||
stats: {
|
||||
colors: false,
|
||||
hash: true,
|
||||
timings: true,
|
||||
assets: true,
|
||||
chunks: true,
|
||||
chunkModules: true,
|
||||
modules: true,
|
||||
children: true,
|
||||
warnings: true,
|
||||
},
|
||||
optimization: {
|
||||
minimize: true,
|
||||
sideEffects: true,
|
||||
},
|
||||
output: {
|
||||
path: ROOT_DIR,
|
||||
library: 'ohifCornerstoneExtension',
|
||||
libraryTarget: 'umd',
|
||||
filename: pkg.main,
|
||||
auxiliaryComment: 'Test Comment',
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(gif|jpe?g|png|svg)$/i,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 8192,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(ttf|eot|woff|woff2)$/i,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 50000,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-cornerstone",
|
||||
"version": "0.0.39-alpha.2",
|
||||
"version": "0.0.39-alpha.8",
|
||||
"description": "OHIF extension for Cornerstone",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
@@ -19,10 +19,11 @@
|
||||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "webpack --config config/webpack.prod.js -d",
|
||||
"dev": "webpack --config .webpack/webpack.dev.js --watch --debug --output-pathinfo",
|
||||
"dev:cornerstone": "yarn run dev",
|
||||
"build": "webpack --config .webpack/webpack.prod.js",
|
||||
"build:package": "yarn run build",
|
||||
"prepublishOnly": "yarn run build",
|
||||
"dev": "webpack --config config/webpack.prod.js -w -d",
|
||||
"start": "yarn run dev"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -31,7 +32,7 @@
|
||||
"cornerstone-core": "^2.2.8",
|
||||
"cornerstone-math": "^0.1.8",
|
||||
"cornerstone-tools": "^3.1.0",
|
||||
"cornerstone-wado-image-loader": "^2.2.3",
|
||||
"cornerstone-wado-image-loader": "^3.0.0",
|
||||
"dcmjs": "^0.3.8",
|
||||
"dicom-parser": "^1.8.3",
|
||||
"hammerjs": "^2.0.8",
|
||||
@@ -43,10 +44,9 @@
|
||||
"redux": "^4.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.2.0",
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"classnames": "^2.2.6",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"react-cornerstone-viewport": "0.1.30"
|
||||
},
|
||||
"gitHead": "a5baa9228c0eda0df880136bde4420d78e6f8706"
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,24 @@
|
||||
import CornerstoneViewport from "react-cornerstone-viewport";
|
||||
import OHIF from "@ohif/core";
|
||||
import { connect } from "react-redux";
|
||||
import throttle from "lodash.throttle";
|
||||
import CornerstoneViewport from 'react-cornerstone-viewport';
|
||||
import OHIF from '@ohif/core';
|
||||
import { connect } from 'react-redux';
|
||||
import throttle from 'lodash.throttle';
|
||||
|
||||
const { setViewportActive, setViewportSpecificData } = OHIF.redux.actions;
|
||||
const {
|
||||
onAdded,
|
||||
onRemoved,
|
||||
onModified,
|
||||
} = OHIF.measurements.MeasurementHandlers;
|
||||
|
||||
// TODO: Transition to enums for the action names so that we can ensure they stay up to date
|
||||
// everywhere they're used.
|
||||
const MEASUREMENT_ACTION_MAP = {
|
||||
added: onAdded,
|
||||
removed: onRemoved,
|
||||
modified: throttle(event => {
|
||||
return onModified(event);
|
||||
}, 300),
|
||||
};
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
let dataFromStore;
|
||||
@@ -37,7 +52,7 @@ const mapStateToProps = (state, ownProps) => {
|
||||
enableStackPrefetch: isActive,
|
||||
//stack: viewportSpecificData.stack,
|
||||
cineToolData: viewportSpecificData.cine,
|
||||
viewport: viewportSpecificData.viewport
|
||||
viewport: viewportSpecificData.viewport,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -64,28 +79,15 @@ const mapDispatchToProps = (dispatch, ownProps) => {
|
||||
dispatch(
|
||||
setViewportSpecificData(viewportIndex, {
|
||||
// TODO: Hack to make sure our plugin info is available from the outset
|
||||
plugin: "cornerstone",
|
||||
dom: enabledElement
|
||||
plugin: 'cornerstone',
|
||||
dom: enabledElement,
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
onMeasurementsChanged: (event, action) => {
|
||||
const {
|
||||
onAdded,
|
||||
onRemoved,
|
||||
onModified
|
||||
} = OHIF.measurements.MeasurementHandlers;
|
||||
const actions = {
|
||||
added: onAdded,
|
||||
removed: onRemoved,
|
||||
modified: throttle(event => {
|
||||
return onModified(event);
|
||||
}, 300)
|
||||
};
|
||||
|
||||
return actions[action](event);
|
||||
}
|
||||
return MEASUREMENT_ACTION_MAP[action](event);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -202,6 +202,10 @@ class OHIFCornerstoneViewport extends Component {
|
||||
frameIndex
|
||||
} = displaySet;
|
||||
|
||||
if (!studyInstanceUid || !displaySetInstanceUid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sopClassUids && sopClassUids.length > 1) {
|
||||
console.warn(
|
||||
"More than one SOPClassUid in the same series is not yet supported."
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import cornerstone from 'cornerstone-core';
|
||||
import cornerstoneTools from 'cornerstone-tools';
|
||||
import OHIF from '@ohif/core';
|
||||
const scroll = cornerstoneTools.import('util/scroll');
|
||||
|
||||
const actions = {
|
||||
rotateViewport: ({ viewports, rotation }) => {
|
||||
@@ -89,15 +91,76 @@ const actions = {
|
||||
// TODO
|
||||
console.warn('updateDisplaySet: ', direction);
|
||||
},
|
||||
clearAnnotations: () => {
|
||||
console.warn('clearAnnotations: not yet implemented');
|
||||
// const toolState =
|
||||
// cornerstoneTools.globalImageIdSpecificToolStateManager.toolState;
|
||||
// if (!toolState) return;
|
||||
// Object.keys(toolState).forEach(imageId => {
|
||||
// if (!cornerstoneImageId || cornerstoneImageId === imageId)
|
||||
// delete toolState[imageId];
|
||||
// });
|
||||
clearAnnotations: ({ viewports }) => {
|
||||
const element = _getActiveViewportEnabledElement(
|
||||
viewports.viewportSpecificData,
|
||||
viewports.activeViewportIndex
|
||||
);
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
const enabledElement = cornerstone.getEnabledElement(element);
|
||||
if (!enabledElement || !enabledElement.image) {
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
toolState,
|
||||
} = cornerstoneTools.globalImageIdSpecificToolStateManager;
|
||||
if (
|
||||
!toolState ||
|
||||
toolState.hasOwnProperty(enabledElement.image.imageId) === false
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const imageIdToolState = toolState[enabledElement.image.imageId];
|
||||
|
||||
const measurementsToRemove = [];
|
||||
|
||||
Object.keys(imageIdToolState).forEach(toolType => {
|
||||
const { data } = imageIdToolState[toolType];
|
||||
|
||||
data.forEach(measurementData => {
|
||||
const { _id, lesionNamingNumber, measurementNumber } = measurementData;
|
||||
if (!_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
measurementsToRemove.push({
|
||||
toolType,
|
||||
_id,
|
||||
lesionNamingNumber,
|
||||
measurementNumber,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
measurementsToRemove.forEach(measurementData => {
|
||||
OHIF.measurements.MeasurementHandlers.onRemoved({
|
||||
detail: {
|
||||
toolType: measurementData.toolType,
|
||||
measurementData,
|
||||
},
|
||||
});
|
||||
});
|
||||
},
|
||||
nextImage: ({ viewports }) => {
|
||||
const enabledElement = _getActiveViewportEnabledElement(
|
||||
viewports.viewportSpecificData,
|
||||
viewports.activeViewportIndex
|
||||
);
|
||||
|
||||
scroll(enabledElement, 1);
|
||||
},
|
||||
previousImage: ({ viewports }) => {
|
||||
const enabledElement = _getActiveViewportEnabledElement(
|
||||
viewports.viewportSpecificData,
|
||||
viewports.activeViewportIndex
|
||||
);
|
||||
|
||||
scroll(enabledElement, -1);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -147,8 +210,21 @@ const definitions = {
|
||||
storeContexts: ['viewports'],
|
||||
options: {},
|
||||
},
|
||||
// TODO: Clear Annotations
|
||||
// TODO: Next/Previous image
|
||||
clearAnnotations: {
|
||||
commandFn: actions.clearAnnotations,
|
||||
storeContexts: ['viewports'],
|
||||
options: {},
|
||||
},
|
||||
nextImage: {
|
||||
commandFn: actions.nextImage,
|
||||
storeContexts: ['viewports'],
|
||||
options: {},
|
||||
},
|
||||
previousImage: {
|
||||
commandFn: actions.previousImage,
|
||||
storeContexts: ['viewports'],
|
||||
options: {},
|
||||
},
|
||||
// TODO: First/Last image
|
||||
// Next/Previous series/DisplaySet
|
||||
nextViewportDisplaySet: {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// -- ACTIVE_ROUTE::VIEWER
|
||||
// -- ACTIVE_VIEWPORT::CORNERSTONE
|
||||
// setToolActive commands should receive the button event that triggered
|
||||
// so we can do the "bind to this butyon" magic
|
||||
// so we can do the "bind to this button" magic
|
||||
|
||||
const TOOLBAR_BUTTON_TYPES = {
|
||||
COMMAND: 'command',
|
||||
@@ -98,6 +98,98 @@ const definitions = [
|
||||
behavior: 'CINE',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'More',
|
||||
label: 'More',
|
||||
icon: 'ellipse-circle',
|
||||
buttons: [
|
||||
{
|
||||
id: 'Magnify',
|
||||
label: 'Magnify',
|
||||
icon: 'circle',
|
||||
//
|
||||
type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
|
||||
commandName: 'setToolActive',
|
||||
commandOptions: { toolName: 'Magnify' },
|
||||
},
|
||||
{
|
||||
id: 'WwwcRegion',
|
||||
label: 'ROI Window',
|
||||
icon: 'stop',
|
||||
//
|
||||
type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
|
||||
commandName: 'setToolActive',
|
||||
commandOptions: { toolName: 'WwwcRegion' },
|
||||
},
|
||||
{
|
||||
id: 'DragProbe',
|
||||
label: 'Probe',
|
||||
icon: 'dot-circle',
|
||||
//
|
||||
type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
|
||||
commandName: 'setToolActive',
|
||||
commandOptions: { toolName: 'DragProbe' },
|
||||
},
|
||||
{
|
||||
id: 'EllipticalRoi',
|
||||
label: 'Ellipse',
|
||||
icon: 'circle-o',
|
||||
//
|
||||
type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
|
||||
commandName: 'setToolActive',
|
||||
commandOptions: { toolName: 'EllipticalRoi' },
|
||||
},
|
||||
{
|
||||
id: 'RectangleRoi',
|
||||
label: 'Rectangle',
|
||||
icon: 'square-o',
|
||||
//
|
||||
type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
|
||||
commandName: 'setToolActive',
|
||||
commandOptions: { toolName: 'RectangleRoi' },
|
||||
},
|
||||
{
|
||||
id: 'Invert',
|
||||
label: 'Invert',
|
||||
icon: 'adjust',
|
||||
//
|
||||
type: TOOLBAR_BUTTON_TYPES.COMMAND,
|
||||
commandName: 'invertViewport',
|
||||
},
|
||||
{
|
||||
id: 'RotateRight',
|
||||
label: 'Rotate Right',
|
||||
icon: 'rotate-right',
|
||||
//
|
||||
type: TOOLBAR_BUTTON_TYPES.COMMAND,
|
||||
commandName: 'rotateViewportCW',
|
||||
},
|
||||
{
|
||||
id: 'FlipH',
|
||||
label: 'Flip H',
|
||||
icon: 'ellipse-h',
|
||||
//
|
||||
type: TOOLBAR_BUTTON_TYPES.COMMAND,
|
||||
commandName: 'flipViewportHorizontal',
|
||||
},
|
||||
{
|
||||
id: 'FlipV',
|
||||
label: 'Flip V',
|
||||
icon: 'ellipse-v',
|
||||
//
|
||||
type: TOOLBAR_BUTTON_TYPES.COMMAND,
|
||||
commandName: 'flipViewportVertical',
|
||||
},
|
||||
{
|
||||
id: 'Clear',
|
||||
label: 'Clear',
|
||||
icon: 'trash',
|
||||
//
|
||||
type: TOOLBAR_BUTTON_TYPES.COMMAND,
|
||||
commandName: 'clearAnnotations',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
const path = require('path');
|
||||
const merge = require('webpack-merge');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.common.js');
|
||||
|
||||
//
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR });
|
||||
|
||||
return merge(commonConfig, {
|
||||
// https://webpack.js.org/configuration/mode/#mode-development
|
||||
mode: 'development',
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
const merge = require('webpack-merge');
|
||||
const path = require('path');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.common.js');
|
||||
const pkg = require('./../package.json');
|
||||
|
||||
const ROOT_DIR = path.join(__dirname, './..');
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR });
|
||||
|
||||
return merge(commonConfig, {
|
||||
// https://webpack.js.org/configuration/mode/#mode-production
|
||||
mode: 'production',
|
||||
devtool: 'source-map',
|
||||
stats: {
|
||||
colors: true,
|
||||
hash: true,
|
||||
timings: true,
|
||||
assets: true,
|
||||
chunks: false,
|
||||
chunkModules: false,
|
||||
modules: false,
|
||||
children: false,
|
||||
warnings: true,
|
||||
},
|
||||
optimization: {
|
||||
minimize: true,
|
||||
sideEffects: true,
|
||||
},
|
||||
output: {
|
||||
path: ROOT_DIR,
|
||||
library: 'ohifExtensionDicomHtml',
|
||||
libraryTarget: 'umd',
|
||||
filename: pkg.main,
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,5 +1,63 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## 0.0.4-alpha.8 (2019-08-14)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-html
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.0.4-alpha.7](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@0.0.4-alpha.6...@ohif/extension-dicom-html@0.0.4-alpha.7) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-html
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.0.4-alpha.6](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@0.0.4-alpha.5...@ohif/extension-dicom-html@0.0.4-alpha.6) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-html
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.0.4-alpha.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@0.0.4-alpha.4...@ohif/extension-dicom-html@0.0.4-alpha.5) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-html
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.0.4-alpha.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@0.0.4-alpha.3...@ohif/extension-dicom-html@0.0.4-alpha.4) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-html
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.0.4-alpha.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@0.0.4-alpha.2...@ohif/extension-dicom-html@0.0.4-alpha.3) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-html
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const ExtractCssChunks = require('extract-css-chunks-webpack-plugin');
|
||||
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
return {
|
||||
entry: {
|
||||
app: `${SRC_DIR}/index.js`,
|
||||
},
|
||||
context: SRC_DIR,
|
||||
resolve: {
|
||||
extensions: ['.js', '.jsx', '.json', '*'],
|
||||
symlinks: true,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
exclude: [/node_modules/],
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
// Find babel.config.js in monorepo root
|
||||
// https://babeljs.io/docs/en/options#rootmode
|
||||
rootMode: 'upward',
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
// Do not transform ES6 modules to another format.
|
||||
// Webpack will take care of that.
|
||||
modules: false,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
'style-loader',
|
||||
ExtractCssChunks.loader,
|
||||
{ loader: 'css-loader', options: { importLoaders: 1 } },
|
||||
{
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
config: {
|
||||
path: './postcss.config.js',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new webpack.EnvironmentPlugin(['NODE_ENV']),
|
||||
new ExtractCssChunks({
|
||||
filename: '[name].css',
|
||||
chunkFilename: '[id].css',
|
||||
// hot: true /* only necessary if hot reloading not function*/
|
||||
}),
|
||||
],
|
||||
};
|
||||
};
|
||||
@@ -1,64 +0,0 @@
|
||||
const merge = require('webpack-merge');
|
||||
const path = require('path');
|
||||
const common = require('./webpack.common');
|
||||
const pkg = require('./../package.json');
|
||||
|
||||
const ROOT_DIR = path.join(__dirname, './..');
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const commonConfig = common(env, argv);
|
||||
|
||||
return merge(commonConfig, {
|
||||
mode: 'production',
|
||||
stats: {
|
||||
colors: false,
|
||||
hash: true,
|
||||
timings: true,
|
||||
assets: true,
|
||||
chunks: true,
|
||||
chunkModules: true,
|
||||
modules: true,
|
||||
children: true,
|
||||
warnings: true,
|
||||
},
|
||||
optimization: {
|
||||
minimize: true,
|
||||
sideEffects: true,
|
||||
},
|
||||
output: {
|
||||
path: ROOT_DIR,
|
||||
library: 'ohifCornerstoneExtension',
|
||||
libraryTarget: 'umd',
|
||||
filename: pkg.main,
|
||||
auxiliaryComment: 'Test Comment',
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(gif|jpe?g|png|svg)$/i,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 8192,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(ttf|eot|woff|woff2)$/i,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 50000,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-dicom-html",
|
||||
"version": "0.0.4-alpha.2",
|
||||
"version": "0.0.4-alpha.8",
|
||||
"description": "OHIF extension for rendering structured reports to HTML",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
@@ -11,9 +11,17 @@
|
||||
"node": ">=8",
|
||||
"npm": ">=5"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "webpack --config config/webpack.prod.js -w -d",
|
||||
"build": "webpack --config config/webpack.prod.js -d",
|
||||
"dev": "webpack --config .webpack/webpack.dev.js --watch --debug --output-pathinfo",
|
||||
"dev:dicom-html": "yarn run dev",
|
||||
"build": "webpack --config .webpack/webpack.prod.js",
|
||||
"build:package": "yarn run build",
|
||||
"prepublishOnly": "yarn run build",
|
||||
"start": "yarn run dev"
|
||||
@@ -26,14 +34,6 @@
|
||||
"react-dom": "^15.0.0 || ^16.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.2.0"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"gitHead": "a5baa9228c0eda0df880136bde4420d78e6f8706"
|
||||
"@babel/runtime": "^7.5.5"
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
import { MODULE_TYPES, utils } from "@ohif/core";
|
||||
import { MODULE_TYPES, utils } from '@ohif/core';
|
||||
|
||||
// TODO: Should probably use dcmjs for this
|
||||
const SOP_CLASS_UIDS = {
|
||||
BASIC_TEXT_SR: "1.2.840.10008.5.1.4.1.1.88.11",
|
||||
ENHANCED_SR: "1.2.840.10008.5.1.4.1.1.88.22",
|
||||
COMPREHENSIVE_SR: "1.2.840.10008.5.1.4.1.1.88.33",
|
||||
PROCEDURE_LOG_STORAGE: "1.2.840.10008.5.1.4.1.1.88.40",
|
||||
MAMMOGRAPHY_CAD_SR: "1.2.840.10008.5.1.4.1.1.88.50",
|
||||
CHEST_CAD_SR: "1.2.840.10008.5.1.4.1.1.88.65",
|
||||
X_RAY_RADIATION_DOSE_SR: "1.2.840.10008.5.1.4.1.1.88.67"
|
||||
BASIC_TEXT_SR: '1.2.840.10008.5.1.4.1.1.88.11',
|
||||
ENHANCED_SR: '1.2.840.10008.5.1.4.1.1.88.22',
|
||||
COMPREHENSIVE_SR: '1.2.840.10008.5.1.4.1.1.88.33',
|
||||
PROCEDURE_LOG_STORAGE: '1.2.840.10008.5.1.4.1.1.88.40',
|
||||
MAMMOGRAPHY_CAD_SR: '1.2.840.10008.5.1.4.1.1.88.50',
|
||||
CHEST_CAD_SR: '1.2.840.10008.5.1.4.1.1.88.65',
|
||||
X_RAY_RADIATION_DOSE_SR: '1.2.840.10008.5.1.4.1.1.88.67',
|
||||
};
|
||||
|
||||
const sopClassUids = Object.values(SOP_CLASS_UIDS);
|
||||
@@ -16,23 +16,24 @@ const sopClassUids = Object.values(SOP_CLASS_UIDS);
|
||||
// TODO: Handle the case where there is more than one SOP Class Handler for the
|
||||
// same SOP Class
|
||||
const OHIFDicomHtmlSopClassHandler = {
|
||||
id: "OHIFDicomHtmlSopClassHandler",
|
||||
id: 'OHIFDicomHtmlSopClassHandler',
|
||||
type: MODULE_TYPES.SOP_CLASS_HANDLER,
|
||||
sopClassUids,
|
||||
getDisplaySetFromSeries(series, study, dicomWebClient, authorizationHeaders) {
|
||||
const instance = series.getFirstInstance();
|
||||
|
||||
return {
|
||||
plugin: "html",
|
||||
plugin: 'html',
|
||||
modality: 'SR',
|
||||
displaySetInstanceUid: utils.guid(),
|
||||
wadoRoot: study.getData().wadoRoot,
|
||||
wadoUri: instance.getData().wadouri,
|
||||
sopInstanceUid: instance.getSOPInstanceUID(),
|
||||
seriesInstanceUid: series.getSeriesInstanceUID(),
|
||||
studyInstanceUid: study.getStudyInstanceUID(),
|
||||
authorizationHeaders
|
||||
authorizationHeaders,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default OHIFDicomHtmlSopClassHandler;
|
||||
@@ -0,0 +1,16 @@
|
||||
const path = require('path');
|
||||
const merge = require('webpack-merge');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.common.js');
|
||||
|
||||
//
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR });
|
||||
|
||||
return merge(commonConfig, {
|
||||
// https://webpack.js.org/configuration/mode/#mode-development
|
||||
mode: 'development',
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
const merge = require('webpack-merge');
|
||||
const path = require('path');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.common.js');
|
||||
const pkg = require('./../package.json');
|
||||
|
||||
const ROOT_DIR = path.join(__dirname, './..');
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR });
|
||||
|
||||
return merge(commonConfig, {
|
||||
// https://webpack.js.org/configuration/mode/#mode-production
|
||||
mode: 'production',
|
||||
devtool: 'source-map',
|
||||
stats: {
|
||||
colors: true,
|
||||
hash: true,
|
||||
timings: true,
|
||||
assets: true,
|
||||
chunks: false,
|
||||
chunkModules: false,
|
||||
modules: false,
|
||||
children: false,
|
||||
warnings: true,
|
||||
},
|
||||
optimization: {
|
||||
minimize: true,
|
||||
sideEffects: true,
|
||||
},
|
||||
output: {
|
||||
path: ROOT_DIR,
|
||||
library: 'ohifExtensionDicomMicroscopy',
|
||||
libraryTarget: 'umd',
|
||||
filename: pkg.main,
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,5 +1,63 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## 0.0.9-alpha.8 (2019-08-14)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.0.9-alpha.7](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-microscopy@0.0.9-alpha.6...@ohif/extension-dicom-microscopy@0.0.9-alpha.7) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.0.9-alpha.6](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-microscopy@0.0.9-alpha.5...@ohif/extension-dicom-microscopy@0.0.9-alpha.6) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.0.9-alpha.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-microscopy@0.0.9-alpha.4...@ohif/extension-dicom-microscopy@0.0.9-alpha.5) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.0.9-alpha.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-microscopy@0.0.9-alpha.3...@ohif/extension-dicom-microscopy@0.0.9-alpha.4) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.0.9-alpha.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-microscopy@0.0.9-alpha.2...@ohif/extension-dicom-microscopy@0.0.9-alpha.3) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-microscopy
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const ExtractCssChunks = require('extract-css-chunks-webpack-plugin');
|
||||
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
return {
|
||||
entry: {
|
||||
app: `${SRC_DIR}/index.js`,
|
||||
},
|
||||
context: SRC_DIR,
|
||||
resolve: {
|
||||
extensions: ['.js', '.jsx', '.json', '*'],
|
||||
symlinks: true,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
exclude: [/node_modules/],
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
// Find babel.config.js in monorepo root
|
||||
// https://babeljs.io/docs/en/options#rootmode
|
||||
rootMode: 'upward',
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
// Do not transform ES6 modules to another format.
|
||||
// Webpack will take care of that.
|
||||
modules: false,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
'style-loader',
|
||||
ExtractCssChunks.loader,
|
||||
{ loader: 'css-loader', options: { importLoaders: 1 } },
|
||||
{
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
config: {
|
||||
path: './postcss.config.js',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new webpack.EnvironmentPlugin(['NODE_ENV']),
|
||||
new ExtractCssChunks({
|
||||
filename: '[name].css',
|
||||
chunkFilename: '[id].css',
|
||||
// hot: true /* only necessary if hot reloading not function*/
|
||||
}),
|
||||
],
|
||||
};
|
||||
};
|
||||
@@ -1,64 +0,0 @@
|
||||
const merge = require('webpack-merge');
|
||||
const path = require('path');
|
||||
const common = require('./webpack.common');
|
||||
const pkg = require('./../package.json');
|
||||
|
||||
const ROOT_DIR = path.join(__dirname, './..');
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const commonConfig = common(env, argv);
|
||||
|
||||
return merge(commonConfig, {
|
||||
mode: 'production',
|
||||
stats: {
|
||||
colors: false,
|
||||
hash: true,
|
||||
timings: true,
|
||||
assets: true,
|
||||
chunks: true,
|
||||
chunkModules: true,
|
||||
modules: true,
|
||||
children: true,
|
||||
warnings: true,
|
||||
},
|
||||
optimization: {
|
||||
minimize: true,
|
||||
sideEffects: true,
|
||||
},
|
||||
output: {
|
||||
path: ROOT_DIR,
|
||||
library: 'ohifCornerstoneExtension',
|
||||
libraryTarget: 'umd',
|
||||
filename: pkg.main,
|
||||
auxiliaryComment: 'Test Comment',
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(gif|jpe?g|png|svg)$/i,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 8192,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(ttf|eot|woff|woff2)$/i,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 50000,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-dicom-microscopy",
|
||||
"version": "0.0.9-alpha.2",
|
||||
"version": "0.0.9-alpha.8",
|
||||
"description": "OHIF extension for Dicom Microscopy",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
@@ -10,30 +10,30 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=8",
|
||||
"npm": ">=5"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "webpack --config config/webpack.prod.js -d",
|
||||
"dev": "webpack --config .webpack/webpack.dev.js --watch --debug --output-pathinfo",
|
||||
"dev:dicom-microscopy": "yarn run dev",
|
||||
"build": "webpack --config .webpack/webpack.prod.js",
|
||||
"build:package": "yarn run build",
|
||||
"prepublishOnly": "yarn run build",
|
||||
"dev": "webpack --config config/webpack.prod.js -w -d",
|
||||
"start": "yarn run dev"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "^0.11.1-alpha.0",
|
||||
"react": "^15.0.0 || ^16.0.0",
|
||||
"react-dom": "^15.0.0 || ^16.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.2.0",
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"classnames": "^2.2.6",
|
||||
"dicom-microscopy-viewer": "^0.4.3"
|
||||
},
|
||||
"gitHead": "a5baa9228c0eda0df880136bde4420d78e6f8706"
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
import OHIF from "@ohif/core";
|
||||
import OHIF from '@ohif/core';
|
||||
|
||||
const { utils } = OHIF;
|
||||
|
||||
const SOP_CLASS_UIDS = {
|
||||
VL_WHOLE_SLIDE_MICROSCOPY_IMAGE_STORAGE: "1.2.840.10008.5.1.4.1.1.77.1.6"
|
||||
VL_WHOLE_SLIDE_MICROSCOPY_IMAGE_STORAGE: '1.2.840.10008.5.1.4.1.1.77.1.6',
|
||||
};
|
||||
|
||||
const DicomMicroscopySopClassHandler = {
|
||||
id: "DicomMicroscopySopClassHandlerPlugin",
|
||||
id: 'DicomMicroscopySopClassHandlerPlugin',
|
||||
sopClassUids: [SOP_CLASS_UIDS.VL_WHOLE_SLIDE_MICROSCOPY_IMAGE_STORAGE],
|
||||
getDisplaySetFromSeries(series, study, dicomWebClient) {
|
||||
const instance = series.getFirstInstance();
|
||||
@@ -15,14 +15,15 @@ const DicomMicroscopySopClassHandler = {
|
||||
// Note: We are passing the dicomweb client into each viewport!
|
||||
|
||||
return {
|
||||
plugin: "microscopy",
|
||||
plugin: 'microscopy',
|
||||
modality: 'SM',
|
||||
displaySetInstanceUid: utils.guid(),
|
||||
dicomWebClient,
|
||||
sopInstanceUid: instance.getSOPInstanceUID(),
|
||||
seriesInstanceUid: series.getSeriesInstanceUID(),
|
||||
studyInstanceUid: study.getStudyInstanceUID()
|
||||
studyInstanceUid: study.getStudyInstanceUID(),
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default DicomMicroscopySopClassHandler;
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import ReactResizeDetector from 'react-resize-detector';
|
||||
import { api } from 'dicom-microscopy-viewer';
|
||||
import debounce from 'lodash.debounce';
|
||||
|
||||
const microscopyViewer = api.VLWholeSlideMicroscopyImageViewer;
|
||||
|
||||
@@ -9,10 +10,16 @@ class DicomMicroscopyViewport extends Component {
|
||||
error: null,
|
||||
};
|
||||
|
||||
viewer = null;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.container = React.createRef();
|
||||
|
||||
this.debouncedResize = debounce(() => {
|
||||
if (this.viewer) this.viewer.resize();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// install the microscopy renderer into the web page.
|
||||
@@ -52,17 +59,18 @@ class DicomMicroscopyViewport extends Component {
|
||||
.then(metadata => {
|
||||
metadata = metadata.filter(m => m);
|
||||
|
||||
const viewer = new microscopyViewer({
|
||||
this.viewer = new microscopyViewer({
|
||||
client: dicomWebClient,
|
||||
metadata,
|
||||
retrieveRendered: false
|
||||
});
|
||||
|
||||
viewer.render({ container, retrieveRendered: true });
|
||||
this.viewer.render({ container });
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { studies, displaySet } = this.props.viewportData;
|
||||
const { displaySet } = this.props.viewportData;
|
||||
|
||||
this.installOpenLayersRenderer(this.container.current, displaySet);
|
||||
}
|
||||
@@ -71,6 +79,13 @@ class DicomMicroscopyViewport extends Component {
|
||||
const style = { width: '100%', height: '100%' };
|
||||
return (
|
||||
<div className={'DicomMicroscopyViewer'} style={style}>
|
||||
{ReactResizeDetector && (
|
||||
<ReactResizeDetector
|
||||
handleWidth
|
||||
handleHeight
|
||||
onResize={this.onWindowResize}
|
||||
/>
|
||||
)}
|
||||
{this.state.error ? (
|
||||
<h2>{JSON.stringify(this.state.error)}</h2>
|
||||
) : (
|
||||
@@ -79,6 +94,10 @@ class DicomMicroscopyViewport extends Component {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
onWindowResize = () => {
|
||||
this.debouncedResize();
|
||||
};
|
||||
}
|
||||
|
||||
export default DicomMicroscopyViewport;
|
||||
@@ -0,0 +1,16 @@
|
||||
const path = require('path');
|
||||
const merge = require('webpack-merge');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.common.js');
|
||||
|
||||
//
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR });
|
||||
|
||||
return merge(commonConfig, {
|
||||
// https://webpack.js.org/configuration/mode/#mode-development
|
||||
mode: 'development',
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
const merge = require('webpack-merge');
|
||||
const path = require('path');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.common.js');
|
||||
const pkg = require('./../package.json');
|
||||
|
||||
const ROOT_DIR = path.join(__dirname, './..');
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR });
|
||||
|
||||
return merge(commonConfig, {
|
||||
// https://webpack.js.org/configuration/mode/#mode-production
|
||||
mode: 'production',
|
||||
devtool: 'source-map',
|
||||
stats: {
|
||||
colors: true,
|
||||
hash: true,
|
||||
timings: true,
|
||||
assets: true,
|
||||
chunks: false,
|
||||
chunkModules: false,
|
||||
modules: false,
|
||||
children: false,
|
||||
warnings: true,
|
||||
},
|
||||
optimization: {
|
||||
minimize: true,
|
||||
sideEffects: true,
|
||||
},
|
||||
output: {
|
||||
path: ROOT_DIR,
|
||||
library: 'ohifExtensionDicomPdf',
|
||||
libraryTarget: 'umd',
|
||||
filename: pkg.main,
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,5 +1,63 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## 0.0.8-alpha.8 (2019-08-14)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.0.8-alpha.7](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-pdf@0.0.8-alpha.6...@ohif/extension-dicom-pdf@0.0.8-alpha.7) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.0.8-alpha.6](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-pdf@0.0.8-alpha.5...@ohif/extension-dicom-pdf@0.0.8-alpha.6) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.0.8-alpha.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-pdf@0.0.8-alpha.4...@ohif/extension-dicom-pdf@0.0.8-alpha.5) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.0.8-alpha.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-pdf@0.0.8-alpha.3...@ohif/extension-dicom-pdf@0.0.8-alpha.4) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.0.8-alpha.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-pdf@0.0.8-alpha.2...@ohif/extension-dicom-pdf@0.0.8-alpha.3) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-dicom-pdf
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const ExtractCssChunks = require('extract-css-chunks-webpack-plugin');
|
||||
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
return {
|
||||
entry: {
|
||||
app: `${SRC_DIR}/index.js`,
|
||||
},
|
||||
context: SRC_DIR,
|
||||
resolve: {
|
||||
extensions: ['.js', '.jsx', '.json', '*'],
|
||||
symlinks: true,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
exclude: [/node_modules/],
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
// Find babel.config.js in monorepo root
|
||||
// https://babeljs.io/docs/en/options#rootmode
|
||||
rootMode: 'upward',
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
// Do not transform ES6 modules to another format.
|
||||
// Webpack will take care of that.
|
||||
modules: false,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
'style-loader',
|
||||
ExtractCssChunks.loader,
|
||||
{ loader: 'css-loader', options: { importLoaders: 1 } },
|
||||
{
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
config: {
|
||||
path: './postcss.config.js',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new webpack.EnvironmentPlugin(['NODE_ENV']),
|
||||
new ExtractCssChunks({
|
||||
filename: '[name].css',
|
||||
chunkFilename: '[id].css',
|
||||
// hot: true /* only necessary if hot reloading not function*/
|
||||
}),
|
||||
],
|
||||
};
|
||||
};
|
||||
@@ -1,64 +0,0 @@
|
||||
const merge = require('webpack-merge');
|
||||
const path = require('path');
|
||||
const common = require('./webpack.common');
|
||||
const pkg = require('./../package.json');
|
||||
|
||||
const ROOT_DIR = path.join(__dirname, './..');
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const commonConfig = common(env, argv);
|
||||
|
||||
return merge(commonConfig, {
|
||||
mode: 'production',
|
||||
stats: {
|
||||
colors: false,
|
||||
hash: true,
|
||||
timings: true,
|
||||
assets: true,
|
||||
chunks: true,
|
||||
chunkModules: true,
|
||||
modules: true,
|
||||
children: true,
|
||||
warnings: true,
|
||||
},
|
||||
optimization: {
|
||||
minimize: true,
|
||||
sideEffects: true,
|
||||
},
|
||||
output: {
|
||||
path: ROOT_DIR,
|
||||
library: 'ohifCornerstoneExtension',
|
||||
libraryTarget: 'umd',
|
||||
filename: pkg.main,
|
||||
auxiliaryComment: 'Test Comment',
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(gif|jpe?g|png|svg)$/i,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 8192,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(ttf|eot|woff|woff2)$/i,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 50000,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-dicom-pdf",
|
||||
"version": "0.0.8-alpha.2",
|
||||
"version": "0.0.8-alpha.8",
|
||||
"description": "OHIF extension for Dicom PDF",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
@@ -19,8 +19,9 @@
|
||||
"README.md"
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "webpack --config config/webpack.prod.js -w -d",
|
||||
"build": "webpack --config config/webpack.prod.js -d",
|
||||
"dev": "webpack --config .webpack/webpack.dev.js --watch --debug --output-pathinfo",
|
||||
"dev:dicom-pdf": "yarn run dev",
|
||||
"build": "webpack --config .webpack/webpack.prod.js",
|
||||
"build:package": "yarn run build",
|
||||
"prepublishOnly": "yarn run build",
|
||||
"start": "yarn run dev"
|
||||
@@ -33,7 +34,7 @@
|
||||
"react-dom": "^15.0.0 || ^16.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.2.0",
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"classnames": "^2.2.6",
|
||||
"lodash.isequal": "^4.5.0"
|
||||
},
|
||||
|
||||
@@ -1,28 +1,29 @@
|
||||
import { MODULE_TYPES, utils } from "@ohif/core";
|
||||
import { MODULE_TYPES, utils } from '@ohif/core';
|
||||
|
||||
// TODO: Should probably use dcmjs for this
|
||||
const SOP_CLASS_UIDS = {
|
||||
ENCAPSULATED_PDF: "1.2.840.10008.5.1.4.1.1.104.1"
|
||||
ENCAPSULATED_PDF: '1.2.840.10008.5.1.4.1.1.104.1',
|
||||
};
|
||||
|
||||
const OHIFDicomPDFSopClassHandler = {
|
||||
id: "OHIFDicomPDFSopClassHandlerPlugin",
|
||||
id: 'OHIFDicomPDFSopClassHandlerPlugin',
|
||||
type: MODULE_TYPES.SOP_CLASS_HANDLER,
|
||||
sopClassUids: [SOP_CLASS_UIDS.ENCAPSULATED_PDF],
|
||||
getDisplaySetFromSeries(series, study, dicomWebClient, authorizationHeaders) {
|
||||
const instance = series.getFirstInstance();
|
||||
|
||||
return {
|
||||
plugin: "pdf",
|
||||
plugin: 'pdf',
|
||||
modality: 'DOC',
|
||||
displaySetInstanceUid: utils.guid(),
|
||||
wadoRoot: study.getData().wadoRoot,
|
||||
wadoUri: instance.getData().wadouri,
|
||||
sopInstanceUid: instance.getSOPInstanceUID(),
|
||||
seriesInstanceUid: series.getSeriesInstanceUID(),
|
||||
studyInstanceUid: study.getStudyInstanceUID(),
|
||||
authorizationHeaders: authorizationHeaders
|
||||
authorizationHeaders: authorizationHeaders,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default OHIFDicomPDFSopClassHandler;
|
||||
@@ -0,0 +1,16 @@
|
||||
const path = require('path');
|
||||
const merge = require('webpack-merge');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.common.js');
|
||||
|
||||
//
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR });
|
||||
|
||||
return merge(commonConfig, {
|
||||
// https://webpack.js.org/configuration/mode/#mode-development
|
||||
mode: 'development',
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
const merge = require('webpack-merge');
|
||||
const path = require('path');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.common.js');
|
||||
const pkg = require('./../package.json');
|
||||
|
||||
const ROOT_DIR = path.join(__dirname, './..');
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR });
|
||||
|
||||
return merge(commonConfig, {
|
||||
// https://webpack.js.org/configuration/mode/#mode-production
|
||||
mode: 'production',
|
||||
devtool: 'source-map',
|
||||
stats: {
|
||||
colors: true,
|
||||
hash: true,
|
||||
timings: true,
|
||||
assets: true,
|
||||
chunks: false,
|
||||
chunkModules: false,
|
||||
modules: false,
|
||||
children: false,
|
||||
warnings: true,
|
||||
},
|
||||
optimization: {
|
||||
minimize: true,
|
||||
sideEffects: true,
|
||||
},
|
||||
output: {
|
||||
path: ROOT_DIR,
|
||||
library: 'ohifExtensionVtk',
|
||||
libraryTarget: 'umd',
|
||||
filename: pkg.main,
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,5 +1,63 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## 0.1.4-alpha.8 (2019-08-14)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-vtk
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.1.4-alpha.7](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.1.4-alpha.6...@ohif/extension-vtk@0.1.4-alpha.7) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-vtk
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.1.4-alpha.6](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.1.4-alpha.5...@ohif/extension-vtk@0.1.4-alpha.6) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-vtk
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.1.4-alpha.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.1.4-alpha.4...@ohif/extension-vtk@0.1.4-alpha.5) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-vtk
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.1.4-alpha.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.1.4-alpha.3...@ohif/extension-vtk@0.1.4-alpha.4) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-vtk
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.1.4-alpha.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.1.4-alpha.2...@ohif/extension-vtk@0.1.4-alpha.3) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-vtk
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
|
||||
+14
-14
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-vtk",
|
||||
"version": "0.1.4-alpha.2",
|
||||
"version": "0.1.4-alpha.8",
|
||||
"description": "OHIF extension for VTK.js",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
@@ -11,15 +11,20 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=8",
|
||||
"npm": ">=5"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "webpack --progress --colors --mode production",
|
||||
"dev": "webpack --config .webpack/webpack.dev.js --watch --debug --output-pathinfo",
|
||||
"dev:dicom-vtk": "yarn run dev",
|
||||
"build": "webpack --config .webpack/webpack.prod.js",
|
||||
"build:package": "yarn run build",
|
||||
"prepublishOnly": "yarn run build",
|
||||
"dev": "webpack --watch --progress --colors --mode development",
|
||||
"start": "yarn run dev"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -27,7 +32,7 @@
|
||||
"@ohif/i18n": "^0.2.3",
|
||||
"@ohif/ui": "^0.2.18-alpha.0",
|
||||
"cornerstone-core": "^2.2.8",
|
||||
"cornerstone-wado-image-loader": "^2.2.3",
|
||||
"cornerstone-wado-image-loader": "^3.0.0",
|
||||
"dcmjs": "^0.4.7",
|
||||
"dicom-parser": "^1.8.3",
|
||||
"i18next": "^17.0.3",
|
||||
@@ -41,15 +46,15 @@
|
||||
"redux": "^4.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.4.5",
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"react-vtkjs-viewport": "0.0.9",
|
||||
"vtk.js": "^8.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ohif/core": "^0.11.1-alpha.2",
|
||||
"@ohif/ui": "^0.2.18-alpha.2",
|
||||
"@ohif/core": "^0.11.1-alpha.8",
|
||||
"@ohif/ui": "^0.2.18-alpha.8",
|
||||
"cornerstone-tools": "^3.13.0",
|
||||
"cornerstone-wado-image-loader": "^2.2.3",
|
||||
"cornerstone-wado-image-loader": "^3.0.0",
|
||||
"dcmjs": "^0.4.7",
|
||||
"dicom-parser": "^1.8.3",
|
||||
"gh-pages": "^2.0.1",
|
||||
@@ -58,10 +63,5 @@
|
||||
"react-i18next": "^10.11.0",
|
||||
"react-redux": "^7.1.0",
|
||||
"redux": "^4.0.1"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md"
|
||||
],
|
||||
"gitHead": "a5baa9228c0eda0df880136bde4420d78e6f8706"
|
||||
}
|
||||
}
|
||||
@@ -189,6 +189,18 @@ class OHIFVTKViewport extends Component {
|
||||
volumeActor.setMapper(volumeMapper);
|
||||
volumeMapper.setInputData(data);
|
||||
|
||||
// TODO: Should look into implementing autoAdjustSampleDistance in vtk
|
||||
const sampleDistance =
|
||||
1.2 *
|
||||
Math.sqrt(
|
||||
data
|
||||
.getSpacing()
|
||||
.map((v) => v * v)
|
||||
.reduce((a, b) => a + b, 0)
|
||||
);
|
||||
|
||||
volumeMapper.setSampleDistance(sampleDistance);
|
||||
|
||||
volumeCache[displaySetInstanceUid] = volumeActor;
|
||||
|
||||
return volumeActor;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
vtkInteractorStyleMPRCrosshairs,
|
||||
vtkInteractorStyleMPRSlice,
|
||||
vtkInteractorStyleMPRWindowLevel,
|
||||
vtkInteractorStyleMPRSlice,
|
||||
vtkSVGCrosshairsWidget,
|
||||
vtkSVGWidgetManager,
|
||||
} from 'react-vtkjs-viewport';
|
||||
@@ -11,9 +11,13 @@ import setViewportToVTK from './utils/setViewportToVTK.js';
|
||||
import vtkCoordinate from 'vtk.js/Sources/Rendering/Core/Coordinate';
|
||||
import vtkMath from 'vtk.js/Sources/Common/Core/Math';
|
||||
import vtkMatrixBuilder from 'vtk.js/Sources/Common/Core/MatrixBuilder';
|
||||
import Constants from 'vtk.js/Sources/Rendering/Core/VolumeMapper/Constants.js';
|
||||
|
||||
const { BlendMode } = Constants;
|
||||
|
||||
// TODO: Put this somewhere else
|
||||
let apis = {};
|
||||
let currentSlabThickness = 0.1;
|
||||
|
||||
function getCrosshairCallbackForIndex(index) {
|
||||
return ({ worldPos }) => {
|
||||
@@ -96,26 +100,24 @@ function _setView(api, sliceNormal, viewUp) {
|
||||
istyle.setSliceNormal(...sliceNormal);
|
||||
camera.setViewUp(...viewUp);
|
||||
|
||||
api.volumes[0].getMapper().setSampleDistance(5.0);
|
||||
api.volumes[0].getMapper().setMaximumSamplesPerRay(2000);
|
||||
|
||||
renderWindow.render();
|
||||
}
|
||||
|
||||
function switchMPRInteractors(api, istyle) {
|
||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
||||
const renderer = api.genericRenderWindow.getRenderer();
|
||||
const camera = renderer.getActiveCamera();
|
||||
const currentIStyle = renderWindow.getInteractor().getInteractorStyle();
|
||||
|
||||
let currentNormal;
|
||||
if (istyle.getSliceNormal) {
|
||||
currentNormal = istyle.getSliceNormal();
|
||||
if (currentIStyle.getSliceNormal && istyle.getSliceNormal) {
|
||||
currentNormal = currentIStyle.getSliceNormal();
|
||||
}
|
||||
|
||||
// TODO: This is a hacky workaround because disabling the vtkInteractorStyleMPRSlice is currently
|
||||
// broken. The camera.onModified is never removed. (https://github.com/Kitware/vtk-js/issues/1110)
|
||||
renderWindow
|
||||
.getInteractor()
|
||||
.getInteractorStyle()
|
||||
.setInteractor(null);
|
||||
let currentSlabThickness;
|
||||
if (currentIStyle.getSlabThickness && istyle.getSlabThickness) {
|
||||
currentSlabThickness = currentIStyle.getSlabThickness();
|
||||
}
|
||||
|
||||
renderWindow.getInteractor().setInteractorStyle(istyle);
|
||||
|
||||
@@ -126,6 +128,11 @@ function switchMPRInteractors(api, istyle) {
|
||||
if (currentNormal) {
|
||||
istyle.setSliceNormal(currentNormal);
|
||||
}
|
||||
|
||||
if (currentSlabThickness) {
|
||||
istyle.setSlabThickness(currentSlabThickness);
|
||||
}
|
||||
|
||||
istyle.setVolumeMapper(api.volumes[0]);
|
||||
}
|
||||
}
|
||||
@@ -152,14 +159,14 @@ const actions = {
|
||||
|
||||
_setView(api, [0, 1, 0], [0, 0, 1]);
|
||||
},
|
||||
enableRotateTool: async ({ viewports }) => {
|
||||
enableRotateTool: () => {
|
||||
apis.forEach(api => {
|
||||
const istyle = vtkInteractorStyleMPRSlice.newInstance();
|
||||
|
||||
switchMPRInteractors(api, istyle);
|
||||
});
|
||||
},
|
||||
enableCrosshairsTool: async ({ viewports }) => {
|
||||
enableCrosshairsTool: () => {
|
||||
apis.forEach((api, index) => {
|
||||
const istyle = vtkInteractorStyleMPRCrosshairs.newInstance();
|
||||
|
||||
@@ -168,13 +175,61 @@ const actions = {
|
||||
istyle.setCallback(getCrosshairCallbackForIndex(index));
|
||||
});
|
||||
},
|
||||
enableLevelTool: async ({ viewports }) => {
|
||||
enableLevelTool: () => {
|
||||
apis.forEach(api => {
|
||||
const istyle = vtkInteractorStyleMPRWindowLevel.newInstance();
|
||||
|
||||
switchMPRInteractors(api, istyle);
|
||||
});
|
||||
},
|
||||
setSlabThickness: slabThickness => {
|
||||
currentSlabThickness = slabThickness;
|
||||
|
||||
apis.forEach(api => {
|
||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
||||
const istyle = renderWindow.getInteractor().getInteractorStyle();
|
||||
|
||||
if (istyle.setSlabThickness) {
|
||||
istyle.setSlabThickness(currentSlabThickness);
|
||||
|
||||
// TODO: Do this inside the interactors in a setSlabThickness function instead
|
||||
const renderer = api.genericRenderWindow.getRenderer();
|
||||
const camera = renderer.getActiveCamera();
|
||||
const dist = camera.getDistance();
|
||||
const near = dist - currentSlabThickness / 2;
|
||||
const far = dist + currentSlabThickness / 2;
|
||||
|
||||
camera.setClippingRange(near, far);
|
||||
}
|
||||
|
||||
renderWindow.render();
|
||||
});
|
||||
},
|
||||
changeSlabThickness: ({ change }) => {
|
||||
currentSlabThickness += change;
|
||||
currentSlabThickness = Math.max(currentSlabThickness, 0.1);
|
||||
|
||||
apis.forEach(api => {
|
||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
||||
const istyle = renderWindow.getInteractor().getInteractorStyle();
|
||||
|
||||
if (istyle.setSlabThickness) {
|
||||
istyle.setSlabThickness(currentSlabThickness);
|
||||
}
|
||||
|
||||
renderWindow.render();
|
||||
});
|
||||
},
|
||||
setBlendMode: ({ blendMode }) => {
|
||||
apis.forEach(api => {
|
||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
||||
const istyle = renderWindow.getInteractor().getInteractorStyle();
|
||||
|
||||
api.volumes[0].getMapper().setBlendMode(blendMode);
|
||||
|
||||
renderWindow.render();
|
||||
});
|
||||
},
|
||||
mpr2d: async ({ viewports }) => {
|
||||
const displaySet =
|
||||
viewports.viewportSpecificData[viewports.activeViewportIndex];
|
||||
@@ -199,20 +254,11 @@ const actions = {
|
||||
});
|
||||
});*/
|
||||
|
||||
apis[0].volumes[0].getMapper().setSampleDistance(1.5);
|
||||
|
||||
apiByViewport.forEach((api, index) => {
|
||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
||||
const renderer = api.genericRenderWindow.getRenderer();
|
||||
const camera = renderer.getActiveCamera();
|
||||
|
||||
// TODO: This is a hacky workaround because disabling the vtkInteractorStyleMPRSlice is currently
|
||||
// broken. The camera.onModified is never removed. (https://github.com/Kitware/vtk-js/issues/1110)
|
||||
renderWindow
|
||||
.getInteractor()
|
||||
.getInteractorStyle()
|
||||
.setInteractor(null);
|
||||
|
||||
const istyle = vtkInteractorStyleMPRCrosshairs.newInstance();
|
||||
renderWindow.getInteractor().setInteractorStyle(istyle);
|
||||
|
||||
@@ -258,6 +304,8 @@ const actions = {
|
||||
},
|
||||
};
|
||||
|
||||
window.vtkActions = actions;
|
||||
|
||||
const definitions = {
|
||||
axial: {
|
||||
commandFn: actions.axial,
|
||||
@@ -276,19 +324,59 @@ const definitions = {
|
||||
},
|
||||
enableRotateTool: {
|
||||
commandFn: actions.enableRotateTool,
|
||||
storeContexts: ['viewports'],
|
||||
storeContexts: [],
|
||||
options: {},
|
||||
},
|
||||
enableCrosshairsTool: {
|
||||
commandFn: actions.enableCrosshairsTool,
|
||||
storeContexts: ['viewports'],
|
||||
storeContexts: [],
|
||||
options: {},
|
||||
},
|
||||
enableLevelTool: {
|
||||
commandFn: actions.enableLevelTool,
|
||||
storeContexts: ['viewports'],
|
||||
storeContexts: [],
|
||||
options: {},
|
||||
},
|
||||
setBlendModeToComposite: {
|
||||
commandFn: actions.setBlendMode,
|
||||
storeContexts: [],
|
||||
options: { blendMode: BlendMode.COMPOSITE_BLEND },
|
||||
},
|
||||
setBlendModeToMaximumIntensity: {
|
||||
commandFn: actions.setBlendMode,
|
||||
storeContexts: [],
|
||||
options: { blendMode: BlendMode.MAXIMUM_INTENSITY_BLEND },
|
||||
},
|
||||
setBlendModeToMinimumIntensity: {
|
||||
commandFn: actions.setBlendMode,
|
||||
storeContexts: [],
|
||||
options: { blendMode: BlendMode.MINIMUM_INTENSITY_BLEND },
|
||||
},
|
||||
setBlendModeToAverageIntensity: {
|
||||
commandFn: actions.setBlendMode,
|
||||
storeContexts: [],
|
||||
options: { blendMode: BlendMode.AVERAGE_INTENSITY_BLEND },
|
||||
},
|
||||
setSlabThickness: {
|
||||
// TODO: How do we pass in a function argument?
|
||||
commandFn: actions.setSlabThickness,
|
||||
storeContexts: [],
|
||||
options: {},
|
||||
},
|
||||
increaseSlabThickness: {
|
||||
commandFn: actions.changeSlabThickness,
|
||||
storeContexts: [],
|
||||
options: {
|
||||
change: 3,
|
||||
},
|
||||
},
|
||||
decreaseSlabThickness: {
|
||||
commandFn: actions.changeSlabThickness,
|
||||
storeContexts: [],
|
||||
options: {
|
||||
change: -3,
|
||||
},
|
||||
},
|
||||
mpr2d: {
|
||||
commandFn: actions.mpr2d,
|
||||
storeContexts: ['viewports'],
|
||||
|
||||
@@ -31,6 +31,43 @@ const definitions = [
|
||||
commandName: 'enableRotateTool',
|
||||
commandOptions: {},
|
||||
},
|
||||
{
|
||||
id: 'setBlendModeToComposite',
|
||||
label: 'Disable MIP',
|
||||
icon: 'times',
|
||||
//
|
||||
type: TOOLBAR_BUTTON_TYPES.COMMAND,
|
||||
commandName: 'setBlendModeToComposite',
|
||||
commandOptions: {},
|
||||
},
|
||||
{
|
||||
id: 'setBlendModeToMaximumIntensity',
|
||||
label: 'Enable MIP',
|
||||
icon: 'soft-tissue',
|
||||
//
|
||||
type: TOOLBAR_BUTTON_TYPES.COMMAND,
|
||||
commandName: 'setBlendModeToMaximumIntensity',
|
||||
commandOptions: {},
|
||||
},
|
||||
|
||||
{
|
||||
id: 'increaseSlabThickness',
|
||||
label: 'Increase Slab Thickness',
|
||||
icon: 'caret-up',
|
||||
//
|
||||
type: TOOLBAR_BUTTON_TYPES.COMMAND,
|
||||
commandName: 'increaseSlabThickness',
|
||||
commandOptions: {},
|
||||
},
|
||||
{
|
||||
id: 'decreaseSlabThickness',
|
||||
label: 'Decrease Slab Thickness',
|
||||
icon: 'caret-down',
|
||||
//
|
||||
type: TOOLBAR_BUTTON_TYPES.COMMAND,
|
||||
commandName: 'decreaseSlabThickness',
|
||||
commandOptions: {},
|
||||
},
|
||||
];
|
||||
|
||||
export default {
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
const path = require("path");
|
||||
const webpack = require("webpack");
|
||||
const autoprefixer = require("autoprefixer");
|
||||
// const vtkHtmlRules = require('vtk.js/Utilities/config/dependency.js').webpack
|
||||
// .core.rules;
|
||||
// Optional if you want to load *.css and *.module.css files
|
||||
// var cssRules = require('vtk.js/Utilities/config/dependency.js').webpack.css.rules;
|
||||
const SRC_DIR = path.join(__dirname, "./src");
|
||||
const OUTPUT_DIR = path.join(__dirname, "./dist");
|
||||
|
||||
module.exports = {
|
||||
mode: "development",
|
||||
entry: {
|
||||
app: `${SRC_DIR}/index.js`
|
||||
},
|
||||
context: SRC_DIR,
|
||||
// ~~~ MODE
|
||||
output: {
|
||||
path: OUTPUT_DIR,
|
||||
library: "ohifVtkExtension",
|
||||
libraryTarget: "umd",
|
||||
filename: "index.umd.js",
|
||||
auxiliaryComment: "Text VTK Extension Comment"
|
||||
},
|
||||
stats: {
|
||||
colors: true,
|
||||
hash: true,
|
||||
timings: true,
|
||||
assets: true,
|
||||
chunks: true,
|
||||
chunkModules: true,
|
||||
modules: true,
|
||||
children: true,
|
||||
warnings: true
|
||||
},
|
||||
optimization: {
|
||||
minimize: false,
|
||||
sideEffects: true
|
||||
},
|
||||
// ~~~ END MODE
|
||||
resolve: {
|
||||
modules: [
|
||||
path.resolve(__dirname, "node_modules"),
|
||||
path.resolve(__dirname, "../../node_modules"),
|
||||
SRC_DIR
|
||||
],
|
||||
extensions: [".js", ".jsx", ".json", "*"],
|
||||
symlinks: true
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(js|jsx)$/,
|
||||
exclude: [/node_modules/],
|
||||
loader: "babel-loader",
|
||||
options: {
|
||||
// Find babel.config.js in monorepo root
|
||||
// https://babeljs.io/docs/en/options#rootmode
|
||||
rootMode: "upward",
|
||||
presets: [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
// Do not transform ES6 modules to another format.
|
||||
// Webpack will take care of that.
|
||||
modules: false
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
/**
|
||||
*
|
||||
*/
|
||||
{
|
||||
test: /\.css$/,
|
||||
exclude: /\.module\.css$/,
|
||||
use: [
|
||||
"style-loader",
|
||||
"css-loader",
|
||||
{
|
||||
loader: "postcss-loader",
|
||||
options: {
|
||||
plugins: () => [autoprefixer("last 2 version", "ie >= 10")]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
/**
|
||||
*
|
||||
*/
|
||||
{
|
||||
test: /\.glsl$/i,
|
||||
include: /vtk\.js[\/\\]Sources/,
|
||||
loader: "shader-loader"
|
||||
},
|
||||
/**
|
||||
*
|
||||
*/
|
||||
{
|
||||
test: /\.worker\.js$/,
|
||||
include: /vtk\.js[\/\\]Sources/,
|
||||
use: [
|
||||
{
|
||||
loader: "worker-loader",
|
||||
options: { inline: true, fallback: false }
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
// externals: [
|
||||
// {
|
||||
// cornerstone: {
|
||||
// commonjs: 'cornerstone',
|
||||
// commonjs2: 'cornerstone',
|
||||
// amd: 'cornerstone',
|
||||
// root: 'cornerstone',
|
||||
// },
|
||||
// 'cornerstone-math': {
|
||||
// commonjs: 'cornerstone-math',
|
||||
// commonjs2: 'cornerstone-math',
|
||||
// amd: 'cornerstone-math',
|
||||
// root: 'cornerstoneMath',
|
||||
// },
|
||||
// },
|
||||
// '@ohif/i18n',
|
||||
// '@ohif/core',
|
||||
// 'dcmjs',
|
||||
// 'react-viewerbase',
|
||||
// 'react', //: 'React',
|
||||
// 'react-dom', //: 'ReactDOM',
|
||||
// 'react-redux', //: 'ReactRedux',
|
||||
// 'react-resize-detector', //: 'ReactResizeDetector',
|
||||
// 'react-viewerbase', //: 'reactViewerbase',
|
||||
// 'prop-types', //: 'PropTypes'
|
||||
// /*/\b(vtk.js)/*/
|
||||
// ],
|
||||
};
|
||||
+2
-2
@@ -5,14 +5,14 @@
|
||||
"useWorkspaces": true,
|
||||
"command": {
|
||||
"publish": {
|
||||
"ignoreChanges": ["*.md"],
|
||||
"ignoreChanges": ["*.md", "*.yml", "*.spec.js", "*.test.js"],
|
||||
"message": "chore(release): publish"
|
||||
},
|
||||
"version": {
|
||||
"conventionalCommits": true,
|
||||
"createRelease": "github",
|
||||
"yes": true,
|
||||
"message": "chore(release): publish %s [skip ci]"
|
||||
"message": "chore(release): publish [skip ci]"
|
||||
}
|
||||
}
|
||||
}
|
||||
+57
-3
@@ -13,6 +13,60 @@ yarn add --dev -W package-name
|
||||
|
||||
- Patch status for PRs (we care about threshold only)
|
||||
- Allows us to use multiproject test runner
|
||||
- Flags per project for merged coverage; easier to break down coverage per project
|
||||
- Remove all-contributors bot; install CLI per project and add per project commands
|
||||
-
|
||||
- Flags per project for merged coverage; easier to break down coverage per
|
||||
project
|
||||
- Remove all-contributors bot; install CLI per project and add per project
|
||||
commands
|
||||
- Verify all have "dev:package-name" command
|
||||
- Should we include `package.json` and `src` as output? (build from ESM)
|
||||
- Should we remove `dev:package-name` commands and suggest navigating to
|
||||
package root?
|
||||
- Fix broken peer dependencies?
|
||||
- Lingering core-js resolution issues when building for Viewer PWA (from project
|
||||
directory)
|
||||
|
||||
## ORBS
|
||||
|
||||
- Cypress: https://circleci.com/orbs/registry/orb/cypress-io/cypress
|
||||
- Slack: https://circleci.com/orbs/registry/orb/circleci/slack
|
||||
- GCP: https://circleci.com/orbs/registry/orb/circleci/gcp-cli
|
||||
- Browser Tools: https://circleci.com/orbs/registry/orb/circleci/browser-tools
|
||||
- Multi-Repo: https://circleci.com/orbs/registry/orb/dnephin/multirepo
|
||||
- PR Comment: https://circleci.com/orbs/registry/orb/benjlevesque/pr-comment
|
||||
|
||||
NOTES:
|
||||
|
||||
# bumps pre-release version of all packages if any changes
|
||||
|
||||
- `npx lerna version prerelease`
|
||||
|
||||
# Releases based on package.json differences from NPM
|
||||
|
||||
- `npx lerna publish from-package --dist-tag canary`
|
||||
|
||||
Use Env options to set config:
|
||||
|
||||
- https://webpack.js.org/api/cli/#environment-options
|
||||
|
||||
## Bundling
|
||||
|
||||
- Extensions must bundle all assets into a single file for UMD
|
||||
- The umd build for Viewer must bundle all of it's assets, and baked-in
|
||||
extension assets
|
||||
- The "skinny" umd build for viewer only needs to bundle it's own assets
|
||||
- The PWA build for Viewer can code-split to it's heart's content
|
||||
- Don't load/bundle a font at any layer other than Application/Viewer
|
||||
- It gets to decide if it should be bundled/cached/external
|
||||
|
||||
* For ESM/Module builds
|
||||
* Not dissimilar from VTK.js consumption
|
||||
* jest --watchAll for individual packages?
|
||||
|
||||
WebPack 5: https://github.com/webpack/webpack/issues/6386#issue-291757876
|
||||
|
||||
Flattened ESM: Less efficient, not as great at code splitting? From source? More
|
||||
loaders, added complexity, slower builds, better output
|
||||
|
||||
Notes:
|
||||
|
||||
- Remove preBuild step in viewer after @3 wado image loader
|
||||
+7
-3
@@ -3,6 +3,10 @@
|
||||
# TOML Reference:
|
||||
# https://www.netlify.com/docs/netlify-toml-reference/
|
||||
#
|
||||
# We use Netlify for deploy previews and deploy previews only.
|
||||
# https://viewer.ohif.org is created using a different process that is
|
||||
# managed by CircleCI and deployed to our Google Hosting
|
||||
#
|
||||
|
||||
# Settings in the [build] context are global and are applied to all contexts
|
||||
# unless otherwise overridden by more specific contexts.
|
||||
@@ -33,7 +37,7 @@
|
||||
# inherit these settings.
|
||||
[context.deploy-preview]
|
||||
base = ""
|
||||
publish = "docs/latest/_book/"
|
||||
publish = ".netlify/www/"
|
||||
command = "yarn config set workspaces-experimental true && chmod +x .netlify/build-deploy-preview.sh && .netlify/build-deploy-preview.sh"
|
||||
|
||||
# Redirects and headers are GLOBAL for all builds – they do not get scoped to
|
||||
@@ -51,8 +55,8 @@
|
||||
status = 200
|
||||
|
||||
[[redirects]]
|
||||
from = "/demo/*"
|
||||
to = "/demo/index.html"
|
||||
from = "/pwa/*"
|
||||
to = "/pwa/index.html"
|
||||
status = 200
|
||||
|
||||
[[headers]]
|
||||
|
||||
+27
-20
@@ -12,15 +12,24 @@
|
||||
},
|
||||
"scripts": {
|
||||
"cm": "npx git-cz",
|
||||
"dev": ".scripts/dev.sh",
|
||||
"build": "lerna run build:viewer",
|
||||
"build:package": "lerna run build:package --parallel",
|
||||
"dev": "lerna run dev:viewer --stream",
|
||||
"dev:project": ".scripts/dev.sh",
|
||||
"build": "lerna run build:viewer --stream",
|
||||
"build:ci": "lerna run build:viewer:ci --stream",
|
||||
"build:package": "lerna run build:viewer:package --stream",
|
||||
"build:package-all": "lerna run build:package --parallel --stream",
|
||||
"test": "yarn run test:unit && yarn run test:e2e:ci",
|
||||
"test:unit": "jest --collectCoverage",
|
||||
"test:unit:ci": "lerna run test:unit:ci --parallel",
|
||||
"test:unit:ci": "lerna run test:unit:ci --parallel --stream",
|
||||
"test:e2e:ci": "cd platform/viewer && yarn run test:e2e:ci",
|
||||
"see-changed": "lerna changed",
|
||||
"publish": "lerna publish --canary --dist-tag test"
|
||||
"release": "yarn run lerna:version && yarn run lerna:publish",
|
||||
"lerna:version": "npx lerna version prerelease --force-publish",
|
||||
"lerna:publish": "lerna publish from-package --canary --dist-tag canary"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"core-js": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.5.0",
|
||||
@@ -30,18 +39,23 @@
|
||||
"@babel/plugin-transform-runtime": "^7.5.0",
|
||||
"@babel/preset-env": "^7.5.0",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"babel-eslint": "^10.0.2",
|
||||
"babel-eslint": "9.x",
|
||||
"babel-loader": "^8.0.6",
|
||||
"babel-plugin-inline-react-svg": "1.1.0",
|
||||
"babel-plugin-module-resolver": "^3.2.0",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"copy-webpack-plugin": "^5.0.3",
|
||||
"cross-env": "^5.2.0",
|
||||
"css-loader": "^3.0.0",
|
||||
"eslint": "^6.0.1",
|
||||
"eslint-plugin-import": "^2.18.0",
|
||||
"css-loader": "^3.2.0",
|
||||
"eslint": "5.16.0",
|
||||
"eslint-config-react-app": "^4.0.1",
|
||||
"eslint-plugin-flowtype": "2.x",
|
||||
"eslint-plugin-import": "2.x",
|
||||
"eslint-plugin-jsx-a11y": "6.x",
|
||||
"eslint-plugin-node": "^9.1.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-react": "^7.14.2",
|
||||
"eslint-plugin-react": "7.x",
|
||||
"eslint-plugin-react-hooks": "1.5.0",
|
||||
"extract-css-chunks-webpack-plugin": "^4.5.4",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"husky": "^3.0.0",
|
||||
@@ -59,6 +73,7 @@
|
||||
"react-scripts": "^3.0.1",
|
||||
"redux-testkit": "^1.0.6",
|
||||
"shader-loader": "^1.3.1",
|
||||
"style-loader": "^1.0.0",
|
||||
"stylelint": "^10.1.0",
|
||||
"stylelint-config-recommended": "^2.2.0",
|
||||
"stylus": "^0.54.5",
|
||||
@@ -71,16 +86,8 @@
|
||||
"workbox-webpack-plugin": "^4.3.1",
|
||||
"worker-loader": "^2.0.0"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,json,md,yml}": [
|
||||
"prettier --write",
|
||||
"git add"
|
||||
]
|
||||
"resolutions": {
|
||||
"**/@babel/runtime": "7.5.5"
|
||||
},
|
||||
"browserslist": [
|
||||
">0.2%",
|
||||
|
||||
@@ -59,6 +59,34 @@
|
||||
"code",
|
||||
"test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "igoroctaviano",
|
||||
"name": "Igor Octaviano",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/13886933?v=4",
|
||||
"profile": "http://igoroctaviano.com",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "dlwire",
|
||||
"name": "David Wire",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/1167291?v=4",
|
||||
"profile": "https://github.com/dlwire",
|
||||
"contributions": [
|
||||
"code",
|
||||
"test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "pavertomato",
|
||||
"name": "Egor Lezhnin",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/878990?v=4",
|
||||
"profile": "http://egor.lezhn.in",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const merge = require('webpack-merge');
|
||||
const path = require('path');
|
||||
const common = require('./webpack.common');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.common.js');
|
||||
const pkg = require('./../package.json');
|
||||
|
||||
const ROOT_DIR = path.join(__dirname, './..');
|
||||
@@ -8,19 +8,21 @@ const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const commonConfig = common(env, argv);
|
||||
const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR });
|
||||
|
||||
return merge(commonConfig, {
|
||||
// https://webpack.js.org/configuration/mode/#mode-production
|
||||
mode: 'production',
|
||||
devtool: 'source-map',
|
||||
stats: {
|
||||
colors: false,
|
||||
colors: true,
|
||||
hash: true,
|
||||
timings: true,
|
||||
assets: true,
|
||||
chunks: true,
|
||||
chunkModules: true,
|
||||
modules: true,
|
||||
children: true,
|
||||
chunks: false,
|
||||
chunkModules: false,
|
||||
modules: false,
|
||||
children: false,
|
||||
warnings: true,
|
||||
},
|
||||
optimization: {
|
||||
@@ -32,7 +34,6 @@ module.exports = (env, argv) => {
|
||||
library: 'ohifCore',
|
||||
libraryTarget: 'umd',
|
||||
filename: pkg.main,
|
||||
auxiliaryComment: 'Test Comment',
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,5 +1,63 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## 0.11.1-alpha.8 (2019-08-14)
|
||||
|
||||
**Note:** Version bump only for package @ohif/core
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.11.1-alpha.7](https://github.com/OHIF/Viewers/compare/@ohif/core@0.11.1-alpha.6...@ohif/core@0.11.1-alpha.7) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/core
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.11.1-alpha.6](https://github.com/OHIF/Viewers/compare/@ohif/core@0.11.1-alpha.5...@ohif/core@0.11.1-alpha.6) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/core
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.11.1-alpha.5](https://github.com/OHIF/Viewers/compare/@ohif/core@0.11.1-alpha.4...@ohif/core@0.11.1-alpha.5) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/core
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.11.1-alpha.4](https://github.com/OHIF/Viewers/compare/@ohif/core@0.11.1-alpha.3...@ohif/core@0.11.1-alpha.4) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/core
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.11.1-alpha.3](https://github.com/OHIF/Viewers/compare/@ohif/core@0.11.1-alpha.2...@ohif/core@0.11.1-alpha.3) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/core
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const ExtractCssChunks = require('extract-css-chunks-webpack-plugin');
|
||||
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
return {
|
||||
entry: {
|
||||
app: `${SRC_DIR}/index.js`,
|
||||
},
|
||||
context: SRC_DIR,
|
||||
resolve: {
|
||||
extensions: ['.js', '.jsx', '.json', '*'],
|
||||
symlinks: true,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: [/node_modules/],
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
// Find babel.config.js in monorepo root
|
||||
// https://babeljs.io/docs/en/options#rootmode
|
||||
rootMode: 'upward',
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
// Do not transform ES6 modules to another format.
|
||||
// Webpack will take care of that.
|
||||
modules: false,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new webpack.EnvironmentPlugin(['NODE_ENV']),
|
||||
new ExtractCssChunks({
|
||||
filename: '[name].css',
|
||||
chunkFilename: '[id].css',
|
||||
// hot: true /* only necessary if hot reloading not function*/
|
||||
}),
|
||||
],
|
||||
};
|
||||
};
|
||||
+15
-17
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/core",
|
||||
"version": "0.11.1-alpha.2",
|
||||
"version": "0.11.1-alpha.8",
|
||||
"description": "Generic business logic for web-based medical imaging applications",
|
||||
"author": "OHIF Core Team",
|
||||
"license": "MIT",
|
||||
@@ -11,40 +11,38 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=8",
|
||||
"npm": ">=5"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "yarn run dev",
|
||||
"dev": "jest --watch",
|
||||
"dev": "jest --watchAll",
|
||||
"dev:core": "yarn run dev",
|
||||
"test:unit": "jest --watch",
|
||||
"test:unit:ci": "jest --ci --runInBand --collectCoverage",
|
||||
"build": "webpack --config config/webpack.prod.js -d",
|
||||
"build": "webpack --config .webpack/webpack.prod.js",
|
||||
"build:package": "yarn run build",
|
||||
"lint": "eslint -c .eslintrc --fix src && prettier --single-quote --write src/**/*.{js,jsx,json,css}",
|
||||
"prepublishOnly": "yarn run build"
|
||||
"prepublishOnly": "yarn run build",
|
||||
"start": "yarn run dev",
|
||||
"test:unit": "jest --watchAll",
|
||||
"test:unit:ci": "jest --ci --runInBand --collectCoverage"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"cornerstone-core": "^2.2.8",
|
||||
"cornerstone-tools": "^3.9.0",
|
||||
"cornerstone-wado-image-loader": "^2.2.3",
|
||||
"cornerstone-wado-image-loader": "^3.0.0",
|
||||
"dicom-parser": "^1.8.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.2.0",
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"ajv": "^6.10.0",
|
||||
"dicomweb-client": "^0.4.2",
|
||||
"dicomweb-client": "^0.5.2",
|
||||
"isomorphic-base64": "^1.0.2",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"lodash.merge": "^4.6.1",
|
||||
"mousetrap": "^1.6.3",
|
||||
"validate.js": "^0.12.0"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md"
|
||||
],
|
||||
"gitHead": "a5baa9228c0eda0df880136bde4420d78e6f8706"
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ export default function getAttribute(element, defaultValue) {
|
||||
|
||||
function convertToInt(input) {
|
||||
function padFour(input) {
|
||||
var l = input.length;
|
||||
const l = input.length;
|
||||
|
||||
if (l == 0) return '0000';
|
||||
if (l == 1) return '000' + input;
|
||||
@@ -33,9 +33,9 @@ function convertToInt(input) {
|
||||
return input;
|
||||
}
|
||||
|
||||
var output = '';
|
||||
for (var i = 0; i < input.length; i++) {
|
||||
for (var j = 0; j < input[i].length; j++) {
|
||||
let output = '';
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
for (let j = 0; j < input[i].length; j++) {
|
||||
output += padFour(input[i].charCodeAt(j).toString(16));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
import getAttribute from './getAttribute';
|
||||
|
||||
describe('getAttribute', () => {
|
||||
it('should return a default value if element is null or undefined', () => {
|
||||
const defaultValue = '0000';
|
||||
const nullElement = null;
|
||||
const undefinedElement = undefined;
|
||||
|
||||
expect(getAttribute(nullElement, defaultValue)).toEqual(defaultValue);
|
||||
expect(getAttribute(undefinedElement, defaultValue)).toEqual(defaultValue);
|
||||
});
|
||||
|
||||
it('should return a default value if element.Value is null, undefined or not present', () => {
|
||||
const defaultValue = '0000';
|
||||
const nullElement = {
|
||||
id: 0,
|
||||
Value: null,
|
||||
};
|
||||
const undefinedElement = {
|
||||
id: 0,
|
||||
Value: undefined,
|
||||
};
|
||||
const noValuePresentElement = {
|
||||
id: 0,
|
||||
};
|
||||
|
||||
expect(getAttribute(nullElement, defaultValue)).toEqual(defaultValue);
|
||||
expect(getAttribute(undefinedElement, defaultValue)).toEqual(defaultValue);
|
||||
expect(getAttribute(noValuePresentElement, defaultValue)).toEqual(
|
||||
defaultValue
|
||||
);
|
||||
});
|
||||
|
||||
it('should return 48 for element with value 0', () => {
|
||||
const returnValue = 48;
|
||||
const element = {
|
||||
Value: '0',
|
||||
};
|
||||
expect(getAttribute(element, null)).toEqual(returnValue);
|
||||
});
|
||||
|
||||
it('should return 3211313 for element with value 11', () => {
|
||||
const returnValue = 3211313;
|
||||
const element = {
|
||||
Value: '11',
|
||||
};
|
||||
expect(getAttribute(element, null)).toEqual(returnValue);
|
||||
});
|
||||
|
||||
it('should return 2.4923405222191973e+35 for element with value 00280009', () => {
|
||||
const returnValue = 2.4923405222191973e35;
|
||||
const element = {
|
||||
id: 0,
|
||||
Value: '00280009',
|
||||
};
|
||||
expect(getAttribute(element, null)).toEqual(returnValue);
|
||||
});
|
||||
|
||||
it('should return 2949169 for element with value -1', () => {
|
||||
const returnValue = 2949169;
|
||||
const element = {
|
||||
id: 0,
|
||||
Value: '-1',
|
||||
};
|
||||
expect(getAttribute(element, null)).toEqual(returnValue);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,82 @@
|
||||
import getAuthorizationHeader from './getAuthorizationHeader';
|
||||
import user from './../user';
|
||||
|
||||
jest.mock('./../user.js');
|
||||
|
||||
describe('getAuthorizationHeader', () => {
|
||||
it('should return a HTTP Basic Auth when server contains requestOptions.auth', () => {
|
||||
const validServer = {
|
||||
requestOptions: {
|
||||
auth: {
|
||||
user: 'dummy_user',
|
||||
password: 'dummy_password',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const expectedAuthorizationHeader = {
|
||||
Authorization: `Basic ${btoa(validServer.requestOptions.auth)}`,
|
||||
};
|
||||
|
||||
const authentication = getAuthorizationHeader(validServer);
|
||||
|
||||
expect(authentication).toEqual(expectedAuthorizationHeader);
|
||||
});
|
||||
|
||||
it('should return a HTTP Basic Auth when server contains requestOptions.auth even though there is no password', () => {
|
||||
const validServerWithoutPassword = {
|
||||
requestOptions: {
|
||||
auth: {
|
||||
user: 'dummy_user',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const expectedAuthorizationHeader = {
|
||||
Authorization: `Basic ${btoa(
|
||||
validServerWithoutPassword.requestOptions.auth
|
||||
)}`,
|
||||
};
|
||||
|
||||
const authentication = getAuthorizationHeader(validServerWithoutPassword);
|
||||
|
||||
expect(authentication).toEqual(expectedAuthorizationHeader);
|
||||
});
|
||||
|
||||
it('should return a HTTP Basic Auth when server contains requestOptions.auth even though there is no username', () => {
|
||||
const validServerWithoutPassword = {
|
||||
requestOptions: {
|
||||
auth: {
|
||||
user: 'dummy_user',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const expectedAuthorizationHeader = {
|
||||
Authorization: `Basic ${btoa(
|
||||
validServerWithoutPassword.requestOptions.auth
|
||||
)}`,
|
||||
};
|
||||
|
||||
const authentication = getAuthorizationHeader(validServerWithoutPassword);
|
||||
|
||||
expect(authentication).toEqual(expectedAuthorizationHeader);
|
||||
});
|
||||
|
||||
it('should return an empty object when there is no either server.requestOptions.auth or accessToken', () => {
|
||||
const authentication = getAuthorizationHeader({});
|
||||
|
||||
expect(authentication).toEqual({});
|
||||
});
|
||||
|
||||
it('should return an Authorization with accessToken when server is not defined and there is an accessToken', () => {
|
||||
user.getAccessToken.mockImplementationOnce(() => 'MOCKED_TOKEN');
|
||||
|
||||
const authentication = getAuthorizationHeader({});
|
||||
const exptecteHeaderBasedOnUserAccessToekn = {
|
||||
Authorization: 'Bearer MOCKED_TOKEN',
|
||||
};
|
||||
|
||||
expect(authentication).toEqual(exptecteHeaderBasedOnUserAccessToekn);
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
export default function getModalities(modality, modalitiesInStudy) {
|
||||
var modalities = {};
|
||||
let modalities = {};
|
||||
if (modality) {
|
||||
modalities = modality;
|
||||
}
|
||||
@@ -7,8 +7,8 @@ export default function getModalities(modality, modalitiesInStudy) {
|
||||
if (modalitiesInStudy) {
|
||||
// Find vr in modalities
|
||||
if (modalities.vr && modalities.vr === modalitiesInStudy.vr) {
|
||||
for (var i = 0; i < modalitiesInStudy.Value.length; i++) {
|
||||
var value = modalitiesInStudy.Value[i];
|
||||
for (let i = 0; i < modalitiesInStudy.Value.length; i++) {
|
||||
const value = modalitiesInStudy.Value[i];
|
||||
if (modalities.Value.indexOf(value) === -1) {
|
||||
modalities.Value.push(value);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import getModalities from './getModalities';
|
||||
|
||||
describe('getModalities', () => {
|
||||
test('should return an empty object when modality and modalitiesInStudy are not present', () => {
|
||||
const modality = null;
|
||||
const modalitiesInStudy = null;
|
||||
|
||||
expect(getModalities(modality, modalitiesInStudy)).toEqual({});
|
||||
});
|
||||
|
||||
test('should return an empty object when modality and modalitiesInStudy are not present', () => {
|
||||
const modality = null;
|
||||
const modalitiesInStudy = null;
|
||||
|
||||
expect(getModalities(modality, modalitiesInStudy)).toEqual({});
|
||||
});
|
||||
|
||||
test('should return modalities in Study when modality is not defined', () => {
|
||||
const modality = null;
|
||||
|
||||
const modalitiesInStudy = {
|
||||
Value: ['MOCKED_VALUE'],
|
||||
vr: 'MOCKED_VALUE',
|
||||
};
|
||||
|
||||
expect(getModalities(modality, modalitiesInStudy)).toEqual(
|
||||
modalitiesInStudy
|
||||
);
|
||||
});
|
||||
|
||||
test('should return only the modalitues that exists in modalitiesInStudy', () => {
|
||||
const modality = {
|
||||
Value: ['DESIRED_VALUE'],
|
||||
vr: 'DESIRED_VR',
|
||||
};
|
||||
|
||||
const modalitiesInStudy = {
|
||||
Value: ['DESIRED_VALUE', 'NOT_DESIRED_VALUE'],
|
||||
vr: 'DESIRED_VR',
|
||||
};
|
||||
|
||||
expect(getModalities(modality, modalitiesInStudy)).toEqual(modality);
|
||||
});
|
||||
|
||||
test('should return the seek modality when the desired modality does not exist in modalitiesInStudy', () => {
|
||||
const modality = {
|
||||
Value: ['DESIRED_VALUE'],
|
||||
vr: 'DESIRED_VR',
|
||||
};
|
||||
|
||||
const modalitiesInStudy = {
|
||||
Value: ['NOT_DESIRED_VALUE'],
|
||||
vr: 'DESIRED_VR',
|
||||
};
|
||||
|
||||
expect(getModalities(modality, modalitiesInStudy)).toEqual(modality);
|
||||
});
|
||||
|
||||
test('should return the seek modality when the desired modality does not exist in modalitiesInStudy VR', () => {
|
||||
const modality = {
|
||||
Value: ['DESIRED_VALUE'],
|
||||
vr: 'DESIRED_VR',
|
||||
};
|
||||
|
||||
const modalitiesInStudy = {
|
||||
Value: ['NOT_DESIRED_VALUE'],
|
||||
vr: 'ANOTHER_VR',
|
||||
};
|
||||
|
||||
expect(getModalities(modality, modalitiesInStudy)).toEqual(
|
||||
modalitiesInStudy
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,62 @@
|
||||
import getName from './getName';
|
||||
|
||||
describe('getName', () => {
|
||||
it('should return a default value if element is null or undefined', () => {
|
||||
const defaultValue = 'DEFAULT_NAME';
|
||||
const nullElement = null;
|
||||
const undefinedElement = undefined;
|
||||
|
||||
expect(getName(nullElement, defaultValue)).toEqual(defaultValue);
|
||||
expect(getName(undefinedElement, defaultValue)).toEqual(defaultValue);
|
||||
});
|
||||
|
||||
it('should return a default value if element.Value is null, undefined or not present', () => {
|
||||
const defaultValue = 'DEFAULT_NAME';
|
||||
const nullElement = {
|
||||
id: 0,
|
||||
Value: null,
|
||||
};
|
||||
const undefinedElement = {
|
||||
id: 0,
|
||||
Value: undefined,
|
||||
};
|
||||
const noValuePresentElement = {
|
||||
id: 0,
|
||||
};
|
||||
|
||||
expect(getName(nullElement, defaultValue)).toEqual(defaultValue);
|
||||
expect(getName(undefinedElement, defaultValue)).toEqual(defaultValue);
|
||||
expect(getName(noValuePresentElement, defaultValue)).toEqual(defaultValue);
|
||||
});
|
||||
|
||||
it('should return A for element when Alphabetic is [A, B, C, D]', () => {
|
||||
const returnValue = 'A';
|
||||
const element = {
|
||||
Value: [
|
||||
{ Alphabetic: 'A' },
|
||||
{ Alphabetic: 'B' },
|
||||
{ Alphabetic: 'C' },
|
||||
{ Alphabetic: 'D' },
|
||||
],
|
||||
};
|
||||
expect(getName(element, null)).toEqual(returnValue);
|
||||
});
|
||||
|
||||
it('should return FIRST for element when Alphabetic is [FIRST, SECOND]', () => {
|
||||
const returnValue = 'FIRST';
|
||||
const element = {
|
||||
Value: [{ Alphabetic: 'FIRST' }, { Alphabetic: 'SECOND' }],
|
||||
};
|
||||
expect(getName(element, null)).toEqual(returnValue);
|
||||
});
|
||||
|
||||
it('should return element.value[0] for element with not Alphabetic and when there is at least on element.Value', () => {
|
||||
const returnValue = {
|
||||
anyOtherProperty: 'FIRST',
|
||||
};
|
||||
const element = {
|
||||
Value: [{ anyOtherProperty: 'FIRST' }, { Alphabetic: 'SECOND' }],
|
||||
};
|
||||
expect(getName(element, null)).toEqual(returnValue);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,57 @@
|
||||
import getNumber from './getNumber';
|
||||
|
||||
describe('getNumber', () => {
|
||||
it('should return a default value if element is null or undefined', () => {
|
||||
const defaultValue = 1.0;
|
||||
const nullElement = null;
|
||||
const undefinedElement = undefined;
|
||||
|
||||
expect(getNumber(nullElement, defaultValue)).toEqual(defaultValue);
|
||||
expect(getNumber(undefinedElement, defaultValue)).toEqual(defaultValue);
|
||||
});
|
||||
|
||||
it('should return a default value if element.Value is null, undefined or not present', () => {
|
||||
const defaultValue = 1.0;
|
||||
const nullElement = {
|
||||
id: 0,
|
||||
Value: null,
|
||||
};
|
||||
const undefinedElement = {
|
||||
id: 0,
|
||||
Value: undefined,
|
||||
};
|
||||
const noValuePresentElement = {
|
||||
id: 0,
|
||||
};
|
||||
|
||||
expect(getNumber(nullElement, defaultValue)).toEqual(defaultValue);
|
||||
expect(getNumber(undefinedElement, defaultValue)).toEqual(defaultValue);
|
||||
expect(getNumber(noValuePresentElement, defaultValue)).toEqual(
|
||||
defaultValue
|
||||
);
|
||||
});
|
||||
|
||||
it('should return 2.0 for element when element.Value[0] = 2', () => {
|
||||
const returnValue = 2.0;
|
||||
const element = {
|
||||
Value: ['2'],
|
||||
};
|
||||
expect(getNumber(element, null)).toEqual(returnValue);
|
||||
});
|
||||
|
||||
it('should return -1.0 for element when element.Value[0] is -1', () => {
|
||||
const returnValue = -1.0;
|
||||
const element = {
|
||||
Value: ['-1'],
|
||||
};
|
||||
expect(getNumber(element, null)).toEqual(returnValue);
|
||||
});
|
||||
|
||||
it('should return -1.0 for element when element.Value is [-1, 2, 5, -10] ', () => {
|
||||
const returnValue = -1.0;
|
||||
const element = {
|
||||
Value: ['-1', '2', '5', '-10'],
|
||||
};
|
||||
expect(getNumber(element, null)).toEqual(returnValue);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,57 @@
|
||||
import getString from './getString';
|
||||
|
||||
describe('getString', () => {
|
||||
it('should return a default value if element is null or undefined', () => {
|
||||
const defaultValue = ['A', 'B', 'C'].join('\\');
|
||||
const nullElement = null;
|
||||
const undefinedElement = undefined;
|
||||
|
||||
expect(getString(nullElement, defaultValue)).toEqual(defaultValue);
|
||||
expect(getString(undefinedElement, defaultValue)).toEqual(defaultValue);
|
||||
});
|
||||
|
||||
it('should return a default value if element.Value is null, undefined or not present', () => {
|
||||
const defaultValue = ['A', 'B', 'C'].join('\\');
|
||||
const nullElement = {
|
||||
id: 0,
|
||||
Value: null,
|
||||
};
|
||||
const undefinedElement = {
|
||||
id: 0,
|
||||
Value: undefined,
|
||||
};
|
||||
const noValuePresentElement = {
|
||||
id: 0,
|
||||
};
|
||||
|
||||
expect(getString(nullElement, defaultValue)).toEqual(defaultValue);
|
||||
expect(getString(undefinedElement, defaultValue)).toEqual(defaultValue);
|
||||
expect(getString(noValuePresentElement, defaultValue)).toEqual(
|
||||
defaultValue
|
||||
);
|
||||
});
|
||||
|
||||
it('should return A,B,C,D for element when element.Value[0] = [A, B, C, D]', () => {
|
||||
const returnValue = ['A', 'B', 'C'].join('\\');
|
||||
const element = {
|
||||
Value: ['A', 'B', 'C'],
|
||||
};
|
||||
expect(getString(element, null)).toEqual(returnValue);
|
||||
});
|
||||
|
||||
it('should return 1,4,5,6 for element when element.Value[0] is [1, 4, 5, 6]', () => {
|
||||
const returnValue = [1, 4, 5, 6].join('\\');
|
||||
const element = {
|
||||
Value: [1, 4, 5, 6],
|
||||
};
|
||||
expect(getString(element, null)).toEqual(returnValue);
|
||||
});
|
||||
|
||||
it('should return A,1,3,R,7,-1 for element when element.Value is [-1, 2, 5, -10] ', () => {
|
||||
const returnValue = ['A', '1', '3', 'R', '7', '-1'].join('\\');
|
||||
const element = {
|
||||
Value: ['A', '1', '3', 'R', '7', '-1'],
|
||||
};
|
||||
expect(getString(element, null)).toEqual(returnValue);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
import * as DICOMWeb from './index.js';
|
||||
|
||||
describe('Top level exports', () => {
|
||||
test('should export the modules getAttribute, getAuthorizationHeader, getModalities, getName, getNumber, getString', () => {
|
||||
const expectedExports = [
|
||||
'getAttribute',
|
||||
'getAuthorizationHeader',
|
||||
'getModalities',
|
||||
'getName',
|
||||
'getNumber',
|
||||
'getString',
|
||||
].sort();
|
||||
|
||||
const exports = Object.keys(DICOMWeb.default).sort();
|
||||
|
||||
expect(exports).toEqual(expectedExports);
|
||||
});
|
||||
});
|
||||
@@ -635,7 +635,17 @@ function _getDisplaySetFromSopClassModule(
|
||||
headers,
|
||||
});
|
||||
|
||||
return plugin.getDisplaySetFromSeries(series, study, dicomWebClient, headers);
|
||||
let displaySet = plugin.getDisplaySetFromSeries(
|
||||
series,
|
||||
study,
|
||||
dicomWebClient,
|
||||
headers
|
||||
);
|
||||
if (displaySet && !displaySet.modality) {
|
||||
const instance = series.getFirstInstance();
|
||||
displaySet.modality = instance.getRawValue('x00080060');
|
||||
}
|
||||
return displaySet;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,7 +6,9 @@ import getImageIdForImagePath from '../lib/getImageIdForImagePath';
|
||||
import guid from '../../utils/guid';
|
||||
import studyMetadataManager from '../../utils/studyMetadataManager';
|
||||
|
||||
const configuration = {};
|
||||
const configuration = {
|
||||
measurementTools: [],
|
||||
};
|
||||
|
||||
export default class MeasurementApi {
|
||||
static Instance;
|
||||
|
||||
@@ -32,6 +32,14 @@ export const MaxTargetsSchema = {
|
||||
minItems: 1,
|
||||
uniqueItems: true,
|
||||
},
|
||||
isNodal: {
|
||||
label: 'Filter to evaluate only nodal or extranodal measurements',
|
||||
type: 'boolean'
|
||||
},
|
||||
message: {
|
||||
label: 'Message to be displayed in case of nonconformity',
|
||||
type: 'string',
|
||||
}
|
||||
},
|
||||
required: ['limit'],
|
||||
};
|
||||
@@ -43,6 +51,7 @@ export const MaxTargetsSchema = {
|
||||
* newTarget: Flag to evaluate only new targets (must be evaluated on both)
|
||||
* locationIn: Filter to evaluate only measurements with the specified locations
|
||||
* locationNotIn: Filter to evaluate only measurements without the specified locations
|
||||
* isNodal: Filter to evaluate only nodal or extranodal measurements
|
||||
* message: Message to be displayed in case of nonconformity
|
||||
*/
|
||||
export class MaxTargetsCriterion extends BaseCriterion {
|
||||
@@ -56,16 +65,31 @@ export class MaxTargetsCriterion extends BaseCriterion {
|
||||
const newTargetNumbers = this.getNewTargetNumbers(data);
|
||||
const measurementNumbers = [];
|
||||
data.targets.forEach(target => {
|
||||
const { location, measurementNumber, isSplitLesion } = target.measurement;
|
||||
if (isSplitLesion) return;
|
||||
if (options.newTarget && !newTargetNumbers.has(measurementNumber)) return;
|
||||
const { location, measurementNumber, isSplitLesion, isNodal } = target.measurement;
|
||||
|
||||
if (isSplitLesion)
|
||||
return;
|
||||
|
||||
if (typeof isNodal === 'boolean' && typeof options.isNodal === 'boolean' && options.isNodal !== isNodal)
|
||||
return;
|
||||
|
||||
if (options.newTarget && !newTargetNumbers.has(measurementNumber))
|
||||
return;
|
||||
|
||||
if (options.locationIn && options.locationIn.indexOf(location) === -1)
|
||||
return;
|
||||
|
||||
if (options.locationNotIn && options.locationNotIn.indexOf(location) > -1)
|
||||
return;
|
||||
|
||||
measurementNumbers.push(measurementNumber);
|
||||
});
|
||||
|
||||
let lesionType = '';
|
||||
if (typeof options.isNodal === 'boolean') {
|
||||
lesionType = options.isNodal ? 'nodal ' : 'extranodal ';
|
||||
}
|
||||
|
||||
let message;
|
||||
if (measurementNumbers.length > options.limit) {
|
||||
const increment = options.newTarget ? 'new ' : '';
|
||||
@@ -73,7 +97,7 @@ export class MaxTargetsCriterion extends BaseCriterion {
|
||||
const amount = options.limit === 0 ? '' : `more than ${options.limit}`;
|
||||
message =
|
||||
options.message ||
|
||||
`The study should not have ${amount} ${increment}target${plural}.`;
|
||||
`The study should not have ${amount} ${increment}${lesionType}target${plural}.`;
|
||||
}
|
||||
|
||||
return this.generateResponse(message);
|
||||
|
||||
@@ -12,6 +12,14 @@ export const MaxTargetsPerOrganSchema = {
|
||||
label: 'Flag to evaluate only new targets',
|
||||
type: 'boolean',
|
||||
},
|
||||
isNodal: {
|
||||
label: 'Filter to evaluate only nodal or extranodal measurements',
|
||||
type: 'boolean'
|
||||
},
|
||||
message: {
|
||||
label: 'Message to be displayed in case of nonconformity',
|
||||
type: 'string',
|
||||
}
|
||||
},
|
||||
required: ['limit'],
|
||||
};
|
||||
@@ -22,6 +30,8 @@ export const MaxTargetsPerOrganSchema = {
|
||||
* Options:
|
||||
* limit: Max targets allowed in study
|
||||
* newTarget: Flag to evaluate only new targets (must be evaluated on both)
|
||||
* isNodal: Filter to evaluate only nodal or extranodal measurements
|
||||
* message: Message to be displayed in case of nonconformity
|
||||
*/
|
||||
export class MaxTargetsPerOrganCriterion extends BaseCriterion {
|
||||
constructor(...props) {
|
||||
@@ -36,9 +46,13 @@ export class MaxTargetsPerOrganCriterion extends BaseCriterion {
|
||||
const newTargetNumbers = this.getNewTargetNumbers(data);
|
||||
data.targets.forEach(target => {
|
||||
const { measurement } = target;
|
||||
const { location, measurementNumber, isSplitLesion } = measurement;
|
||||
const { location, measurementNumber, isSplitLesion, isNodal } = measurement;
|
||||
|
||||
if (isSplitLesion) return;
|
||||
if (isSplitLesion)
|
||||
return;
|
||||
|
||||
if (typeof isNodal === 'boolean' && typeof options.isNodal === 'boolean' && options.isNodal !== isNodal)
|
||||
return;
|
||||
|
||||
if (!targetsPerOrgan[location]) {
|
||||
targetsPerOrgan[location] = new Set();
|
||||
@@ -59,7 +73,7 @@ export class MaxTargetsPerOrganCriterion extends BaseCriterion {
|
||||
message =
|
||||
options.message ||
|
||||
`Each organ should not have more than ${
|
||||
options.limit
|
||||
options.limit
|
||||
} ${increment}targets.`;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,10 @@ export const MeasurementsLengthSchema = {
|
||||
minItems: 1,
|
||||
uniqueItems: true,
|
||||
},
|
||||
isNodal: {
|
||||
label: 'Filter to evaluate only nodal or extranodal measurements',
|
||||
type: 'boolean'
|
||||
},
|
||||
message: {
|
||||
label: 'Message to be displayed in case of nonconformity',
|
||||
type: 'string',
|
||||
@@ -89,6 +93,7 @@ export const MeasurementsLengthSchema = {
|
||||
* modalityNotIn: Filter to evaluate only measurements without the specified modalities
|
||||
* locationIn: Filter to evaluate only measurements with the specified locations
|
||||
* locationNotIn: Filter to evaluate only measurements without the specified locations
|
||||
* isNodal: Filter to evaluate only nodal or extranodal measurements
|
||||
* message: Message to be displayed in case of nonconformity
|
||||
*/
|
||||
export class MeasurementsLengthCriterion extends BaseCriterion {
|
||||
@@ -107,7 +112,7 @@ export class MeasurementsLengthCriterion extends BaseCriterion {
|
||||
const { metadata, measurement } = item;
|
||||
const { location } = measurement;
|
||||
|
||||
let { longestDiameter, shortestDiameter } = measurement;
|
||||
let { longestDiameter, shortestDiameter, isNodal } = measurement;
|
||||
if (measurement.childToolsCount) {
|
||||
const child = measurement.bidirectional;
|
||||
longestDiameter = (child && child.longestDiameter) || 0;
|
||||
@@ -118,6 +123,8 @@ export class MeasurementsLengthCriterion extends BaseCriterion {
|
||||
const modality = (metadata.getRawValue('x00080060') || '').toUpperCase();
|
||||
|
||||
// Stop here if the measurement does not match the modality and location filters
|
||||
if (typeof isNodal === 'boolean' && typeof options.isNodal === 'boolean' && options.isNodal !== isNodal)
|
||||
return;
|
||||
if (options.locationIn && options.locationIn.indexOf(location) === -1)
|
||||
return;
|
||||
if (options.modalityIn && options.modalityIn.indexOf(modality) === -1)
|
||||
|
||||
@@ -9,7 +9,11 @@ const studySearchPromises = new Map();
|
||||
* @returns {Promise} resolved with an array of studies information or rejected with an error
|
||||
*/
|
||||
export default function searchStudies(server, filter) {
|
||||
const promiseKey = JSON.stringify(filter);
|
||||
const promiseKeyObj = {
|
||||
qidoRoot: server.qidoRoot,
|
||||
filter,
|
||||
};
|
||||
const promiseKey = JSON.stringify(promiseKeyObj);
|
||||
if (studySearchPromises.has(promiseKey)) {
|
||||
return studySearchPromises.get(promiseKey);
|
||||
} else {
|
||||
|
||||
@@ -42,6 +42,7 @@ function getQIDOQueryParams(filter, serverSupportsQIDOIncludeField) {
|
||||
ModalitiesInStudy: filter.modalitiesInStudy,
|
||||
limit: filter.limit,
|
||||
offset: filter.offset,
|
||||
fuzzymatching: filter.fuzzymatching,
|
||||
includefield: serverSupportsQIDOIncludeField ? commaSeparatedFields : 'all',
|
||||
};
|
||||
|
||||
|
||||
@@ -164,9 +164,10 @@ function getPaletteColor(server, instance, tag, lutDescriptor) {
|
||||
return byteArray[position] + byteArray[position + 1] * 256;
|
||||
};
|
||||
|
||||
const arrayBufferToPaletteColorLUT = arraybuffer => {
|
||||
const byteArray = new Uint8Array(arraybuffer);
|
||||
const lut = [];
|
||||
const arrayBufferToPaletteColorLUT = result => {
|
||||
const arraybuffer = result[0]
|
||||
const byteArray = new Uint8Array(arraybuffer)
|
||||
const lut = []
|
||||
|
||||
for (let i = 0; i < numLutEntries; i++) {
|
||||
if (bits === 16) {
|
||||
@@ -390,6 +391,7 @@ async function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
|
||||
DICOMWeb.getString(instance['00181065'])
|
||||
),
|
||||
sliceThickness: DICOMWeb.getNumber(instance['00180050']),
|
||||
spacingBetweenSlices: DICOMWeb.getString(instance['00180088']),
|
||||
lossyImageCompression: DICOMWeb.getString(instance['00282110']),
|
||||
derivationDescription: DICOMWeb.getString(instance['00282111']),
|
||||
lossyImageCompressionRatio: DICOMWeb.getString(instance['00282112']),
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
export default function absoluteUrl(path) {
|
||||
const absoluteUrl = path => {
|
||||
let absolutePath = '/';
|
||||
|
||||
if (!path) return absolutePath;
|
||||
|
||||
// TODO: Find another way to get root url
|
||||
const absoluteUrl = window.location.origin;
|
||||
const absoluteUrlParts = absoluteUrl.split('/');
|
||||
@@ -13,4 +15,6 @@ export default function absoluteUrl(path) {
|
||||
}
|
||||
|
||||
return absolutePath.replace(/\/\/+/g, '/');
|
||||
}
|
||||
};
|
||||
|
||||
export default absoluteUrl;
|
||||
@@ -0,0 +1,51 @@
|
||||
import absoluteUrl from './absoluteUrl';
|
||||
|
||||
describe('absoluteUrl', () => {
|
||||
test('should return /path_1/path_2/path_3/path_to_destination when the window.location.origin is http://dummy.com/path_1/path_2 and the path is /path_3/path_to_destination', () => {
|
||||
let global = {
|
||||
window: Object.create(window),
|
||||
};
|
||||
const url = 'http://dummy.com/path_1/path_2';
|
||||
Object.defineProperty(window, 'location', {
|
||||
value: {
|
||||
origin: url,
|
||||
},
|
||||
writable: true,
|
||||
});
|
||||
const absoluteUrlOutput = absoluteUrl('/path_3/path_to_destination');
|
||||
expect(absoluteUrlOutput).toEqual(
|
||||
'/path_1/path_2/path_3/path_to_destination'
|
||||
);
|
||||
});
|
||||
|
||||
test('should return / when the path is not defined', () => {
|
||||
const absoluteUrlOutput = absoluteUrl(undefined);
|
||||
expect(absoluteUrlOutput).toBe('/');
|
||||
});
|
||||
|
||||
test('should return the original path when there path in the window.origin after the domain and port', () => {
|
||||
global.window = Object.create(window);
|
||||
const url = 'http://dummy.com';
|
||||
Object.defineProperty(window, 'location', {
|
||||
value: {
|
||||
origin: url,
|
||||
},
|
||||
writable: true,
|
||||
});
|
||||
const absoluteUrlOutput = absoluteUrl('path_1/path_2/path_3');
|
||||
expect(absoluteUrlOutput).toEqual('/path_1/path_2/path_3');
|
||||
});
|
||||
|
||||
test('should be able to return the absolute path even when the path contains duplicates', () => {
|
||||
global.window = Object.create(window);
|
||||
const url = 'http://dummy.com';
|
||||
Object.defineProperty(window, 'location', {
|
||||
value: {
|
||||
origin: url,
|
||||
},
|
||||
writable: true,
|
||||
});
|
||||
const absoluteUrlOutput = absoluteUrl('path_1/path_1/path_1');
|
||||
expect(absoluteUrlOutput).toEqual('/path_1/path_1/path_1');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,82 @@
|
||||
import addServers from './addServers';
|
||||
|
||||
describe('addServers', () => {
|
||||
const servers = {
|
||||
dicomWeb: [
|
||||
{
|
||||
name: 'DCM4CHEE',
|
||||
wadoUriRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado',
|
||||
qidoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
|
||||
wadoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
|
||||
qidoSupportsIncludeField: true,
|
||||
imageRendering: 'wadors',
|
||||
thumbnailRendering: 'wadors',
|
||||
requestOptions: {
|
||||
requestFromBrowser: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
oidc: [
|
||||
{
|
||||
authority: 'http://127.0.0.1/auth/realms/ohif',
|
||||
client_id: 'ohif-viewer',
|
||||
redirect_uri: 'http://127.0.0.1/callback',
|
||||
response_type: 'code',
|
||||
scope: 'openid',
|
||||
post_logout_redirect_uri: '/logout-redirect.html',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const store = {
|
||||
dispatch: jest.fn(),
|
||||
};
|
||||
|
||||
test('should be able to add a server and dispatch to the store successfuly', () => {
|
||||
addServers(servers, store);
|
||||
expect(store.dispatch).toBeCalledWith({
|
||||
server: {
|
||||
authority: 'http://127.0.0.1/auth/realms/ohif',
|
||||
client_id: 'ohif-viewer',
|
||||
post_logout_redirect_uri: '/logout-redirect.html',
|
||||
redirect_uri: 'http://127.0.0.1/callback',
|
||||
response_type: 'code',
|
||||
scope: 'openid',
|
||||
type: 'oidc',
|
||||
},
|
||||
type: 'ADD_SERVER',
|
||||
});
|
||||
expect(store.dispatch).toBeCalledWith({
|
||||
server: {
|
||||
imageRendering: 'wadors',
|
||||
name: 'DCM4CHEE',
|
||||
qidoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
|
||||
qidoSupportsIncludeField: true,
|
||||
requestOptions: { requestFromBrowser: true },
|
||||
thumbnailRendering: 'wadors',
|
||||
type: 'dicomWeb',
|
||||
wadoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
|
||||
wadoUriRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado',
|
||||
},
|
||||
type: 'ADD_SERVER',
|
||||
});
|
||||
});
|
||||
|
||||
test('should throw an error if servers list is not defined', () => {
|
||||
expect(() => addServers(undefined, store)).toThrowError(
|
||||
new Error('The servers and store must be defined')
|
||||
);
|
||||
});
|
||||
|
||||
test('should throw an error if store is not defined', () => {
|
||||
expect(() => addServers(servers, undefined)).toThrowError(
|
||||
new Error('The servers and store must be defined')
|
||||
);
|
||||
});
|
||||
|
||||
test('should throw an error when both server and store are not defined', () => {
|
||||
expect(() => addServers(undefined, undefined)).toThrowError(
|
||||
new Error('The servers and store must be defined')
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,9 @@
|
||||
// TODO: figure out where else to put this function
|
||||
export default function addServers(servers, store) {
|
||||
const addServers = (servers, store) => {
|
||||
if (!servers || !store) {
|
||||
throw new Error('The servers and store must be defined');
|
||||
}
|
||||
|
||||
Object.keys(servers).forEach(serverType => {
|
||||
const endpoints = servers[serverType];
|
||||
endpoints.forEach(endpoint => {
|
||||
@@ -12,4 +16,6 @@ export default function addServers(servers, store) {
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default addServers;
|
||||
@@ -6,10 +6,10 @@ function getWADORSImageUrl(instance, frame) {
|
||||
}
|
||||
|
||||
// We need to sum 1 because WADO-RS frame number is 1-based
|
||||
frame = (frame || 0) + 1;
|
||||
frame = frame ? parseInt(frame) + 1 : 1;
|
||||
|
||||
// Replaces /frame/1 by /frame/{frame}
|
||||
wadorsuri = wadorsuri.replace(/(%2Fframes%2F)(\d+)/, `$1${frame}`);
|
||||
wadorsuri = wadorsuri.replace(/frames\/(\d+)/, `frames/${frame}`);
|
||||
|
||||
return wadorsuri;
|
||||
}
|
||||
@@ -18,6 +18,7 @@ function getWADORSImageUrl(instance, frame) {
|
||||
* Obtain an imageId for Cornerstone based on the WADO-RS scheme
|
||||
*
|
||||
* @param {object} instanceMetada metadata object (InstanceMetadata)
|
||||
* @param {(string\|number)} [frame] the frame number
|
||||
* @returns {string} The imageId to be used by Cornerstone
|
||||
*/
|
||||
export default function getWADORSImageId(instance, frame) {
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import getWADORSImageId from './getWADORSImageId';
|
||||
|
||||
describe('getWADORSImageId', () => {
|
||||
it('should always return undefined if the instance has no `wadorsuri` property', () => {
|
||||
const frame = '42';
|
||||
const instance = {};
|
||||
|
||||
expect(getWADORSImageId(instance)).toBeUndefined();
|
||||
expect(getWADORSImageId(instance, frame)).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should always prepend the `wadorsuri` with `wadors:`', () => {
|
||||
const frame = '42';
|
||||
const instance = {
|
||||
wadorsuri: 'wadorsuri',
|
||||
};
|
||||
|
||||
expect(getWADORSImageId(instance)).toEqual('wadors:wadorsuri');
|
||||
expect(getWADORSImageId(instance, frame)).toEqual('wadors:wadorsuri');
|
||||
});
|
||||
|
||||
describe('with no frame provided', () => {
|
||||
it('should replace `frames/:number` with `frames/1`', () => {
|
||||
const instance = {
|
||||
wadorsuri: 'frames/42',
|
||||
};
|
||||
|
||||
expect(getWADORSImageId(instance)).toEqual('wadors:frames/1');
|
||||
});
|
||||
|
||||
it('should work on a real wadorsuri', () => {
|
||||
const instance = {
|
||||
wadorsuri:
|
||||
'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs/studies/1.3.6.1.4.1.25403.52237031786.3872.20100510032220.1/series/1.3.6.1.4.1.25403.52237031786.3872.20100510032220.2/instances/1.3.6.1.4.1.25403.52237031786.3872.20100510032220.8/frames/22',
|
||||
};
|
||||
|
||||
expect(getWADORSImageId(instance)).toEqual(
|
||||
'wadors:https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs/studies/1.3.6.1.4.1.25403.52237031786.3872.20100510032220.1/series/1.3.6.1.4.1.25403.52237031786.3872.20100510032220.2/instances/1.3.6.1.4.1.25403.52237031786.3872.20100510032220.8/frames/1'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with a frame provided', () => {
|
||||
it('should replace `frames/:number` with the argument frame plus one', () => {
|
||||
const frame = '42';
|
||||
const instance = {
|
||||
wadorsuri: 'frames/1',
|
||||
};
|
||||
|
||||
expect(getWADORSImageId(instance, frame)).toEqual('wadors:frames/43');
|
||||
});
|
||||
|
||||
it('should work on a real wadorsuri', () => {
|
||||
const frame = '42';
|
||||
const instance = {
|
||||
wadorsuri:
|
||||
'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs/studies/1.3.6.1.4.1.25403.52237031786.3872.20100510032220.1/series/1.3.6.1.4.1.25403.52237031786.3872.20100510032220.2/instances/1.3.6.1.4.1.25403.52237031786.3872.20100510032220.8/frames/22',
|
||||
};
|
||||
|
||||
expect(getWADORSImageId(instance, frame)).toEqual(
|
||||
'wadors:https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs/studies/1.3.6.1.4.1.25403.52237031786.3872.20100510032220.1/series/1.3.6.1.4.1.25403.52237031786.3872.20100510032220.2/instances/1.3.6.1.4.1.25403.52237031786.3872.20100510032220.8/frames/43'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -3,24 +3,26 @@
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
export default function guid() {
|
||||
function s4() {
|
||||
const guid = () => {
|
||||
const getFourRandomValues = () => {
|
||||
return Math.floor((1 + Math.random()) * 0x10000)
|
||||
.toString(16)
|
||||
.substring(1);
|
||||
}
|
||||
};
|
||||
return (
|
||||
s4() +
|
||||
s4() +
|
||||
getFourRandomValues() +
|
||||
getFourRandomValues() +
|
||||
'-' +
|
||||
s4() +
|
||||
getFourRandomValues() +
|
||||
'-' +
|
||||
s4() +
|
||||
getFourRandomValues() +
|
||||
'-' +
|
||||
s4() +
|
||||
getFourRandomValues() +
|
||||
'-' +
|
||||
s4() +
|
||||
s4() +
|
||||
s4()
|
||||
getFourRandomValues() +
|
||||
getFourRandomValues() +
|
||||
getFourRandomValues()
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default guid;
|
||||
@@ -0,0 +1,46 @@
|
||||
import guid from './guid';
|
||||
|
||||
describe('guid', () => {
|
||||
Math.random = jest.fn(() => 0.4677647565236618);
|
||||
const guidValue = guid();
|
||||
|
||||
afterAll(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('should return 77bf77bf-77bf-77bf-77bf-77bf77bf77bf when the random value is fixed on 0.4677647565236618', () => {
|
||||
expect(guidValue).toBe('77bf77bf-77bf-77bf-77bf-77bf77bf77bf');
|
||||
});
|
||||
|
||||
test('should always return a guid of size 36', () => {
|
||||
expect(guidValue.length).toBe(36);
|
||||
});
|
||||
|
||||
test('should always return a guid with five sequences', () => {
|
||||
expect(guidValue.split('-').length).toBe(5);
|
||||
});
|
||||
|
||||
test('should always return a guid with four dashes', () => {
|
||||
expect(guidValue.split('-').length - 1).toBe(4);
|
||||
});
|
||||
|
||||
test('should return the first sequence with length of eigth', () => {
|
||||
expect(guidValue.split('-')[0].length).toBe(8);
|
||||
});
|
||||
|
||||
test('should return the second sequence with length of four', () => {
|
||||
expect(guidValue.split('-')[1].length).toBe(4);
|
||||
});
|
||||
|
||||
test('should return the third sequence with length of four', () => {
|
||||
expect(guidValue.split('-')[2].length).toBe(4);
|
||||
});
|
||||
|
||||
test('should return the fourth sequence with length of four', () => {
|
||||
expect(guidValue.split('-')[3].length).toBe(4);
|
||||
});
|
||||
|
||||
test('should return the last sequence with length of twelve', () => {
|
||||
expect(guidValue.split('-')[4].length).toBe(12);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import * as utils from './index.js';
|
||||
|
||||
describe('Top level exports', () => {
|
||||
test('should export the modules ', () => {
|
||||
const expectedExports = [
|
||||
'guid',
|
||||
'ObjectPath',
|
||||
'absoluteUrl',
|
||||
'addServers',
|
||||
'sortBy',
|
||||
'writeScript',
|
||||
'StackManager',
|
||||
'studyMetadataManager',
|
||||
// Updates WADO-RS metaDataManager
|
||||
'updateMetaDataManager',
|
||||
'DICOMTagDescriptions',
|
||||
].sort();
|
||||
|
||||
const exports = Object.keys(utils.default).sort();
|
||||
|
||||
expect(exports).toEqual(expectedExports);
|
||||
});
|
||||
});
|
||||
@@ -1,76 +1,62 @@
|
||||
import { sopClassDictionary } from './sopClassDictionary';
|
||||
|
||||
const imagesTypes = [
|
||||
sopClassDictionary.ComputedRadiographyImageStorage,
|
||||
sopClassDictionary.DigitalXRayImageStorageForPresentation,
|
||||
sopClassDictionary.DigitalXRayImageStorageForProcessing,
|
||||
sopClassDictionary.DigitalMammographyXRayImageStorageForPresentation,
|
||||
sopClassDictionary.DigitalMammographyXRayImageStorageForProcessing,
|
||||
sopClassDictionary.DigitalIntraOralXRayImageStorageForPresentation,
|
||||
sopClassDictionary.DigitalIntraOralXRayImageStorageForProcessing,
|
||||
sopClassDictionary.CTImageStorage,
|
||||
sopClassDictionary.EnhancedCTImageStorage,
|
||||
sopClassDictionary.LegacyConvertedEnhancedCTImageStorage,
|
||||
sopClassDictionary.UltrasoundMultiframeImageStorage,
|
||||
sopClassDictionary.MRImageStorage,
|
||||
sopClassDictionary.EnhancedMRImageStorage,
|
||||
sopClassDictionary.EnhancedMRColorImageStorage,
|
||||
sopClassDictionary.LegacyConvertedEnhancedMRImageStorage,
|
||||
sopClassDictionary.UltrasoundImageStorage,
|
||||
sopClassDictionary.SecondaryCaptureImageStorage,
|
||||
sopClassDictionary.MultiframeSingleBitSecondaryCaptureImageStorage,
|
||||
sopClassDictionary.MultiframeGrayscaleByteSecondaryCaptureImageStorage,
|
||||
sopClassDictionary.MultiframeGrayscaleWordSecondaryCaptureImageStorage,
|
||||
sopClassDictionary.MultiframeTrueColorSecondaryCaptureImageStorage,
|
||||
sopClassDictionary.XRayAngiographicImageStorage,
|
||||
sopClassDictionary.EnhancedXAImageStorage,
|
||||
sopClassDictionary.XRayRadiofluoroscopicImageStorage,
|
||||
sopClassDictionary.EnhancedXRFImageStorage,
|
||||
sopClassDictionary.XRay3DAngiographicImageStorage,
|
||||
sopClassDictionary.XRay3DCraniofacialImageStorage,
|
||||
sopClassDictionary.BreastTomosynthesisImageStorage,
|
||||
sopClassDictionary.BreastProjectionXRayImageStorageForPresentation,
|
||||
sopClassDictionary.BreastProjectionXRayImageStorageForProcessing,
|
||||
sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForPresentation,
|
||||
sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForProcessing,
|
||||
sopClassDictionary.NuclearMedicineImageStorage,
|
||||
sopClassDictionary.VLEndoscopicImageStorage,
|
||||
sopClassDictionary.VideoEndoscopicImageStorage,
|
||||
sopClassDictionary.VLMicroscopicImageStorage,
|
||||
sopClassDictionary.VideoMicroscopicImageStorage,
|
||||
sopClassDictionary.VLSlideCoordinatesMicroscopicImageStorage,
|
||||
sopClassDictionary.VLPhotographicImageStorage,
|
||||
sopClassDictionary.VideoPhotographicImageStorage,
|
||||
sopClassDictionary.OphthalmicPhotography8BitImageStorage,
|
||||
sopClassDictionary.OphthalmicPhotography16BitImageStorage,
|
||||
sopClassDictionary.OphthalmicTomographyImageStorage,
|
||||
sopClassDictionary.VLWholeSlideMicroscopyImageStorage,
|
||||
sopClassDictionary.PositronEmissionTomographyImageStorage,
|
||||
sopClassDictionary.EnhancedPETImageStorage,
|
||||
sopClassDictionary.LegacyConvertedEnhancedPETImageStorage,
|
||||
sopClassDictionary.RTImageStorage,
|
||||
];
|
||||
|
||||
/**
|
||||
* Checks whether dicom files with specified SOP Class UID have image data
|
||||
* @param {string} sopClassUid - SOP Class UID to be checked
|
||||
* @returns {boolean} - true if it has image data
|
||||
*/
|
||||
export function isImage(sopClassUid) {
|
||||
if (
|
||||
sopClassUid === sopClassDictionary.ComputedRadiographyImageStorage ||
|
||||
sopClassUid === sopClassDictionary.DigitalXRayImageStorageForPresentation ||
|
||||
sopClassUid === sopClassDictionary.DigitalXRayImageStorageForProcessing ||
|
||||
sopClassUid ===
|
||||
sopClassDictionary.DigitalMammographyXRayImageStorageForPresentation ||
|
||||
sopClassUid ===
|
||||
sopClassDictionary.DigitalMammographyXRayImageStorageForProcessing ||
|
||||
sopClassUid ===
|
||||
sopClassDictionary.DigitalIntraOralXRayImageStorageForPresentation ||
|
||||
sopClassUid ===
|
||||
sopClassDictionary.DigitalIntraOralXRayImageStorageForProcessing ||
|
||||
sopClassUid === sopClassDictionary.CTImageStorage ||
|
||||
sopClassUid === sopClassDictionary.EnhancedCTImageStorage ||
|
||||
sopClassUid === sopClassDictionary.LegacyConvertedEnhancedCTImageStorage ||
|
||||
sopClassUid === sopClassDictionary.UltrasoundMultiframeImageStorage ||
|
||||
sopClassUid === sopClassDictionary.MRImageStorage ||
|
||||
sopClassUid === sopClassDictionary.EnhancedMRImageStorage ||
|
||||
sopClassUid === sopClassDictionary.EnhancedMRColorImageStorage ||
|
||||
sopClassUid === sopClassDictionary.LegacyConvertedEnhancedMRImageStorage ||
|
||||
sopClassUid === sopClassDictionary.UltrasoundImageStorage ||
|
||||
sopClassUid === sopClassDictionary.SecondaryCaptureImageStorage ||
|
||||
sopClassUid ===
|
||||
sopClassDictionary.MultiframeSingleBitSecondaryCaptureImageStorage ||
|
||||
sopClassUid ===
|
||||
sopClassDictionary.MultiframeGrayscaleByteSecondaryCaptureImageStorage ||
|
||||
sopClassUid ===
|
||||
sopClassDictionary.MultiframeGrayscaleWordSecondaryCaptureImageStorage ||
|
||||
sopClassUid ===
|
||||
sopClassDictionary.MultiframeTrueColorSecondaryCaptureImageStorage ||
|
||||
sopClassUid === sopClassDictionary.XRayAngiographicImageStorage ||
|
||||
sopClassUid === sopClassDictionary.EnhancedXAImageStorage ||
|
||||
sopClassUid === sopClassDictionary.XRayRadiofluoroscopicImageStorage ||
|
||||
sopClassUid === sopClassDictionary.EnhancedXRFImageStorage ||
|
||||
sopClassUid === sopClassDictionary.XRay3DAngiographicImageStorage ||
|
||||
sopClassUid === sopClassDictionary.XRay3DCraniofacialImageStorage ||
|
||||
sopClassUid === sopClassDictionary.BreastTomosynthesisImageStorage ||
|
||||
sopClassUid ===
|
||||
sopClassDictionary.BreastProjectionXRayImageStorageForPresentation ||
|
||||
sopClassUid ===
|
||||
sopClassDictionary.BreastProjectionXRayImageStorageForProcessing ||
|
||||
sopClassUid ===
|
||||
sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForPresentation ||
|
||||
sopClassUid ===
|
||||
sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForProcessing ||
|
||||
sopClassUid === sopClassDictionary.NuclearMedicineImageStorage ||
|
||||
sopClassUid === sopClassDictionary.VLEndoscopicImageStorage ||
|
||||
sopClassUid === sopClassDictionary.VideoEndoscopicImageStorage ||
|
||||
sopClassUid === sopClassDictionary.VLMicroscopicImageStorage ||
|
||||
sopClassUid === sopClassDictionary.VideoMicroscopicImageStorage ||
|
||||
sopClassUid ===
|
||||
sopClassDictionary.VLSlideCoordinatesMicroscopicImageStorage ||
|
||||
sopClassUid === sopClassDictionary.VLPhotographicImageStorage ||
|
||||
sopClassUid === sopClassDictionary.VideoPhotographicImageStorage ||
|
||||
sopClassUid === sopClassDictionary.OphthalmicPhotography8BitImageStorage ||
|
||||
sopClassUid === sopClassDictionary.OphthalmicPhotography16BitImageStorage ||
|
||||
sopClassUid === sopClassDictionary.OphthalmicTomographyImageStorage ||
|
||||
sopClassUid === sopClassDictionary.VLWholeSlideMicroscopyImageStorage ||
|
||||
sopClassUid === sopClassDictionary.PositronEmissionTomographyImageStorage ||
|
||||
sopClassUid === sopClassDictionary.EnhancedPETImageStorage ||
|
||||
sopClassUid === sopClassDictionary.LegacyConvertedEnhancedPETImageStorage ||
|
||||
sopClassUid === sopClassDictionary.RTImageStorage
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
export const isImage = sopClassUid => {
|
||||
if (!sopClassUid) return false;
|
||||
return imagesTypes.indexOf(sopClassUid) !== -1;
|
||||
};
|
||||
@@ -0,0 +1,333 @@
|
||||
import { sopClassDictionary } from './sopClassDictionary';
|
||||
import { isImage } from './isImage';
|
||||
|
||||
describe('isImage', () => {
|
||||
test('should return true when the image is of type sopClassDictionary.ComputedRadiographyImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.ComputedRadiographyImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.DigitalXRayImageStorageForPresentation', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.DigitalXRayImageStorageForPresentation
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.DigitalXRayImageStorageForProcessing', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.DigitalXRayImageStorageForProcessing
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.DigitalMammographyXRayImageStorageForPresentation', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.DigitalMammographyXRayImageStorageForPresentation
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.DigitalMammographyXRayImageStorageForProcessing', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.DigitalMammographyXRayImageStorageForProcessing
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.DigitalIntraOralXRayImageStorageForPresentation', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.DigitalIntraOralXRayImageStorageForPresentation
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.DigitalIntraOralXRayImageStorageForProcessing', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.DigitalIntraOralXRayImageStorageForProcessing
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.CTImageStorage', () => {
|
||||
const isImageStatus = isImage(sopClassDictionary.CTImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.EnhancedCTImageStorage', () => {
|
||||
const isImageStatus = isImage(sopClassDictionary.EnhancedCTImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.LegacyConvertedEnhancedCTImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.LegacyConvertedEnhancedCTImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.UltrasoundMultiframeImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.UltrasoundMultiframeImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.MRImageStorage', () => {
|
||||
const isImageStatus = isImage(sopClassDictionary.MRImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.EnhancedMRImageStorage', () => {
|
||||
const isImageStatus = isImage(sopClassDictionary.EnhancedMRImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.EnhancedMRColorImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.EnhancedMRColorImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.LegacyConvertedEnhancedMRImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.LegacyConvertedEnhancedMRImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.UltrasoundImageStorage', () => {
|
||||
const isImageStatus = isImage(sopClassDictionary.UltrasoundImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.SecondaryCaptureImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.SecondaryCaptureImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.MultiframeSingleBitSecondaryCaptureImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.MultiframeSingleBitSecondaryCaptureImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.MultiframeGrayscaleByteSecondaryCaptureImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.MultiframeGrayscaleByteSecondaryCaptureImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.MultiframeGrayscaleWordSecondaryCaptureImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.MultiframeGrayscaleWordSecondaryCaptureImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.MultiframeTrueColorSecondaryCaptureImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.MultiframeTrueColorSecondaryCaptureImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.XRayAngiographicImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.XRayAngiographicImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.EnhancedXAImageStorage', () => {
|
||||
const isImageStatus = isImage(sopClassDictionary.EnhancedXAImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.XRayRadiofluoroscopicImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.XRayRadiofluoroscopicImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.EnhancedXRFImageStorage', () => {
|
||||
const isImageStatus = isImage(sopClassDictionary.EnhancedXRFImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.XRay3DAngiographicImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.XRay3DAngiographicImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.XRay3DCraniofacialImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.XRay3DCraniofacialImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.BreastTomosynthesisImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.BreastTomosynthesisImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.BreastProjectionXRayImageStorageForPresentation', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.BreastProjectionXRayImageStorageForPresentation
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.BreastProjectionXRayImageStorageForProcessing', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.BreastProjectionXRayImageStorageForProcessing
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForPresentation', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForPresentation
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForProcessing', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForProcessing
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.NuclearMedicineImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.NuclearMedicineImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.VLEndoscopicImageStorage', () => {
|
||||
const isImageStatus = isImage(sopClassDictionary.VLEndoscopicImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.VideoEndoscopicImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.VideoEndoscopicImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.VLMicroscopicImageStorage', () => {
|
||||
const isImageStatus = isImage(sopClassDictionary.VLMicroscopicImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.VideoMicroscopicImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.VideoMicroscopicImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.VLSlideCoordinatesMicroscopicImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.VLSlideCoordinatesMicroscopicImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.VLPhotographicImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.VLPhotographicImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.VideoPhotographicImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.VideoPhotographicImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.OphthalmicPhotography8BitImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.OphthalmicPhotography8BitImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.OphthalmicPhotography16BitImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.OphthalmicPhotography16BitImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.OphthalmicTomographyImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.OphthalmicTomographyImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.VLWholeSlideMicroscopyImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.VLWholeSlideMicroscopyImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.PositronEmissionTomographyImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.PositronEmissionTomographyImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.EnhancedPETImageStorage', () => {
|
||||
const isImageStatus = isImage(sopClassDictionary.EnhancedPETImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.LegacyConvertedEnhancedPETImageStorage', () => {
|
||||
const isImageStatus = isImage(
|
||||
sopClassDictionary.LegacyConvertedEnhancedPETImageStorage
|
||||
);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true when the image is of type sopClassDictionary.RTImageStorage', () => {
|
||||
const isImageStatus = isImage(sopClassDictionary.RTImageStorage);
|
||||
expect(isImageStatus).toBe(true);
|
||||
});
|
||||
|
||||
test('should return false when the image is of type sopClassDictionary.SpatialFiducialsStorage', () => {
|
||||
const isImageStatus = isImage(sopClassDictionary.SpatialFiducialsStorage);
|
||||
expect(isImageStatus).toBe(false);
|
||||
});
|
||||
|
||||
test('should return false when the image is undefined', () => {
|
||||
const isImageStatus = isImage(undefined);
|
||||
expect(isImageStatus).toBe(false);
|
||||
});
|
||||
|
||||
test('should return false when the image is null', () => {
|
||||
const isImageStatus = isImage(null);
|
||||
expect(isImageStatus).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,99 @@
|
||||
import objectPath from './objectPath';
|
||||
|
||||
describe('objectPath', () => {
|
||||
test('should return false when the supplied argument is not a real JavaScript Object instance such as undefined', () => {
|
||||
expect(objectPath.isValidObject(undefined)).toBe(false);
|
||||
});
|
||||
|
||||
test('should return false when the supplied argument is not a real JavaScript Object instance such as null', () => {
|
||||
expect(objectPath.isValidObject(null)).toBe(false);
|
||||
});
|
||||
|
||||
test('should return true when the supplied argument is a real JavaScript Object instance', () => {
|
||||
expect(objectPath.isValidObject({})).toBe(true);
|
||||
});
|
||||
|
||||
test('should return [path1, path2, path3] when the path is path1.path2.path3', () => {
|
||||
const path = 'path1.path2.path3';
|
||||
const expectedPathComponents = objectPath.getPathComponents(path);
|
||||
expect(expectedPathComponents).toEqual(['path1', 'path2', 'path3']);
|
||||
});
|
||||
|
||||
test('should return null when the path is not a string', () => {
|
||||
const path = 20;
|
||||
const expectedPathComponents = objectPath.getPathComponents(path);
|
||||
expect(expectedPathComponents).toEqual(null);
|
||||
});
|
||||
|
||||
test('should return [path1path2path3] when the path is path1path2path3', () => {
|
||||
const path = 'path1path2path3';
|
||||
const expectedPathComponents = objectPath.getPathComponents(path);
|
||||
expect(expectedPathComponents).toEqual(['path1path2path3']);
|
||||
});
|
||||
|
||||
test('should return the property obj.myProperty when the object contains myProperty', () => {
|
||||
const searchObject = {
|
||||
obj: {
|
||||
myProperty: 'MOCK_VALUE',
|
||||
},
|
||||
};
|
||||
const path = 'obj.myProperty';
|
||||
const expectedPathComponents = objectPath.get(searchObject, path);
|
||||
expect(expectedPathComponents).toEqual(searchObject.obj.myProperty);
|
||||
});
|
||||
|
||||
test('should return undefined when the object does not contain a property', () => {
|
||||
const searchObject = {
|
||||
obj: {
|
||||
myProperty: 'MOCK_VALUE',
|
||||
},
|
||||
};
|
||||
const path = 'obj.unknownProperty';
|
||||
const expectedPathComponents = objectPath.get(searchObject, path);
|
||||
expect(expectedPathComponents).toEqual(undefined);
|
||||
});
|
||||
|
||||
test('should return undefined when the object is not a valid object', () => {
|
||||
const searchObject = undefined;
|
||||
const path = 'obj.unknownProperty';
|
||||
const expectedPathComponents = objectPath.get(searchObject, path);
|
||||
expect(expectedPathComponents).toEqual(undefined);
|
||||
});
|
||||
|
||||
test('should return undefined when the inner object is not a valid object', () => {
|
||||
const searchObject = {
|
||||
obj: {
|
||||
myProperty: null,
|
||||
},
|
||||
};
|
||||
const path = 'obj.unknownProperty';
|
||||
const expectedPathComponents = objectPath.get(searchObject, path);
|
||||
expect(expectedPathComponents).toEqual(undefined);
|
||||
});
|
||||
|
||||
test('should set the property obj.myProperty when the object does not contain myProperty', () => {
|
||||
const searchObject = {
|
||||
obj: {
|
||||
anyProperty: 'MOCK_VALUE',
|
||||
},
|
||||
};
|
||||
const newValue = 'NEW_VALUE';
|
||||
const path = 'obj.myProperty';
|
||||
const output = objectPath.set(searchObject, path, newValue);
|
||||
expect(output).toBe(true);
|
||||
expect(searchObject.obj.myProperty).toEqual(newValue);
|
||||
});
|
||||
|
||||
test('should return false when the object which is being set is not in a valid path', () => {
|
||||
const searchObject = {
|
||||
obj: {
|
||||
myProperty: 'MOCK_VALUE',
|
||||
},
|
||||
};
|
||||
const path = undefined;
|
||||
const newValue = 'NEW_VALUE';
|
||||
|
||||
const output = objectPath.set(searchObject, path, newValue);
|
||||
expect(output).toEqual(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
const path = require('path');
|
||||
const merge = require('webpack-merge');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.common.js');
|
||||
|
||||
//
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR });
|
||||
|
||||
return merge(commonConfig, {
|
||||
// https://webpack.js.org/configuration/mode/#mode-development
|
||||
mode: 'development',
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
const merge = require('webpack-merge');
|
||||
const path = require('path');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.common.js');
|
||||
const pkg = require('./../package.json');
|
||||
|
||||
const ROOT_DIR = path.join(__dirname, './..');
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const commonConfig = webpackCommon(env, argv, { SRC_DIR, DIST_DIR });
|
||||
|
||||
return merge(commonConfig, {
|
||||
// https://webpack.js.org/configuration/mode/#mode-production
|
||||
mode: 'production',
|
||||
devtool: 'source-map',
|
||||
stats: {
|
||||
colors: true,
|
||||
hash: true,
|
||||
timings: true,
|
||||
assets: true,
|
||||
chunks: false,
|
||||
chunkModules: false,
|
||||
modules: false,
|
||||
children: false,
|
||||
warnings: true,
|
||||
},
|
||||
optimization: {
|
||||
minimize: true,
|
||||
sideEffects: true,
|
||||
},
|
||||
output: {
|
||||
path: ROOT_DIR,
|
||||
library: 'ohifI18n',
|
||||
libraryTarget: 'umd',
|
||||
filename: pkg.main,
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,5 +1,63 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## 0.2.3-alpha.8 (2019-08-14)
|
||||
|
||||
**Note:** Version bump only for package @ohif/i18n
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.2.3-alpha.7](https://github.com/OHIF/Viewers/compare/@ohif/i18n@0.2.3-alpha.6...@ohif/i18n@0.2.3-alpha.7) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/i18n
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.2.3-alpha.6](https://github.com/OHIF/Viewers/compare/@ohif/i18n@0.2.3-alpha.5...@ohif/i18n@0.2.3-alpha.6) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/i18n
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.2.3-alpha.5](https://github.com/OHIF/Viewers/compare/@ohif/i18n@0.2.3-alpha.4...@ohif/i18n@0.2.3-alpha.5) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/i18n
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.2.3-alpha.4](https://github.com/OHIF/Viewers/compare/@ohif/i18n@0.2.3-alpha.3...@ohif/i18n@0.2.3-alpha.4) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/i18n
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.2.3-alpha.3](https://github.com/OHIF/Viewers/compare/@ohif/i18n@0.2.3-alpha.2...@ohif/i18n@0.2.3-alpha.3) (2019-08-08)
|
||||
|
||||
**Note:** Version bump only for package @ohif/i18n
|
||||
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file. See
|
||||
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const ExtractCssChunks = require('extract-css-chunks-webpack-plugin');
|
||||
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
return {
|
||||
entry: {
|
||||
app: `${SRC_DIR}/index.js`,
|
||||
},
|
||||
context: SRC_DIR,
|
||||
resolve: {
|
||||
extensions: ['.js', '.jsx', '.json', '*'],
|
||||
symlinks: true,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
exclude: [/node_modules/],
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
// Find babel.config.js in monorepo root
|
||||
// https://babeljs.io/docs/en/options#rootmode
|
||||
rootMode: 'upward',
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
// Do not transform ES6 modules to another format.
|
||||
// Webpack will take care of that.
|
||||
modules: false,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
'style-loader',
|
||||
ExtractCssChunks.loader,
|
||||
{ loader: 'css-loader', options: { importLoaders: 1 } },
|
||||
{
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
config: {
|
||||
path: './postcss.config.js',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new webpack.EnvironmentPlugin(['NODE_ENV']),
|
||||
new ExtractCssChunks({
|
||||
filename: '[name].css',
|
||||
chunkFilename: '[id].css',
|
||||
// hot: true /* only necessary if hot reloading not function*/
|
||||
}),
|
||||
],
|
||||
};
|
||||
};
|
||||
@@ -1,64 +0,0 @@
|
||||
const merge = require('webpack-merge');
|
||||
const path = require('path');
|
||||
const common = require('./webpack.common');
|
||||
const pkg = require('./../package.json');
|
||||
|
||||
const ROOT_DIR = path.join(__dirname, './..');
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const commonConfig = common(env, argv);
|
||||
|
||||
return merge(commonConfig, {
|
||||
mode: 'production',
|
||||
stats: {
|
||||
colors: false,
|
||||
hash: true,
|
||||
timings: true,
|
||||
assets: true,
|
||||
chunks: true,
|
||||
chunkModules: true,
|
||||
modules: true,
|
||||
children: true,
|
||||
warnings: true,
|
||||
},
|
||||
optimization: {
|
||||
minimize: true,
|
||||
sideEffects: true,
|
||||
},
|
||||
output: {
|
||||
path: ROOT_DIR,
|
||||
library: 'ohifCornerstoneExtension',
|
||||
libraryTarget: 'umd',
|
||||
filename: pkg.main,
|
||||
auxiliaryComment: 'Test Comment',
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(gif|jpe?g|png|svg)$/i,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 8192,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(ttf|eot|woff|woff2)$/i,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 50000,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/i18n",
|
||||
"version": "0.2.3-alpha.2",
|
||||
"version": "0.2.3-alpha.8",
|
||||
"description": "Internationalization library for The OHIF Viewer",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
@@ -19,14 +19,14 @@
|
||||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"test:unit": "echo 'platform/i18n: missing unit tests'",
|
||||
"test:unit:ci": "echo 'platform/i18n: missing unit tests'",
|
||||
"dev": "webpack --config config/webpack.prod.js -w -d",
|
||||
"dev": "webpack --config .webpack/webpack.dev.js --watch --debug --output-pathinfo",
|
||||
"dev:i18n": "yarn run dev",
|
||||
"prepublishOnly": "yarn run build",
|
||||
"build": "webpack --config config/webpack.prod.js -d",
|
||||
"build": "webpack --config .webpack/webpack.prod.js",
|
||||
"build:package": "yarn run build",
|
||||
"pullTranslations": "./pullTranslations.sh"
|
||||
"prepublishOnly": "yarn run build",
|
||||
"pullTranslations": "./pullTranslations.sh",
|
||||
"test:unit": "echo 'platform/i18n: missing unit tests'",
|
||||
"test:unit:ci": "echo 'platform/i18n: missing unit tests'"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"i18next": "^17.0.3",
|
||||
@@ -36,7 +36,7 @@
|
||||
"react-i18next": "^10.11.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.2.0",
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"classnames": "^2.2.6",
|
||||
"i18next-locize-backend": "^2.0.0",
|
||||
"locize-editor": "^2.0.0",
|
||||
@@ -48,6 +48,5 @@
|
||||
"i18next-browser-languagedetector": "^3.0.1",
|
||||
"locize-cli": "^4.8.0",
|
||||
"react-i18next": "^10.11.0"
|
||||
},
|
||||
"gitHead": "a5baa9228c0eda0df880136bde4420d78e6f8706"
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
rm -rf src/locales/
|
||||
mkdir -p src/locales/
|
||||
cd src/locales/
|
||||
npx locize --config-path ../../.locize download --ver latest
|
||||
cd ../../
|
||||
node ./writeLocaleIndexFiles.js
|
||||
@@ -39,4 +39,4 @@
|
||||
"Stop": "$t(Common:Stop)",
|
||||
"Themes": "Themes",
|
||||
"Zoom": "Zoom"
|
||||
}
|
||||
}
|
||||
Loaded 100 of 297 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user