Compare commits
47
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b68c307fc | ||
|
|
7a9b477609 | ||
|
|
8f758186c1 | ||
|
|
d48b617e1c | ||
|
|
7c2b444cf9 | ||
|
|
d86f758125 | ||
|
|
d26035fa55 | ||
|
|
ec4e2ef1a6 | ||
|
|
619d363243 | ||
|
|
073c0af7f7 | ||
|
|
4aa49f4e26 | ||
|
|
a6dbe952d8 | ||
|
|
196694f5a6 | ||
|
|
552df4c9a8 | ||
|
|
467712f8cd | ||
|
|
681c160f08 | ||
|
|
a88d865a9b | ||
|
|
d76fab0bc9 | ||
|
|
e74f8fb536 | ||
|
|
ba20093b81 | ||
|
|
ee68b7bcd3 | ||
|
|
9138b554e3 | ||
|
|
89079e9d37 | ||
|
|
e09670ada2 | ||
|
|
84cd2237c5 | ||
|
|
0a2acdf2a0 | ||
|
|
be6e53db0d | ||
|
|
aa48749959 | ||
|
|
df6fbb416d | ||
|
|
95cff27b95 | ||
|
|
4c322067a0 | ||
|
|
312e5826e6 | ||
|
|
4d219bdaca | ||
|
|
f56bed2aa4 | ||
|
|
496b0a8343 | ||
|
|
d09fb4e71c | ||
|
|
2cf355856b | ||
|
|
e7e2dcc4b6 | ||
|
|
3f7d29dd76 | ||
|
|
d46cccc652 | ||
|
|
d0c0690e0c | ||
|
|
38ea92d2a3 | ||
|
|
98c40bc607 | ||
|
|
51472b2276 | ||
|
|
63a9b3464d | ||
|
|
20d8f0f5db | ||
|
|
be8ab62ab4 |
No files matched your search
@@ -0,0 +1,69 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Set directory to location of this script
|
||||
# https://stackoverflow.com/a/3355423/1867984
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
yarn -v
|
||||
node -v
|
||||
|
||||
echo 'Installing Gitbook CLI'
|
||||
|
||||
yarn global bin
|
||||
yarn config get prefix
|
||||
yarn config set prefix ~/.yarn
|
||||
export PATH="$PATH:`yarn global bin`"
|
||||
|
||||
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
|
||||
gitbook install
|
||||
gitbook 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 [ -d "${D}" ]; then
|
||||
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
|
||||
|
||||
# Back to repo root
|
||||
cd ..
|
||||
|
||||
echo "Done generating documentation output"
|
||||
echo 'STARTING PUBLISH'
|
||||
|
||||
# WILL ALWAYS FAIL IF INITIATED FROM PR BRANCH
|
||||
./node_modules/.bin/gh-pages \
|
||||
--silent \
|
||||
--repo https://$GITHUB_TOKEN@github.com/OHIF/Viewers.git \
|
||||
--message 'Autogenerated Message: [ci skip]' \
|
||||
--dist docs/latest/_book
|
||||
+28
-37
@@ -187,13 +187,10 @@ jobs:
|
||||
no\n" > ~/.ssh/config
|
||||
- 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 gitbook-cli
|
||||
- run: yarn global add gh-pages
|
||||
- run:
|
||||
name: Generate Docs
|
||||
command: yarn run staticDeploy
|
||||
- run:
|
||||
name: Publish Docs
|
||||
command: yarn run docs:publish
|
||||
- run: chmod +x ~/repo/.circleci/build-and-publish-docs.sh
|
||||
- run: ~/repo/.circleci/build-and-publish-docs.sh
|
||||
|
||||
docker_publish:
|
||||
<<: *defaults
|
||||
@@ -224,7 +221,7 @@ jobs:
|
||||
docker push ohif/$IMAGE_NAME:latest
|
||||
fi
|
||||
|
||||
deploy_demo_site:
|
||||
viewer_demo_build:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
@@ -233,21 +230,20 @@ jobs:
|
||||
- run:
|
||||
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
|
||||
export FILE_1=$(find ./build/static/js -type f -name "2.*.js" -exec basename {} \;)
|
||||
export FILE_MAIN=$(find ./build/static/js -type f -name "main.*.js" -exec basename {} \;)
|
||||
export FILE_RUNTIME_MAIN=$(find ./build/static/js -type f -name "runtime~main.*.js" -exec basename {} \;)
|
||||
curl https://api.rollbar.com/api/1/sourcemap -F source_map=@build/static/js/$FILE_1.map -F access_token=$ROLLBAR_TOKEN -F version=$CIRCLE_SHA1 -F minified_url=https://$GOOGLE_STORAGE_BUCKET/static/js/$FILE_1
|
||||
curl https://api.rollbar.com/api/1/sourcemap -F source_map=@build/static/js/$FILE_MAIN.map -F access_token=$ROLLBAR_TOKEN -F version=$CIRCLE_SHA1 -F minified_url=https://$GOOGLE_STORAGE_BUCKET/static/js/$FILE_MAIN
|
||||
curl https://api.rollbar.com/api/1/sourcemap -F source_map=@build/static/js/$FILE_RUNTIME_MAIN.map -F access_token=$ROLLBAR_TOKEN -F version=$CIRCLE_SHA1 -F minified_url=https://$GOOGLE_STORAGE_BUCKET/static/js/$FILE_RUNTIME_MAIN
|
||||
npx lerna run build:viewer:demo --stream
|
||||
# export FILE_1=$(find ./build/static/js -type f -name "2.*.js" -exec basename {} \;)
|
||||
# export FILE_MAIN=$(find ./build/static/js -type f -name "main.*.js" -exec basename {} \;)
|
||||
# export FILE_RUNTIME_MAIN=$(find ./build/static/js -type f -name "runtime~main.*.js" -exec basename {} \;)
|
||||
# curl https://api.rollbar.com/api/1/sourcemap -F source_map=@build/static/js/$FILE_1.map -F access_token=$ROLLBAR_TOKEN -F version=$CIRCLE_SHA1 -F minified_url=https://$GOOGLE_STORAGE_BUCKET/static/js/$FILE_1
|
||||
# curl https://api.rollbar.com/api/1/sourcemap -F source_map=@build/static/js/$FILE_MAIN.map -F access_token=$ROLLBAR_TOKEN -F version=$CIRCLE_SHA1 -F minified_url=https://$GOOGLE_STORAGE_BUCKET/static/js/$FILE_MAIN
|
||||
# curl https://api.rollbar.com/api/1/sourcemap -F source_map=@build/static/js/$FILE_RUNTIME_MAIN.map -F access_token=$ROLLBAR_TOKEN -F version=$CIRCLE_SHA1 -F minified_url=https://$GOOGLE_STORAGE_BUCKET/static/js/$FILE_RUNTIME_MAIN
|
||||
curl --request POST https://api.rollbar.com/api/1/deploy/ -F access_token=$ROLLBAR_TOKEN -F environment=$GOOGLE_STORAGE_BUCKET -F revision=$CIRCLE_SHA1 -F local_username=CircleCI
|
||||
# Persist :+1:
|
||||
- persist_to_workspace:
|
||||
root: ~/repo
|
||||
paths: .
|
||||
|
||||
demo_site_publish:
|
||||
viewer_demo_publish:
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: google/cloud-sdk
|
||||
@@ -259,18 +255,13 @@ jobs:
|
||||
- run:
|
||||
name: Deploy latest version to viewer.ohif.org
|
||||
command: |
|
||||
# This file will exist if a new version was published by
|
||||
# our `semantic-release` command in the previous job
|
||||
#if [[ ! -e tmp/updated-version.txt ]]; then
|
||||
# exit 0
|
||||
#else
|
||||
echo $GCLOUD_SERVICE_KEY | gcloud auth activate-service-account --key-file=-
|
||||
gcloud --quiet config set project ${GOOGLE_PROJECT_ID}
|
||||
gcloud --quiet config set compute/zone ${GOOGLE_COMPUTE_ZONE}
|
||||
|
||||
gsutil -m rm gs://$GOOGLE_STORAGE_BUCKET/**
|
||||
gsutil -m rsync -R build gs://$GOOGLE_STORAGE_BUCKET
|
||||
#fi
|
||||
# https://circleci.com/docs/2.0/google-auth/#authorization
|
||||
echo $GCLOUD_SERVICE_KEY | gcloud auth activate-service-account --key-file=-
|
||||
gcloud --quiet config set project ${GOOGLE_PROJECT_ID}
|
||||
gcloud --quiet config set compute/zone ${GOOGLE_COMPUTE_ZONE}
|
||||
# Remove all files in Storage Bucket; Push latest
|
||||
gsutil -m rm gs://$GOOGLE_STORAGE_BUCKET/**
|
||||
gsutil -m rsync -R platform/viewer/dist gs://$GOOGLE_STORAGE_BUCKET
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
@@ -330,17 +321,17 @@ workflows:
|
||||
requires:
|
||||
- cypress/run
|
||||
# Update docs.ohif.org
|
||||
# - docs_publish:
|
||||
# requires:
|
||||
# - cypress/run
|
||||
- docs_publish:
|
||||
requires:
|
||||
- cypress/run
|
||||
# Update hub.docker.org
|
||||
# - docker_publish:
|
||||
# requires:
|
||||
# - npm_publish
|
||||
# Update viewer.ohif.org
|
||||
# - build_demo_site:
|
||||
# requires:
|
||||
# - cypress/run
|
||||
# - demo_site_publish:
|
||||
# requires:
|
||||
# - build_demo_site
|
||||
- viewer_demo_build:
|
||||
requires:
|
||||
- cypress/run
|
||||
- viewer_demo_publish:
|
||||
requires:
|
||||
- viewer_demo_build
|
||||
@@ -1,15 +0,0 @@
|
||||
<script>
|
||||
// Note: This is a client access token so there is no issue with having it publicly available
|
||||
var _rollbarConfig = {
|
||||
accessToken: "739c64cd39e84592ba062bc29aac9769",
|
||||
captureUncaught: true,
|
||||
captureUnhandledRejections: true,
|
||||
payload: {
|
||||
environment: "viewer.ohif.org"
|
||||
}
|
||||
};
|
||||
// Rollbar Snippet
|
||||
!function(r){var e={};function o(n){if(e[n])return e[n].exports;var t=e[n]={i:n,l:!1,exports:{}};return r[n].call(t.exports,t,t.exports,o),t.l=!0,t.exports}o.m=r,o.c=e,o.d=function(r,e,n){o.o(r,e)||Object.defineProperty(r,e,{enumerable:!0,get:n})},o.r=function(r){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(r,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(r,"__esModule",{value:!0})},o.t=function(r,e){if(1&e&&(r=o(r)),8&e)return r;if(4&e&&"object"==typeof r&&r&&r.__esModule)return r;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:r}),2&e&&"string"!=typeof r)for(var t in r)o.d(n,t,function(e){return r[e]}.bind(null,t));return n},o.n=function(r){var e=r&&r.__esModule?function(){return r.default}:function(){return r};return o.d(e,"a",e),e},o.o=function(r,e){return Object.prototype.hasOwnProperty.call(r,e)},o.p="",o(o.s=0)}([function(r,e,o){var n=o(1),t=o(4);_rollbarConfig=_rollbarConfig||{},_rollbarConfig.rollbarJsUrl=_rollbarConfig.rollbarJsUrl||"https://cdnjs.cloudflare.com/ajax/libs/rollbar.js/2.7.1/rollbar.min.js",_rollbarConfig.async=void 0===_rollbarConfig.async||_rollbarConfig.async;var a=n.setupShim(window,_rollbarConfig),l=t(_rollbarConfig);window.rollbar=n.Rollbar,a.loadFull(window,document,!_rollbarConfig.async,_rollbarConfig,l)},function(r,e,o){var n=o(2);function t(r){return function(){try{return r.apply(this,arguments)}catch(r){try{console.error("[Rollbar]: Internal error",r)}catch(r){}}}}var a=0;function l(r,e){this.options=r,this._rollbarOldOnError=null;var o=a++;this.shimId=function(){return o},"undefined"!=typeof window&&window._rollbarShims&&(window._rollbarShims[o]={handler:e,messages:[]})}var i=o(3),d=function(r,e){return new l(r,e)},c=function(r){return new i(d,r)};function s(r){return t(function(){var e=Array.prototype.slice.call(arguments,0),o={shim:this,method:r,args:e,ts:new Date};window._rollbarShims[this.shimId()].messages.push(o)})}l.prototype.loadFull=function(r,e,o,n,a){var l=!1,i=e.createElement("script"),d=e.getElementsByTagName("script")[0],c=d.parentNode;i.crossOrigin="",i.src=n.rollbarJsUrl,o||(i.async=!0),i.onload=i.onreadystatechange=t(function(){if(!(l||this.readyState&&"loaded"!==this.readyState&&"complete"!==this.readyState)){i.onload=i.onreadystatechange=null;try{c.removeChild(i)}catch(r){}l=!0,function(){var e;if(void 0===r._rollbarDidLoad){e=new Error("rollbar.js did not load");for(var o,n,t,l,i=0;o=r._rollbarShims[i++];)for(o=o.messages||[];n=o.shift();)for(t=n.args||[],i=0;i<t.length;++i)if("function"==typeof(l=t[i])){l(e);break}}"function"==typeof a&&a(e)}()}}),c.insertBefore(i,d)},l.prototype.wrap=function(r,e,o){try{var n;if(n="function"==typeof e?e:function(){return e||{}},"function"!=typeof r)return r;if(r._isWrap)return r;if(!r._rollbar_wrapped&&(r._rollbar_wrapped=function(){o&&"function"==typeof o&&o.apply(this,arguments);try{return r.apply(this,arguments)}catch(o){var e=o;throw e&&("string"==typeof e&&(e=new String(e)),e._rollbarContext=n()||{},e._rollbarContext._wrappedSource=r.toString(),window._rollbarWrappedError=e),e}},r._rollbar_wrapped._isWrap=!0,r.hasOwnProperty))for(var t in r)r.hasOwnProperty(t)&&(r._rollbar_wrapped[t]=r[t]);return r._rollbar_wrapped}catch(e){return r}};for(var p="log,debug,info,warn,warning,error,critical,global,configure,handleUncaughtException,handleUnhandledRejection,captureEvent,captureDomContentLoaded,captureLoad".split(","),u=0;u<p.length;++u)l.prototype[p[u]]=s(p[u]);r.exports={setupShim:function(r,e){if(r){var o=e.globalAlias||"Rollbar";if("object"==typeof r[o])return r[o];r._rollbarShims={},r._rollbarWrappedError=null;var a=new c(e);return t(function(){e.captureUncaught&&(a._rollbarOldOnError=r.onerror,n.captureUncaughtExceptions(r,a,!0),n.wrapGlobals(r,a,!0)),e.captureUnhandledRejections&&n.captureUnhandledRejections(r,a,!0);var t=e.autoInstrument;return!1!==e.enabled&&(void 0===t||!0===t||"object"==typeof t&&t.network)&&r.addEventListener&&(r.addEventListener("load",a.captureLoad.bind(a)),r.addEventListener("DOMContentLoaded",a.captureDomContentLoaded.bind(a))),r[o]=a,a})()}},Rollbar:c}},function(r,e){function o(r,e,o){if(e.hasOwnProperty&&e.hasOwnProperty("addEventListener")){for(var n=e.addEventListener;n._rollbarOldAdd&&n.belongsToShim;)n=n._rollbarOldAdd;var t=function(e,o,t){n.call(this,e,r.wrap(o),t)};t._rollbarOldAdd=n,t.belongsToShim=o,e.addEventListener=t;for(var a=e.removeEventListener;a._rollbarOldRemove&&a.belongsToShim;)a=a._rollbarOldRemove;var l=function(r,e,o){a.call(this,r,e&&e._rollbar_wrapped||e,o)};l._rollbarOldRemove=a,l.belongsToShim=o,e.removeEventListener=l}}r.exports={captureUncaughtExceptions:function(r,e,o){if(r){var n;if("function"==typeof e._rollbarOldOnError)n=e._rollbarOldOnError;else if(r.onerror){for(n=r.onerror;n._rollbarOldOnError;)n=n._rollbarOldOnError;e._rollbarOldOnError=n}var t=function(){var o=Array.prototype.slice.call(arguments,0);!function(r,e,o,n){r._rollbarWrappedError&&(n[4]||(n[4]=r._rollbarWLine truncated
|
||||
// End Rollbar Snippet
|
||||
</script>
|
||||
</head>
|
||||
@@ -0,0 +1,28 @@
|
||||
# GitHub App: Stale
|
||||
# https://github.com/apps/stale
|
||||
#
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 21
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- 'Story 🙌'
|
||||
- 'Bug: Verified 🐛'
|
||||
- 'Task: CI/Tooling 🤖'
|
||||
- 'Task: Docs 📖'
|
||||
- 'Task: Docs :book:'
|
||||
- 'Task: Refactor 🛠'
|
||||
- 'Task: Tests 🔬'
|
||||
- 'PR: Awaiting Review 👀'
|
||||
- 'Triage 🏳️'
|
||||
- 'Announcement 🎉'
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: 'Stale :baguette_bread:'
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
||||
@@ -13,9 +13,6 @@ node -v
|
||||
# should also symlink all projects appropriately
|
||||
yarn install --no-ignore-optional --pure-lockfile
|
||||
|
||||
dir
|
||||
ls
|
||||
|
||||
# Build && Move PWA Output
|
||||
yarn run build:ci
|
||||
mkdir -p ./.netlify/www/pwa
|
||||
@@ -27,4 +24,4 @@ mv platform/viewer/dist/* .netlify/www/pwa -v
|
||||
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
|
||||
# npx cross-env PUBLIC_URL=/demo APP_CONFIG=config/netlify.js react-scripts --max_old_space_size=4096 build
|
||||
@@ -1,13 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Set directory to location of this script
|
||||
# https://stackoverflow.com/a/3355423/1867984
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
echo 'PUBLISHING'
|
||||
|
||||
./node_modules/.bin/gh-pages \
|
||||
--silent \
|
||||
--repo https://$GITHUB_TOKEN@github.com/OHIF/Viewers.git \
|
||||
--message 'Autogenerated Message: [ci skip]' \
|
||||
--dist docs/latest/_book
|
||||
Regular → Executable
File mode changed.
@@ -0,0 +1,101 @@
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const autoprefixer = require('autoprefixer');
|
||||
|
||||
module.exports = (env, argv, { SRC_DIR, DIST_DIR }) => {
|
||||
const mode =
|
||||
process.env.NODE_ENV === 'production' ? 'production' : 'development';
|
||||
|
||||
return {
|
||||
mode,
|
||||
entry: {
|
||||
bundle: `${SRC_DIR}/index.js`,
|
||||
},
|
||||
context: SRC_DIR,
|
||||
module: {
|
||||
rules: [
|
||||
/**
|
||||
* JSX
|
||||
*/
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
exclude: [/node_modules/, /packages\\extension/],
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
// Find babel.config.js in monorepo root
|
||||
// https://babeljs.io/docs/en/options#rootmode
|
||||
rootMode: 'upward',
|
||||
envName: mode,
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
// Do not transform ES6 modules to another format.
|
||||
// Webpack will take care of that.
|
||||
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,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
/**
|
||||
* This allows us to include web workers in our bundle, and VTK.js
|
||||
* web workers in our bundle. While this increases bundle size, it
|
||||
* cuts down on the number of includes we need for `script tag` usage.
|
||||
*/
|
||||
{
|
||||
test: /\.worker\.js$/,
|
||||
include: /vtk\.js[\/\\]Sources/,
|
||||
use: [
|
||||
{
|
||||
loader: 'worker-loader',
|
||||
options: { inline: true, fallback: false },
|
||||
},
|
||||
],
|
||||
},
|
||||
/**
|
||||
* This is exclusively used by `vtk.js` to bundle glsl files.
|
||||
*/
|
||||
{
|
||||
test: /\.glsl$/i,
|
||||
include: /vtk\.js[\/\\]Sources/,
|
||||
loader: 'shader-loader',
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
// Which directories to search when resolving modules
|
||||
modules: [
|
||||
// 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', '*'],
|
||||
// symlinked resources are resolved to their real path, not their symlinked location
|
||||
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',
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -1,10 +1,13 @@
|
||||
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 }) => {
|
||||
const mode =
|
||||
process.env.NODE_ENV === 'production' ? 'production' : 'development';
|
||||
|
||||
return {
|
||||
mode,
|
||||
entry: {
|
||||
bundle: `${SRC_DIR}/index.js`,
|
||||
},
|
||||
@@ -22,6 +25,7 @@ module.exports = (env, argv, { SRC_DIR, DIST_DIR }) => {
|
||||
// Find babel.config.js in monorepo root
|
||||
// https://babeljs.io/docs/en/options#rootmode
|
||||
rootMode: 'upward',
|
||||
envName: mode,
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
@@ -115,7 +119,7 @@ module.exports = (env, argv, { SRC_DIR, DIST_DIR }) => {
|
||||
'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 || ''),
|
||||
'process.env.PUBLIC_URL': JSON.stringify(process.env.PUBLIC_URL || '/'),
|
||||
}),
|
||||
],
|
||||
// Fix: https://github.com/webpack-contrib/css-loader/issues/447#issuecomment-285598881
|
||||
|
||||
@@ -22,6 +22,7 @@ module.exports = {
|
||||
// https://babeljs.io/docs/en/options#babelrcroots
|
||||
babelrcRoots: ['./platform/*', './extensions/*'],
|
||||
plugins: [
|
||||
'react-hot-loader/babel',
|
||||
'inline-react-svg',
|
||||
'@babel/plugin-proposal-class-properties',
|
||||
'@babel/plugin-proposal-object-rest-spread',
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Set directory to location of this script
|
||||
# https://stackoverflow.com/a/3355423/1867984
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
yarn -v
|
||||
node -v
|
||||
|
||||
echo 'Installing Gitbook CLI'
|
||||
yarn global add 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
|
||||
gitbook install
|
||||
gitbook 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 [ -d "${D}" ]; then
|
||||
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
|
||||
|
||||
# Back to repo root
|
||||
cd ..
|
||||
|
||||
echo "Done generating documentation output"
|
||||
echo 'PUBLISHING'
|
||||
|
||||
./node_modules/.bin/gh-pages \
|
||||
--silent \
|
||||
--repo https://$GITHUB_TOKEN@github.com/OHIF/Viewers.git \
|
||||
--message 'Autogenerated Message: [ci skip]' \
|
||||
--dist docs/latest/_book
|
||||
@@ -10,7 +10,7 @@
|
||||
<!-- CORNERSTONE.js -->
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://www.npmjs.com/package/ohif-cornerstone-extension">
|
||||
<a href="https://www.npmjs.com/package/@ohif/extension-cornerstone">
|
||||
Cornerstone
|
||||
</a>
|
||||
</td>
|
||||
@@ -22,7 +22,7 @@
|
||||
<!-- VTK.js -->
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://www.npmjs.com/package/ohif-vtk-extension">
|
||||
<a href="https://www.npmjs.com/package/@ohif/extension-vtk">
|
||||
VTK.js
|
||||
</a>
|
||||
</td>
|
||||
@@ -33,30 +33,30 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="">HTML</a>
|
||||
<a href="https://www.npmjs.com/package/@ohif/extension-dicom-html">DICOM HTML</a>
|
||||
</td>
|
||||
<td>
|
||||
Renders text and HTML content for <a href="https://github.com/OHIF/Viewers/blob/react/extensions/ohif-dicom-html-extension/src/OHIFDicomHtmlSopClassHandler.js#L7-L15">specific SopClassUIDs</a>.
|
||||
Renders text and HTML content for <a href="https://github.com/OHIF/Viewers/blob/master/extensions/dicom-html/src/OHIFDicomHtmlSopClassHandler.js#L4-L12">specific SopClassUIDs</a>.
|
||||
</td>
|
||||
<td>Viewport, SopClassHandler</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://www.npmjs.com/package/ohif-dicom-pdf-extension">PDF</a>
|
||||
<a href="https://www.npmjs.com/package/@ohif/extension-dicom-pdf">DICOM PDF</a>
|
||||
</td>
|
||||
<td>
|
||||
Renders PDFs for a <a href="https://github.com/OHIF/Viewers/blob/react/extensions/ohif-dicom-pdf-extension/src/OHIFDicomPDFSopClassHandler.js#L8">specific SopClassUID</a>.
|
||||
Renders PDFs for a <a href="https://github.com/OHIF/Viewers/blob/master/extensions/dicom-pdf/src/OHIFDicomPDFSopClassHandler.js#L4-L6">specific SopClassUID</a>.
|
||||
</td>
|
||||
<td>Viewport, SopClassHandler</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="https://www.npmjs.com/package/ohif-dicom-microscopy-extension">Microscopy</a>
|
||||
<a href="https://www.npmjs.com/package/@ohif/extension-dicom-microscopy">DICOM Microscopy</a>
|
||||
</td>
|
||||
<td>
|
||||
Renders Microscopy images for a <a href="https://github.com/OHIF/Viewers/blob/react/extensions/ohif-dicom-microscopy-extension/src/DicomMicroscopySopClassHandler.js#L6">specific SopClassUID</a>.
|
||||
Renders Microscopy images for a <a href="https://github.com/OHIF/Viewers/blob/master/extensions/dicom-microscopy/src/DicomMicroscopySopClassHandler.js#L5-L7">specific SopClassUID</a>.
|
||||
</td>
|
||||
<td>Viewport, SopClassHandler</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</table>
|
||||
@@ -152,7 +152,7 @@ is used depends on:
|
||||
<center><i>An example of three Viewports</i></center>
|
||||
|
||||
For a complete example implementation,
|
||||
[check out the OHIFCornerstoneViewport](https://github.com/OHIF/Viewers/blob/react/extensions/ohif-cornerstone-extension/src/OHIFCornerstoneViewport.js).
|
||||
[check out the OHIFCornerstoneViewport](https://github.com/OHIF/Viewers/blob/master/extensions/cornerstone/src/OHIFCornerstoneViewport.js).
|
||||
|
||||
#### Toolbar
|
||||
|
||||
@@ -168,7 +168,7 @@ store.
|
||||
Toolbar components are rendered in the `ToolbarRow` component.
|
||||
|
||||
For a complete example implementation,
|
||||
[check out the OHIFCornerstoneViewport's Toolbar Module](https://github.com/OHIF/Viewers/blob/react/extensions/ohif-cornerstone-extension/src/ToolbarModule.js).
|
||||
[check out the OHIFCornerstoneViewport's Toolbar Module](https://github.com/OHIF/Viewers/blob/master/extensions/cornerstone/src/toolbarModule.js).
|
||||
|
||||
#### SopClassHandler
|
||||
|
||||
@@ -197,9 +197,9 @@ would like included at startup.
|
||||
_app.js_
|
||||
|
||||
```js
|
||||
import { createStore, combineReducers } from "redux";
|
||||
import OHIF from "@ohif/core";
|
||||
import OHIFCornerstoneExtension from "ohif-cornerstone-extension";
|
||||
import { createStore, combineReducers } from 'redux';
|
||||
import OHIF from '@ohif/core';
|
||||
import OHIFCornerstoneExtension from 'ohif-cornerstone-extension';
|
||||
|
||||
const combined = combineReducers(OHIF.redux.reducers);
|
||||
const store = createStore(combined);
|
||||
@@ -214,8 +214,8 @@ ExtensionManager.registerExtensions(store, extensions);
|
||||
|
||||
A small number of powerful extensions for popular use cases are maintained by
|
||||
OHIF. They're co-located in the
|
||||
[`OHIF/Viewers`](https://github.com/OHIF/Viewers/tree/react/) repository, in the
|
||||
top level [`extensions/`](https://github.com/OHIF/Viewers/tree/react/extensions)
|
||||
[`OHIF/Viewers`](https://github.com/OHIF/Viewers) repository, in the top level
|
||||
[`extensions/`](https://github.com/OHIF/Viewers/tree/master/extensions)
|
||||
directory.
|
||||
|
||||
{% include "./_maintained-extensions-table.md" %}
|
||||
@@ -225,6 +225,6 @@ directory.
|
||||
-->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[example-ext-src]: https://github.com/OHIF/Viewers/blob/master/extensions/_ohif-example-extension/src/index.js)
|
||||
[module-types]: https://github.com/OHIF/ohif-core/blob/43c08a29eff3fb646a0e83a03a236ddd84f4a6e8/src/plugins.js#L1-L6
|
||||
[example-ext-src]: https://github.com/OHIF/Viewers/tree/master/extensions/_example/src
|
||||
[module-types]: https://github.com/OHIF/Viewers/blob/master/platform/core/src/extensions/MODULE_TYPES.js
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -53,7 +53,7 @@ Images can even be transcoded on the fly if this is desired.
|
||||
```bash
|
||||
cd OHIFViewer
|
||||
yarn install
|
||||
REACT_APP_CONFIG=config/google.js yarn run dev
|
||||
APP_CONFIG=config/google.js yarn run dev
|
||||
```
|
||||
|
||||
## Running via Docker
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
# Contributing: Tests
|
||||
|
||||
> Testing is an opinionated topic. Here is a rough overview of our testing
|
||||
> philosiphy. See something you want to discuss or think should be changed? Open
|
||||
> a PR and let's discuss.
|
||||
|
||||
You're an engineer. You know how to write code, and writing tests isn't all that
|
||||
different. But do you know why we write tests? Do you know when to write one, or
|
||||
what kind of test to write? How do you know if a test is a _"good"_ test? This
|
||||
document's goal is to give you the tools you need to make those determinations.
|
||||
|
||||
Okay. So why do we write tests? To increase our... **CONFIDENCE**
|
||||
|
||||
- If I do a large refactor, does everything still work?
|
||||
- If I changed some critical piece of code, is it safe to push to production?
|
||||
|
||||
Gaining the confidence we need to answer these questions after every change is
|
||||
costly. Good tests allow us to answer them without manual regression testing.
|
||||
What and how we choose to test to increase that confidence is nuanced.
|
||||
|
||||
## Kinds of Tests
|
||||
|
||||
Test's buy us confidence, but not all tests are created equal. Each kind of test
|
||||
has a different cost to write and maintain. An expensive test is worth it if it
|
||||
gives us confidence that a payment is processed, but it may not be the best
|
||||
choice for asserting an element's border color.
|
||||
|
||||
| Test Type | Example | Speed | Cost |
|
||||
| ----------- | ------------------------------------------------------------------------ | ---------------- | ------------------------------------------------------------------------ |
|
||||
| Static | `addNums(1, '2')` called with `string`, expected `int`. | :rocket: Instant | :money_with_wings: |
|
||||
| Unit | `addNums(1, 2)` returns expected result `3` | :airplane: Fast | :money_with_wings::money_with_wings: |
|
||||
| Integration | Clicking "Sign In", navigates to the dashboard (mocked network requests) | :running: Okay | :money_with_wings::money_with_wings::money_with_wings: |
|
||||
| End-to-end | Clicking "Sign In", navigates to the dashboard (no mocks) | :turtle: Slow | :money_with_wings::money_with_wings::money_with_wings::money_with_wings: |
|
||||
|
||||
- :rocket: Speed: How quickly tests run
|
||||
- :money_with_wings: Cost: Time to write, and to debug when broken (more points
|
||||
of failure)
|
||||
|
||||
### Static Code Analysis
|
||||
|
||||
Modern tooling gives us this "for free". It can catch invalid regular
|
||||
expressions, unused variables, and guarantee we're calling methods/functions
|
||||
with the expected paramater types.
|
||||
|
||||
Example Tooling:
|
||||
|
||||
- [ESLint][eslint-rules]
|
||||
- [TypeScript][typescript-docs] or [Flow][flow-org]
|
||||
|
||||
### Unit Tests
|
||||
|
||||
The building blocks of our libraries and applications. For these, you'll often
|
||||
be testing a single function or method. Conceptually, this equates to:
|
||||
|
||||
_Pure Function Test:_
|
||||
|
||||
- If I call `sum(2, 2)`, I expect the output to be `4`
|
||||
|
||||
_Side Effect Test:_
|
||||
|
||||
- If I call `resetViewport(viewport)`, I expect `cornerstone.reset` to be called
|
||||
with `viewport`
|
||||
|
||||
#### When to use
|
||||
|
||||
Anything that is exposed as public API should have unit tests.
|
||||
|
||||
#### When to avoid
|
||||
|
||||
You're actually testing implementation details. You're testing implementation
|
||||
details if:
|
||||
|
||||
- Your test does something that the consumer of your code would never do.
|
||||
- IE. Using a private function
|
||||
- A refactor can break your tests
|
||||
|
||||
### Integration Tests
|
||||
|
||||
We write integration tests to gain confidence that several units work together.
|
||||
Generally, we want to mock as little as possible for these tests. In practice,
|
||||
this means only mocking network requests.
|
||||
|
||||
#### When to use
|
||||
|
||||
...
|
||||
|
||||
### End-to-End Tests
|
||||
|
||||
These are the most expensive tests to write and maintain. Largely because, when
|
||||
they fail, they have the largest number of potential points of failure. So why
|
||||
do we write them? Because they also buy us the most confidence.
|
||||
|
||||
#### When to use
|
||||
|
||||
Mission critical features and functionality, or to cover a large breadth of
|
||||
functionality until unit tests catch up. Unsure if we should have a test for
|
||||
feature `X` or scenario `Y`? Open an issue and let's discuss.
|
||||
|
||||
## Summary
|
||||
|
||||
- Does your test increase confidence?
|
||||
- Does the test type chosen balance the cost-to-confidence ratio?
|
||||
|
||||
## Further Reading
|
||||
|
||||
### General
|
||||
|
||||
- [Assert(js) Conf 2018 Talks][assert-js-talks]
|
||||
- [Write tests. Not too many. Mostly integration.][kent-talk] - Kent C. Dodds
|
||||
- [I see your point, but…][gleb-talk] - Gleb Bahmutov
|
||||
- [Static vs Unit vs Integration vs E2E Testing][kent-blog] - Kent C. Dodds
|
||||
(Blog)
|
||||
|
||||
### End-to-end Testing w/ Cypress
|
||||
|
||||
- [Getting Started](https://docs.cypress.io/guides/overview/why-cypress.html)
|
||||
- Be sure to check out `Getting Started` and `Core Concepts`
|
||||
- [Best Practices](https://docs.cypress.io/guides/references/best-practices.html)
|
||||
- [Example Recipes](https://docs.cypress.io/examples/examples/recipes.html)
|
||||
|
||||
## Testing Dorito
|
||||
|
||||
[![testing dorito][testing-dorito-img]][testing-dorito]
|
||||
|
||||
<!--
|
||||
Links
|
||||
-->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[eslint-rules]: https://eslint.org/docs/rules/
|
||||
[typescript-docs]: https://www.typescriptlang.org/docs/home.html
|
||||
[flow-org]: https://flow.org/
|
||||
<!-- Talks -->
|
||||
[assert-js-talks]: https://www.youtube.com/playlist?list=PLZ66c9_z3umNSrKSb5cmpxdXZcIPNvKGw
|
||||
[kent-talk]: https://www.youtube.com/watch?list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf
|
||||
[gleb-talk]: https://www.youtube.com/watch?v=5FnalKRjpZk
|
||||
[kent-blog]: https://kentcdodds.com/blog/unit-vs-integration-vs-e2e-tests
|
||||
<!-- Images -->
|
||||
[testing-trophy]: https://twitter.com/kentcdodds/status/960723172591992832?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E960723172591992832&ref_url=https%3A%2F%2Fkentcdodds.com%2Fblog%2Fwrite-tests
|
||||
[aaron-square]: https://twitter.com/Carofine247/status/966727489274961920
|
||||
[gleb-pyramid]: https://twitter.com/Carofine247/status/966764532046684160/photo/3
|
||||
[testing-pyramid]: https://dojo.ministryoftesting.com/dojo/lessons/the-mobile-test-pyramid
|
||||
[testing-dorito]: https://twitter.com/denvercoder/status/960752578198843392
|
||||
[testing-dorito-img]: https://pbs.twimg.com/media/DVVHXycUMAAcN-F?format=jpg&name=4096x4096
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -71,11 +71,11 @@ how to configure the project for your own imaging archive below.
|
||||
#### How it Works
|
||||
|
||||
The configuration for our project is in the `/public/config` directory. Our
|
||||
build process knows which configuration file to use based on the
|
||||
`REACT_APP_CONFIG` environment variable. By default, its value is
|
||||
[`default.js`](https://github.com/OHIF/Viewers/blob/react/public/config/default.js).
|
||||
When we build, the `%REACT_APP_CONFIG%` value in
|
||||
our[`/public/index.html`](https://github.com/OHIF/Viewers/blob/react/public/index.html#L12-L15)
|
||||
build process knows which configuration file to use based on the `APP_CONFIG`
|
||||
environment variable. By default, its value is
|
||||
[`default.js`](https://github.com/OHIF/Viewers/blob/master/platform/viewer/public/config/default.js).
|
||||
When we build, the `%APP_CONFIG%` value in
|
||||
our[`/public/index.html`](https://github.com/OHIF/Viewers/blob/master/platform/viewer/public/index.html)
|
||||
file is substituted for the correct configuration file's name. This sets
|
||||
the`window.config` equal to our configuration file's value.
|
||||
|
||||
@@ -104,17 +104,17 @@ window.config = {
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
You can also create a new config file and specify its path relative to the build
|
||||
output's root by setting the `REACT_APP_CONFIG` environment variable. You can
|
||||
set the value of this environment variable a few different ways:
|
||||
output's root by setting the `APP_CONFIG` environment variable. You can set the
|
||||
value of this environment variable a few different ways:
|
||||
|
||||
- [Add a temporary environment variable in your shell](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-temporary-environment-variables-in-your-shell)
|
||||
- [Add environment specific variables in `.env` file(s)](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-development-environment-variables-in-env)
|
||||
- Using the `cross-env` package in an npm script:
|
||||
- `"build": "cross-env REACT_APP_CONFIG=config/my-config.js react-scripts build"`
|
||||
- `"build": "cross-env APP_CONFIG=config/my-config.js react-scripts build"`
|
||||
|
||||
After updating the configuration, `yarn run build:web` to generate updated build
|
||||
output.
|
||||
|
||||
@@ -11,7 +11,7 @@ control.
|
||||
Do not use this recipe to host sensitive medical data on the open web. Depending
|
||||
on your company's policies, this may be an appropriate setup on an internal
|
||||
network when protected with a server's basic authentication. For a more robust
|
||||
setup, check out our [user account control recpie](./user-account-control.md)
|
||||
setup, check out our [user account control recipe](./user-account-control.md)
|
||||
that builds on the lessons learned here.
|
||||
|
||||
## Overview
|
||||
@@ -51,7 +51,7 @@ We can solve this one of two ways:
|
||||
|
||||
This solution uses the first approach, but you can see an example of the second
|
||||
in the `docker-compose` bundled with this project for local development:
|
||||
[HERE](#)
|
||||
[HERE](https://github.com/OHIF/Viewers/blob/master/platform/viewer/.recipes/Nginx-Orthanc/docker-compose.yml)
|
||||
|
||||
You can read more about CORS in this Medium article: [Understanding
|
||||
CORS][understanding-cors]
|
||||
@@ -124,10 +124,10 @@ likely want to update:
|
||||
The OHIF Viewer's configuration is imported from a static `.js` file and made
|
||||
available globally at `window.config`. The configuration we use is set to a
|
||||
specific file when we build the viewer, and determined by the env variable:
|
||||
`REACT_APP_CONFIG`. You can see where we set its value in the `dockerfile` for
|
||||
this solution:
|
||||
`APP_CONFIG`. You can see where we set its value in the `dockerfile` for this
|
||||
solution:
|
||||
|
||||
`ENV REACT_APP_CONFIG=config/docker_openresty-orthanc.js`
|
||||
`ENV APP_CONFIG=config/docker_openresty-orthanc.js`
|
||||
|
||||
You can find the configuration we're using here:
|
||||
`/public/config/docker_openresty-orthanc.js`
|
||||
|
||||
@@ -125,10 +125,10 @@ likely want to update:
|
||||
The OHIF Viewer's configuration is imported from a static `.js` file and made
|
||||
available globally at `window.config`. The configuration we use is set to a
|
||||
specific file when we build the viewer, and determined by the env variable:
|
||||
`REACT_APP_CONFIG`. You can see where we set its value in the `dockerfile` for
|
||||
this solution:
|
||||
`APP_CONFIG`. You can see where we set its value in the `dockerfile` for this
|
||||
solution:
|
||||
|
||||
`ENV REACT_APP_CONFIG=config/docker_openresty-orthanc-keycloak.js`
|
||||
`ENV APP_CONFIG=config/docker_openresty-orthanc-keycloak.js`
|
||||
|
||||
You can find the configuration we're using here:
|
||||
`/public/config/docker_openresty-orthanc-keycloak.js`
|
||||
@@ -281,9 +281,9 @@ community members put together:
|
||||
[orthanc-docs]: http://book.orthanc-server.com/users/configuration.html#configuration
|
||||
[lua-resty-openidc-docs]: https://github.com/zmartzone/lua-resty-openidc
|
||||
<!-- SRC -->
|
||||
[config]: #
|
||||
[dockerfile]: #
|
||||
[config-nginx]: #
|
||||
[config-orthanc]: #
|
||||
[config-keycloak]: #
|
||||
[config]: https://github.com/OHIF/Viewers/blob/master/platform/viewer/src/config.js
|
||||
[dockerfile]: https://github.com/OHIF/Viewers/tree/master/platform/viewer/.recipes
|
||||
[config-nginx]: https://github.com/OHIF/Viewers/tree/master/platform/viewer/.recipes
|
||||
[config-orthanc]: https://github.com/OHIF/Viewers/tree/master/platform/viewer/.recipes
|
||||
[config-keycloak]: https://github.com/OHIF/Viewers/tree/master/platform/viewer/.recipes
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -7,11 +7,11 @@
|
||||
## How it Works
|
||||
|
||||
The configuration for our project is in the `/public/config` directory. Our
|
||||
build process knows which configuration file to use based on the
|
||||
`REACT_APP_CONFIG` environment variable. By default, its value is
|
||||
[`default.js`](https://github.com/OHIF/Viewers/blob/react/public/config/default.js).
|
||||
When we build, the `%REACT_APP_CONFIG%` value in
|
||||
our[`/public/index.html`](https://github.com/OHIF/Viewers/blob/react/public/index.html#L12-L15)
|
||||
build process knows which configuration file to use based on the `APP_CONFIG`
|
||||
environment variable. By default, its value is
|
||||
[`default.js`](https://github.com/OHIF/Viewers/blob/master/platform/viewer/public/config/default.js).
|
||||
When we build, the `%APP_CONFIG%` value in
|
||||
our[`/public/index.html`](https://github.com/OHIF/Viewers/blob/master/platform/viewer/public/index.html)
|
||||
file is substituted for the correct configuration file's name. This sets the
|
||||
`window.config` equal to our configuration file's value.
|
||||
|
||||
@@ -40,17 +40,17 @@ window.config = {
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
You can also create a new config file and specify its path relative to the build
|
||||
output's root by setting the `REACT_APP_CONFIG` environment variable. You can
|
||||
set the value of this environment variable a few different ways:
|
||||
output's root by setting the `APP_CONFIG` environment variable. You can set the
|
||||
value of this environment variable a few different ways:
|
||||
|
||||
- [Add a temporary environment variable in your shell](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-temporary-environment-variables-in-your-shell)
|
||||
- [Add environment specific variables in `.env` file(s)](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-development-environment-variables-in-env)
|
||||
- Using the `cross-env` package in an npm script:
|
||||
- `"build": "cross-env REACT_APP_CONFIG=config/my-config.js react-scripts build"`
|
||||
- `"build": "cross-env APP_CONFIG=config/my-config.js react-scripts build"`
|
||||
|
||||
After updating the configuration, `yarn run build:web` to generate updated build
|
||||
output.
|
||||
@@ -60,8 +60,8 @@ _Upload your first Study:_
|
||||
#### Orthanc: Learn More
|
||||
|
||||
You can see the `docker-compose.yml` file this command runs at
|
||||
[`<project-root>/docker/Nginx-Docker/`](#), and more on Orthanc for Docker in
|
||||
[Orthanc's documentation][orthanc-docker].
|
||||
[`<project-root>/platform/viewer/.recipes/Nginx-Orthanc/`](https://github.com/OHIF/Viewers/tree/master/platform/viewer/.recipes/Nginx-Orthanc),
|
||||
and more on Orthanc for Docker in [Orthanc's documentation][orthanc-docker].
|
||||
|
||||
### Connecting to Orthanc
|
||||
|
||||
@@ -87,19 +87,18 @@ is running the `dev:orthanc` script in our project's `package.json`. That script
|
||||
is:
|
||||
|
||||
```js
|
||||
cross-env PORT=5000 REACT_APP_CONFIG=config/docker_nginx-orthanc.js react-scripts start
|
||||
cross-env PORT=5000 APP_CONFIG=config/docker_nginx-orthanc.js react-scripts start
|
||||
```
|
||||
|
||||
- `cross-env` sets two environment variables
|
||||
- PORT: 5000
|
||||
- REACT_APP_CONFIG: `config/docker_nginx-orthanc.js`
|
||||
- APP_CONFIG: `config/docker_nginx-orthanc.js`
|
||||
- `react-scripts` runs it's `start` script. This is [the de-facto
|
||||
way][cra-start] to run a "Create React App" in development mode.
|
||||
|
||||
The `REACT_APP_CONFIG` value tells our app which file to load on to
|
||||
`window.config`. By default, our app uses the file at
|
||||
`<project-root>/public/config/default.js`. Here is what that configuration looks
|
||||
like:
|
||||
The `APP_CONFIG` value tells our app which file to load on to `window.config`.
|
||||
By default, our app uses the file at `<project-root>/public/config/default.js`.
|
||||
Here is what that configuration looks like:
|
||||
|
||||
```js
|
||||
window.config = {
|
||||
|
||||
@@ -37,8 +37,8 @@ Some tips for filing a new issue:
|
||||
At the moment we are in the process of defining our roadmap and will do our best
|
||||
to communicate this to the community. If your requested feature is on the
|
||||
roadmap, then it will most likely be built at some point. If it is not, you are
|
||||
welcome to build it yourself and [contribute it](../contributing.md). If you
|
||||
have resources and would like to fund the development of a feature, please
|
||||
welcome to build it yourself and [contribute it](contributing.md). If you have
|
||||
resources and would like to fund the development of a feature, please
|
||||
[contact us](http://www.ohif.org).
|
||||
|
||||
### Who should I contact about Academic Collaborations?
|
||||
|
||||
@@ -3,6 +3,33 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.50.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.50.3...@ohif/extension-vtk@0.50.4) (2019-08-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-vtk
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.50.2...@ohif/extension-vtk@0.50.3) (2019-08-22)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-vtk
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.50.1...@ohif/extension-vtk@0.50.2) (2019-08-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Update vtk and viewport dependencies ([98c40bc](https://github.com/OHIF/Viewers/commit/98c40bc))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.50.0-alpha.10...@ohif/extension-vtk@0.50.1) (2019-08-14)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-vtk
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-vtk",
|
||||
"version": "0.50.1",
|
||||
"version": "0.50.4",
|
||||
"description": "OHIF extension for VTK.js",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
@@ -48,15 +48,15 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"react-vtkjs-viewport": "0.0.9",
|
||||
"vtk.js": "^8.11.0"
|
||||
"react-vtkjs-viewport": "0.0.11",
|
||||
"vtk.js": "^9.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ohif/core": "^0.50.1",
|
||||
"@ohif/core": "^0.50.3",
|
||||
"@ohif/ui": "^0.50.1",
|
||||
"cornerstone-tools": "^3.13.0",
|
||||
"cornerstone-wado-image-loader": "^3.0.0",
|
||||
"dcmjs": "^0.4.7",
|
||||
"dcmjs": "^0.5.1",
|
||||
"dicom-parser": "^1.8.3",
|
||||
"gh-pages": "^2.0.1",
|
||||
"i18next": "^17.0.3",
|
||||
|
||||
+4
-1
@@ -23,6 +23,7 @@
|
||||
"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",
|
||||
"docs:publish": "chmod +x ./build-and-publish-docs.sh && ./build-and-publish-docs.sh",
|
||||
"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"
|
||||
@@ -64,13 +65,14 @@
|
||||
"jest-junit": "^6.4.0",
|
||||
"lerna": "^3.15.0",
|
||||
"lint-staged": "^9.0.2",
|
||||
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
||||
"postcss-import": "^12.0.1",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"postcss-preset-env": "^6.6.0",
|
||||
"prettier": "^1.18.2",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-scripts": "^3.0.1",
|
||||
"react-hot-loader": "^4.12.11",
|
||||
"redux-testkit": "^1.0.6",
|
||||
"shader-loader": "^1.3.1",
|
||||
"style-loader": "^1.0.0",
|
||||
@@ -78,6 +80,7 @@
|
||||
"stylelint-config-recommended": "^2.2.0",
|
||||
"stylus": "^0.54.5",
|
||||
"stylus-loader": "^3.0.2",
|
||||
"terser-webpack-plugin": "^1.4.1",
|
||||
"webpack": "^4.35.2",
|
||||
"webpack-cli": "^3.3.5",
|
||||
"webpack-dev-server": "^3.7.2",
|
||||
|
||||
@@ -3,6 +3,25 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.50.3](https://github.com/OHIF/Viewers/compare/@ohif/core@0.50.2...@ohif/core@0.50.3) (2019-08-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Studies:** Qidosupportsincludefield should be true by default ([#801](https://github.com/OHIF/Viewers/issues/801)) ([a88d865](https://github.com/OHIF/Viewers/commit/a88d865))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.2](https://github.com/OHIF/Viewers/compare/@ohif/core@0.50.1...@ohif/core@0.50.2) (2019-08-22)
|
||||
|
||||
**Note:** Version bump only for package @ohif/core
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.1](https://github.com/OHIF/Viewers/compare/@ohif/core@0.50.0-alpha.10...@ohif/core@0.50.1) (2019-08-14)
|
||||
|
||||
**Note:** Version bump only for package @ohif/core
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/core",
|
||||
"version": "0.50.1",
|
||||
"version": "0.50.3",
|
||||
"description": "Generic business logic for web-based medical imaging applications",
|
||||
"author": "OHIF Core Team",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -18,8 +18,6 @@ import { StudyMetadataSource } from './StudyMetadataSource';
|
||||
import { StudyPrefetcher } from './StudyPrefetcher';
|
||||
import { TypeSafeCollection } from './TypeSafeCollection';
|
||||
|
||||
//import { StudySummary } from './metadata/StudySummary';
|
||||
|
||||
export {
|
||||
OHIFStudyMetadataSource,
|
||||
MetadataProvider,
|
||||
@@ -27,7 +25,7 @@ export {
|
||||
HotkeysManager,
|
||||
ImageSet,
|
||||
StudyPrefetcher,
|
||||
//StudyLoadingListener,
|
||||
StudyLoadingListener,
|
||||
StackLoadingListener,
|
||||
DICOMFileLoadingListener,
|
||||
StudyMetadata,
|
||||
|
||||
@@ -1,458 +0,0 @@
|
||||
var dialogPolyfill = (function() {
|
||||
var supportCustomEvent = window.CustomEvent;
|
||||
if (!supportCustomEvent || typeof supportCustomEvent == 'object') {
|
||||
supportCustomEvent = function CustomEvent(event, x) {
|
||||
x = x || {};
|
||||
var ev = document.createEvent('CustomEvent');
|
||||
ev.initCustomEvent(event, !!x.bubbles, !!x.cancelable, x.detail || null);
|
||||
return ev;
|
||||
};
|
||||
supportCustomEvent.prototype = window.Event.prototype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the nearest <dialog> from the passed element.
|
||||
*
|
||||
* @param {Element} el to search from
|
||||
* @param {HTMLDialogElement} dialog found
|
||||
*/
|
||||
function findNearestDialog(el) {
|
||||
while (el) {
|
||||
if (el.nodeName == 'DIALOG') {
|
||||
return el;
|
||||
}
|
||||
el = el.parentElement;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
var dialogPolyfill = {};
|
||||
|
||||
dialogPolyfill.reposition = function(element) {
|
||||
var scrollTop =
|
||||
document.body.scrollTop || document.documentElement.scrollTop;
|
||||
var topValue = scrollTop + (window.innerHeight - element.offsetHeight) / 2;
|
||||
element.style.top = Math.max(0, topValue) + 'px';
|
||||
element.dialogPolyfillInfo.isTopOverridden = true;
|
||||
};
|
||||
|
||||
dialogPolyfill.inNodeList = function(nodeList, node) {
|
||||
for (var i = 0; i < nodeList.length; ++i) {
|
||||
if (nodeList[i] == node) return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
dialogPolyfill.isInlinePositionSetByStylesheet = function(element) {
|
||||
for (var i = 0; i < document.styleSheets.length; ++i) {
|
||||
var styleSheet = document.styleSheets[i];
|
||||
var cssRules = null;
|
||||
// Some browsers throw on cssRules.
|
||||
try {
|
||||
cssRules = styleSheet.cssRules;
|
||||
} catch (e) {}
|
||||
if (!cssRules) continue;
|
||||
for (var j = 0; j < cssRules.length; ++j) {
|
||||
var rule = cssRules[j];
|
||||
var selectedNodes = null;
|
||||
// Ignore errors on invalid selector texts.
|
||||
try {
|
||||
selectedNodes = document.querySelectorAll(rule.selectorText);
|
||||
} catch (e) {}
|
||||
if (
|
||||
!selectedNodes ||
|
||||
!dialogPolyfill.inNodeList(selectedNodes, element)
|
||||
)
|
||||
continue;
|
||||
var cssTop = rule.style.getPropertyValue('top');
|
||||
var cssBottom = rule.style.getPropertyValue('bottom');
|
||||
if ((cssTop && cssTop != 'auto') || (cssBottom && cssBottom != 'auto'))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
dialogPolyfill.needsCentering = function(dialog) {
|
||||
var computedStyle = window.getComputedStyle(dialog);
|
||||
if (computedStyle.position != 'absolute') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We must determine whether the top/bottom specified value is non-auto. In
|
||||
// WebKit/Blink, checking computedStyle.top == 'auto' is sufficient, but
|
||||
// Firefox returns the used value. So we do this crazy thing instead: check
|
||||
// the inline style and then go through CSS rules.
|
||||
if (
|
||||
(dialog.style.top != 'auto' && dialog.style.top != '') ||
|
||||
(dialog.style.bottom != 'auto' && dialog.style.bottom != '')
|
||||
)
|
||||
return false;
|
||||
return !dialogPolyfill.isInlinePositionSetByStylesheet(dialog);
|
||||
};
|
||||
|
||||
dialogPolyfill.showDialog = function(isModal) {
|
||||
if (this.open) {
|
||||
throw 'InvalidStateError: showDialog called on open dialog';
|
||||
}
|
||||
this.open = true; // TODO: should be a getter mapped to attribute
|
||||
this.setAttribute('open', 'open');
|
||||
|
||||
if (isModal) {
|
||||
// Find element with `autofocus` attribute or first form control
|
||||
var first_form_ctrl = null;
|
||||
var autofocus = null;
|
||||
var findElementToFocus = function(root) {
|
||||
if (!root.children) {
|
||||
return;
|
||||
}
|
||||
for (var i = 0; i < root.children.length; i++) {
|
||||
var elem = root.children[i];
|
||||
if (
|
||||
first_form_ctrl === null &&
|
||||
!elem.disabled &&
|
||||
(elem.nodeName == 'BUTTON' ||
|
||||
elem.nodeName == 'INPUT' ||
|
||||
elem.nodeName == 'KEYGEN' ||
|
||||
elem.nodeName == 'SELECT' ||
|
||||
elem.nodeName == 'TEXTAREA')
|
||||
) {
|
||||
first_form_ctrl = elem;
|
||||
}
|
||||
if (elem.autofocus) {
|
||||
autofocus = elem;
|
||||
return;
|
||||
}
|
||||
findElementToFocus(elem);
|
||||
if (autofocus !== null) return;
|
||||
}
|
||||
};
|
||||
|
||||
findElementToFocus(this);
|
||||
|
||||
if (autofocus !== null) {
|
||||
autofocus.focus();
|
||||
} else if (first_form_ctrl !== null) {
|
||||
first_form_ctrl.focus();
|
||||
}
|
||||
}
|
||||
|
||||
if (dialogPolyfill.needsCentering(this)) dialogPolyfill.reposition(this);
|
||||
if (isModal) {
|
||||
this.dialogPolyfillInfo.modal = true;
|
||||
dialogPolyfill.dm.pushDialog(this);
|
||||
}
|
||||
|
||||
// IE sometimes complains when calling .focus() that it
|
||||
// "Can't move focus to the control because it is invisible, not enabled, or of a type that does not accept the focus."
|
||||
try {
|
||||
if (autofocus !== null) {
|
||||
autofocus.focus();
|
||||
} else if (first_form_ctrl !== null) {
|
||||
first_form_ctrl.focus();
|
||||
}
|
||||
} catch (e) {}
|
||||
this.style.zoom = 1;
|
||||
};
|
||||
|
||||
dialogPolyfill.close = function(retval) {
|
||||
if (!this.open && !window.HTMLDialogElement) {
|
||||
// Native implementations will set .open to false, so ignore this error.
|
||||
throw 'InvalidStateError: close called on closed dialog';
|
||||
}
|
||||
this.open = false;
|
||||
this.removeAttribute('open');
|
||||
|
||||
// Leave returnValue untouched in case it was set directly on the element
|
||||
if (typeof retval != 'undefined') {
|
||||
this.returnValue = retval;
|
||||
}
|
||||
|
||||
// This won't match the native <dialog> exactly because if the user sets top
|
||||
// on a centered polyfill dialog, that top gets thrown away when the dialog is
|
||||
// closed. Not sure it's possible to polyfill this perfectly.
|
||||
if (this.dialogPolyfillInfo.isTopOverridden) {
|
||||
this.style.top = 'auto';
|
||||
}
|
||||
|
||||
if (this.dialogPolyfillInfo.modal) {
|
||||
dialogPolyfill.dm.removeDialog(this);
|
||||
}
|
||||
|
||||
// Triggering "close" event for any attached listeners on the <dialog>
|
||||
var event;
|
||||
if (document.createEvent) {
|
||||
event = document.createEvent('HTMLEvents');
|
||||
event.initEvent('close', true, true);
|
||||
} else {
|
||||
event = new Event('close');
|
||||
}
|
||||
this.dispatchEvent(event);
|
||||
|
||||
return this.returnValue;
|
||||
};
|
||||
|
||||
dialogPolyfill.registerDialog = function(element) {
|
||||
if (element.show) {
|
||||
// console.warn("This browser already supports <dialog>, the polyfill " +
|
||||
// "may not work correctly.");
|
||||
}
|
||||
element.show = dialogPolyfill.showDialog.bind(element, false);
|
||||
element.showModal = dialogPolyfill.showDialog.bind(element, true);
|
||||
element.close = dialogPolyfill.close.bind(element);
|
||||
element.dialogPolyfillInfo = {};
|
||||
element.open = false;
|
||||
};
|
||||
|
||||
// The overlay is used to simulate how a modal dialog blocks the document. The
|
||||
// blocking dialog is positioned on top of the overlay, and the rest of the
|
||||
// dialogs on the pending dialog stack are positioned below it. In the actual
|
||||
// implementation, the modal dialog stacking is controlled by the top layer,
|
||||
// where z-index has no effect.
|
||||
var TOP_LAYER_ZINDEX = 100000;
|
||||
var MAX_PENDING_DIALOGS = 100000;
|
||||
|
||||
dialogPolyfill.DialogManager = function() {
|
||||
this.pendingDialogStack = [];
|
||||
this.overlay = document.createElement('div');
|
||||
this.overlay.style.width = '100%';
|
||||
this.overlay.style.height = '100%';
|
||||
this.overlay.style.position = 'fixed';
|
||||
this.overlay.style.left = '0px';
|
||||
this.overlay.style.top = '0px';
|
||||
this.overlay.style.backgroundColor = 'rgba(0,0,0,0.0)';
|
||||
|
||||
this.focusPageLast = this.createFocusable();
|
||||
this.overlay.appendChild(this.focusPageLast);
|
||||
|
||||
this.overlay.addEventListener('click', function(e) {
|
||||
var redirectedEvent = document.createEvent('MouseEvents');
|
||||
redirectedEvent.initMouseEvent(
|
||||
e.type,
|
||||
e.bubbles,
|
||||
e.cancelable,
|
||||
window,
|
||||
e.detail,
|
||||
e.screenX,
|
||||
e.screenY,
|
||||
e.clientX,
|
||||
e.clientY,
|
||||
e.ctrlKey,
|
||||
e.altKey,
|
||||
e.shiftKey,
|
||||
e.metaKey,
|
||||
e.button,
|
||||
e.relatedTarget
|
||||
);
|
||||
document.body.dispatchEvent(redirectedEvent);
|
||||
});
|
||||
|
||||
// TODO: Only install when any dialogs are open.
|
||||
document.addEventListener(
|
||||
'submit',
|
||||
function(ev) {
|
||||
var method = ev.target.getAttribute('method');
|
||||
method = method ? method.toLowerCase() : '';
|
||||
if (method != 'dialog') {
|
||||
return;
|
||||
}
|
||||
ev.preventDefault();
|
||||
|
||||
var dialog = findNearestDialog(ev.target);
|
||||
if (!dialog) {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: The original event doesn't contain the INPUT element used to
|
||||
// submit the form (if any). Look in some possible places.
|
||||
var returnValue;
|
||||
var cands = [document.activeElement, ev.explicitOriginalTarget];
|
||||
cands.some(function(cand) {
|
||||
if (cand && cand.nodeName == 'INPUT' && cand.form == ev.target) {
|
||||
returnValue = cand.value;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
dialog.close(returnValue);
|
||||
},
|
||||
true
|
||||
);
|
||||
};
|
||||
|
||||
dialogPolyfill.DialogManager.prototype.createFocusable = function(tabIndex) {
|
||||
var span = document.createElement('span');
|
||||
span.tabIndex = tabIndex || 0;
|
||||
span.style.opacity = 0;
|
||||
span.style.position = 'static';
|
||||
return span;
|
||||
};
|
||||
|
||||
dialogPolyfill.DialogManager.prototype.blockDocument = function() {
|
||||
if (!document.body.contains(this.overlay)) {
|
||||
document.body.appendChild(this.overlay);
|
||||
|
||||
// On Safari/Mac (and possibly other browsers), the documentElement is
|
||||
// not focusable. This is required for modal dialogs as it is the first
|
||||
// element to be hit by a tab event, and further tabs are redirected to
|
||||
// the most visible dialog.
|
||||
if (this.needsDocumentElementFocus === undefined) {
|
||||
document.documentElement.focus();
|
||||
this.needsDocumentElementFocus =
|
||||
document.activeElement != document.documentElement;
|
||||
}
|
||||
if (this.needsDocumentElementFocus) {
|
||||
document.documentElement.tabIndex = 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
dialogPolyfill.DialogManager.prototype.unblockDocument = function() {
|
||||
document.body.removeChild(this.overlay);
|
||||
if (this.needsDocumentElementFocus) {
|
||||
// TODO: Restore the previous tabIndex, rather than clearing it.
|
||||
document.documentElement.tabIndex = '';
|
||||
}
|
||||
};
|
||||
|
||||
dialogPolyfill.DialogManager.prototype.updateStacking = function() {
|
||||
if (this.pendingDialogStack.length == 0) {
|
||||
this.unblockDocument();
|
||||
return;
|
||||
}
|
||||
this.blockDocument();
|
||||
|
||||
var zIndex = TOP_LAYER_ZINDEX;
|
||||
for (var i = 0; i < this.pendingDialogStack.length; i++) {
|
||||
if (i == this.pendingDialogStack.length - 1)
|
||||
this.overlay.style.zIndex = zIndex++;
|
||||
var dialog = this.pendingDialogStack[i];
|
||||
dialog.dialogPolyfillInfo.backdrop.style.zIndex = zIndex++;
|
||||
dialog.style.zIndex = zIndex++;
|
||||
}
|
||||
};
|
||||
|
||||
dialogPolyfill.DialogManager.prototype.handleKey = function(event) {
|
||||
var dialogCount = this.pendingDialogStack.length;
|
||||
if (dialogCount == 0) {
|
||||
return;
|
||||
}
|
||||
var dialog = this.pendingDialogStack[dialogCount - 1];
|
||||
var pfi = dialog.dialogPolyfillInfo;
|
||||
|
||||
switch (event.keyCode) {
|
||||
case 9 /* tab */:
|
||||
var activeElement = document.activeElement;
|
||||
var forward = !event.shiftKey;
|
||||
if (forward) {
|
||||
// Tab forward, so look for document or fake last focus element.
|
||||
if (
|
||||
activeElement == document.documentElement ||
|
||||
activeElement == document.body ||
|
||||
activeElement == pfi.backdrop
|
||||
) {
|
||||
pfi.focusFirst.focus();
|
||||
} else if (activeElement == pfi.focusLast) {
|
||||
// TODO: Instead of wrapping to focusFirst, escape to browser chrome.
|
||||
pfi.focusFirst.focus();
|
||||
}
|
||||
} else {
|
||||
// Tab backwards, so look for fake first focus element.
|
||||
if (activeElement == pfi.focusFirst) {
|
||||
// TODO: Instead of wrapping to focusLast, escape to browser chrome.
|
||||
pfi.focusLast.focus();
|
||||
} else if (activeElement == this.focusPageLast) {
|
||||
// The focus element is at the end of the page (e.g., shift-tab from
|
||||
// the window chrome): move current focus to the last element in the
|
||||
// dialog instead.
|
||||
pfi.focusLast.focus();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 27 /* esc */:
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
var cancelEvent = new supportCustomEvent('cancel', {
|
||||
bubbles: false,
|
||||
cancelable: true,
|
||||
});
|
||||
if (dialog.dispatchEvent(cancelEvent)) {
|
||||
dialog.close();
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
dialogPolyfill.DialogManager.prototype.pushDialog = function(dialog) {
|
||||
if (this.pendingDialogStack.length >= MAX_PENDING_DIALOGS) {
|
||||
throw 'Too many modal dialogs';
|
||||
}
|
||||
|
||||
var backdrop = document.createElement('div');
|
||||
backdrop.className = 'backdrop';
|
||||
var clickEventListener = function(e) {
|
||||
var redirectedEvent = document.createEvent('MouseEvents');
|
||||
redirectedEvent.initMouseEvent(
|
||||
e.type,
|
||||
e.bubbles,
|
||||
e.cancelable,
|
||||
window,
|
||||
e.detail,
|
||||
e.screenX,
|
||||
e.screenY,
|
||||
e.clientX,
|
||||
e.clientY,
|
||||
e.ctrlKey,
|
||||
e.altKey,
|
||||
e.shiftKey,
|
||||
e.metaKey,
|
||||
e.button,
|
||||
e.relatedTarget
|
||||
);
|
||||
dialog.dispatchEvent(redirectedEvent);
|
||||
};
|
||||
backdrop.addEventListener('click', clickEventListener);
|
||||
dialog.parentNode.insertBefore(backdrop, dialog.nextSibling);
|
||||
dialog.dialogPolyfillInfo.backdrop = backdrop;
|
||||
dialog.dialogPolyfillInfo.clickEventListener = clickEventListener;
|
||||
this.pendingDialogStack.push(dialog);
|
||||
this.updateStacking();
|
||||
|
||||
dialog.dialogPolyfillInfo.focusFirst = this.createFocusable();
|
||||
dialog.dialogPolyfillInfo.focusLast = this.createFocusable();
|
||||
dialog.appendChild(dialog.dialogPolyfillInfo.focusLast);
|
||||
dialog.insertBefore(
|
||||
dialog.dialogPolyfillInfo.focusFirst,
|
||||
dialog.firstChild
|
||||
);
|
||||
};
|
||||
|
||||
dialogPolyfill.DialogManager.prototype.removeDialog = function(dialog) {
|
||||
var index = this.pendingDialogStack.indexOf(dialog);
|
||||
if (index == -1) {
|
||||
return;
|
||||
}
|
||||
this.pendingDialogStack.splice(index, 1);
|
||||
var backdrop = dialog.dialogPolyfillInfo.backdrop;
|
||||
var clickEventListener = dialog.dialogPolyfillInfo.clickEventListener;
|
||||
backdrop.removeEventListener('click', clickEventListener);
|
||||
backdrop.parentNode.removeChild(backdrop);
|
||||
dialog.dialogPolyfillInfo.backdrop = null;
|
||||
dialog.dialogPolyfillInfo.clickEventListener = null;
|
||||
this.updateStacking();
|
||||
|
||||
dialog.removeChild(dialog.dialogPolyfillInfo.focusFirst);
|
||||
dialog.removeChild(dialog.dialogPolyfillInfo.focusLast);
|
||||
dialog.dialogPolyfillInfo.focusFirst = null;
|
||||
dialog.dialogPolyfillInfo.focusLast = null;
|
||||
};
|
||||
|
||||
dialogPolyfill.dm = new dialogPolyfill.DialogManager();
|
||||
|
||||
document.addEventListener(
|
||||
'keydown',
|
||||
dialogPolyfill.dm.handleKey.bind(dialogPolyfill.dm)
|
||||
);
|
||||
|
||||
return dialogPolyfill;
|
||||
})();
|
||||
@@ -1,34 +0,0 @@
|
||||
dialog
|
||||
position: absolute
|
||||
left: 0
|
||||
right: 0
|
||||
width: -moz-fit-content
|
||||
width: -webkit-fit-content
|
||||
width: fit-content
|
||||
height: -moz-fit-content
|
||||
height: -webkit-fit-content
|
||||
height: fit-content
|
||||
margin: auto
|
||||
border: solid
|
||||
padding: 1em
|
||||
background: white
|
||||
color: black
|
||||
display: none
|
||||
|
||||
dialog[open]
|
||||
display: block
|
||||
|
||||
dialog + .backdrop
|
||||
position: fixed
|
||||
top: 0
|
||||
right: 0
|
||||
bottom: 0
|
||||
left: 0
|
||||
background: rgba(0,0,0,0.1)
|
||||
|
||||
/* for small devices, modal dialogs go full-screen */
|
||||
@media screen and (max-width: 540px)
|
||||
dialog[_polyfill_modal]
|
||||
top: 0
|
||||
width: auto
|
||||
margin: 1em
|
||||
@@ -1 +0,0 @@
|
||||
import './styleProperty.js';
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* https://github.com/swederik/dragula/blob/ccc15d75186f5168e7abadbe3077cf12dab09f8b/styleProperty.js
|
||||
*/
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const browserProps = {};
|
||||
|
||||
function eachVendor(prop, fn) {
|
||||
const prefixes = ['Webkit', 'Moz', 'ms', 'O'];
|
||||
fn(prop);
|
||||
for (let i = 0; i < prefixes.length; i++) {
|
||||
fn(prefixes[i] + prop.charAt(0).toUpperCase() + prop.slice(1));
|
||||
}
|
||||
}
|
||||
|
||||
function check(property, testValue) {
|
||||
const sandbox = document.createElement('iframe');
|
||||
const element = document.createElement('p');
|
||||
|
||||
document.body.appendChild(sandbox);
|
||||
sandbox.contentDocument.body.appendChild(element);
|
||||
const support = set(element, property, testValue);
|
||||
|
||||
// We have to do this because remove() is not supported by IE11 and below
|
||||
sandbox.parentElement.removeChild(sandbox);
|
||||
return support;
|
||||
}
|
||||
|
||||
function checkComputed(el, prop) {
|
||||
const computed = window.getComputedStyle(el).getPropertyValue(prop);
|
||||
return computed !== void 0 && computed.length > 0 && computed !== 'none';
|
||||
}
|
||||
|
||||
function set(el, prop, value) {
|
||||
let match = false;
|
||||
|
||||
if (browserProps[prop] === void 0) {
|
||||
eachVendor(prop, function(vendorProp) {
|
||||
if (el.style[vendorProp] !== void 0 && match === false) {
|
||||
el.style[vendorProp] = value;
|
||||
if (checkComputed(el, vendorProp)) {
|
||||
match = true;
|
||||
browserProps[prop] = vendorProp;
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
el.style[browserProps[prop]] = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
const styleProperty = {
|
||||
check,
|
||||
set,
|
||||
};
|
||||
|
||||
OHIF.ui.styleProperty = styleProperty;
|
||||
})();
|
||||
|
||||
const { styleProperty } = OHIF.ui;
|
||||
|
||||
export { styleProperty };
|
||||
@@ -1,150 +0,0 @@
|
||||
/*!
|
||||
* transition-to-from-auto 0.5.2
|
||||
* https://github.com/75lb/transition-to-from-auto
|
||||
* Copyright 2015 Lloyd Brookes <75pound@gmail.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
@module
|
||||
@alias transition
|
||||
*/
|
||||
(function(window, document) {
|
||||
'use strict';
|
||||
|
||||
var getComputedStyle = window.getComputedStyle;
|
||||
var isTransition = 'data-ttfaInTransition';
|
||||
|
||||
var elements = [];
|
||||
var data = [];
|
||||
|
||||
// Transition detecting
|
||||
var transitionProp = false;
|
||||
var transitionEnd = false;
|
||||
var testStyle = document.createElement('a').style;
|
||||
var testProp;
|
||||
|
||||
if (testStyle[(testProp = 'webkitTransition')] !== undefined) {
|
||||
transitionProp = testProp;
|
||||
transitionEnd = testProp + 'End';
|
||||
}
|
||||
|
||||
if (testStyle[(testProp = 'transition')] !== undefined) {
|
||||
transitionProp = testProp;
|
||||
transitionEnd = testProp + 'end';
|
||||
}
|
||||
|
||||
function process(options, data) {
|
||||
var el = options.element;
|
||||
var val = options.val;
|
||||
var prop = options.prop;
|
||||
var style = el.style;
|
||||
var startVal;
|
||||
var autoVal;
|
||||
|
||||
if (!transitionProp) {
|
||||
return (style[prop] = val);
|
||||
}
|
||||
|
||||
if (el.hasAttribute(isTransition)) {
|
||||
el.removeEventListener(transitionEnd, data.l);
|
||||
} else {
|
||||
style[transitionProp] = 'none';
|
||||
|
||||
startVal = getComputedStyle(el)[prop];
|
||||
style[prop] = 'auto';
|
||||
autoVal = getComputedStyle(el)[prop];
|
||||
|
||||
// Interrupt
|
||||
if (startVal === val || (val === 'auto' && startVal === autoVal)) {
|
||||
return;
|
||||
}
|
||||
|
||||
data.auto = autoVal;
|
||||
el.setAttribute(isTransition, 1);
|
||||
|
||||
// Transition
|
||||
style[prop] = startVal;
|
||||
el.offsetWidth;
|
||||
style[transitionProp] = options.style;
|
||||
}
|
||||
|
||||
style[prop] = val === 'auto' ? data.auto : val;
|
||||
|
||||
data.l = function(e) {
|
||||
if (e.propertyName === prop) {
|
||||
el.removeAttribute(isTransition);
|
||||
el.removeEventListener(transitionEnd, data.l);
|
||||
if (val === 'auto') {
|
||||
/* avoid transition flashes in Safari */
|
||||
style[transitionProp] = 'none';
|
||||
style[prop] = val;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
el.addEventListener(transitionEnd, data.l);
|
||||
}
|
||||
|
||||
/**
|
||||
@param options {Object}
|
||||
@param options.element {string | element} - The DOM element or selector to transition
|
||||
@param options.val {string} - The value you want to transition to
|
||||
@param [options.prop] {string} - The CSS property to transition, defaults to `"height"`
|
||||
@param [options.style] {string} - The desired value for the `transition` CSS property (e.g. `"height 1s"`). If specified, this value is added inline and will override your CSS. Leave this value blank if you already have it defined in your stylesheet.
|
||||
@alias module:transition-to-from-auto
|
||||
*/
|
||||
function transition(options) {
|
||||
var element = options.element;
|
||||
var datum;
|
||||
var index;
|
||||
|
||||
if (typeof element === 'string') {
|
||||
element = document.querySelector(element);
|
||||
}
|
||||
|
||||
element = options.element = element instanceof Node ? element : false;
|
||||
options.prop = options.prop || 'height';
|
||||
options.style = options.style || '';
|
||||
|
||||
if (element) {
|
||||
index = elements.indexOf(element);
|
||||
if (~index) {
|
||||
datum = data[index];
|
||||
} else {
|
||||
datum = {};
|
||||
elements.push(element);
|
||||
data.push(datum);
|
||||
}
|
||||
|
||||
process(options, datum);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The name of the vendor-specific transition CSS property
|
||||
@type {string}
|
||||
@example
|
||||
el.style[transition.prop + 'Duration'] = '1s';
|
||||
*/
|
||||
transition.prop = transitionProp;
|
||||
|
||||
/**
|
||||
* The name of the [transition end event](https://developer.mozilla.org/en-US/docs/Web/Events/transitionend) in the current browser (typically `"transitionend"` or `"webkitTransitionEnd"`)
|
||||
* @type {string}
|
||||
* @example
|
||||
* el.addEventListener(transition.end, function(){
|
||||
* // the transition ended..
|
||||
* });
|
||||
*/
|
||||
transition.end = transitionEnd;
|
||||
|
||||
if (typeof module === 'object' && module.exports) {
|
||||
module.exports = transition;
|
||||
} else if (typeof define === 'function' && define.amd) {
|
||||
define(function() {
|
||||
return transition;
|
||||
});
|
||||
} else {
|
||||
window.transition = transition;
|
||||
}
|
||||
})(window, document);
|
||||
@@ -13,7 +13,6 @@ import metadata from './classes/metadata/';
|
||||
import object from './object.js';
|
||||
import redux from './redux/';
|
||||
import string from './string.js';
|
||||
//import './schema.js';
|
||||
import studies from './studies/';
|
||||
import ui from './ui';
|
||||
import user from './user.js';
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
//import SimpleSchema from 'simpl-schema'
|
||||
|
||||
/*
|
||||
Extend the available options on schema definitions:
|
||||
|
||||
* valuesLabels: Used in conjunction with allowedValues to define the text
|
||||
label for each value (used on forms)
|
||||
|
||||
* textOptional: Used to allow empty strings
|
||||
|
||||
*/
|
||||
/*SimpleSchema.extendOptions({
|
||||
valuesLabels: Match.Optional([String]),
|
||||
textOptional: Match.Optional(Boolean)
|
||||
});
|
||||
|
||||
// Add default required validation for empty strings which can be bypassed
|
||||
// using textOptional=true definition
|
||||
SimpleSchema.addValidator(function() {
|
||||
if (
|
||||
this.definition.optional !== true &&
|
||||
this.definition.textOptional !== true &&
|
||||
this.value === ''
|
||||
) {
|
||||
return 'required';
|
||||
}
|
||||
});*/
|
||||
|
||||
// Including [label] for some messages
|
||||
/*SimpleSchema.messages({
|
||||
maxCount: '[label] can not have more than [maxCount] values',
|
||||
minCount: '[label] must have at least [minCount] values',
|
||||
notAllowed: '[label] has an invalid value: "[value]"'
|
||||
});*/
|
||||
@@ -1,320 +0,0 @@
|
||||
/*import SimpleSchema from 'simpl-schema';
|
||||
|
||||
const serverNameDefinitions = {
|
||||
type: String,
|
||||
label: 'Server Name',
|
||||
max: 100
|
||||
};
|
||||
|
||||
const serverTypeDefinitions = {
|
||||
type: String,
|
||||
label: 'Server Type',
|
||||
allowedValues: ['dicomWeb', 'dimse'],
|
||||
valuesLabels: ['DICOM Web', 'DIMSE'],
|
||||
optional: true
|
||||
};
|
||||
|
||||
const wadoUriRootDefinitions = {
|
||||
type: String,
|
||||
label: 'WADO URI root',
|
||||
max: 1000
|
||||
};
|
||||
|
||||
const availableMouseButtonTools = ['wwwc', 'zoom', 'pan', 'stackScroll'];
|
||||
|
||||
export const DICOMWebRequestOptions = new SimpleSchema({
|
||||
auth: {
|
||||
type: String,
|
||||
label: 'Authentication',
|
||||
defaultValue: 'orthanc:orthanc',
|
||||
optional: true
|
||||
},
|
||||
requestFromBrowser: {
|
||||
type: Boolean,
|
||||
label: 'Make DICOMWeb requests from the Browser',
|
||||
defaultValue: false,
|
||||
optional: true
|
||||
},
|
||||
logRequests: {
|
||||
type: Boolean,
|
||||
defaultValue: true,
|
||||
label: 'Requests'
|
||||
},
|
||||
logResponses: {
|
||||
type: Boolean,
|
||||
defaultValue: false,
|
||||
label: 'Responses'
|
||||
},
|
||||
logTiming: {
|
||||
type: Boolean,
|
||||
defaultValue: true,
|
||||
label: 'Timing'
|
||||
}
|
||||
});
|
||||
|
||||
export const DICOMWebServer = new SimpleSchema({
|
||||
name: serverNameDefinitions,
|
||||
type: serverTypeDefinitions,
|
||||
wadoUriRoot: wadoUriRootDefinitions,
|
||||
wadoRoot: {
|
||||
type: String,
|
||||
label: 'WADO root',
|
||||
max: 1000
|
||||
},
|
||||
imageRendering: {
|
||||
type: String,
|
||||
label: 'Image rendering',
|
||||
allowedValues: ['wadouri', 'wadors'],
|
||||
valuesLabels: ['WADO URI', 'WADO RS'],
|
||||
defaultValue: 'wadouri'
|
||||
},
|
||||
thumbnailRendering: {
|
||||
type: String,
|
||||
label: 'Thumbnail rendering',
|
||||
allowedValues: ['wadouri', 'wadors'],
|
||||
valuesLabels: ['WADO URI', 'WADO RS'],
|
||||
defaultValue: 'wadouri'
|
||||
},
|
||||
qidoRoot: {
|
||||
type: String,
|
||||
label: 'QIDO root',
|
||||
max: 1000
|
||||
},
|
||||
qidoSupportsIncludeField: {
|
||||
type: Boolean,
|
||||
label: 'QIDO supports "includefield" query key',
|
||||
defaultValue: false
|
||||
},
|
||||
requestOptions: {
|
||||
type: DICOMWebRequestOptions,
|
||||
label: 'Request Options'
|
||||
}
|
||||
});
|
||||
|
||||
export const DIMSEPeer = new SimpleSchema({
|
||||
aeTitle: {
|
||||
type: String,
|
||||
label: 'AE Title'
|
||||
},
|
||||
hostAE: {
|
||||
type: String,
|
||||
label: 'AE Host',
|
||||
optional: true
|
||||
},
|
||||
host: {
|
||||
type: String,
|
||||
label: 'Host Domain/IP',
|
||||
regEx: SimpleSchema.RegEx.WeakDomain
|
||||
},
|
||||
port: {
|
||||
type: Number,
|
||||
label: 'Port',
|
||||
min: 1,
|
||||
defaultValue: 11112,
|
||||
max: 65535
|
||||
},
|
||||
default: {
|
||||
type: Boolean,
|
||||
label: 'Default',
|
||||
defaultValue: false
|
||||
},
|
||||
server: {
|
||||
type: Boolean,
|
||||
label: 'Server',
|
||||
defaultValue: false
|
||||
},
|
||||
supportsInstanceRetrievalByStudyUid: {
|
||||
type: Boolean,
|
||||
label: 'Supports instance retrieval by StudyUid',
|
||||
defaultValue: true
|
||||
}
|
||||
});
|
||||
|
||||
export const DIMSEServer = new SimpleSchema({
|
||||
name: serverNameDefinitions,
|
||||
type: serverTypeDefinitions,
|
||||
wadoUriRoot: wadoUriRootDefinitions,
|
||||
requestOptions: {
|
||||
type: DICOMWebRequestOptions,
|
||||
label: 'Request Options'
|
||||
},
|
||||
peers: {
|
||||
type: [DIMSEPeer],
|
||||
label: 'Peer List',
|
||||
minCount: 1
|
||||
}
|
||||
});
|
||||
|
||||
export const UISettings = new SimpleSchema({
|
||||
studyListFunctionsEnabled: {
|
||||
type: Boolean,
|
||||
label: 'Study List Functions Enabled?',
|
||||
defaultValue: true
|
||||
},
|
||||
leftSidebarOpen: {
|
||||
type: Boolean,
|
||||
label: 'Left sidebar open by default?',
|
||||
defaultValue: false
|
||||
},
|
||||
leftSidebarDragAndDrop: {
|
||||
type: Boolean,
|
||||
label:
|
||||
'Left sidebar allows thumbnail drag and drop. If false, images will be loaded on single click.',
|
||||
defaultValue: true
|
||||
},
|
||||
displaySetNavigationLoopOverSeries: {
|
||||
type: Boolean,
|
||||
label:
|
||||
'The UP/DOWN display set navigation buttons will start over when reach the last display set in viewport?',
|
||||
defaultValue: true
|
||||
},
|
||||
displaySetNavigationMultipleViewports: {
|
||||
type: Boolean,
|
||||
label:
|
||||
'The UP/DOWN display set navigation buttons will iterate over all the viewports at once?',
|
||||
defaultValue: false
|
||||
},
|
||||
displayEchoUltrasoundWorkflow: {
|
||||
type: Boolean,
|
||||
label: 'Enable cine dialog enhancements for multiframe images.',
|
||||
defaultValue: false
|
||||
},
|
||||
autoPositionMeasurementsTextCallOuts: {
|
||||
type: String,
|
||||
label: 'Auto position text call-outs for measurements when creating them.',
|
||||
defaultValue: 'TRBL'
|
||||
},
|
||||
studyListDateFilterNumDays: {
|
||||
type: Number,
|
||||
label: 'Number of days to be used on Study List date filter',
|
||||
min: 1
|
||||
},
|
||||
showStackLoadingProgressBar: {
|
||||
type: Boolean,
|
||||
label:
|
||||
'Show a progress bar closest to the thumbnail showing how much the stack has loaded',
|
||||
defaultValue: true
|
||||
},
|
||||
cornerstoneRenderer: {
|
||||
type: String,
|
||||
label: 'Cornerstone default image renderer',
|
||||
defaultValue: 'webgl'
|
||||
},
|
||||
sortSeriesByIncomingOrder: {
|
||||
type: Boolean,
|
||||
label:
|
||||
"Define if the series' images shall be sorted by incoming order. Sort by Instance Number by default.",
|
||||
defaultValue: false
|
||||
},
|
||||
useMiddleSeriesInstanceAsThumbnail: {
|
||||
type: Boolean,
|
||||
label:
|
||||
'Define if the middle instance of a series will be used as thumbnail. If not, the first instance will be used.',
|
||||
defaultValue: true
|
||||
}
|
||||
});
|
||||
|
||||
export const PrefetchSchema = new SimpleSchema({
|
||||
order: {
|
||||
type: String,
|
||||
label: 'Prefetch Order',
|
||||
allowedValues: ['topdown', 'downward', 'closest'],
|
||||
optional: false
|
||||
},
|
||||
displaySetCount: {
|
||||
type: Number,
|
||||
label: 'Display Set Count',
|
||||
min: 1,
|
||||
defaultValue: 1
|
||||
}
|
||||
});
|
||||
|
||||
export const MouseButtonToolSchema = new SimpleSchema({
|
||||
left: {
|
||||
type: String,
|
||||
label: 'Left Mouse Button',
|
||||
allowedValues: availableMouseButtonTools,
|
||||
optional: true
|
||||
},
|
||||
right: {
|
||||
type: String,
|
||||
label: 'Right Mouse Button',
|
||||
allowedValues: availableMouseButtonTools,
|
||||
optional: true
|
||||
},
|
||||
middle: {
|
||||
type: String,
|
||||
label: 'Middle Mouse Button',
|
||||
allowedValues: availableMouseButtonTools,
|
||||
optional: true
|
||||
}
|
||||
});
|
||||
|
||||
export const PublicServerConfig = new SimpleSchema({
|
||||
verifyEmail: {
|
||||
type: Boolean,
|
||||
label: 'Verify Email',
|
||||
defaultValue: false
|
||||
},
|
||||
demoUserEnabled: {
|
||||
type: Boolean,
|
||||
label: 'Creates demo user on startup and show TestDrive button',
|
||||
defaultValue: true
|
||||
},
|
||||
userAuthenticationRoutesEnabled: {
|
||||
type: Boolean,
|
||||
label: 'Enables routing to /login page.',
|
||||
defaultValue: false
|
||||
},
|
||||
ui: {
|
||||
type: UISettings,
|
||||
label: 'UI Settings'
|
||||
},
|
||||
prefetch: {
|
||||
type: PrefetchSchema,
|
||||
label: 'Prefetch settings'
|
||||
},
|
||||
defaultMouseButtonTools: {
|
||||
type: MouseButtonToolSchema,
|
||||
label: 'Default Mouse Button Tools'
|
||||
}
|
||||
});
|
||||
|
||||
export const Servers = new SimpleSchema({
|
||||
dicomWeb: {
|
||||
type: [DICOMWebServer],
|
||||
label: 'DICOMWeb Servers',
|
||||
optional: true
|
||||
},
|
||||
dimse: {
|
||||
type: [DIMSEServer],
|
||||
label: 'DIMSE Servers',
|
||||
optional: true
|
||||
}
|
||||
});
|
||||
|
||||
export const ServerConfiguration = new SimpleSchema({
|
||||
servers: {
|
||||
type: Servers,
|
||||
label: 'Servers'
|
||||
},
|
||||
defaultServiceType: {
|
||||
type: String,
|
||||
label: 'Default Service Type',
|
||||
defaultValue: 'dicomWeb'
|
||||
},
|
||||
dropCollections: {
|
||||
type: Boolean,
|
||||
label: 'Drop database collections',
|
||||
defaultValue: false
|
||||
},
|
||||
public: {
|
||||
type: PublicServerConfig,
|
||||
label: 'Public Server Configuration'
|
||||
},
|
||||
origin: {
|
||||
type: String,
|
||||
label: 'Origin',
|
||||
optional: true
|
||||
}
|
||||
});*/
|
||||
@@ -118,6 +118,10 @@ export default function Studies(server, filter) {
|
||||
};
|
||||
|
||||
const dicomWeb = new api.DICOMwebClient(config);
|
||||
server.qidoSupportsIncludeField =
|
||||
server.qidoSupportsIncludeField === undefined
|
||||
? true
|
||||
: server.qidoSupportsIncludeField;
|
||||
const queryParams = getQIDOQueryParams(
|
||||
filter,
|
||||
server.qidoSupportsIncludeField
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
# https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-development-environment-variables-in-env
|
||||
#
|
||||
|
||||
PUBLIC_URL=/demo
|
||||
PUBLIC_URL=/demo/
|
||||
APP_CONFIG=config/netlify.js
|
||||
@@ -69,7 +69,7 @@ services:
|
||||
# - orthanc
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- REACT_APP_CONFIG=config/local_dcm4chee
|
||||
- APP_CONFIG=config/local_dcm4chee
|
||||
restart: always
|
||||
networks:
|
||||
- dcm4che_default
|
||||
|
||||
@@ -28,7 +28,7 @@ FROM node:11.2.0-slim as builder
|
||||
RUN mkdir /usr/src/app
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
ENV REACT_APP_CONFIG=config/docker_openresty-orthanc-keycloak.js
|
||||
ENV APP_CONFIG=config/docker_openresty-orthanc-keycloak.js
|
||||
ENV PATH /usr/src/app/node_modules/.bin:$PATH
|
||||
|
||||
COPY package.json /usr/src/app/package.json
|
||||
|
||||
@@ -28,7 +28,7 @@ FROM node:11.2.0-slim as builder
|
||||
RUN mkdir /usr/src/app
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
ENV REACT_APP_CONFIG=config/docker_openresty-orthanc.js
|
||||
ENV APP_CONFIG=config/docker_openresty-orthanc.js
|
||||
ENV PATH /usr/src/app/node_modules/.bin:$PATH
|
||||
|
||||
COPY package.json /usr/src/app/package.json
|
||||
|
||||
@@ -19,7 +19,8 @@ const DIST_DIR = path.join(__dirname, '../dist');
|
||||
const PUBLIC_DIR = path.join(__dirname, '../public');
|
||||
const ASSET_PATH = process.env.ASSET_PATH || '/';
|
||||
// Env Vars
|
||||
const PUBLIC_URL = process.env.PUBLIC_URL || '';
|
||||
const HTML_TEMPLATE = process.env.HTML_TEMPLATE || 'index.html';
|
||||
const PUBLIC_URL = process.env.PUBLIC_URL || '/';
|
||||
const APP_CONFIG = process.env.APP_CONFIG || 'config/default.js';
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
@@ -42,16 +43,21 @@ module.exports = (env, argv) => {
|
||||
to: DIST_DIR,
|
||||
toType: 'dir',
|
||||
// Ignore our HtmlWebpackPlugin template file
|
||||
ignore: ['index.html', '.DS_Store'],
|
||||
// Ignore our configuration files
|
||||
ignore: ['config/*', 'html-templates/*', '.DS_Store'],
|
||||
},
|
||||
// Copy over and rename our target app config file
|
||||
{
|
||||
from: `${PUBLIC_DIR}/${APP_CONFIG}`,
|
||||
to: `${DIST_DIR}/app-config.js`,
|
||||
},
|
||||
]),
|
||||
// Generate "index.html" w/ correct includes/imports
|
||||
new HtmlWebpackPlugin({
|
||||
template: `${PUBLIC_DIR}/index.html`,
|
||||
template: `${PUBLIC_DIR}/html-templates/${HTML_TEMPLATE}`,
|
||||
filename: 'index.html',
|
||||
templateParameters: {
|
||||
PUBLIC_URL: PUBLIC_URL,
|
||||
APP_CONFIG: APP_CONFIG,
|
||||
},
|
||||
}),
|
||||
],
|
||||
|
||||
@@ -62,8 +62,6 @@ module.exports = (env, argv) => {
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
// Longer build. Let's report progress
|
||||
new webpack.ProgressPlugin(),
|
||||
// Clean output.path
|
||||
new CleanWebpackPlugin(),
|
||||
],
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
const path = require('path');
|
||||
const merge = require('webpack-merge');
|
||||
const webpack = require('webpack');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.common.js');
|
||||
const webpackCommon = require('./../../../.webpack/webpack.common-pwa.js');
|
||||
// Plugins
|
||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
const ExtractCssChunksPlugin = require('extract-css-chunks-webpack-plugin');
|
||||
const TerserJSPlugin = require('terser-webpack-plugin');
|
||||
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const workboxPlugin = require('workbox-webpack-plugin');
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
|
||||
.BundleAnalyzerPlugin;
|
||||
//
|
||||
const SRC_DIR = path.join(__dirname, '../src');
|
||||
const DIST_DIR = path.join(__dirname, '../dist');
|
||||
const PUBLIC_DIR = path.join(__dirname, '../public');
|
||||
// Env Vars
|
||||
const PUBLIC_URL = process.env.PUBLIC_URL || '';
|
||||
const HTML_TEMPLATE = process.env.HTML_TEMPLATE || 'index.html';
|
||||
const PUBLIC_URL = process.env.PUBLIC_URL || '/';
|
||||
const APP_CONFIG = process.env.APP_CONFIG || 'config/default.js';
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
@@ -22,6 +27,8 @@ module.exports = (env, argv) => {
|
||||
return merge(commonConfig, {
|
||||
// https://webpack.js.org/configuration/mode/#mode-production
|
||||
mode: 'production',
|
||||
// Out of memory -- Code Split
|
||||
// devtool: 'source-map',
|
||||
stats: {
|
||||
colors: true,
|
||||
hash: true,
|
||||
@@ -36,17 +43,81 @@ module.exports = (env, argv) => {
|
||||
optimization: {
|
||||
minimize: true,
|
||||
sideEffects: true,
|
||||
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
|
||||
},
|
||||
output: {
|
||||
path: DIST_DIR,
|
||||
filename: '[name].bundle.[chunkhash].js',
|
||||
publicPath: PUBLIC_URL, // Used by HtmlWebPackPlugin for asset prefix
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.styl$/,
|
||||
use: [
|
||||
{
|
||||
loader: ExtractCssChunksPlugin.loader,
|
||||
options: {
|
||||
hot: process.env.NODE_ENV === 'development',
|
||||
},
|
||||
},
|
||||
{ loader: 'css-loader' },
|
||||
{ loader: 'stylus-loader' },
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(sa|sc|c)ss$/,
|
||||
use: [
|
||||
{
|
||||
loader: ExtractCssChunksPlugin.loader,
|
||||
options: {
|
||||
hot: process.env.NODE_ENV === 'development',
|
||||
},
|
||||
},
|
||||
'css-loader',
|
||||
'postcss-loader',
|
||||
// 'sass-loader',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.styl$/,
|
||||
use: [
|
||||
{
|
||||
loader: ExtractCssChunksPlugin.loader,
|
||||
options: {
|
||||
hot: process.env.NODE_ENV === 'development',
|
||||
},
|
||||
},
|
||||
{ loader: 'css-loader' },
|
||||
{ loader: 'stylus-loader' },
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(sa|sc|c)ss$/,
|
||||
use: [
|
||||
{
|
||||
loader: ExtractCssChunksPlugin.loader,
|
||||
options: {
|
||||
hot: process.env.NODE_ENV === 'development',
|
||||
},
|
||||
},
|
||||
'css-loader',
|
||||
'postcss-loader',
|
||||
// 'sass-loader',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
// TODO:
|
||||
// Do we need to rip anything out of the more generic common.js we're
|
||||
// merging with this?
|
||||
plugins: [
|
||||
// Longer build. Let's report progress
|
||||
new webpack.ProgressPlugin(),
|
||||
// Uncomment to generate bundle analyzer
|
||||
// new BundleAnalyzerPlugin(),
|
||||
// Clean output.path
|
||||
new CleanWebpackPlugin(),
|
||||
// "Public" Folder
|
||||
@@ -56,24 +127,30 @@ module.exports = (env, argv) => {
|
||||
to: DIST_DIR,
|
||||
toType: 'dir',
|
||||
// Ignore our HtmlWebpackPlugin template file
|
||||
ignore: ['index.html', '.DS_Store'],
|
||||
// Ignore our configuration files
|
||||
ignore: ['config/*', 'html-templates/*', '.DS_Store'],
|
||||
},
|
||||
// Copy over and rename our target app config file
|
||||
{
|
||||
from: `${PUBLIC_DIR}/${APP_CONFIG}`,
|
||||
to: `${DIST_DIR}/app-config.js`,
|
||||
},
|
||||
]),
|
||||
// https://github.com/faceyspacey/extract-css-chunks-webpack-plugin#webpack-4-standalone-installation
|
||||
new ExtractCssChunksPlugin({
|
||||
filename: '[name].css',
|
||||
chunkFilename: '[id].css',
|
||||
// hot: true /* only necessary if hot reloading not function*/
|
||||
ignoreOrder: false, // Enable to remove warnings about conflicting order
|
||||
}),
|
||||
/**
|
||||
* This generates our index.html file from the specified template.
|
||||
* This is the easiest way to inject custom configuration and extensions.
|
||||
*/
|
||||
new HtmlWebpackPlugin({
|
||||
template: `${PUBLIC_DIR}/index.html`,
|
||||
template: `${PUBLIC_DIR}/html-templates/${HTML_TEMPLATE}`,
|
||||
filename: 'index.html',
|
||||
templateParameters: {
|
||||
PUBLIC_URL: PUBLIC_URL,
|
||||
APP_CONFIG: APP_CONFIG,
|
||||
},
|
||||
// favicon: `${PUBLIC_DIR}/favicon.ico`,
|
||||
}),
|
||||
|
||||
@@ -3,6 +3,114 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.50.13](https://github.com/OHIF/Viewers/compare/@ohif/viewer@0.50.12...@ohif/viewer@0.50.13) (2019-09-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 Activating Pan and Zoom on right and middle click by def ([#841](https://github.com/OHIF/Viewers/issues/841)) ([7a9b477](https://github.com/OHIF/Viewers/commit/7a9b477))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.12](https://github.com/OHIF/Viewers/compare/@ohif/viewer@0.50.11...@ohif/viewer@0.50.12) (2019-08-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* asset resolution when at non-root route ([#828](https://github.com/OHIF/Viewers/issues/828)) ([d48b617](https://github.com/OHIF/Viewers/commit/d48b617))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.11](https://github.com/OHIF/Viewers/compare/@ohif/viewer@0.50.10...@ohif/viewer@0.50.11) (2019-08-29)
|
||||
|
||||
**Note:** Version bump only for package @ohif/viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.10](https://github.com/OHIF/Viewers/compare/@ohif/viewer@0.50.9...@ohif/viewer@0.50.10) (2019-08-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.9](https://github.com/OHIF/Viewers/compare/@ohif/viewer@0.50.8...@ohif/viewer@0.50.9) (2019-08-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.8](https://github.com/OHIF/Viewers/compare/@ohif/viewer@0.50.7...@ohif/viewer@0.50.8) (2019-08-26)
|
||||
|
||||
**Note:** Version bump only for package @ohif/viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.7](https://github.com/OHIF/Viewers/compare/@ohif/viewer@0.50.6...@ohif/viewer@0.50.7) (2019-08-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 Update for changes in ExpandableToolMenu props ([e09670a](https://github.com/OHIF/Viewers/commit/e09670a))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.6](https://github.com/OHIF/Viewers/compare/@ohif/viewer@0.50.5...@ohif/viewer@0.50.6) (2019-08-22)
|
||||
|
||||
**Note:** Version bump only for package @ohif/viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.5](https://github.com/OHIF/Viewers/compare/@ohif/viewer@0.50.4...@ohif/viewer@0.50.5) (2019-08-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **StandaloneRouting:** Promise rejection - added `return` ([#791](https://github.com/OHIF/Viewers/issues/791)) ([d09fb4e](https://github.com/OHIF/Viewers/commit/d09fb4e))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.4](https://github.com/OHIF/Viewers/compare/@ohif/viewer@0.50.3...@ohif/viewer@0.50.4) (2019-08-20)
|
||||
|
||||
**Note:** Version bump only for package @ohif/viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.3](https://github.com/OHIF/Viewers/compare/@ohif/viewer@0.50.2...@ohif/viewer@0.50.3) (2019-08-15)
|
||||
|
||||
**Note:** Version bump only for package @ohif/viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.2](https://github.com/OHIF/Viewers/compare/@ohif/viewer@0.50.1...@ohif/viewer@0.50.2) (2019-08-15)
|
||||
|
||||
**Note:** Version bump only for package @ohif/viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.1](https://github.com/OHIF/Viewers/compare/@ohif/viewer@0.50.0-alpha.13...@ohif/viewer@0.50.1) (2019-08-14)
|
||||
|
||||
**Note:** Version bump only for package @ohif/viewer
|
||||
|
||||
@@ -5,18 +5,18 @@ describe('ViewerRouting', () => {
|
||||
cy.get('#studyListData > :nth-child(1) > .patientId').click();
|
||||
});
|
||||
|
||||
it('thumbnails list has more than 2 items', () => {
|
||||
cy.get('.scrollable-study-thumbnails div.ThumbnailEntryContainer')
|
||||
.its('length')
|
||||
.should('be.gte', 2);
|
||||
});
|
||||
// it('thumbnails list has more than 2 items', () => {
|
||||
// cy.get('.scrollable-study-thumbnails div.ThumbnailEntryContainer')
|
||||
// .its('length')
|
||||
// .should('be.gte', 2);
|
||||
// });
|
||||
|
||||
it('loads route with at least 2 thumbnails', () => {
|
||||
cy.get(
|
||||
':nth-child(1) > .ThumbnailEntry > .p-x-1 > .ImageThumbnail > .image-thumbnail-canvas > canvas'
|
||||
).should('be.visible');
|
||||
cy.get(
|
||||
':nth-child(2) > .ThumbnailEntry > .p-x-1 > .ImageThumbnail > .image-thumbnail-canvas > canvas'
|
||||
).should('be.visible');
|
||||
});
|
||||
// it('loads route with at least 2 thumbnails', () => {
|
||||
// cy.get(
|
||||
// ':nth-child(1) > .ThumbnailEntry > .p-x-1 > .ImageThumbnail > .image-thumbnail-canvas > canvas'
|
||||
// ).should('be.visible');
|
||||
// cy.get(
|
||||
// ':nth-child(2) > .ThumbnailEntry > .p-x-1 > .ImageThumbnail > .image-thumbnail-canvas > canvas'
|
||||
// ).should('be.visible');
|
||||
// });
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/viewer",
|
||||
"version": "0.50.1",
|
||||
"version": "0.50.13",
|
||||
"description": "OHIF Viewer",
|
||||
"author": "OHIF Contributors",
|
||||
"license": "MIT",
|
||||
@@ -17,9 +17,10 @@
|
||||
},
|
||||
"proxy": "http://localhost:8042",
|
||||
"scripts": {
|
||||
"build:package": "webpack --config .webpack/commonjs.prod.js",
|
||||
"build:viewer": "webpack --config .webpack/pwa.prod.js",
|
||||
"build:viewer:ci": "cross-env PUBLIC_URL=/pwa APP_CONFIG=config/netlify.js webpack --config .webpack/pwa.prod.js",
|
||||
"build:package": "cross-env NODE_ENV=production node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/commonjs.prod.js",
|
||||
"build:viewer": "cross-env NODE_ENV=production node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/pwa.prod.js",
|
||||
"build:viewer:ci": "cross-env NODE_ENV=production PUBLIC_URL=/pwa/ APP_CONFIG=config/netlify.js node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/pwa.prod.js",
|
||||
"build:viewer:demo": "cross-env NODE_ENV=production APP_CONFIG=config/demo.js HTML_TEMPLATE=rollbar.html node --max_old_space_size=4096 ./../../node_modules/webpack/bin/webpack.js --config .webpack/pwa.prod.js",
|
||||
"build:viewer:package": "yarn run build:package",
|
||||
"dev": "webpack-dev-server --config .webpack/all.dev.js -w",
|
||||
"dev:orthanc": "cross-env APP_CONFIG=config/docker_nginx-orthanc.js react-scripts start",
|
||||
@@ -44,12 +45,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"@ohif/core": "^0.50.1",
|
||||
"@ohif/core": "^0.50.3",
|
||||
"@ohif/extension-cornerstone": "^0.50.1",
|
||||
"@ohif/extension-dicom-html": "^0.50.1",
|
||||
"@ohif/extension-dicom-microscopy": "^0.50.1",
|
||||
"@ohif/extension-dicom-pdf": "^0.50.1",
|
||||
"@ohif/extension-vtk": "^0.50.1",
|
||||
"@ohif/extension-vtk": "^0.50.4",
|
||||
"@ohif/i18n": "^0.50.1",
|
||||
"@ohif/ui": "^0.50.1",
|
||||
"@tanem/react-nprogress": "^1.1.25",
|
||||
|
||||
+2
-2
@@ -8,10 +8,10 @@
|
||||
/>
|
||||
<meta name="theme-color" content="#000000" />
|
||||
|
||||
<link rel="manifest" href="<%= PUBLIC_URL %>/manifest.json" />
|
||||
<link rel="manifest" href="<%= PUBLIC_URL %>manifest.json" />
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="<%= PUBLIC_URL %>/<%= APP_CONFIG %>"
|
||||
src="<%= PUBLIC_URL %>app-config.js"
|
||||
></script>
|
||||
|
||||
<title>OHIF Viewer</title>
|
||||
@@ -0,0 +1,50 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, shrink-to-fit=no"
|
||||
/>
|
||||
<meta name="theme-color" content="#000000" />
|
||||
|
||||
<link rel="manifest" href="<%= PUBLIC_URL %>manifest.json" />
|
||||
<script type="text/javascript" src="<%= PUBLIC_URL %>app-config.js"></script>
|
||||
|
||||
<title>OHIF Viewer</title>
|
||||
|
||||
<!-- WEB FONTS -->
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700|Sanchez&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<!-- EXTENSIONS -->
|
||||
<!-- <script type="text/javascript" src="path/to/some-extension.js"></script>
|
||||
|
||||
<script>
|
||||
window.config.extensions = [SomeExtension];
|
||||
</script> -->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript> You need to enable JavaScript to run this app. </noscript>
|
||||
|
||||
<div id="root"></div>
|
||||
|
||||
<script>
|
||||
// Note: This is a client access token so there is no issue with having it publicly available
|
||||
var _rollbarConfig = {
|
||||
accessToken: "739c64cd39e84592ba062bc29aac9769",
|
||||
captureUncaught: true,
|
||||
captureUnhandledRejections: true,
|
||||
payload: {
|
||||
environment: "viewer.ohif.org"
|
||||
}
|
||||
};
|
||||
// Rollbar Snippet
|
||||
!function(r){var e={};function o(n){if(e[n])return e[n].exports;var t=e[n]={i:n,l:!1,exports:{}};return r[n].call(t.exports,t,t.exports,o),t.l=!0,t.exports}o.m=r,o.c=e,o.d=function(r,e,n){o.o(r,e)||Object.defineProperty(r,e,{enumerable:!0,get:n})},o.r=function(r){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(r,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(r,"__esModule",{value:!0})},o.t=function(r,e){if(1&e&&(r=o(r)),8&e)return r;if(4&e&&"object"==typeof r&&r&&r.__esModule)return r;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:r}),2&e&&"string"!=typeof r)for(var t in r)o.d(n,t,function(e){return r[e]}.bind(null,t));return n},o.n=function(r){var e=r&&r.__esModule?function(){return r.default}:function(){return r};return o.d(e,"a",e),e},o.o=function(r,e){return Object.prototype.hasOwnProperty.call(r,e)},o.p="",o(o.s=0)}([function(r,e,o){var n=o(1),t=o(4);_rollbarConfig=_rollbarConfig||{},_rollbarConfig.rollbarJsUrl=_rollbarConfig.rollbarJsUrl||"https://cdnjs.cloudflare.com/ajax/libs/rollbar.js/2.7.1/rollbar.min.js",_rollbarConfig.async=void 0===_rollbarConfig.async||_rollbarConfig.async;var a=n.setupShim(window,_rollbarConfig),l=t(_rollbarConfig);window.rollbar=n.Rollbar,a.loadFull(window,document,!_rollbarConfig.async,_rollbarConfig,l)},function(r,e,o){var n=o(2);function t(r){return function(){try{return r.apply(this,arguments)}catch(r){try{console.error("[Rollbar]: Internal error",r)}catch(r){}}}}var a=0;function l(r,e){this.options=r,this._rollbarOldOnError=null;var o=a++;this.shimId=function(){return o},"undefined"!=typeof window&&window._rollbarShims&&(window._rollbarShims[o]={handler:e,messages:[]})}var i=o(3),d=function(r,e){return new l(r,e)},c=function(r){return new i(d,r)};function s(r){return t(function(){var e=Array.prototype.slice.call(arguments,0),o={shim:this,method:r,args:e,ts:new Date};window._rollbarShims[this.shimId()].messages.push(o)})}l.prototype.loadFull=function(r,e,o,n,a){var l=!1,i=e.createElement("script"),d=e.getElementsByTagName("script")[0],c=d.parentNode;i.crossOrigin="",i.src=n.rollbarJsUrl,o||(i.async=!0),i.onload=i.onreadystatechange=t(function(){if(!(l||this.readyState&&"loaded"!==this.readyState&&"complete"!==this.readyState)){i.onload=i.onreadystatechange=null;try{c.removeChild(i)}catch(r){}l=!0,function(){var e;if(void 0===r._rollbarDidLoad){e=new Error("rollbar.js did not load");for(var o,n,t,l,i=0;o=r._rollbarShims[i++];)for(o=o.messages||[];n=o.shift();)for(t=n.args||[],i=0;i<t.length;++i)if("function"==typeof(l=t[i])){l(e);break}}"function"==typeof a&&a(e)}()}}),c.insertBefore(i,d)},l.prototype.wrap=function(r,e,o){try{var n;if(n="function"==typeof e?e:function(){return e||{}},"function"!=typeof r)return r;if(r._isWrap)return r;if(!r._rollbar_wrapped&&(r._rollbar_wrapped=function(){o&&"function"==typeof o&&o.apply(this,arguments);try{return r.apply(this,arguments)}catch(o){var e=o;throw e&&("string"==typeof e&&(e=new String(e)),e._rollbarContext=n()||{},e._rollbarContext._wrappedSource=r.toString(),window._rollbarWrappedError=e),e}},r._rollbar_wrapped._isWrap=!0,r.hasOwnProperty))for(var t in r)r.hasOwnProperty(t)&&(r._rollbar_wrapped[t]=r[t]);return r._rollbar_wrapped}catch(e){return r}};for(var p="log,debug,info,warn,warning,error,critical,global,configure,handleUncaughtException,handleUnhandledRejection,captureEvent,captureDomContentLoaded,captureLoad".split(","),u=0;u<p.length;++u)l.prototype[p[u]]=s(p[u]);r.exports={setupShim:function(r,e){if(r){var o=e.globalAlias||"Rollbar";if("object"==typeof r[o])return r[o];r._rollbarShims={},r._rollbarWrappedError=null;var a=new c(e);return t(function(){e.captureUncaught&&(a._rollbarOldOnError=r.onerror,n.captureUncaughtExceptions(r,a,!0),n.wrapGlobals(r,a,!0)),e.captureUnhandledRejections&&n.captureUnhandledRejections(r,a,!0);var t=e.autoInstrument;return!1!==e.enabled&&(void 0===t||!0===t||"object"==typeof t&&t.network)&&r.addEventListener&&(r.addEventListener("load",a.captureLoad.bind(a)),r.addEventListener("DOMContentLoaded",a.captureDomContentLoaded.bind(a))),r[o]=a,a})()}},Rollbar:c}},function(r,e){function o(r,e,o){if(e.hasOwnProperty&&e.hasOwnProperty("addEventListener")){for(var n=e.addEventListener;n._rollbarOldAdd&&n.belongsToShim;)n=n._rollbarOldAdd;var t=function(e,o,t){n.call(this,e,r.wrap(o),t)};t._rollbarOldAdd=n,t.belongsToShim=o,e.addEventListener=t;for(var a=e.removeEventListener;a._rollbarOldRemove&&a.belongsToShim;)a=a._rollbarOldRemove;var l=function(r,e,o){a.call(this,r,e&&e._rollbar_wrapped||e,o)};l._rollbarOldRemove=a,l.belongsToShim=o,e.removeEventListener=l}}r.exports={captureUncaughtExceptions:function(r,e,o){if(r){var n;if("function"==typeof e._rollbarOldOnError)n=e._rollbarOldOnError;else if(r.onerror){for(n=r.onerror;n._rollbarOldOnError;)n=n._rollbarOldOnError;e._rollbarOldOnError=n}var t=function(){var o=Array.prototype.slice.call(arguments,0);!function(r,e,o,n){r._rollbarWrappedError&&(n[4]||(n[4]=r._roLine truncated
|
||||
// End Rollbar Snippet
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,4 +1,7 @@
|
||||
import { hot } from 'react-hot-loader/root';
|
||||
|
||||
import './config';
|
||||
|
||||
// Polyfills
|
||||
// PWA Only?
|
||||
import 'core-js/features/array/flat';
|
||||
@@ -194,5 +197,8 @@ function _makeAbsoluteIfNecessary(url, base_url) {
|
||||
return base_url + url;
|
||||
}
|
||||
|
||||
export default App;
|
||||
// Only wrap/use hot if in dev
|
||||
const ExportedApp = process.env.NODE_ENV === 'development' ? hot(App) : App;
|
||||
|
||||
export default ExportedApp;
|
||||
export { commandsManager, extensionManager, hotkeysManager };
|
||||
@@ -13,7 +13,7 @@ class PluginSwitch extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div className="PluginSwitch">
|
||||
<ExpandableToolMenu buttons={this.props.buttons} text={'View'} />
|
||||
<ExpandableToolMenu buttons={this.props.buttons} label={'View'} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ function _getButtonComponents(toolbarButtons, activeButtons) {
|
||||
return (
|
||||
<ExpandableToolMenu
|
||||
key={button.id}
|
||||
text={button.label}
|
||||
label={button.label}
|
||||
icon={button.icon}
|
||||
buttons={childButtons}
|
||||
activeCommand={activeCommand}
|
||||
|
||||
@@ -31,8 +31,6 @@ const appDefaults = {
|
||||
relativeWebWorkerScriptsPath: '',
|
||||
};
|
||||
|
||||
console.log(OHIFVTKExtension);
|
||||
|
||||
if (window) {
|
||||
config = window.config || {};
|
||||
config.extensions = [
|
||||
|
||||
@@ -26,7 +26,7 @@ class StandaloneRouting extends Component {
|
||||
const url = query.url;
|
||||
|
||||
if (!url) {
|
||||
reject(new Error("No URL was specified. Use ?url=$yourURL"));
|
||||
return reject(new Error("No URL was specified. Use ?url=$yourURL"));
|
||||
}
|
||||
|
||||
// Define a request to the server to retrieve the study data
|
||||
|
||||
@@ -142,8 +142,8 @@ function getResetLabellingAndContextMenu(store) {
|
||||
export default function setupTools(store) {
|
||||
const toolLabellingFlowCallback = getToolLabellingFlowCallback(store);
|
||||
const availableTools = [
|
||||
{ name: 'Pan', mouseButtonMasks: [4] },
|
||||
{ name: 'Zoom', mouseButtonMasks: [2] },
|
||||
{ name: 'Pan', mouseButtonMasks: [1, 4] },
|
||||
{ name: 'Zoom', mouseButtonMasks: [1, 2] },
|
||||
{ name: 'Wwwc', mouseButtonMasks: [1] },
|
||||
{ name: 'Magnify' },
|
||||
{ name: 'WwwcRegion' },
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import { applyMiddleware, combineReducers, createStore } from "redux";
|
||||
import {
|
||||
applyMiddleware,
|
||||
combineReducers,
|
||||
createStore,
|
||||
} from 'redux/es/redux.js';
|
||||
|
||||
// import { createLogger } from 'redux-logger';
|
||||
import layoutReducers from "./layout/reducers.js";
|
||||
import { reducer as oidcReducer } from "redux-oidc";
|
||||
import { redux } from "@ohif/core";
|
||||
import thunkMiddleware from "redux-thunk";
|
||||
import layoutReducers from './layout/reducers.js';
|
||||
import { reducer as oidcReducer } from 'redux-oidc';
|
||||
import { redux } from '@ohif/core';
|
||||
import thunkMiddleware from 'redux-thunk';
|
||||
|
||||
// Combine our ohif-core, ui, and oidc reducers
|
||||
// Set init data, using values found in localStorage
|
||||
@@ -28,7 +32,7 @@ const store = createStore(
|
||||
// Update our cached preferences in localStorage
|
||||
store.subscribe(() => {
|
||||
localStorage.saveState({
|
||||
preferences: store.getState().preferences
|
||||
preferences: store.getState().preferences,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user