diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..750935f33 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +dist/ +node_modules/ +.git +Dockerfile +.DS_Store +.gitignore +README.md +.vscode +.circleci +example/ diff --git a/.gitignore b/.gitignore index 1c9ea6cdc..85cfb5b26 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,8 @@ npm-debug.log package-lock.json yarn-error.log .DS_Store + +# Common Example Data Directories +sampledata/ +example/deps/ +docker/dcm4che/dcm4che-arc diff --git a/config-react/ccc.json b/config-react/ccc.json deleted file mode 100644 index d889ddca2..000000000 --- a/config-react/ccc.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "servers": { - "dicomWeb": [ - { - "name": "DCM4CHEE", - "wadoUriRoot": "https://cancer.crowds-cure.org/dcm4chee-arc/aets/DCM4CHEE/wado", - "qidoRoot": "https://cancer.crowds-cure.org/dcm4chee-arc/aets/DCM4CHEE/rs", - "wadoRoot": "https://cancer.crowds-cure.org/dcm4chee-arc/aets/DCM4CHEE/rs", - "qidoSupportsIncludeField": true, - "imageRendering": "wadors", - "thumbnailRendering": "wadors", - "requestOptions": { - "requestFromBrowser": true - } - } - ] - }, - "oidc": [{ - "authServerUrl": "https://cancer.crowds-cure.org/auth/realms/dcm4che", - "authRedirectUri": "http://localhost:5000/callback", - "clientId": "crowds-cure-cancer", - "postLogoutRedirectUri": "http://localhost:5000/logout-redirect.html", - "responseType": "id_token token", - "scope": "email profile openid", - "revokeAccessTokenOnSignout": true, - "extraQueryParams": { - "kc_idp_hint": "crowds-cure-cancer-auth0-oidc", - "client_id": "crowds-cure-cancer" - } - }] -} diff --git a/config-react/local_dcm4chee.json b/config-react/local_dcm4chee.json deleted file mode 100644 index dcadfef52..000000000 --- a/config-react/local_dcm4chee.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "servers": { - "dicomWeb": [ - { - "name": "DCM4CHEE", - "wadoUriRoot": "http://localhost:8080/dcm4chee-arc/aets/DCM4CHEE/wado", - "qidoRoot": "http://localhost:8080/dcm4chee-arc/aets/DCM4CHEE/rs", - "wadoRoot": "http://localhost:8080/dcm4chee-arc/aets/DCM4CHEE/rs", - "qidoSupportsIncludeField": true, - "imageRendering": "wadors", - "thumbnailRendering": "wadors", - "requestOptions": { - "requestFromBrowser": true, - "auth": "admin:admin" - } - } - ] - } -} diff --git a/config-react/public_dicomweb.json b/config-react/public_dicomweb.json deleted file mode 100644 index 699143e69..000000000 --- a/config-react/public_dicomweb.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "servers": { - "dicomWeb": [ - { - "name": "DCM4CHEE", - "wadoUriRoot": "https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado", - "qidoRoot": "https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs", - "wadoRoot": "https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs", - "qidoSupportsIncludeField": true, - "imageRendering": "wadors", - "thumbnailRendering": "wadors", - "requestOptions": { - "requestFromBrowser": true - } - } - ] - } -} diff --git a/config/ccc.js b/config/ccc.js new file mode 100644 index 000000000..a8766db8c --- /dev/null +++ b/config/ccc.js @@ -0,0 +1,36 @@ +dicomWebServers = { + servers: { + dicomWeb: [ + { + name: "DCM4CHEE", + wadoUriRoot: + "https://cancer.crowds-cure.org/dcm4chee-arc/aets/DCM4CHEE/wado", + qidoRoot: + "https://cancer.crowds-cure.org/dcm4chee-arc/aets/DCM4CHEE/rs", + wadoRoot: + "https://cancer.crowds-cure.org/dcm4chee-arc/aets/DCM4CHEE/rs", + qidoSupportsIncludeField: true, + imageRendering: "wadors", + thumbnailRendering: "wadors", + requestOptions: { + requestFromBrowser: true + } + } + ] + }, + oidc: [ + { + authServerUrl: "https://cancer.crowds-cure.org/auth/realms/dcm4che", + authRedirectUri: "http://localhost:5000/callback", + clientId: "crowds-cure-cancer", + postLogoutRedirectUri: "http://localhost:5000/logout-redirect.html", + responseType: "id_token token", + scope: "email profile openid", + revokeAccessTokenOnSignout: true, + extraQueryParams: { + kc_idp_hint: "crowds-cure-cancer-auth0-oidc", + client_id: "crowds-cure-cancer" + } + } + ] +} diff --git a/config/local_dcm4chee.js b/config/local_dcm4chee.js new file mode 100644 index 000000000..b4d887fc3 --- /dev/null +++ b/config/local_dcm4chee.js @@ -0,0 +1,19 @@ +dicomWebServers = { + servers: { + dicomWeb: [ + { + name: "DCM4CHEE", + wadoUriRoot: "http://localhost:8080/dcm4chee-arc/aets/DCM4CHEE/wado", + qidoRoot: "http://localhost:8080/dcm4chee-arc/aets/DCM4CHEE/rs", + wadoRoot: "http://localhost:8080/dcm4chee-arc/aets/DCM4CHEE/rs", + qidoSupportsIncludeField: true, + imageRendering: "wadors", + thumbnailRendering: "wadors", + requestOptions: { + requestFromBrowser: true, + auth: "admin:admin" + } + } + ] + } +} diff --git a/config/local_orthanc.js b/config/local_orthanc.js new file mode 100644 index 000000000..2aacadfd5 --- /dev/null +++ b/config/local_orthanc.js @@ -0,0 +1,21 @@ +dicomWebServers = { + servers: { + dicomWeb: [ + { + name: "Orthanc", + wadoUriRoot: "http://localhost:8899/wado", + qidoRoot: "http://localhost:8899/dicom-web", + wadoRoot: "http://localhost:8899/dicom-web", + qidoSupportsIncludeField: false, + imageRendering: "wadors", + thumbnailRendering: "wadors", + requestOptions: { + auth: "orthanc:orthanc", + logRequests: true, + logResponses: false, + logTiming: true + } + } + ] + } +} diff --git a/config/public_dicomweb.js b/config/public_dicomweb.js new file mode 100644 index 000000000..4bde53033 --- /dev/null +++ b/config/public_dicomweb.js @@ -0,0 +1,18 @@ +dicomWebServers = { + servers: { + dicomWeb: [ + { + name: "DCM4CHEE", + wadoUriRoot: "https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado", + qidoRoot: "https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs", + wadoRoot: "https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs", + qidoSupportsIncludeField: true, + imageRendering: "wadors", + thumbnailRendering: "wadors", + requestOptions: { + requestFromBrowser: true + } + } + ] + } +}; diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 000000000..438fd9dd0 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,42 @@ +# Docker compose files + +This folder contains docker-compose files used to spin up OHIF-Viewer with differnt options such as locally or with any PAS you desire to + +## Public Server +#### build + +`$ docker-compose -f docker-compose-publicserver.yml build` + +#### run +`$ docker-compose -f docker-compose-publicserver.yml up -d` + +then, access the application at [http://localhost](http://localhost) + +## Local Orthanc +#### build + +`$ docker-compose -f docker-compose-orthanc.yml build` + +#### run +`$ docker-compose -f docker-compose-orthanc.yml up -d` + +then, access the application at [http://localhost](http://localhost) + +**remember that you have to access orthanc application and include your studies there** + +## Local Dcm4chee +#### build + +`$ docker-compose -f docker-compose-dcm4chee.yml build` + +#### run +`$ docker-compose -f docker-compose-dcm4chee.yml up -d` + +then, access the application at [http://localhost](http://localhost) + +**remember that you have to access dcm4chee application and include your studies there** +You can use the following command to import your studies into dcm4che + +`$ docker run -v {YOUR_STUDY_FOLDER}:/tmp --rm --network=docker_dcm4che_default dcm4che/dcm4che-tools:5.14.0 storescu -cDCM4CHEE@arc:11112 /tmp` + +**make sure that your Docker network name is docker_dcm4chee_default or change it to the right one** \ No newline at end of file diff --git a/docker/dcm4che/docker-compose-dcm4che.env b/docker/dcm4che/docker-compose-dcm4che.env new file mode 100644 index 000000000..54961c376 --- /dev/null +++ b/docker/dcm4che/docker-compose-dcm4che.env @@ -0,0 +1,4 @@ +STORAGE_DIR=/storage/fs1 +POSTGRES_DB=pacsdb +POSTGRES_USER=pacs +POSTGRES_PASSWORD=pacs diff --git a/docker/dcm4che/etc/localtime b/docker/dcm4che/etc/localtime new file mode 100644 index 000000000..e69de29bb diff --git a/docker/dcm4che/etc/timezone b/docker/dcm4che/etc/timezone new file mode 100644 index 000000000..27f725e77 --- /dev/null +++ b/docker/dcm4che/etc/timezone @@ -0,0 +1 @@ +America/New_York \ No newline at end of file diff --git a/docker/docker-compose-dcm4che.yml b/docker/docker-compose-dcm4che.yml new file mode 100644 index 000000000..5a34ff182 --- /dev/null +++ b/docker/docker-compose-dcm4che.yml @@ -0,0 +1,77 @@ +version: '3.5' + +services: + ldap: + image: dcm4che/slapd-dcm4chee:2.4.44-15.0 + logging: + driver: json-file + options: + max-size: '10m' + ports: + - '389:389' + env_file: ./dcm4che/docker-compose-dcm4che.env + volumes: + - ./dcm4che/etc/localtime:/etc/localtime:ro + - ./dcm4che/etc/timezone:/etc/timezone:ro + - ./dcm4che/dcm4che-arc/ldap:/var/lib/ldap + - ./dcm4che/dcm4che-arc/slapd.d:/etc/ldap/slapd.d + networks: + - dcm4che_default + db: + image: dcm4che/postgres-dcm4chee:11.1-15 + logging: + driver: json-file + options: + max-size: '10m' + ports: + - '5432:5432' + env_file: ./dcm4che/docker-compose-dcm4che.env + volumes: + - ./dcm4che/etc/localtime:/etc/localtime:ro + - ./dcm4che/etc/timezone:/etc/timezone:ro + - ./dcm4che/dcm4che-arc/db:/var/lib/postgresql/data + networks: + - dcm4che_default + arc: + image: dcm4che/dcm4chee-arc-psql:5.15.0 + logging: + driver: json-file + options: + max-size: '10m' + ports: + - '8080:8080' + - '8443:8443' + - '9990:9990' + - '11112:11112' + - '2575:2575' + env_file: ./dcm4che/docker-compose-dcm4che.env + environment: + WILDFLY_CHOWN: /opt/wildfly/standalone /storage + WILDFLY_WAIT_FOR: ldap:389 db:5432 + depends_on: + - ldap + - db + volumes: + - ./dcm4che/etc/localtime:/etc/localtime:ro + - ./dcm4che/etc/timezone:/etc/timezone:ro + - ./dcm4che/dcm4che-arc/wildfly:/opt/wildfly/standalone + - ./dcm4che/dcm4che-arc/storage:/storage + networks: + - dcm4che_default + viewer: + container_name: ohif-viewer + build: + context: ../ + dockerfile: Dockerfile + ports: + - '80:80' + # depends_on: + # - orthanc + environment: + - NODE_ENV=production + - REACT_APP_CONFIG=config/local_dcm4chee + restart: always + networks: + - dcm4che_default + +networks: dcm4che_default: diff --git a/docker/docker-compose-orthanc.yml b/docker/docker-compose-orthanc.yml new file mode 100644 index 000000000..1706b4c2b --- /dev/null +++ b/docker/docker-compose-orthanc.yml @@ -0,0 +1,34 @@ +version: '3.5' + +services: + orthanc: + container_name: orthanc + image: jodogne/orthanc-plugins + volumes: + - ../sampledata:/sampledata + ports: + - '4242:4242' + - '8042:8042' + restart: always + viewer: + container_name: ohif-viewer + build: + context: ../ + dockerfile: Dockerfile + ports: + - '80:80' + depends_on: + - orthanc + environment: + - NODE_ENV=production + - REACT_APP_CONFIG=config/local_orthanc + restart: always + volumes: + - ../config/local_orthanc.js:/usr/share/nginx/html/servers.js + proxy: + image: nginx + restart: always + ports: + - 8899:80 + volumes: + - ./nginx-proxy/conf/nginx.conf:/etc/nginx/nginx.conf:ro diff --git a/docker/docker-compose-publicserver.yml b/docker/docker-compose-publicserver.yml new file mode 100644 index 000000000..be969291a --- /dev/null +++ b/docker/docker-compose-publicserver.yml @@ -0,0 +1,13 @@ +version: '3.5' + +services: + viewer: + container_name: ohif-viewer + build: + context: ../ + dockerfile: Dockerfile + ports: + - '80:80' + environment: + - NODE_ENV=production + - REACT_APP_CONFIG=config/public_dicomweb diff --git a/docker/nginx-proxy/conf/nginx.conf b/docker/nginx-proxy/conf/nginx.conf new file mode 100644 index 000000000..de38c7f00 --- /dev/null +++ b/docker/nginx-proxy/conf/nginx.conf @@ -0,0 +1,49 @@ +events { + worker_connections 4096; ## Default: 1024 +} + +http { + server { + listen 80 default_server; + server_name localhost; + + # + # Wide-open CORS config for nginx + # + location / { + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; + # + # Custom headers and headers various browsers *should* be OK with but aren't + # + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; + # + # Tell client that this pre-flight info is valid for 20 days + # + add_header 'Access-Control-Allow-Headers' 'Authorization'; + add_header 'Access-Control-Allow-Credentials' true; + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Length' 0; + return 204; + } + if ($request_method = 'POST') { + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; + add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; + } + if ($request_method = 'GET') { + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; + add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; + add_header 'Access-Control-Allow-Headers' 'Authorization'; + add_header 'Access-Control-Allow-Credentials' true; + } + + proxy_pass http://orthanc:8042; + } + + } +} \ No newline at end of file diff --git a/dockerfile b/dockerfile index 958e6277f..f20d2ac68 100644 --- a/dockerfile +++ b/dockerfile @@ -2,28 +2,25 @@ # docker build -t ohif/viewer:latest . FROM node:11.2.0-slim as builder -RUN apt-get update && apt-get install -y git yarn +# RUN apt-get update && apt-get install -y git yarn RUN mkdir /usr/src/app WORKDIR /usr/src/app ENV PATH /usr/src/app/node_modules/.bin:$PATH + COPY package.json /usr/src/app/package.json COPY yarn.lock /usr/src/app/yarn.lock ADD . /usr/src/app/ RUN yarn install -RUN yarn run build -WORKDIR example -RUN yarn install -RUN yarn run prepare -ADD example /usr/src/app/build +RUN yarn run build:web -# Stage 2: Bundle the built application into a Docker container -# which runs Nginx using Alpine Linux +# # Stage 2: Bundle the built application into a Docker container +# # which runs Nginx using Alpine Linux FROM nginx:1.15.5-alpine RUN rm -rf /etc/nginx/conf.d COPY conf /etc/nginx -COPY --from=builder /usr/src/app/build /usr/share/nginx/html +COPY --from=builder /usr/src/app/public /usr/share/nginx/html EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] diff --git a/docs/latest/assets/gif/loadingStudy.gif b/docs/latest/assets/gif/loadingStudy.gif new file mode 100644 index 000000000..c010830ee Binary files /dev/null and b/docs/latest/assets/gif/loadingStudy.gif differ diff --git a/docs/latest/assets/img/homePage.png b/docs/latest/assets/img/homePage.png new file mode 100644 index 000000000..9ae0624cc Binary files /dev/null and b/docs/latest/assets/img/homePage.png differ diff --git a/docs/latest/essentials/getting-started.md b/docs/latest/essentials/getting-started.md index 8f025c2d4..5ee74492f 100644 --- a/docs/latest/essentials/getting-started.md +++ b/docs/latest/essentials/getting-started.md @@ -10,33 +10,50 @@ git clone git@github.com:OHIF/Viewers.git or [Download the latest Master as a ZIP File](https://github.com/OHIF/Viewers/archive/master.zip). -## Test the archive against our public DICOM server +## Run the OHIF Viewer application against our public DICOM server +You can either spin up locally or run with Docker. + +### running locally -## Set up and test the OHIF Viewer application: 1. [Install Node.js](https://nodejs.org/en/) -2. Open a new terminal tab in the `ohif-viewer` directory and install all dependency packages via NPM +2. Open a new terminal tab, go under `ohif-viewer` directory and install all dependency packages via `yarn` ````bash - cd Packages-react/ohif-viewer - npm install + yarn install ```` 3. Run the application ````bash - npm start + yarn start ```` Note: This will connect to our public DICOMWeb server so you can verify your installation. Follow the next section to connect to your own local or remote DICOMWeb server. -4. Launch the OHIF Viewer Study List by visiting [http://localhost:3000/](http://localhost:3000/) in a web browser. +4. Launch the OHIF Viewer Study List. By default the address is [http://localhost:3000/](http://localhost:3000/). The port may vary so check the start up output messages such as: + +```bash +Compiled successfully! + +You can now view ohif-viewer in the browser. + + Local: http://localhost:5000/ + On Your Network: http://10.74.20.83:5000/ + +Note that the development build is not optimized. +To create a production build, use yarn build. +``` **If everything is working correctly, you should see the studies from our public archive when you visit the Study List.** +![OHIF Viewer Home](../assets/img/homePage.png) + 5. Double-click on a Study in the Study List to launch it in the Viewer **If everything is working correctly, you should see your study load into the Viewer.** +![Loading the first study](../assets/gif/loadingStudy.gif) + ## Set up a local DICOM server 1. Choose and install an Image Archive @@ -55,20 +72,63 @@ Archive | Installation *Feel free to make a Pull Request if you want to add to this list.* -## Set up and test the OHIF Viewer application: -1. [Install Node.js](https://nodejs.org/en/) -2. Open a new terminal tab in the `ohif-viewer` directory and install all dependency packages via NPM +#### Orthanc with Docker + +Depending on whether or not you want uploaded studies to persist in Orthanc after Docker has been closed, there are two different methods for starting the Docker image: + +##### Temporary data storage +This command will start an instance of the jodogne/orthanc-plugins Docker image. *All data will be removed when the instance is stopped!* + +```` +docker run --rm -p 4242:4242 -p 8042:8042 jodogne/orthanc-plugins +```` + +##### Persistent data storage +In order to allow your data to persist after the instance is stopped, you first need to create an image and attached data volume with Docker. The steps are as follows: + +1. Create a persistent data volume for Orthanc to use + + ```` + docker create --name sampledata -v /sampledata jodogne/orthanc-plugins + ```` + + **Note: On Windows, you need to use an absolute path for the data volume, like so:** + + ```` + docker create --name sampledata -v '//C/Users/erik/sampledata' jodogne/orthanc-plugins + ```` + +2. Run Orthanc from Docker with the data volume attached + + ```` + docker run --volumes-from sampledata -p 4242:4242 -p 8042:8042 jodogne/orthanc-plugins + ```` + +3. Upload your data and it will be persisted + + +### Setting up OHIF Viewer with Orthanc as an example + +Once you have Orthanc running with docker either with temporary data storage or persistent data storage we con move forward with the next steps. + +1. Load orthanc with a dataset you might want to use. To upload data use [http://localhost:8042/app/explorer.html](http://localhost:8042/app/explorer.html). + + **orthanc is the username and password for orthanc docker** + +2. Go under [http://localhost:8042/app/explorer.html#upload](http://localhost:8042/app/explorer.html#upload) and upload your DICOM files there + +3. After you load the data, open a new terminal tab in the `ohif-viewer` directory and install all dependency packages via Yarn ````bash - cd Packages-react/ohif-viewer - npm install + yarn install ```` 3. Run the application using one of the available configuration files. + **the following command assumes you are under the `root` folder** ````bash - REACT_APP_CONFIG=$(cat ../../config-react/ccc.json) - npm start + export REACT_APP_CONFIG=$(cat ./config/local_orthanc.js) + yarn start ```` This uses the [Custom Environment Variables of Create-React-App](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables) to pass in your configuration. The example above will not work on Windows. Please visit the link to read about how to set environment variables on Windows. @@ -84,4 +144,5 @@ Archive | Installation #### Troubleshooting * If you receive a *"No Studies Found"* message and do not see your studies, try changing the Study Date filters to a wider range. * If you see a 'Loading' message which never resolves, check your browser JavaScript console inside the Developer Tools to identify any errors. -* If you see any errors in your server console, check the [Troubleshooting](../troubleshooting.md) page for more in depth advice. +* If you receive `exit code 137`, increase the amount of memory available to your docker instances. +* If you see any errors in your server console, check the [Troubleshooting](./troubleshooting.md) page for more in depth advice. diff --git a/package.json b/package.json index ffbe35ce3..6940bcce8 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "dev:debug": "cross-env PORT=5000 react-scripts start", "build:package": "yarn run preBuild && node --max-old-space-size=4096 node_modules/rollup/bin/rollup -c", "build:package:ci": "yarn run preBuild && cross-env REACT_APP_CONFIG=config/default node --max-old-space-size=4096 node_modules/rollup/bin/rollup -c", - "build:web": "yarn run preBuild && react-scripts build", + "build:web": "yarn run preBuild && react-scripts --max_old_space_size=4096 build", "build:web:ci": "yarn run preBuild && react-scripts --max_old_space_size=4096 build && cpx 'build/**/*' docs/latest/_book/demo --verbose", "lint": "eslint -c .eslintrc --fix src && prettier --single-quote --write src/**/*.{js,jsx,json,css}", "test": "jest", @@ -73,7 +73,7 @@ "hammerjs": "^2.0.8", "lodash.isequal": "4.5.0", "moment": "^2.24.0", - "ohif-core": "^0.3.5", + "ohif-core": "0.4.1", "ohif-cornerstone-extension": "^0.0.26", "ohif-dicom-html-extension": "^0.0.2", "ohif-dicom-microscopy-extension": "^0.0.5", diff --git a/public/config/local_dcm4chee.js b/public/config/local_dcm4chee.js new file mode 100644 index 000000000..be7d02d20 --- /dev/null +++ b/public/config/local_dcm4chee.js @@ -0,0 +1,23 @@ +window.config = { + // default: '/' + routerBasename: '/', + // default: '' + relativeWebWorkerScriptsPath: '', + servers: { + dicomWeb: [ + { + name: 'DCM4CHEE', + wadoUriRoot: 'http://localhost:8080/dcm4chee-arc/aets/DCM4CHEE/wado', + qidoRoot: 'http://localhost:8080/dcm4chee-arc/aets/DCM4CHEE/rs', + wadoRoot: 'http://localhost:8080/dcm4chee-arc/aets/DCM4CHEE/rs', + qidoSupportsIncludeField: true, + imageRendering: 'wadors', + thumbnailRendering: 'wadors', + requestOptions: { + requestFromBrowser: true, + auth: 'admin:admin', + }, + }, + ], + }, +} diff --git a/public/config/local_orthanc.js b/public/config/local_orthanc.js new file mode 100644 index 000000000..27554ed49 --- /dev/null +++ b/public/config/local_orthanc.js @@ -0,0 +1,25 @@ +window.config = { + // default: '/' + routerBasename: '/', + // default: '' + relativeWebWorkerScriptsPath: '', + servers: { + dicomWeb: [ + { + name: 'Orthanc', + wadoUriRoot: 'http://localhost:8899/wado', + qidoRoot: 'http://localhost:8899/dicom-web', + wadoRoot: 'http://localhost:8899/dicom-web', + qidoSupportsIncludeField: false, + imageRendering: 'wadors', + thumbnailRendering: 'wadors', + requestOptions: { + auth: 'orthanc:orthanc', + logRequests: true, + logResponses: false, + logTiming: true, + }, + }, + ], + }, +} diff --git a/public/config/public_dicomweb.js b/public/config/public_dicomweb.js new file mode 100644 index 000000000..1fa5659cf --- /dev/null +++ b/public/config/public_dicomweb.js @@ -0,0 +1,19 @@ +window.config = { + routerBasename: '/', + servers: { + dicomWeb: [ + { + name: 'DCM4CHEE', + wadoUriRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado', + qidoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs', + wadoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs', + qidoSupportsIncludeField: true, + imageRendering: 'wadors', + thumbnailRendering: 'wadors', + requestOptions: { + requestFromBrowser: true, + }, + }, + ], + }, +} diff --git a/src/routes/StandaloneRouting.js b/src/routes/StandaloneRouting.js index f1d584c00..195d6feab 100644 --- a/src/routes/StandaloneRouting.js +++ b/src/routes/StandaloneRouting.js @@ -1,104 +1,114 @@ -import React, { Component } from "react"; -import PropTypes from "prop-types"; -import qs from 'query-string' -import Viewer from "../connectedComponents/Viewer"; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import qs from 'querystring'; +import Viewer from '../connectedComponents/Viewer'; import OHIF from 'ohif-core'; const { createDisplaySets } = OHIF.utils; class StandaloneRouting extends Component { - state = { - studies: null, - error: null - } + state = { + studies: null, + error: null + }; - static propTypes = { - location: PropTypes.object, - store: PropTypes.object - }; + static propTypes = { + location: PropTypes.object, + store: PropTypes.object + }; - static parseQueryAndFetchStudies(query) { - return new Promise((resolve, reject) => { - const url = query.url; + static parseQueryAndFetchStudies(query) { + return new Promise((resolve, reject) => { + const url = query.url; - if (!url) { - reject(new Error('No URL was specified. Use ?url=$yourURL')); - } + if (!url) { + reject(new Error('No URL was specified. Use ?url=$yourURL')); + } - // Define a request to the server to retrieve the study data - // as JSON, given a URL that was in the Route - const oReq = new XMLHttpRequest(); + // Define a request to the server to retrieve the study data + // as JSON, given a URL that was in the Route + const oReq = new XMLHttpRequest(); - // Add event listeners for request failure - oReq.addEventListener('error', (error) => { - OHIF.log.warn('An error occurred while retrieving the JSON data'); - reject(error) - }); + // Add event listeners for request failure + oReq.addEventListener('error', error => { + OHIF.log.warn('An error occurred while retrieving the JSON data'); + reject(error); + }); - // When the JSON has been returned, parse it into a JavaScript Object - // and render the OHIF Viewer with this data - oReq.addEventListener('load', () => { - // Parse the response content - // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseText - if (!oReq.responseText) { - OHIF.log.warn('Response was undefined'); - reject(new Error('Response was undefined')); - } - - OHIF.log.info(JSON.stringify(oReq.responseText, null, 2)); - - const data = JSON.parse(oReq.responseText); - if (data.servers && query.studyInstanceUids) { - const server = data.servers.dicomWeb[0]; - server.type = 'dicomWeb'; - - const studyInstanceUids = query.studyInstanceUids.split(';'); - const seriesInstanceUids = []; - - OHIF.studies.retrieveStudiesMetadata(server, studyInstanceUids, seriesInstanceUids).then(studies => { - resolve(studies); - }, error => { - reject(error); - }); - } else { - resolve(data.studies); - } - }); - - // Open the Request to the server for the JSON data - // In this case we have a server-side route called /api/ - // which responds to GET requests with the study data - OHIF.log.info(`Sending Request to: ${url}`); - oReq.open('GET', url); - oReq.setRequestHeader('Accept', 'application/json') - - // Fire the request to the server - oReq.send(); - }); - } - - componentDidMount() { - const query = qs.parse(this.props.location.search); - StandaloneRouting.parseQueryAndFetchStudies(query).then(studies => { - const updatedStudies = createDisplaySets(studies); - - this.setState({ studies: updatedStudies }); - }, error => { - this.setState({ error }); - }); - } - - render() { - if (this.state.error) { - return (
Error: {JSON.stringify(this.state.error)}
); - } else if (!this.state.studies) { - return (
Loading...
); + // When the JSON has been returned, parse it into a JavaScript Object + // and render the OHIF Viewer with this data + oReq.addEventListener('load', () => { + // Parse the response content + // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseText + if (!oReq.responseText) { + OHIF.log.warn('Response was undefined'); + reject(new Error('Response was undefined')); } - return ( - - ); + OHIF.log.info(JSON.stringify(oReq.responseText, null, 2)); + + const data = JSON.parse(oReq.responseText); + if (data.servers && query.studyInstanceUids) { + const server = data.servers.dicomWeb[0]; + server.type = 'dicomWeb'; + + const studyInstanceUids = query.studyInstanceUids.split(';'); + const seriesInstanceUids = []; + + OHIF.studies + .retrieveStudiesMetadata( + server, + studyInstanceUids, + seriesInstanceUids + ) + .then( + studies => { + resolve(studies); + }, + error => { + reject(error); + } + ); + } else { + resolve(data.studies); + } + }); + + // Open the Request to the server for the JSON data + // In this case we have a server-side route called /api/ + // which responds to GET requests with the study data + OHIF.log.info(`Sending Request to: ${url}`); + oReq.open('GET', url); + oReq.setRequestHeader('Accept', 'application/json'); + + // Fire the request to the server + oReq.send(); + }); + } + + componentDidMount() { + const query = qs.parse(this.props.location.search); + StandaloneRouting.parseQueryAndFetchStudies(query).then( + studies => { + const updatedStudies = createDisplaySets(studies); + + this.setState({ studies: updatedStudies }); + }, + error => { + this.setState({ error }); + } + ); + } + + render() { + if (this.state.error) { + return
Error: {JSON.stringify(this.state.error)}
; + } else if (!this.state.studies) { + return
Loading...
; } + + return ; + } } export default StandaloneRouting; diff --git a/yarn.lock b/yarn.lock index 71b945888..40d129666 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7501,11 +7501,6 @@ joi@^11.1.1: isemail "3.x.x" topo "2.x.x" -jquery.hotkeys@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/jquery.hotkeys/-/jquery.hotkeys-0.1.0.tgz#a88f636494fe75de41e4b753a059e5a523b83273" - integrity sha1-qI9jZJT+dd5B5LdToFnlpSO4MnM= - jquery@^3.3.1: version "3.4.0" resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.0.tgz#8de513fa0fa4b2c7d2e48a530e26f0596936efdf" @@ -8647,6 +8642,11 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" +mime-db@1.40.0: + version "1.40.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" + integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== + "mime-db@>= 1.38.0 < 2": version "1.39.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.39.0.tgz#f95a20275742f7d2ad0429acfe40f4233543780e" @@ -8664,6 +8664,13 @@ mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.18, mime-types@~2.1.19: dependencies: mime-db "~1.38.0" +mime-types@~2.1.24: + version "2.1.24" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" + integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== + dependencies: + mime-db "1.40.0" + mime@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" @@ -9577,17 +9584,16 @@ octokit-pagination-methods@^1.1.0: resolved "https://registry.yarnpkg.com/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz#cf472edc9d551055f9ef73f6e42b4dbb4c80bea4" integrity sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ== -ohif-core@^0.3.5: - version "0.3.9" - resolved "https://registry.yarnpkg.com/ohif-core/-/ohif-core-0.3.9.tgz#359ea7451e70f06f67c4bf5fcecf5f844ad922fb" - integrity sha512-sdJzAHiK+PhJK+ID1CilqvPw9z3EY4sDYwKUFXqnJLmf+a42x5FWNb3F7iH5Hw4V3sn6V4H6YZApbk2NVdam7g== +ohif-core@0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/ohif-core/-/ohif-core-0.4.1.tgz#3a2b0b92b22f8da80b04fe487dc1faf6c0c2ed6c" + integrity sha512-QJRnx3NDf45a655JZQMCNj9tLtyh5YaH7X/tGPsA0Y2zPWEKxWKAQQDUE+TCZNsec135mB+xxYw++a/GkqLX0A== dependencies: "@babel/runtime" "^7.2.0" ajv "^6.10.0" dicomweb-client "^0.4.2" isomorphic-base64 "^1.0.2" jquery "^3.3.1" - jquery.hotkeys "^0.1.0" lodash.clonedeep "^4.5.0" lodash.merge "^4.6.1" validate.js "^0.12.0" @@ -11254,7 +11260,7 @@ querystring@0.2.0: resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= -querystringify@^2.0.0: +querystringify@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e" integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA== @@ -12464,9 +12470,9 @@ run-queue@^1.0.0, run-queue@^1.0.3: aproba "^1.1.1" rxjs@^6.1.0, rxjs@^6.3.3, rxjs@^6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.4.0.tgz#f3bb0fe7bda7fb69deac0c16f17b50b0b8790504" - integrity sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw== + version "6.5.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.1.tgz#f7a005a9386361921b8524f38f54cbf80e5d08f4" + integrity sha512-y0j31WJc83wPu31vS1VlAFW5JGrnGC+j+TtGAa1fRQphy48+fDYiDmX8tjGloToEsMkxnouOg/1IzXGKkJnZMg== dependencies: tslib "^1.9.0" @@ -13889,9 +13895,9 @@ tryer@^1.0.0: integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== ts-pnp@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.0.1.tgz#fde74a6371676a167abaeda1ffc0fdb423520098" - integrity sha512-Zzg9XH0anaqhNSlDRibNC8Kp+B9KNM0uRIpLpGkGyrgRIttA7zZBhotTSEoEyuDrz3QW2LGtu2dxuk34HzIGnQ== + version "1.1.2" + resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.1.2.tgz#be8e4bfce5d00f0f58e0666a82260c34a57af552" + integrity sha512-f5Knjh7XCyRIzoC/z1Su1yLLRrPrFCgtUAh/9fCSP6NKbATwpOL1+idQVXQokK9GRFURn/jYPGPfegIctwunoA== tslib@^1.9.0: version "1.9.3" @@ -13923,12 +13929,12 @@ type-check@~0.3.2: prelude-ls "~1.1.2" type-is@~1.6.16: - version "1.6.16" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" - integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q== + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== dependencies: media-typer "0.3.0" - mime-types "~2.1.18" + mime-types "~2.1.24" typedarray-to-buffer@~1.0.0: version "1.0.4" @@ -13954,9 +13960,9 @@ uglify-js@3.4.x: source-map "~0.6.1" uglify-js@^3.1.4: - version "3.5.4" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.5.4.tgz#4a64d57f590e20a898ba057f838dcdfb67a939b9" - integrity sha512-GpKo28q/7Bm5BcX9vOu4S46FwisbPbAmkkqPnGIpKvKTM96I85N6XHQV+k4I6FA2wxgLhcsSyHoNhzucwCflvA== + version "3.5.8" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.5.8.tgz#496f62a8c23c3e6791563acbc04908edaca4025f" + integrity sha512-GFSjB1nZIzoIq70qvDRtWRORHX3vFkAnyK/rDExc0BN7r9+/S+Voz3t/fwJuVfjppAMz+ceR2poE7tkhvnVwQQ== dependencies: commander "~2.20.0" source-map "~0.6.1" @@ -14197,11 +14203,11 @@ url-parse-lax@^1.0.0: prepend-http "^1.0.1" url-parse@^1.4.3: - version "1.4.6" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.6.tgz#baf91d6e6783c8a795eb476892ffef2737fc0456" - integrity sha512-/B8AD9iQ01seoXmXf9z/MjLZQIdOoYl/+gvsQF6+mpnxaTfG9P7srYaiqaDMyKkR36XMXfhqSHss5MyFAO8lew== + version "1.4.7" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278" + integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg== dependencies: - querystringify "^2.0.0" + querystringify "^2.1.1" requires-port "^1.0.0" url-template@^2.0.8: @@ -14367,9 +14373,9 @@ vm-browserify@0.0.4: indexof "0.0.1" vtk.js@^8.3.11: - version "8.4.3" - resolved "https://registry.yarnpkg.com/vtk.js/-/vtk.js-8.4.3.tgz#e09b583e458e5a9db06aec61b8d9e7c055213b1b" - integrity sha512-3SZAyIeroqzbHNDqqVuzrVBIuwC1IZX+US8BwJAuEImFLoyi1GHGGw91iAJdPROvWDDFj4CUTMB9jxIq8b8hoA== + version "8.4.9" + resolved "https://registry.yarnpkg.com/vtk.js/-/vtk.js-8.4.9.tgz#139d3cf2f36139e836fc1cf360b47e0d05f0b3be" + integrity sha512-5Ye/G89aDpsLdRq2bW40CRtysK2FaK6l7WN5xIhmECqBxAqDDH9iUiKiM7C4IJ2EXjVo1R+a/rp7+1bIAtyUAQ== dependencies: base64-js "1.2.1" blueimp-md5 "2.10.0" @@ -14567,9 +14573,9 @@ websocket-extensions@>=0.1.1: integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg== webvr-polyfill-dpdb@^1.0.11: - version "1.0.15" - resolved "https://registry.yarnpkg.com/webvr-polyfill-dpdb/-/webvr-polyfill-dpdb-1.0.15.tgz#37c9ff013023b0cb118007f9e7869b310205def9" - integrity sha512-EfjKbmt9n0WCSrTZgvL76IEjMl5yaZ8kZIlgWZnRJzmuKSMB0lrzZzlCJC5AtDizGnpWXlVn9UtAEgVd2nAIjA== + version "1.0.16" + resolved "https://registry.yarnpkg.com/webvr-polyfill-dpdb/-/webvr-polyfill-dpdb-1.0.16.tgz#7f2cf88460c002a5f10ff69b2bf3a5663e0ad9dd" + integrity sha512-FCciTtPhwkYYHGL0K67G8k7ZnNVqnEx3u4NVHLJ0+Ya6f2VTZUl/GJpaEo1Id2pBP/2l0RYZ3IGZE4Pe8fRalg== webvr-polyfill@0.10.8: version "0.10.8"