Compare commits

..
Author SHA1 Message Date
ohif-bot a08caa9bdb chore(release): publish [skip ci]
- @ohif/extension-cornerstone@2.10.7
 - @ohif/extension-dicom-html@1.3.5
 - @ohif/extension-dicom-rt@0.6.8
 - @ohif/extension-dicom-segmentation@0.6.3
 - @ohif/extension-dicom-tag-browser@0.2.6
 - @ohif/extension-vtk@1.11.5
 - @ohif/core@2.13.4
 - @ohif/viewer@4.9.9
2021-04-15 13:13:50 +00:00
Igor Octaviano 29afddb3a6 Merge pull request #2363 from OHIF/fix/window-level-issues
fix(MetadataProvider): Update metadata provider to resolve issues after dicomweb update/new return value
2021-04-15 10:10:48 -03:00
igoroctaviano f85f856734 Comment cache 2021-04-15 09:40:37 -03:00
igoroctaviano c6bc19c002 Rollback circle ci test 2021-04-15 09:29:50 -03:00
igoroctaviano 538555f000 Merge branch 'master' of github.com:OHIF/Viewers into fix/window-level-issues 2021-04-15 09:17:54 -03:00
igoroctaviano 8681036b21 fix(wl): fix metadata provider window level issues after dicomweb update (string vs number) 2021-04-15 09:15:42 -03:00
Davide Punzo e55b909ca6 IDC2345: Update dcmjs to version 0.18.4 (#2362) 2021-04-15 13:33:13 +02:00
Davide Punzo 4bb36704ee IDC2346: fix images sorting (#2358) 2021-04-14 19:43:58 +02:00
Davide Punzo 9bbdb35d88 IDC2259: do not check uniform spacing in the 4th dimension for 4D datasets (#2356) 2021-04-13 12:57:28 +02:00
qqalexqq 2f443fa2ef fix: Update Dockerfile node version - fix missing dependencies (#2349)
There were some utilities missing: python, make, g++. Also node version was too old - current node builds without problems.
2021-04-05 09:47:57 +02:00
ohif-bot 6d7d7da287 chore(release): publish [skip ci]
- @ohif/extension-dicom-segmentation@0.6.2
 - @ohif/viewer@4.9.8
2021-03-31 10:24:08 +00:00
Davide Punzo 1f6751f95b IDC2332 (#2341)
1) fix the loading of the segmentations when filtering study with ?seriesInstanceUID= syntax
2) add time in the dates of the items of the segmentation combobox list
3) order segmentation combobox list in reverse time order
2021-03-31 12:20:34 +02:00
ohif-bot 92081a097d chore(release): publish [skip ci]
- @ohif/extension-cornerstone@2.10.6
 - @ohif/viewer@4.9.7
2021-03-26 18:38:58 +00:00
Igor Octaviano ba1a33c3ac Merge pull request #2335 from OHIF/idc-2334
IDC-2334: Resolve choppy scrolling in 2D mode
2021-03-26 15:36:07 -03:00
igoroctaviano 193ff12b6e Fix scroll speed 2021-03-26 13:27:51 -03:00
ohif-bot 3296ffaa07 chore(release): publish [skip ci]
- @ohif/extension-vtk@1.11.4
 - @ohif/core@2.13.3
 - @ohif/ui@1.9.1
 - @ohif/viewer@4.9.6
2021-03-26 10:35:50 +00:00
Davide Punzo 0456d92462 IDC 2259: add warning UI for series inconsistencies (#2331)
IDC 2259: add warning UI for series inconsistencies

remove VTKMPRToolbarButton component memoization (it is not anymore necessary)
2021-03-26 11:32:10 +01:00
ohif-bot db3b15e537 chore(release): publish [skip ci]
- @ohif/extension-vtk@1.11.3
 - @ohif/core@2.13.2
 - @ohif/viewer@4.9.5
2021-03-25 16:16:14 +00:00
Igor OctavianoandDavide Punzo 6e723ebced fix: IDC-2288: Update toolbar tabs after derived displayset loaded (#2307)
* Update toolbar tabs after derived displayset loaded

* trigger CI

Co-authored-by: Davide Punzo <punzodavide@hotmail.it>
2021-03-25 17:12:20 +01:00
ohif-bot a6a231c81e chore(release): publish [skip ci]
- @ohif/extension-debugging@0.2.1
 - @ohif/viewer@4.9.4
2021-03-19 18:54:21 +00:00
Igor Octaviano 7c2bd9b76a Merge pull request #2321 from OHIF/bugfix/idc-2006
bug(IDC-2006): Fix bug introduced with new logger service which broke debugger mailto functionality
2021-03-19 15:51:01 -03:00
igoroctaviano 5dfa8d465d Force pipeline 2021-03-19 15:12:37 -03:00
igoroctaviano fc5301e904 bug(debugger):Fix bug that breaks mailto introduced by logger service 2021-03-18 07:40:59 -03:00
ohif-bot 88e5a7e54a chore(release): publish [skip ci]
- @ohif/extension-cornerstone@2.10.5
 - @ohif/viewer@4.9.3
2021-03-15 20:12:36 +00:00
Igor Octaviano 5d24bb4b73 Merge pull request #2315 from OHIF/igoroctaviano/react-cornerstone-viewport-4.0.5
Update dependency: react-cornerstone-viewport@4.0.5
2021-03-15 17:09:16 -03:00
igoroctaviano 03a4056179 Update dependency: react-cornerstone-viewport@4.0.5
react-cornerstone-viewport
  * @ohif/extension-cornerstone: 4.0.4 → 4.0.5
2021-03-15 16:42:24 -03:00
ohif-bot ec76bc3b0b chore(release): publish [skip ci]
- @ohif/extension-cornerstone@2.10.4
 - @ohif/extension-dicom-html@1.3.4
 - @ohif/extension-dicom-rt@0.6.7
 - @ohif/extension-dicom-segmentation@0.6.1
 - @ohif/extension-dicom-tag-browser@0.2.5
 - @ohif/extension-vtk@1.11.2
 - @ohif/core@2.13.1
 - @ohif/viewer@4.9.2
2021-03-09 19:43:21 +00:00
Davide Punzo b1070acaca Update dependency: dcmjs@0.18.3 (#2302) 2021-03-09 20:38:19 +01:00
ohif-bot 7b5beb8f98 chore(release): publish [skip ci]
- @ohif/extension-vtk@1.11.1
 - @ohif/viewer@4.9.1
2021-03-09 15:55:47 +00:00
97410e12b9 Added memoization on VTKMPRToolbarButton component to avoid unnecesary rebuilds (#2274)
* Added memoization on VTKMPRToolbarButton component to avoid unnecessary rebuilds

* update isDisplaySetReconstructable for float precision

Co-authored-by: Rodrigo Cáceres Vicencio <rcaceres@nursoft.cl>
Co-authored-by: Davide Punzo <punzodavide@hotmail.it>
2021-03-09 16:52:56 +01:00
ohif-bot bdecbfeee3 chore(release): publish [skip ci]
- @ohif/extension-debugging@0.2.0
 - @ohif/extension-dicom-microscopy@0.52.0
 - @ohif/extension-dicom-segmentation@0.6.0
 - @ohif/extension-vtk@1.11.0
 - @ohif/core@2.13.0
 - @ohif/ui@1.9.0
 - @ohif/viewer@4.9.0
2021-03-04 21:44:04 +00:00
Igor Octaviano 5a970056ae Merge pull request #2283 from OHIF/IDC-2223-update
feat(IDC-2223): add new log service to be used by debugger extension
2021-03-04 18:41:04 -03:00
igoroctaviano 8581405352 Add logger to viewport grid 2021-03-04 18:20:57 -03:00
igoroctaviano df8c4db2ed Update broken test 2021-03-03 20:06:58 -03:00
igoroctaviano ea62bdaddf Merge branch 'master' of github.com:OHIF/Viewers into IDC-2223-update 2021-03-03 19:18:36 -03:00
igoroctaviano e983b02677 Add onerror event to cover all other unhandled errors 2021-03-03 19:16:49 -03:00
ohif-bot 1e4b78d78d chore(release): publish [skip ci]
- @ohif/extension-cornerstone@2.10.3
 - @ohif/extension-dicom-html@1.3.3
 - @ohif/extension-dicom-rt@0.6.6
 - @ohif/extension-dicom-segmentation@0.5.4
 - @ohif/extension-dicom-tag-browser@0.2.4
 - @ohif/extension-vtk@1.10.6
 - @ohif/core@2.12.5
 - @ohif/viewer@4.8.12
2021-03-03 18:31:51 +00:00
igoroctaviano ee6131f98e Merge branch 'master' of github.com:OHIF/Viewers into IDC-2223-update 2021-03-03 15:28:23 -03:00
Igor Octaviano a56bdd035b Merge pull request #2290 from OHIF/bump-dcmjs
Update dependency: dcmjs@0.18.2
2021-03-03 15:27:54 -03:00
igoroctaviano 04901c296e Update dependency: dcmjs@0.18.2
dcmjs
  * @ohif/core: 0.18.1 → 0.18.2
  * @ohif/extension-cornerstone: 0.18.1 → 0.18.2
  * @ohif/extension-dicom-html: 0.18.1 → 0.18.2
  * @ohif/extension-dicom-rt: 0.18.1 → 0.18.2
  * @ohif/extension-dicom-segmentation: 0.18.1 → 0.18.2
  * @ohif/extension-dicom-tag-browser: 0.18.1 → 0.18.2
  * @ohif/extension-vtk: 0.18.1 → 0.18.2
  * @ohif/viewer: 0.18.1 → 0.18.2
2021-03-03 14:35:06 -03:00
ohif-bot 59cadad98c chore(release): publish [skip ci]
- @ohif/extension-cornerstone@2.10.2
 - @ohif/extension-dicom-html@1.3.2
 - @ohif/extension-dicom-rt@0.6.5
 - @ohif/extension-dicom-segmentation@0.5.3
 - @ohif/extension-dicom-tag-browser@0.2.3
 - @ohif/extension-vtk@1.10.5
 - @ohif/core@2.12.4
 - @ohif/viewer@4.8.11
2021-02-25 21:31:47 +00:00
igoroctaviano 14d6454eaf feat(log): add new log service 2021-02-25 18:29:28 -03:00
Igor Octaviano 64f87d2c93 Merge pull request #2281 from OHIF/fix/bump-dcmjs
Update dependency: dcmjs@0.18.1
2021-02-25 18:28:37 -03:00
igoroctaviano cfd66e5ef7 Update dependency: dcmjs@0.18.1
dcmjs
  * @ohif/core: 0.17.2 → 0.18.1
  * @ohif/extension-cornerstone: 0.17.2 → 0.18.1
  * @ohif/extension-dicom-html: 0.17.2 → 0.18.1
  * @ohif/extension-dicom-rt: 0.17.2 → 0.18.1
  * @ohif/extension-dicom-segmentation: 0.17.2 → 0.18.1
  * @ohif/extension-dicom-tag-browser: 0.17.2 → 0.18.1
  * @ohif/extension-vtk: 0.17.2 → 0.18.1
  * @ohif/viewer: 0.17.2 → 0.18.1
2021-02-25 17:05:24 -03:00
Andrey Fedorovandigoroctaviano 6480389778 chore: add acknowledgment of IDC (#2255)
* add acknowldgment of IDC

resolves #1136

* Fix typo + remove IDC ack example

Co-authored-by: igoroctaviano <igoroctaviano@gmail.com>
2021-02-12 12:08:43 +01:00
ohif-bot 0e736e7a56 chore(release): publish [skip ci]
- @ohif/viewer@4.8.10
2021-02-08 11:56:46 +00:00
Igor Octaviano d246cd9842 Merge pull request #2267 from OHIF/IDC-2251
IDC-2251: Add error page and not found pages if failed to retrieve study data
2021-02-08 08:53:35 -03:00
igoroctaviano 4fa1eb683d Merge branch 'master' of github.com:OHIF/Viewers into IDC-2251 2021-02-07 22:29:45 -03:00
igoroctaviano d97270f995 Merge branch 'master' of github.com:OHIF/Viewers into IDC-2251 2021-02-05 17:00:06 -03:00
igoroctaviano 7c5f9c44b6 Add error page and not found pages if failed to retrieve study data 2021-02-03 13:58:46 -03:00
63 changed files with 1299 additions and 256 deletions

No files matched your search

+35 -27
View File
@@ -48,12 +48,12 @@ jobs:
- checkout: - checkout:
post: post:
- git fetch --all - git fetch --all
- restore_cache: # - restore_cache:
name: Restore Yarn and Cypress Package Cache # name: Restore Yarn and Cypress Package Cache
keys: # keys:
# when lock file changes, use increasingly general patterns to restore cache # # when lock file changes, use increasingly general patterns to restore cache
- yarn-packages-{{ checksum "yarn.lock" }} # - yarn-packages-{{ checksum "yarn.lock" }}
- yarn-packages- # - yarn-packages-
- run: - run:
name: Install Dependencies name: Install Dependencies
command: yarn install --frozen-lockfile command: yarn install --frozen-lockfile
@@ -107,12 +107,12 @@ jobs:
post: post:
- git fetch --all - git fetch --all
- restore_cache: # - restore_cache:
name: Restore Yarn and Cypress Package Cache # name: Restore Yarn and Cypress Package Cache
keys: # keys:
# when lock file changes, use increasingly general patterns to restore cache # # when lock file changes, use increasingly general patterns to restore cache
- yarn-packages-{{ checksum "yarn.lock" }} # - yarn-packages-{{ checksum "yarn.lock" }}
- yarn-packages- # - yarn-packages-
- run: - run:
name: Install Dependencies name: Install Dependencies
@@ -143,12 +143,12 @@ jobs:
- checkout: - checkout:
post: post:
- git fetch --all - git fetch --all
- restore_cache: # - restore_cache:
name: Restore Yarn and Cypress Package Cache # name: Restore Yarn and Cypress Package Cache
keys: # keys:
# when lock file changes, use increasingly general patterns to restore cache # # when lock file changes, use increasingly general patterns to restore cache
- yarn-packages-{{ checksum "yarn.lock" }} # - yarn-packages-{{ checksum "yarn.lock" }}
- yarn-packages- # - yarn-packages-
- run: - run:
name: Install Dependencies name: Install Dependencies
command: yarn install --frozen-lockfile command: yarn install --frozen-lockfile
@@ -237,11 +237,11 @@ jobs:
post: post:
- git fetch --all - git fetch --all
# Use increasingly general patterns to restore cache # Use increasingly general patterns to restore cache
- restore_cache: # - restore_cache:
name: Restore Yarn and Cypress Package Cache # name: Restore Yarn and Cypress Package Cache
keys: # keys:
- yarn-packages-{{ checksum "yarn.lock" }} # - yarn-packages-{{ checksum "yarn.lock" }}
- yarn-packages- # - yarn-packages-
- run: - run:
name: Install Dependencies name: Install Dependencies
command: yarn install --frozen-lockfile command: yarn install --frozen-lockfile
@@ -346,7 +346,9 @@ workflows:
record: true record: true
store_artifacts: true store_artifacts: true
working_directory: platform/viewer working_directory: platform/viewer
build: npx cross-env QUICK_BUILD=true APP_CONFIG=config/dicomweb-server.js yarn run build build:
npx cross-env QUICK_BUILD=true APP_CONFIG=config/dicomweb-server.js
yarn run build
start: yarn run test:e2e:serve start: yarn run test:e2e:serve
spec: 'cypress/integration/common/**/*,cypress/integration/pwa/**/*' spec: 'cypress/integration/common/**/*,cypress/integration/pwa/**/*'
wait-on: 'http://localhost:3000' wait-on: 'http://localhost:3000'
@@ -372,7 +374,9 @@ workflows:
record: true record: true
store_artifacts: true store_artifacts: true
working_directory: platform/viewer working_directory: platform/viewer
build: npx cross-env QUICK_BUILD=true APP_CONFIG=config/dicomweb-server.js yarn run build:package build:
npx cross-env QUICK_BUILD=true APP_CONFIG=config/dicomweb-server.js
yarn run build:package
start: yarn run test:e2e:serve start: yarn run test:e2e:serve
spec: 'cypress/integration/common/**/*,cypress/integration/script-tag/**/*' spec: 'cypress/integration/common/**/*,cypress/integration/script-tag/**/*'
wait-on: 'http://localhost:3000' wait-on: 'http://localhost:3000'
@@ -403,7 +407,9 @@ workflows:
yarn: true yarn: true
store_artifacts: false store_artifacts: false
working_directory: platform/viewer working_directory: platform/viewer
build: npx cross-env QUICK_BUILD=true APP_CONFIG=config/dicomweb-server.js yarn run build build:
npx cross-env QUICK_BUILD=true APP_CONFIG=config/dicomweb-server.js
yarn run build
# start server --> verify running --> percy + chrome + cypress # start server --> verify running --> percy + chrome + cypress
command: yarn run test:e2e:dist command: yarn run test:e2e:dist
cache-key: 'yarn-packages-{{ checksum "yarn.lock" }}' cache-key: 'yarn-packages-{{ checksum "yarn.lock" }}'
@@ -480,7 +486,9 @@ workflows:
yarn: true yarn: true
store_artifacts: false store_artifacts: false
working_directory: platform/viewer working_directory: platform/viewer
build: npx cross-env QUICK_BUILD=true APP_CONFIG=config/dicomweb-server.js yarn run build build:
npx cross-env QUICK_BUILD=true APP_CONFIG=config/dicomweb-server.js
yarn run build
# start server --> verify running --> percy + chrome + cypress # start server --> verify running --> percy + chrome + cypress
command: yarn run test:e2e:dist command: yarn run test:e2e:dist
cache-key: 'yarn-packages-{{ checksum "yarn.lock" }}' cache-key: 'yarn-packages-{{ checksum "yarn.lock" }}'
+2 -1
View File
@@ -21,7 +21,7 @@
# Stage 1: Build the application # Stage 1: Build the application
# docker build -t ohif/viewer:latest . # docker build -t ohif/viewer:latest .
FROM node:10.16.3-slim as builder FROM node:15.13.0-slim as builder
RUN mkdir /usr/src/app RUN mkdir /usr/src/app
WORKDIR /usr/src/app WORKDIR /usr/src/app
@@ -39,6 +39,7 @@ COPY package.json /usr/src/app/package.json
COPY postcss.config.js /usr/src/app/postcss.config.js COPY postcss.config.js /usr/src/app/postcss.config.js
COPY yarn.lock /usr/src/app/yarn.lock COPY yarn.lock /usr/src/app/yarn.lock
RUN apt-get update && apt-get install -y python make g++
# Run the install before copying the rest of the files # Run the install before copying the rest of the files
RUN yarn config set workspaces-experimental true RUN yarn config set workspaces-experimental true
RUN yarn install RUN yarn install
+16 -3
View File
@@ -248,9 +248,6 @@ To acknowledge the OHIF Viewer in an academic publication, please cite
> >
> _Cancer Research_, November 1 2017 (77) (21) e119-e122 DOI: > _Cancer Research_, November 1 2017 (77) (21) e119-e122 DOI:
> [10.1158/0008-5472.CAN-17-0334](https://www.doi.org/10.1158/0008-5472.CAN-17-0334) > [10.1158/0008-5472.CAN-17-0334](https://www.doi.org/10.1158/0008-5472.CAN-17-0334)
>
> NCI Imaging Data Commons: contract number 19X037Q from Leidos Biomedical
> Research under Task Order HHSN26100071 from NCI.
**Note:** If you use or find this repository helpful, please take the time to **Note:** If you use or find this repository helpful, please take the time to
star this repository on Github. This is an easy way for us to assess adoption star this repository on Github. This is an easy way for us to assess adoption
@@ -261,6 +258,22 @@ Cancer Institute, Informatics Technology for Cancer Research (ITCR) program,
under a under a
[grant to Dr. Gordon Harris at Massachusetts General Hospital (U24 CA199460)](https://projectreporter.nih.gov/project_info_description.cfm?aid=8971104). [grant to Dr. Gordon Harris at Massachusetts General Hospital (U24 CA199460)](https://projectreporter.nih.gov/project_info_description.cfm?aid=8971104).
## Projects that contributed to OHIF Viewer
The following is a (partial) list of projects that contributed resources towards
development of OHIF Viewer:
- [NCI Imaging Data Commons (IDC) project](https://imaging.datacommons.cancer.gov/)
supported development of new features and bug fixes marked with
["IDC:priority"](https://github.com/OHIF/Viewers/issues?q=is%3Aissue+is%3Aopen+label%3AIDC%3Apriority),
["IDC:candidate"](https://github.com/OHIF/Viewers/issues?q=is%3Aissue+is%3Aopen+label%3AIDC%3Acandidate)
or
["IDC:collaboration"](https://github.com/OHIF/Viewers/issues?q=is%3Aissue+is%3Aopen+label%3AIDC%3Acollaboration).
NCI Imaging Data Commons is supported by the contract number 19X037Q from
Leidos Biomedical Research under Task Order HHSN26100071 from NCI.
[IDC Viewer](https://learn.canceridc.dev/portal/visualization) is a customized
version of the OHIF Viewer.
## License ## License
MIT © [OHIF](https://github.com/OHIF) MIT © [OHIF](https://github.com/OHIF)
+48
View File
@@ -3,6 +3,54 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.10.7](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.10.6...@ohif/extension-cornerstone@2.10.7) (2021-04-15)
**Note:** Version bump only for package @ohif/extension-cornerstone
## [2.10.6](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.10.5...@ohif/extension-cornerstone@2.10.6) (2021-03-26)
**Note:** Version bump only for package @ohif/extension-cornerstone
## [2.10.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.10.4...@ohif/extension-cornerstone@2.10.5) (2021-03-15)
**Note:** Version bump only for package @ohif/extension-cornerstone
## [2.10.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.10.3...@ohif/extension-cornerstone@2.10.4) (2021-03-09)
**Note:** Version bump only for package @ohif/extension-cornerstone
## [2.10.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.10.2...@ohif/extension-cornerstone@2.10.3) (2021-03-03)
**Note:** Version bump only for package @ohif/extension-cornerstone
## [2.10.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.10.1...@ohif/extension-cornerstone@2.10.2) (2021-02-25)
**Note:** Version bump only for package @ohif/extension-cornerstone
## [2.10.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.10.0...@ohif/extension-cornerstone@2.10.1) (2021-02-05) ## [2.10.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.10.0...@ohif/extension-cornerstone@2.10.1) (2021-02-05)
**Note:** Version bump only for package @ohif/extension-cornerstone **Note:** Version bump only for package @ohif/extension-cornerstone
+3 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "@ohif/extension-cornerstone", "name": "@ohif/extension-cornerstone",
"version": "2.10.1", "version": "2.10.7",
"description": "OHIF extension for Cornerstone", "description": "OHIF extension for Cornerstone",
"author": "OHIF", "author": "OHIF",
"license": "MIT", "license": "MIT",
@@ -36,7 +36,7 @@
"cornerstone-math": "^0.1.8", "cornerstone-math": "^0.1.8",
"cornerstone-tools": "^4.20.1", "cornerstone-tools": "^4.20.1",
"cornerstone-wado-image-loader": "^3.1.0", "cornerstone-wado-image-loader": "^3.1.0",
"dcmjs": "0.17.2", "dcmjs": "0.18.4",
"dicom-parser": "^1.8.3", "dicom-parser": "^1.8.3",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
@@ -51,6 +51,6 @@
"classnames": "^2.2.6", "classnames": "^2.2.6",
"lodash.merge": "^4.6.2", "lodash.merge": "^4.6.2",
"lodash.throttle": "^4.1.1", "lodash.throttle": "^4.1.1",
"react-cornerstone-viewport": "4.0.4" "react-cornerstone-viewport": "4.0.5"
} }
} }
@@ -179,7 +179,7 @@ class OHIFCornerstoneViewport extends Component {
if ( if (
displaySet.displaySetInstanceUID !== displaySet.displaySetInstanceUID !==
prevDisplaySet.displaySetInstanceUID || prevDisplaySet.displaySetInstanceUID ||
displaySet.SOPInstanceUID !== prevDisplaySet.SOPInstanceUID || displaySet.SOPInstanceUID !== prevDisplaySet.SOPInstanceUID ||
displaySet.frameIndex !== prevDisplaySet.frameIndex displaySet.frameIndex !== prevDisplaySet.frameIndex
) { ) {
@@ -235,8 +235,8 @@ class OHIFCornerstoneViewport extends Component {
viewportIndex={viewportIndex} viewportIndex={viewportIndex}
imageIds={imageIds} imageIds={imageIds}
imageIdIndex={currentImageIdIndex} imageIdIndex={currentImageIdIndex}
onNewImage={newImageHandler} onNewImageDebounced={newImageHandler}
onNewImageDebounceTime={700} onNewImageDebounceTime={300}
// ~~ Connected (From REDUX) // ~~ Connected (From REDUX)
// frameRate={frameRate} // frameRate={frameRate}
// isPlaying={false} // isPlaying={false}
+8 -1
View File
@@ -268,6 +268,7 @@ const commandsModule = ({ servicesManager }) => {
SOPInstanceUID, SOPInstanceUID,
frameIndex, frameIndex,
activeViewportIndex, activeViewportIndex,
refreshViewports = true,
}) => { }) => {
const study = studyMetadataManager.get(StudyInstanceUID); const study = studyMetadataManager.get(StudyInstanceUID);
@@ -278,6 +279,10 @@ const commandsModule = ({ servicesManager }) => {
); );
}); });
if (!displaySet) {
return;
}
displaySet.SOPInstanceUID = SOPInstanceUID; displaySet.SOPInstanceUID = SOPInstanceUID;
displaySet.frameIndex = frameIndex; displaySet.frameIndex = frameIndex;
@@ -285,7 +290,9 @@ const commandsModule = ({ servicesManager }) => {
setViewportSpecificData(activeViewportIndex, displaySet) setViewportSpecificData(activeViewportIndex, displaySet)
); );
refreshCornerstoneViewports(); if (refreshViewports) {
refreshCornerstoneViewports();
}
}, },
}; };
+7
View File
@@ -38,7 +38,14 @@ export default {
}, },
getViewportModule({ commandsManager }) { getViewportModule({ commandsManager }) {
const ExtendedOHIFCornerstoneViewport = props => { const ExtendedOHIFCornerstoneViewport = props => {
/**
* TODO: This appears to be used to set the redux parameters for
* the viewport when new images are loaded. It's very ugly
* and we should remove it.
*/
const onNewImageHandler = jumpData => { const onNewImageHandler = jumpData => {
/** Do not trigger all viewports to render unnecessarily */
jumpData.refreshViewports = false;
commandsManager.runCommand('jumpToImage', jumpData); commandsManager.runCommand('jumpToImage', jumpData);
}; };
return ( return (
+19
View File
@@ -3,6 +3,25 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [0.2.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-debugging@0.2.0...@ohif/extension-debugging@0.2.1) (2021-03-19)
**Note:** Version bump only for package @ohif/extension-debugging
# [0.2.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-debugging@0.1.6...@ohif/extension-debugging@0.2.0) (2021-03-04)
### Features
* **log:** add new log service ([14d6454](https://github.com/OHIF/Viewers/commit/14d6454eafaa2ccb50e133c2945c9558052ea27e))
## [0.1.6](https://github.com/OHIF/Viewers/compare/@ohif/extension-debugging@0.1.5...@ohif/extension-debugging@0.1.6) (2020-10-06) ## [0.1.6](https://github.com/OHIF/Viewers/compare/@ohif/extension-debugging@0.1.5...@ohif/extension-debugging@0.1.6) (2020-10-06)
**Note:** Version bump only for package @ohif/extension-debugging **Note:** Version bump only for package @ohif/extension-debugging
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@ohif/extension-debugging", "name": "@ohif/extension-debugging",
"version": "0.1.6", "version": "0.2.1",
"description": "OHIF extension for debugging.", "description": "OHIF extension for debugging.",
"author": "OHIF", "author": "OHIF",
"license": "MIT", "license": "MIT",
@@ -12,3 +12,15 @@
display: flex; display: flex;
flex-direction: row; flex-direction: row;
} }
.debug-report-modal-container .errors {
margin-top: 10px;
}
.debug-report-modal-container .errors-container {
border: 1px solid var(--active-color);
border-radius: 5px;
padding: 10px;
overflow: scroll;
max-height: 300px;
}
@@ -10,6 +10,7 @@ const DubugReportModal = ({
extensionManager, extensionManager,
mailTo, mailTo,
debugModalMessage, debugModalMessage,
errors = [],
}) => { }) => {
const copyDebugDataToClipboard = () => { const copyDebugDataToClipboard = () => {
const body = getEmailBody(); const body = getEmailBody();
@@ -131,6 +132,19 @@ const DubugReportModal = ({
{getLayout(viewports)} {getLayout(viewports)}
</table> </table>
</div> </div>
<div className="errors">
<h3>Errors ({errors.length})</h3>
<div className="errors-container">
{errors.map(error => {
return (
<div>
<pre>Message: {error.message}</pre>
{error.error && <pre>Stack: {error.error.stack}</pre>}
</div>
);
})}
</div>
</div>
</div> </div>
); );
}; };
@@ -1,4 +1,6 @@
import OHIF from '@ohif/core'; import OHIF from '@ohif/core';
import { useLogger } from '@ohif/ui';
import { import {
save, save,
upload, upload,
@@ -95,6 +97,7 @@ export function getCommands(context, servicesManager, extensionManager) {
const { UIModalService } = servicesManager.services; const { UIModalService } = servicesManager.services;
const WrappedDebugReportModal = function() { const WrappedDebugReportModal = function() {
const { state: loggerState } = useLogger();
return ( return (
<DebugReportModal <DebugReportModal
viewports={viewports} viewports={viewports}
@@ -103,6 +106,7 @@ export function getCommands(context, servicesManager, extensionManager) {
extensionManager={extensionManager} extensionManager={extensionManager}
mailTo={state.mailTo} mailTo={state.mailTo}
debugModalMessage={state.debugModalMessage} debugModalMessage={state.debugModalMessage}
errors={loggerState.errors}
/> />
); );
}; };
+1 -1
View File
@@ -1,3 +1,3 @@
const state = { mailTo: undefined, message: undefined }; const state = { mailTo: undefined, debugModalMessage: undefined };
export default state; export default state;
+32
View File
@@ -3,6 +3,38 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.3.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@1.3.4...@ohif/extension-dicom-html@1.3.5) (2021-04-15)
**Note:** Version bump only for package @ohif/extension-dicom-html
## [1.3.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@1.3.3...@ohif/extension-dicom-html@1.3.4) (2021-03-09)
**Note:** Version bump only for package @ohif/extension-dicom-html
## [1.3.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@1.3.2...@ohif/extension-dicom-html@1.3.3) (2021-03-03)
**Note:** Version bump only for package @ohif/extension-dicom-html
## [1.3.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@1.3.1...@ohif/extension-dicom-html@1.3.2) (2021-02-25)
**Note:** Version bump only for package @ohif/extension-dicom-html
## [1.3.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@1.3.0...@ohif/extension-dicom-html@1.3.1) (2021-02-05) ## [1.3.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-html@1.3.0...@ohif/extension-dicom-html@1.3.1) (2021-02-05)
**Note:** Version bump only for package @ohif/extension-dicom-html **Note:** Version bump only for package @ohif/extension-dicom-html
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@ohif/extension-dicom-html", "name": "@ohif/extension-dicom-html",
"version": "1.3.1", "version": "1.3.5",
"description": "OHIF extension for rendering structured reports to HTML", "description": "OHIF extension for rendering structured reports to HTML",
"author": "OHIF", "author": "OHIF",
"license": "MIT", "license": "MIT",
@@ -29,7 +29,7 @@
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "^0.50.0", "@ohif/core": "^0.50.0",
"dcmjs": "0.17.2", "dcmjs": "0.18.4",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"react": "^16.8.6", "react": "^16.8.6",
"react-dom": "^16.8.6" "react-dom": "^16.8.6"
+11
View File
@@ -3,6 +3,17 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [0.52.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-microscopy@0.51.4...@ohif/extension-dicom-microscopy@0.52.0) (2021-03-04)
### Features
* **log:** add new log service ([14d6454](https://github.com/OHIF/Viewers/commit/14d6454eafaa2ccb50e133c2945c9558052ea27e))
## [0.51.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-microscopy@0.51.3...@ohif/extension-dicom-microscopy@0.51.4) (2021-01-21) ## [0.51.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-microscopy@0.51.3...@ohif/extension-dicom-microscopy@0.51.4) (2021-01-21)
**Note:** Version bump only for package @ohif/extension-dicom-microscopy **Note:** Version bump only for package @ohif/extension-dicom-microscopy
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@ohif/extension-dicom-microscopy", "name": "@ohif/extension-dicom-microscopy",
"version": "0.51.4", "version": "0.52.0",
"description": "OHIF extension for Dicom Microscopy", "description": "OHIF extension for Dicom Microscopy",
"author": "OHIF", "author": "OHIF",
"license": "MIT", "license": "MIT",
@@ -70,12 +70,18 @@ class DicomMicroscopyViewport extends Component {
}); });
} catch (error) { } catch (error) {
console.error('[Microscopy Viewer] Failed to load:', error); console.error('[Microscopy Viewer] Failed to load:', error);
const { UINotificationService } = this.props.servicesManager.services; const {
UINotificationService,
LoggerService,
} = this.props.servicesManager.services;
if (UINotificationService) { if (UINotificationService) {
const message =
'Failed to load viewport. Please check that you have hardware acceleration enabled.';
LoggerService.error({ error, message });
UINotificationService.show({ UINotificationService.show({
autoClose: false,
title: 'Microscopy Viewport', title: 'Microscopy Viewport',
message: message,
'Failed to load viewport. Please check that you have hardware acceleration enabled.',
type: 'error', type: 'error',
}); });
} }
+32
View File
@@ -3,6 +3,38 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [0.6.8](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.6.7...@ohif/extension-dicom-rt@0.6.8) (2021-04-15)
**Note:** Version bump only for package @ohif/extension-dicom-rt
## [0.6.7](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.6.6...@ohif/extension-dicom-rt@0.6.7) (2021-03-09)
**Note:** Version bump only for package @ohif/extension-dicom-rt
## [0.6.6](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.6.5...@ohif/extension-dicom-rt@0.6.6) (2021-03-03)
**Note:** Version bump only for package @ohif/extension-dicom-rt
## [0.6.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.6.4...@ohif/extension-dicom-rt@0.6.5) (2021-02-25)
**Note:** Version bump only for package @ohif/extension-dicom-rt
## [0.6.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.6.3...@ohif/extension-dicom-rt@0.6.4) (2021-02-05) ## [0.6.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-rt@0.6.3...@ohif/extension-dicom-rt@0.6.4) (2021-02-05)
**Note:** Version bump only for package @ohif/extension-dicom-rt **Note:** Version bump only for package @ohif/extension-dicom-rt
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@ohif/extension-dicom-rt", "name": "@ohif/extension-dicom-rt",
"version": "0.6.4", "version": "0.6.8",
"description": "OHIF extension for rendering DICOM RTSTRUCTs on top of cornerstone images.", "description": "OHIF extension for rendering DICOM RTSTRUCTs on top of cornerstone images.",
"author": "OHIF", "author": "OHIF",
"license": "MIT", "license": "MIT",
@@ -31,7 +31,7 @@
"@ohif/core": "^0.50.0", "@ohif/core": "^0.50.0",
"cornerstone-core": "^2.2.8", "cornerstone-core": "^2.2.8",
"cornerstone-tools": "^4.20.1", "cornerstone-tools": "^4.20.1",
"dcmjs": "0.17.2", "dcmjs": "0.18.4",
"gl-matrix": "^3.3.0", "gl-matrix": "^3.3.0",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"react": "^16.8.6", "react": "^16.8.6",
@@ -3,6 +3,57 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [0.6.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.6.2...@ohif/extension-dicom-segmentation@0.6.3) (2021-04-15)
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
## [0.6.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.6.1...@ohif/extension-dicom-segmentation@0.6.2) (2021-03-31)
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
## [0.6.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.6.0...@ohif/extension-dicom-segmentation@0.6.1) (2021-03-09)
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
# [0.6.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.5.4...@ohif/extension-dicom-segmentation@0.6.0) (2021-03-04)
### Features
* **log:** add new log service ([14d6454](https://github.com/OHIF/Viewers/commit/14d6454eafaa2ccb50e133c2945c9558052ea27e))
## [0.5.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.5.3...@ohif/extension-dicom-segmentation@0.5.4) (2021-03-03)
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
## [0.5.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.5.2...@ohif/extension-dicom-segmentation@0.5.3) (2021-02-25)
**Note:** Version bump only for package @ohif/extension-dicom-segmentation
## [0.5.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.5.1...@ohif/extension-dicom-segmentation@0.5.2) (2021-02-05) ## [0.5.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-segmentation@0.5.1...@ohif/extension-dicom-segmentation@0.5.2) (2021-02-05)
**Note:** Version bump only for package @ohif/extension-dicom-segmentation **Note:** Version bump only for package @ohif/extension-dicom-segmentation
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@ohif/extension-dicom-segmentation", "name": "@ohif/extension-dicom-segmentation",
"version": "0.5.2", "version": "0.6.3",
"description": "OHIF extension for viewing segmentations in the 2D MPR view", "description": "OHIF extension for viewing segmentations in the 2D MPR view",
"author": "OHIF", "author": "OHIF",
"license": "MIT", "license": "MIT",
@@ -31,7 +31,7 @@
"@ohif/core": "^0.50.0", "@ohif/core": "^0.50.0",
"cornerstone-core": "^2.2.8", "cornerstone-core": "^2.2.8",
"cornerstone-tools": "^4.20.1", "cornerstone-tools": "^4.20.1",
"dcmjs": "0.17.2", "dcmjs": "0.18.4",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"react": "^16.8.6", "react": "^16.8.6",
"react-dom": "^16.8.6" "react-dom": "^16.8.6"
@@ -289,7 +289,7 @@ const SegmentationPanel = ({
/* Map to display representation */ /* Map to display representation */
const dateStr = `${SeriesDate}:${SeriesTime}`.split('.')[0]; const dateStr = `${SeriesDate}:${SeriesTime}`.split('.')[0];
const date = moment(dateStr, 'YYYYMMDD:HHmmss'); const date = moment(dateStr, 'YYYYMMDD:HHmmss');
const displayDate = date.format('ddd, MMM Do YYYY'); const displayDate = date.format('ddd, MMM Do YYYY, h:mm:ss a');
const displayDescription = displaySet.SeriesDescription; const displayDescription = displaySet.SeriesDescription;
return { return {
@@ -709,7 +709,7 @@ const _getReferencedSegDisplaysets = (StudyInstanceUID, SeriesInstanceUID) => {
referencedDisplaysets.sort((a, b) => { referencedDisplaysets.sort((a, b) => {
const aNumber = Number(`${a.SeriesDate}${a.SeriesTime}`); const aNumber = Number(`${a.SeriesDate}${a.SeriesTime}`);
const bNumber = Number(`${b.SeriesDate}${b.SeriesTime}`); const bNumber = Number(`${b.SeriesDate}${b.SeriesTime}`);
return aNumber - bNumber; return bNumber - aNumber;
}); });
return referencedDisplaysets; return referencedDisplaysets;
+2 -1
View File
@@ -25,12 +25,13 @@ export default {
return toolbarModule; return toolbarModule;
}, },
getPanelModule({ commandsManager, api, servicesManager }) { getPanelModule({ commandsManager, api, servicesManager }) {
const { UINotificationService } = servicesManager.services; const { UINotificationService, LoggerService } = servicesManager.services;
const ExtendedSegmentationPanel = props => { const ExtendedSegmentationPanel = props => {
const { activeContexts } = api.hooks.useAppContext(); const { activeContexts } = api.hooks.useAppContext();
const onDisplaySetLoadFailureHandler = error => { const onDisplaySetLoadFailureHandler = error => {
LoggerService.error({ error, message: error.message });
UINotificationService.show({ UINotificationService.show({
title: 'DICOM Segmentation Loader', title: 'DICOM Segmentation Loader',
message: error.message, message: error.message,
+32
View File
@@ -3,6 +3,38 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [0.2.6](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-tag-browser@0.2.5...@ohif/extension-dicom-tag-browser@0.2.6) (2021-04-15)
**Note:** Version bump only for package @ohif/extension-dicom-tag-browser
## [0.2.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-tag-browser@0.2.4...@ohif/extension-dicom-tag-browser@0.2.5) (2021-03-09)
**Note:** Version bump only for package @ohif/extension-dicom-tag-browser
## [0.2.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-tag-browser@0.2.3...@ohif/extension-dicom-tag-browser@0.2.4) (2021-03-03)
**Note:** Version bump only for package @ohif/extension-dicom-tag-browser
## [0.2.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-tag-browser@0.2.2...@ohif/extension-dicom-tag-browser@0.2.3) (2021-02-25)
**Note:** Version bump only for package @ohif/extension-dicom-tag-browser
## [0.2.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-tag-browser@0.2.1...@ohif/extension-dicom-tag-browser@0.2.2) (2021-02-05) ## [0.2.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-tag-browser@0.2.1...@ohif/extension-dicom-tag-browser@0.2.2) (2021-02-05)
**Note:** Version bump only for package @ohif/extension-dicom-tag-browser **Note:** Version bump only for package @ohif/extension-dicom-tag-browser
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@ohif/extension-dicom-tag-browser", "name": "@ohif/extension-dicom-tag-browser",
"version": "0.2.2", "version": "0.2.6",
"description": "OHIF extension for checking DICOM headers.", "description": "OHIF extension for checking DICOM headers.",
"author": "OHIF", "author": "OHIF",
"license": "MIT", "license": "MIT",
@@ -28,7 +28,7 @@
}, },
"peerDependencies": { "peerDependencies": {
"@ohif/core": "^2.6.0", "@ohif/core": "^2.6.0",
"dcmjs": "0.17.2", "dcmjs": "0.18.4",
"react": "^16.8.6" "react": "^16.8.6"
}, },
"dependencies": { "dependencies": {
+67
View File
@@ -3,6 +3,73 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.11.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.11.4...@ohif/extension-vtk@1.11.5) (2021-04-15)
**Note:** Version bump only for package @ohif/extension-vtk
## [1.11.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.11.3...@ohif/extension-vtk@1.11.4) (2021-03-26)
**Note:** Version bump only for package @ohif/extension-vtk
## [1.11.3](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.11.2...@ohif/extension-vtk@1.11.3) (2021-03-25)
**Note:** Version bump only for package @ohif/extension-vtk
## [1.11.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.11.1...@ohif/extension-vtk@1.11.2) (2021-03-09)
**Note:** Version bump only for package @ohif/extension-vtk
## [1.11.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.11.0...@ohif/extension-vtk@1.11.1) (2021-03-09)
**Note:** Version bump only for package @ohif/extension-vtk
# [1.11.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.10.6...@ohif/extension-vtk@1.11.0) (2021-03-04)
### Features
* **log:** add new log service ([14d6454](https://github.com/OHIF/Viewers/commit/14d6454eafaa2ccb50e133c2945c9558052ea27e))
## [1.10.6](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.10.5...@ohif/extension-vtk@1.10.6) (2021-03-03)
**Note:** Version bump only for package @ohif/extension-vtk
## [1.10.5](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.10.4...@ohif/extension-vtk@1.10.5) (2021-02-25)
**Note:** Version bump only for package @ohif/extension-vtk
## [1.10.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.10.3...@ohif/extension-vtk@1.10.4) (2021-02-05) ## [1.10.4](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.10.3...@ohif/extension-vtk@1.10.4) (2021-02-05)
**Note:** Version bump only for package @ohif/extension-vtk **Note:** Version bump only for package @ohif/extension-vtk
+4 -4
View File
@@ -1,6 +1,6 @@
{ {
"name": "@ohif/extension-vtk", "name": "@ohif/extension-vtk",
"version": "1.10.4", "version": "1.11.5",
"description": "OHIF extension for VTK.js", "description": "OHIF extension for VTK.js",
"author": "OHIF", "author": "OHIF",
"license": "MIT", "license": "MIT",
@@ -35,7 +35,7 @@
"cornerstone-core": "^2.2.8", "cornerstone-core": "^2.2.8",
"cornerstone-tools": "^4.20.1", "cornerstone-tools": "^4.20.1",
"cornerstone-wado-image-loader": "^3.1.0", "cornerstone-wado-image-loader": "^3.1.0",
"dcmjs": "0.17.2", "dcmjs": "0.18.4",
"dicom-parser": "^1.8.3", "dicom-parser": "^1.8.3",
"i18next": "^17.0.3", "i18next": "^17.0.3",
"i18next-browser-languagedetector": "^3.0.1", "i18next-browser-languagedetector": "^3.0.1",
@@ -53,8 +53,8 @@
"react-vtkjs-viewport": "^0.14.2" "react-vtkjs-viewport": "^0.14.2"
}, },
"devDependencies": { "devDependencies": {
"@ohif/core": "^2.12.3", "@ohif/core": "^2.13.4",
"@ohif/ui": "^1.8.2", "@ohif/ui": "^1.9.1",
"cornerstone-tools": "^4.20.1", "cornerstone-tools": "^4.20.1",
"cornerstone-wado-image-loader": "^3.1.0", "cornerstone-wado-image-loader": "^3.1.0",
"dicom-parser": "^1.8.3", "dicom-parser": "^1.8.3",
+10 -3
View File
@@ -360,12 +360,15 @@ class OHIFVTKViewport extends Component {
} catch (error) { } catch (error) {
const errorTitle = 'Failed to load 2D MPR'; const errorTitle = 'Failed to load 2D MPR';
console.error(errorTitle, error); console.error(errorTitle, error);
const { UINotificationService } = this.props.servicesManager.services; const {
UINotificationService,
LoggerService,
} = this.props.servicesManager.services;
if (this.props.viewportIndex === 0) { if (this.props.viewportIndex === 0) {
const message = error.message.includes('buffer') const message = error.message.includes('buffer')
? 'Dataset is too big to display in MPR' ? 'Dataset is too big to display in MPR'
: error.message; : error.message;
console.error(errorTitle, error); LoggerService.error({ error, message });
UINotificationService.show({ UINotificationService.show({
title: errorTitle, title: errorTitle,
message, message,
@@ -428,11 +431,15 @@ class OHIFVTKViewport extends Component {
}; };
const onPixelDataInsertedErrorCallback = error => { const onPixelDataInsertedErrorCallback = error => {
const { UINotificationService } = this.props.servicesManager.services; const {
UINotificationService,
LoggerService,
} = this.props.servicesManager.services;
if (!this.hasError) { if (!this.hasError) {
if (this.props.viewportIndex === 0) { if (this.props.viewportIndex === 0) {
// Only show the notification from one viewport 1 in MPR2D. // Only show the notification from one viewport 1 in MPR2D.
LoggerService.error({ error, message: error.message });
UINotificationService.show({ UINotificationService.show({
title: 'MPR Load Error', title: 'MPR Load Error',
message: error.message, message: error.message,
+8 -4
View File
@@ -14,7 +14,9 @@ import OHIFVTKViewport from './OHIFVTKViewport';
const { BlendMode } = Constants; const { BlendMode } = Constants;
const commandsModule = ({ commandsManager, UINotificationService }) => { const commandsModule = ({ commandsManager, servicesManager }) => {
const { UINotificationService, LoggerService } = servicesManager.services;
// TODO: Put this somewhere else // TODO: Put this somewhere else
let apis = {}; let apis = {};
let defaultVOI; let defaultVOI;
@@ -175,7 +177,7 @@ const commandsModule = ({ commandsManager, UINotificationService }) => {
segmentNumber, segmentNumber,
frameIndex, frameIndex,
frame, frame,
done = () => { }, done = () => {},
}) => { }) => {
let api = apis[viewports.activeViewportIndex]; let api = apis[viewports.activeViewportIndex];
@@ -473,10 +475,12 @@ const commandsModule = ({ commandsManager, UINotificationService }) => {
const volumeLength = dimensions[0] * dimensions[1] * dimensions[2]; const volumeLength = dimensions[0] * dimensions[1] * dimensions[2];
if (volumeLength > maxBufferLengthFloat32) { if (volumeLength > maxBufferLengthFloat32) {
const message =
'This volume is too large to fit in WebGL 1 textures and will display incorrectly. Please use a different browser to view this data';
LoggerService.error({ message });
UINotificationService.show({ UINotificationService.show({
title: 'Browser does not support WebGL 2', title: 'Browser does not support WebGL 2',
message: message,
'This volume is too large to fit in WebGL 1 textures and will display incorrectly. Please use a different browser to view this data',
type: 'error', type: 'error',
autoClose: false, autoClose: false,
}); });
+1 -2
View File
@@ -35,8 +35,7 @@ const vtkExtension = {
return toolbarModule; return toolbarModule;
}, },
getCommandsModule({ commandsManager, servicesManager }) { getCommandsModule({ commandsManager, servicesManager }) {
const { UINotificationService } = servicesManager.services; return commandsModule({ commandsManager, servicesManager });
return commandsModule({ commandsManager, UINotificationService });
}, },
}; };
@@ -31,63 +31,7 @@ const _isDisplaySetReconstructable = (viewportSpecificData = {}, activeViewportI
if (!displaySet) { if (!displaySet) {
return false; return false;
} };
// 2D MPR is not currently available for 4D datasets.
// Assuming that slices at different time have the same position, here we just check if
// there are multiple slices for the same ImagePositionPatient and disable MPR.
// A better heuristic would be checking 4D tags, e.g. the presence of multiple TemporalPositionIdentifier values.
// However, some studies (e.g. https://github.com/OHIF/Viewers/issues/2113) do not have such tags.
for (let ii = 0; ii < displaySet.numImageFrames; ++ii) {
const image = displaySet.images[ii];
if (!image) continue;
const imageIdControl = image.getImageId()
const instanceMetadataControl = cornerstone.metaData.get('instance', imageIdControl)
if (!instanceMetadataControl ||
instanceMetadataControl === undefined ||
!instanceMetadataControl.ImagePositionPatient ||
instanceMetadataControl.ImagePositionPatient === undefined) {
// if ImagePositionPatient is missing, skip the 4D datasets check.
// do not return false, because it could be a 3D dataset.
continue;
}
let xImagePositionPatientControl = instanceMetadataControl.ImagePositionPatient[0];
let yImagePositionPatientControl = instanceMetadataControl.ImagePositionPatient[1];
let zImagePositionPatientControl = instanceMetadataControl.ImagePositionPatient[2];
for (let jj = ii + 1; jj < displaySet.numImageFrames; ++jj) {
const image = displaySet.images[jj];
if (!image) continue;
const imageId = image.getImageId()
const instanceMetadata = cornerstone.metaData.get('instance', imageId)
if (!instanceMetadata ||
instanceMetadata === undefined ||
!instanceMetadata.ImagePositionPatient ||
instanceMetadata.ImagePositionPatient === undefined) {
// if ImagePositionPatient is missing, skip the 4D datasets check.
// do not return false, because it could be a 3D dataset.
continue;
}
let xImagePositionPatient = instanceMetadata.ImagePositionPatient[0];
let yImagePositionPatient = instanceMetadata.ImagePositionPatient[1];
let zImagePositionPatient = instanceMetadata.ImagePositionPatient[2];
if (xImagePositionPatientControl === xImagePositionPatient &&
yImagePositionPatientControl === yImagePositionPatient &&
zImagePositionPatientControl === zImagePositionPatient) {
return false;
}
}
}
return displaySet.isReconstructable; return displaySet.isReconstructable;
}; };
+65
View File
@@ -3,6 +3,71 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.13.4](https://github.com/OHIF/Viewers/compare/@ohif/core@2.13.3...@ohif/core@2.13.4) (2021-04-15)
### Bug Fixes
* **wl:** fix metadata provider window level issues after dicomweb update (string vs number) ([8681036](https://github.com/OHIF/Viewers/commit/8681036b2133cfc325658691a256a86b5e36705f))
## [2.13.3](https://github.com/OHIF/Viewers/compare/@ohif/core@2.13.2...@ohif/core@2.13.3) (2021-03-26)
**Note:** Version bump only for package @ohif/core
## [2.13.2](https://github.com/OHIF/Viewers/compare/@ohif/core@2.13.1...@ohif/core@2.13.2) (2021-03-25)
### Bug Fixes
* IDC-2288: Update toolbar tabs after derived displayset loaded ([#2307](https://github.com/OHIF/Viewers/issues/2307)) ([6e723eb](https://github.com/OHIF/Viewers/commit/6e723ebced58852007ca553792c740976cfc4201))
## [2.13.1](https://github.com/OHIF/Viewers/compare/@ohif/core@2.13.0...@ohif/core@2.13.1) (2021-03-09)
**Note:** Version bump only for package @ohif/core
# [2.13.0](https://github.com/OHIF/Viewers/compare/@ohif/core@2.12.5...@ohif/core@2.13.0) (2021-03-04)
### Features
* **log:** add new log service ([14d6454](https://github.com/OHIF/Viewers/commit/14d6454eafaa2ccb50e133c2945c9558052ea27e))
## [2.12.5](https://github.com/OHIF/Viewers/compare/@ohif/core@2.12.4...@ohif/core@2.12.5) (2021-03-03)
**Note:** Version bump only for package @ohif/core
## [2.12.4](https://github.com/OHIF/Viewers/compare/@ohif/core@2.12.3...@ohif/core@2.12.4) (2021-02-25)
**Note:** Version bump only for package @ohif/core
## [2.12.3](https://github.com/OHIF/Viewers/compare/@ohif/core@2.12.2...@ohif/core@2.12.3) (2021-02-05) ## [2.12.3](https://github.com/OHIF/Viewers/compare/@ohif/core@2.12.2...@ohif/core@2.12.3) (2021-02-05)
**Note:** Version bump only for package @ohif/core **Note:** Version bump only for package @ohif/core
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@ohif/core", "name": "@ohif/core",
"version": "2.12.3", "version": "2.13.4",
"description": "Generic business logic for web-based medical imaging applications", "description": "Generic business logic for web-based medical imaging applications",
"author": "OHIF Core Team", "author": "OHIF Core Team",
"license": "MIT", "license": "MIT",
@@ -39,7 +39,7 @@
"dependencies": { "dependencies": {
"@babel/runtime": "^7.5.5", "@babel/runtime": "^7.5.5",
"ajv": "^6.10.0", "ajv": "^6.10.0",
"dcmjs": "0.17.2", "dcmjs": "0.18.4",
"dicomweb-client": "^0.6.0", "dicomweb-client": "^0.6.0",
"immer": "6.0.2", "immer": "6.0.2",
"isomorphic-base64": "^1.0.2", "isomorphic-base64": "^1.0.2",
+7 -2
View File
@@ -63,10 +63,15 @@ export class HotkeysManager {
definitions.forEach(definition => this.registerHotkeys(definition)); definitions.forEach(definition => this.registerHotkeys(definition));
} catch (error) { } catch (error) {
const { UINotificationService } = this._servicesManager.services; const {
UINotificationService,
LoggerService,
} = this._servicesManager.services;
const message = 'Erro while setting hotkeys';
LoggerService.error({ error, message });
UINotificationService.show({ UINotificationService.show({
title: 'Hotkeys Manager', title: 'Hotkeys Manager',
message: 'Erro while setting hotkeys', message,
type: 'error', type: 'error',
}); });
} }
@@ -4,6 +4,7 @@ import dicomParser from 'dicom-parser';
import getPixelSpacingInformation from '../utils/metadataProvider/getPixelSpacingInformation'; import getPixelSpacingInformation from '../utils/metadataProvider/getPixelSpacingInformation';
import fetchPaletteColorLookupTableData from '../utils/metadataProvider/fetchPaletteColorLookupTableData'; import fetchPaletteColorLookupTableData from '../utils/metadataProvider/fetchPaletteColorLookupTableData';
import fetchOverlayData from '../utils/metadataProvider/fetchOverlayData'; import fetchOverlayData from '../utils/metadataProvider/fetchOverlayData';
import validNumber from '../utils/metadataProvider/validNumber';
class MetadataProvider { class MetadataProvider {
constructor() { constructor() {
@@ -284,7 +285,7 @@ class MetadataProvider {
break; break;
case WADO_IMAGE_LOADER_TAGS.VOI_LUT_MODULE: case WADO_IMAGE_LOADER_TAGS.VOI_LUT_MODULE:
const { WindowCenter, WindowWidth } = instance; let { WindowCenter, WindowWidth } = instance;
const windowCenter = Array.isArray(WindowCenter) const windowCenter = Array.isArray(WindowCenter)
? WindowCenter ? WindowCenter
@@ -294,15 +295,17 @@ class MetadataProvider {
: [WindowWidth]; : [WindowWidth];
metadata = { metadata = {
windowCenter, windowCenter: validNumber(windowCenter),
windowWidth, windowWidth: validNumber(windowWidth),
}; };
break; break;
case WADO_IMAGE_LOADER_TAGS.MODALITY_LUT_MODULE: case WADO_IMAGE_LOADER_TAGS.MODALITY_LUT_MODULE:
const rescaleSlope = validNumber(instance.RescaleSlope);
const rescaleIntercept = validNumber(instance.RescaleIntercept);
metadata = { metadata = {
rescaleIntercept: instance.RescaleIntercept, rescaleIntercept,
rescaleSlope: instance.RescaleSlope, rescaleSlope,
rescaleType: instance.RescaleType, rescaleType: instance.RescaleType,
}; };
break; break;
@@ -9,7 +9,7 @@ import { SeriesMetadata } from './SeriesMetadata';
import { api } from 'dicomweb-client'; import { api } from 'dicomweb-client';
// - createStacks // - createStacks
import { isImage } from '../../utils/isImage'; import { isImage } from '../../utils/isImage';
import isDisplaySetReconstructable from '../../utils/isDisplaySetReconstructable'; import { isDisplaySetReconstructable, isSpacingUniform } from '../../utils/isDisplaySetReconstructable';
import errorHandler from '../../errorHandler'; import errorHandler from '../../errorHandler';
import isLowPriorityModality from '../../utils/isLowPriorityModality'; import isLowPriorityModality from '../../utils/isLowPriorityModality';
@@ -767,6 +767,16 @@ const isMultiFrame = instance => {
return instance.getTagValue('NumberOfFrames') > 1; return instance.getTagValue('NumberOfFrames') > 1;
}; };
/**
* Creates a display set for a series.
* Checks if a series is reconstructable to a 3D volume.
* If reconstructable, the frames are sorted.
*
* @param {SeriesMetadata} series The series metadata object from which the display sets will be created
* @param {Object[]} instances An array of `OHIFInstanceMetadata` objects.
*
* @returns {Object} imageSet.
*/
const makeDisplaySet = (series, instances) => { const makeDisplaySet = (series, instances) => {
const instance = instances[0]; const instance = instances[0];
const imageSet = new ImageSet(instances); const imageSet = new ImageSet(instances);
@@ -786,7 +796,7 @@ const makeDisplaySet = (series, instances) => {
isMultiFrame: isMultiFrame(instance), isMultiFrame: isMultiFrame(instance),
}); });
// Sort the images in this series if needed // Sort the images in this series by instanceNumber
const shallSort = true; //!OHIF.utils.ObjectPath.get(Meteor, 'settings.public.ui.sortSeriesByIncomingOrder'); const shallSort = true; //!OHIF.utils.ObjectPath.get(Meteor, 'settings.public.ui.sortSeriesByIncomingOrder');
if (shallSort) { if (shallSort) {
imageSet.sortBy((a, b) => { imageSet.sortBy((a, b) => {
@@ -804,18 +814,32 @@ const makeDisplaySet = (series, instances) => {
imageSet.getImage(0).getTagValue('InstanceNumber') imageSet.getImage(0).getTagValue('InstanceNumber')
); );
const isReconstructable = isDisplaySetReconstructable(instances); const displayReconstructableInfo = isDisplaySetReconstructable(instances);
imageSet.isReconstructable = displayReconstructableInfo.value;
imageSet.isReconstructable = isReconstructable.value;
let displaySpacingInfo = undefined;
if (shallSort && imageSet.isReconstructable) { if (shallSort && imageSet.isReconstructable) {
// sort images by image position
imageSet.sortByImagePositionPatient(); imageSet.sortByImagePositionPatient();
// check if the spacing is uniform and update isReconstructable
const datasetIs4D = displayReconstructableInfo.warningIssues.find
(issue => issue === ReconstructionIssues.DATASET_4D);
displaySpacingInfo = isSpacingUniform(imageSet.images, datasetIs4D);
imageSet.isReconstructable = displaySpacingInfo.isUniform;
if (displaySpacingInfo.missingFrames) {
// TODO -> This is currently unused, but may be used for reconstructing
// Volumes with gaps later on.
imageSet.missingFrames = displaySpacingInfo.missingFrames;
}
} }
if (isReconstructable.missingFrames) { if (!imageSet.displayReconstructableInfo) {
// TODO -> This is currently unused, but may be used for reconstructing // It is not reconstrabale Save type of warning
// Volumes with gaps later on. imageSet.warningIssues = displaySpacingInfo ?
imageSet.missingFrames = isReconstructable.missingFrames; displayReconstructableInfo.warningIssues.concat(displaySpacingInfo.warningIssues) :
displayReconstructableInfo.warningIssues;
} }
return imageSet; return imageSet;
+11
View File
@@ -0,0 +1,11 @@
const ReconstructionIssues = {
DATASET_4D: 'datasetis4D',
VARYING_IMAGESDIMENSIONS: 'imagesdimensionsvarying',
VARYING_IMAGESCOMPONENTS: 'imagescomponentsvarying',
VARYING_IMAGESORIENTATION: 'imagesorientationvarying',
MISSING_FRAMES: 'missingframes',
IRREGULAR_SPACING: 'irregularspacing',
MULTIFFRAMES: 'multiframe',
};
export {ReconstructionIssues};
+3
View File
@@ -26,6 +26,7 @@ import {
UIModalService, UIModalService,
UIDialogService, UIDialogService,
MeasurementService, MeasurementService,
LoggerService,
} from './services'; } from './services';
const OHIF = { const OHIF = {
@@ -60,6 +61,7 @@ const OHIF = {
UIModalService, UIModalService,
UIDialogService, UIDialogService,
MeasurementService, MeasurementService,
LoggerService,
}; };
export { export {
@@ -93,6 +95,7 @@ export {
UIModalService, UIModalService,
UIDialogService, UIDialogService,
MeasurementService, MeasurementService,
LoggerService,
}; };
export { OHIF }; export { OHIF };
+1
View File
@@ -14,6 +14,7 @@ describe('Top level exports', () => {
'UIModalService', 'UIModalService',
'UIDialogService', 'UIDialogService',
'MeasurementService', 'MeasurementService',
'LoggerService',
// //
'utils', 'utils',
'hotkeys', 'hotkeys',
@@ -0,0 +1,67 @@
const name = 'LoggerService';
const publicAPI = {
name,
info: _info,
error: _error,
setServiceImplementation,
};
const serviceImplementation = {
_info: () => console.warn('info() NOT IMPLEMENTED'),
_error: () => console.warn('error() NOT IMPLEMENTED'),
};
/**
* Logs an info
*
* @param {object} props { message, displayOnConsole }
*/
function _info({ message, displayOnConsole }) {
return serviceImplementation._info({
message,
displayOnConsole,
});
}
/**
* Logs an error
*
* @param {object} props { error, stack, message, displayOnConsole }
* @returns void
*/
function _error({ error, stack, message, displayOnConsole }) {
return serviceImplementation._error({
error,
stack,
message,
displayOnConsole,
});
}
/**
*
*
* @param {*} {
* info: infoImplementation,
* error: errorImplementation,
* }
*/
function setServiceImplementation({
info: infoImplementation,
error: errorImplementation,
}) {
if (infoImplementation) {
serviceImplementation._info = infoImplementation;
}
if (errorImplementation) {
serviceImplementation._error = errorImplementation;
}
}
export default {
name,
create: ({ configuration = {} }) => {
return publicAPI;
},
};
+2
View File
@@ -3,6 +3,7 @@ import UINotificationService from './UINotificationService';
import UIModalService from './UIModalService'; import UIModalService from './UIModalService';
import UIDialogService from './UIDialogService'; import UIDialogService from './UIDialogService';
import MeasurementService from './MeasurementService'; import MeasurementService from './MeasurementService';
import LoggerService from './LoggerService';
export { export {
UINotificationService, UINotificationService,
@@ -10,4 +11,5 @@ export {
UIDialogService, UIDialogService,
ServicesManager, ServicesManager,
MeasurementService, MeasurementService,
LoggerService,
}; };
@@ -1,9 +1,14 @@
import { ReconstructionIssues } from './../enums.js';
/** /**
* Checks if a series is reconstructable to a 3D volume. * Checks if a series is reconstructable to a 3D volume.
* *
* @param {Object[]} instances An array of `OHIFInstanceMetadata` objects. * @param {Object[]} An array of `OHIFInstanceMetadata` objects.
*
* @returns {Object} value, warningIssues.
*/ */
export default function isDisplaySetReconstructable(instances) { function isDisplaySetReconstructable(instances) {
if (!instances.length) { if (!instances.length) {
return { value: false }; return { value: false };
} }
@@ -23,31 +28,45 @@ export default function isDisplaySetReconstructable(instances) {
} }
if (isMultiframe) { if (isMultiframe) {
return processMultiframe(instances[0]); return processMultiframe();
} else { } else {
return processSingleframe(instances); return processSingleframe(instances);
} }
} }
function processMultiframe(instance) { /**
//TODO: deal with multriframe checks! return false for now as can't reconstruct. * Process reconstructable multiframes checks
return { value: false }; * TODO: deal with multriframe checks! return false for now as can't reconstruct.
* *
* @returns {Object} value and warningIssues.
*/
function processMultiframe() {
const warningIssues = [ReconstructionIssues.MULTIFRAMES];
return { value: false, warningIssues };
} }
/**
* Process reconstructable single frame checks
*
* @param {Object[]} An array of `OHIFInstanceMetadata` objects.
*
* @returns {Object} value and warningIssues.
*/
function processSingleframe(instances) { function processSingleframe(instances) {
const n = instances.length;
const firstImage = instances[0].getData().metadata; const firstImage = instances[0].getData().metadata;
const firstImageRows = firstImage.Rows; const firstImageRows = firstImage.Rows;
const firstImageColumns = firstImage.Columns; const firstImageColumns = firstImage.Columns;
const firstImageSamplesPerPixel = firstImage.SamplesPerPixel; const firstImageSamplesPerPixel = firstImage.SamplesPerPixel;
const firstImageOrientationPatient = firstImage.ImageOrientationPatient; const firstImageOrientationPatient = firstImage.ImageOrientationPatient;
const firstImagePositionPatient = firstImage.ImagePositionPatient;
const warningIssues = [];
// Can't reconstruct if we: // Can't reconstruct if we:
// -- Have a different dimensions within a displaySet. // -- Have a different dimensions within a displaySet.
// -- Have a different number of components within a displaySet. // -- Have a different number of components within a displaySet.
// -- Have different orientations within a displaySet. // -- Have different orientations within a displaySet.
for (let i = 1; i < instances.length; i++) { for (let ii = 1; ii < n; ++ii) {
const instance = instances[i].getData().metadata; const instance = instances[ii].getData().metadata;
const { const {
Rows, Rows,
Columns, Columns,
@@ -55,67 +74,146 @@ function processSingleframe(instances) {
ImageOrientationPatient, ImageOrientationPatient,
} = instance; } = instance;
if ( if (Rows !== firstImageRows || Columns !== firstImageColumns) {
Rows !== firstImageRows || warningIssues.push(ReconstructionIssues.VARYING_IMAGESDIMENSIONS);
Columns !== firstImageColumns || } else if (SamplesPerPixel !== firstImageSamplesPerPixel) {
SamplesPerPixel !== firstImageSamplesPerPixel || warningIssues.push(ReconstructionIssues.VARYING_IMAGESCOMPONENTS);
!_isSameOrientation(ImageOrientationPatient, firstImageOrientationPatient) } else if (!_isSameArray(ImageOrientationPatient, firstImageOrientationPatient)) {
) { warningIssues.push(ReconstructionIssues.VARYING_IMAGESORIENTATION);
return { value: false }; }
if (warningIssues.length !== 0) {
break;
} }
} }
// check if dataset is 4D
if (_isDataset4D(instances)) {
warningIssues.push(ReconstructionIssues.DATASET_4D);
}
return { value: warningIssues.length === 0 ? true : false, warningIssues };
}
/**
* Check is the spacing is uniform.
* The input metadata array has to be ordered by image position.
*
* @param {Object[]} An array of `OHIFInstanceMetadata` objects.
* @param {boolean} is the dataset 4D.
*
* @returns {Object} isUniform, warningIssues and missingFrames
*/
function isSpacingUniform(instances, datasetIs4D) {
const n = instances.length;
const firstImage = instances[0].getData().metadata;
const firstImagePositionPatient = firstImage.ImagePositionPatient;
const warningIssues = [];
let missingFrames = 0; let missingFrames = 0;
// Check if frame spacing is approximately equal within a spacingTolerance. // Check if frame spacing is approximately equal within a spacingTolerance.
// If spacing is on a uniform grid but we are missing frames, // If spacing is on a uniform grid but we are missing frames,
// Allow reconstruction, but pass back the number of missing frames. // Allow reconstruction, but pass back the number of missing frames.
if (instances.length > 2) { if (n > 2) {
const lastIpp = instances[instances.length - 1].getData().metadata const lastIpp = instances[n - 1].getData().metadata
.ImagePositionPatient; .ImagePositionPatient;
// We can't reconstruct if we are missing ImagePositionPatient values // We can't reconstruct if we are missing ImagePositionPatient values
if (!firstImagePositionPatient || !lastIpp) { if (firstImagePositionPatient && lastIpp) {
return { value: false }; const averageSpacingBetweenFrames =
} _getPerpendicularDistance(firstImagePositionPatient, lastIpp) /
(n - 1);
const averageSpacingBetweenFrames = let previousImagePositionPatient = firstImagePositionPatient;
_getPerpendicularDistance(firstImagePositionPatient, lastIpp) /
(instances.length - 1);
let previousImagePositionPatient = firstImagePositionPatient; for (let ii = 1; ii < n; ++ii) {
const instance = instances[ii].getData().metadata;
const { ImagePositionPatient } = instance;
for (let i = 1; i < instances.length; i++) { const spacingBetweenFrames = _getPerpendicularDistance(
const instance = instances[i].getData().metadata; ImagePositionPatient,
const { ImagePositionPatient } = instance; previousImagePositionPatient
);
const spacingBetweenFrames = _getPerpendicularDistance( if (datasetIs4D && spacingBetweenFrames < 1.e-3) {
ImagePositionPatient, // the dataset is 4D, if the distance is zero, means that we are
previousImagePositionPatient // checking the 4th dimension. Do not return, since we want still to
); // check the 3rd dimension spacing.
const spacingIssue = _getSpacingIssue( continue;
spacingBetweenFrames,
averageSpacingBetweenFrames
);
if (spacingIssue) {
const issue = spacingIssue.issue;
if (issue === reconstructionIssues.MISSING_FRAMES) {
missingFrames += spacingIssue.missingFrames;
} else if (issue === reconstructionIssues.IRREGULAR_SPACING) {
return { value: false };
} }
}
previousImagePositionPatient = ImagePositionPatient; const spacingIssue = _getSpacingIssue(
spacingBetweenFrames,
averageSpacingBetweenFrames
);
if (spacingIssue) {
const issue = spacingIssue.issue;
if (issue === ReconstructionIssues.MISSING_FRAMES) {
missingFrames += spacingIssue.missingFrames;
} else if (issue === ReconstructionIssues.IRREGULAR_SPACING) {
warningIssues.push(issue);
break;
}
}
previousImagePositionPatient = ImagePositionPatient;
}
} }
} }
return { value: true, missingFrames }; return { isUniform: warningIssues.length === 0 ? true : false, missingFrames, warningIssues };
} }
function _isSameOrientation(iop1, iop2) {
/**
* Check if 4D dataset.
*
* Assuming that slices at different time have the same position, here we just check if
* there are multiple slices for the same ImagePositionPatient and disable MPR.
*
* A better heuristic would be checking 4D tags, e.g. the presence of multiple TemporalPositionIdentifier values.
* However, some studies (e.g. https://github.com/OHIF/Viewers/issues/2113) do not have such tags.
*
* @param {Object[]} instances An array of `OHIFInstanceMetadata` objects.
*
* @returns {boolean} dataset4D value.
*/
function _isDataset4D(instances) {
const n = instances.length;
for (let ii = 0; ii < n; ++ii) {
const instanceMetadataControl = instances[ii].getData().metadata;
if (
!instanceMetadataControl ||
instanceMetadataControl === undefined ||
!instanceMetadataControl.ImagePositionPatient ||
instanceMetadataControl.ImagePositionPatient === undefined
) {
continue;
}
for (let jj = ii + 1; jj < n; ++jj) {
const instanceMetadata = instances[jj].getData().metadata;
if (
!instanceMetadata ||
instanceMetadata === undefined ||
!instanceMetadata.ImagePositionPatient ||
instanceMetadata.ImagePositionPatient === undefined
) {
continue;
}
if (_isSameArray(instanceMetadataControl.ImagePositionPatient, instanceMetadata.ImagePositionPatient)) {
return true;
}
}
}
return false;
}
function _isSameArray(iop1, iop2) {
if (iop1 === undefined || !iop2 === undefined) { if (iop1 === undefined || !iop2 === undefined) {
return; return;
} }
@@ -156,12 +254,12 @@ function _getSpacingIssue(spacing, averageSpacing) {
if (errorForEachSpacing < spacingTolerance * averageSpacing) { if (errorForEachSpacing < spacingTolerance * averageSpacing) {
return { return {
issue: reconstructionIssues.MISSING_FRAMES, issue: ReconstructionIssues.MISSING_FRAMES,
missingFrames: numberOfSpacings - 1, missingFrames: numberOfSpacings - 1,
}; };
} }
return { issue: reconstructionIssues.IRREGULAR_SPACING }; return { issue: ReconstructionIssues.IRREGULAR_SPACING };
} }
function _getPerpendicularDistance(a, b) { function _getPerpendicularDistance(a, b) {
@@ -173,7 +271,5 @@ function _getPerpendicularDistance(a, b) {
} }
const constructableModalities = ['MR', 'CT', 'PT', 'NM']; const constructableModalities = ['MR', 'CT', 'PT', 'NM'];
const reconstructionIssues = {
MISSING_FRAMES: 'missingframes', export {isDisplaySetReconstructable, isSpacingUniform};
IRREGULAR_SPACING: 'irregularspacing',
};
@@ -49,9 +49,7 @@ import studyMetadataManager from './studyMetadataManager';
*/ */
const loadAndCacheDerivedDisplaySets = (referencedDisplaySet, studies) => { const loadAndCacheDerivedDisplaySets = (referencedDisplaySet, studies) => {
const { StudyInstanceUID, SeriesInstanceUID } = referencedDisplaySet; const { StudyInstanceUID, SeriesInstanceUID } = referencedDisplaySet;
const promises = []; const promises = [];
const studyMetadata = studyMetadataManager.get(StudyInstanceUID); const studyMetadata = studyMetadataManager.get(StudyInstanceUID);
if (!studyMetadata) { if (!studyMetadata) {
@@ -112,6 +110,16 @@ const loadAndCacheDerivedDisplaySets = (referencedDisplaySet, studies) => {
promises.push(recentDisplaySet.load(referencedDisplaySet, studies)); promises.push(recentDisplaySet.load(referencedDisplaySet, studies));
}); });
Promise.all(promises).then(() => {
/*
* TODO: Improve the way we notify parts of the app
* that depends on derived display sets to be loaded.
* (Implement pubsub for better tracking of derived display sets)
*/
const event = new CustomEvent('deriveddisplaysetsloadedandcached');
document.dispatchEvent(event);
});
return promises; return promises;
}; };
@@ -0,0 +1,9 @@
const validNumber = val => {
if (Array.isArray(val)) {
return val.map(v => (v !== undefined ? Number(v) : v));
} else {
return val !== undefined ? Number(val) : val;
}
};
export default validNumber;
+19
View File
@@ -3,6 +3,25 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.9.1](https://github.com/OHIF/Viewers/compare/@ohif/ui@1.9.0...@ohif/ui@1.9.1) (2021-03-26)
**Note:** Version bump only for package @ohif/ui
# [1.9.0](https://github.com/OHIF/Viewers/compare/@ohif/ui@1.8.2...@ohif/ui@1.9.0) (2021-03-04)
### Features
* **log:** add new log service ([14d6454](https://github.com/OHIF/Viewers/commit/14d6454eafaa2ccb50e133c2945c9558052ea27e))
## [1.8.2](https://github.com/OHIF/Viewers/compare/@ohif/ui@1.8.1...@ohif/ui@1.8.2) (2021-02-05) ## [1.8.2](https://github.com/OHIF/Viewers/compare/@ohif/ui@1.8.1...@ohif/ui@1.8.2) (2021-02-05)
**Note:** Version bump only for package @ohif/ui **Note:** Version bump only for package @ohif/ui
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@ohif/ui", "name": "@ohif/ui",
"version": "1.8.2", "version": "1.9.1",
"description": "A set of React components for Medical Imaging Viewers", "description": "A set of React components for Medical Imaging Viewers",
"author": "OHIF Contributors", "author": "OHIF Contributors",
"license": "MIT", "license": "MIT",
@@ -28,6 +28,7 @@ function StudyBrowser(props) {
SeriesDescription, SeriesDescription,
SeriesNumber, SeriesNumber,
stackPercentComplete, stackPercentComplete,
hasWarnings,
} = thumb; } = thumb;
return ( return (
@@ -50,6 +51,7 @@ function StudyBrowser(props) {
numImageFrames={numImageFrames} numImageFrames={numImageFrames}
SeriesDescription={SeriesDescription} SeriesDescription={SeriesDescription}
SeriesNumber={SeriesNumber} SeriesNumber={SeriesNumber}
hasWarnings={hasWarnings}
stackPercentComplete={stackPercentComplete} stackPercentComplete={stackPercentComplete}
// Events // Events
onClick={onThumbnailClick.bind( onClick={onThumbnailClick.bind(
@@ -1,8 +1,11 @@
import React from 'react'; import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useDrag } from 'react-dnd'; import { useDrag } from 'react-dnd';
import ImageThumbnail from './ImageThumbnail'; import ImageThumbnail from './ImageThumbnail';
import classNames from 'classnames'; import classNames from 'classnames';
import { Icon } from './../../elements/Icon';
import { Tooltip } from './../tooltip';
import { OverlayTrigger } from './../overlayTrigger';
import './Thumbnail.styl'; import './Thumbnail.styl';
@@ -11,7 +14,22 @@ function ThumbnailFooter({
SeriesNumber, SeriesNumber,
InstanceNumber, InstanceNumber,
numImageFrames, numImageFrames,
hasWarnings
}) { }) {
const [warningList, warningListSet] = useState([]);
useEffect(() => {
let unmounted = false
hasWarnings.then(response => {
if (!unmounted) {
warningListSet(response)
}
})
return () => {
unmounted = true
}
}, [])
const infoOnly = !SeriesDescription; const infoOnly = !SeriesDescription;
const getInfo = (value, icon, className = '') => { const getInfo = (value, icon, className = '') => {
@@ -22,28 +40,73 @@ function ThumbnailFooter({
</div> </div>
); );
}; };
const getWarningContent = (warningList) => {
if (Array.isArray(warningList)) {
const listedWarnings = warningList.map((warn, index) => {
return <li key={index}>{warn}</li>;
});
return <ol>{listedWarnings}</ol>;
} else {
return <React.Fragment>{warningList}</React.Fragment>;
}
};
const getWarningInfo = (SeriesNumber, warningList) => {
return(
<React.Fragment>
{warningList.length != 0 ? (
<OverlayTrigger
key={SeriesNumber}
placement="left"
overlay={
<Tooltip
placement="left"
className="in tooltip-warning"
id="tooltip-left"
>
<div className="warningTitle">Series Inconsistencies</div>
<div className="warningContent">{getWarningContent(warningList)}</div>
</Tooltip>
}
>
<div className={classNames('warning')}>
<span className="warning-icon">
<Icon name="exclamation-triangle" />
</span>
</div>
</OverlayTrigger>
) : (
<React.Fragment></React.Fragment>
)}
</React.Fragment>
);
};
const getSeriesInformation = ( const getSeriesInformation = (
SeriesNumber, SeriesNumber,
InstanceNumber, InstanceNumber,
numImageFrames numImageFrames,
warningList
) => { ) => {
if (!SeriesNumber && !InstanceNumber && !numImageFrames) { if (!SeriesNumber && !InstanceNumber && !numImageFrames) {
return; return;
} }
const seriesInformation =
return (
<div className="series-information"> <div className="series-information">
{getInfo(SeriesNumber, 'S:')} {getInfo(SeriesNumber, 'S:')}
{getInfo(InstanceNumber, 'I:')} {getInfo(InstanceNumber, 'I:')}
{getInfo(numImageFrames, '', 'image-frames')} {getInfo(numImageFrames, '', 'image-frames')}
{getWarningInfo(SeriesNumber, warningList)}
</div> </div>
);
return (seriesInformation);
}; };
return ( return (
<div className={classNames('series-details', { 'info-only': infoOnly })}> <div className={classNames('series-details', { 'info-only': infoOnly })}>
<div className="series-description">{SeriesDescription}</div> <div className="series-description">{SeriesDescription}</div>
{getSeriesInformation(SeriesNumber, InstanceNumber, numImageFrames)} {getSeriesInformation(SeriesNumber, InstanceNumber, numImageFrames, warningList)}
</div> </div>
); );
} }
@@ -60,6 +123,7 @@ function Thumbnail(props) {
numImageFrames, numImageFrames,
SeriesDescription, SeriesDescription,
SeriesNumber, SeriesNumber,
hasWarnings,
stackPercentComplete, stackPercentComplete,
StudyInstanceUID, StudyInstanceUID,
onClick, onClick,
@@ -126,13 +190,14 @@ Thumbnail.propTypes = {
stackPercentComplete: PropTypes.number, stackPercentComplete: PropTypes.number,
/** /**
altImageText will be used when no imageId or imageSrc is provided. altImageText will be used when no imageId or imageSrc is provided.
It will be displayed inside the <div>. This is useful when it is difficult It will be displayed inside the <div>. This is useful when it is difficult
to make a preview for a type of DICOM series (e.g. DICOM-SR) to make a preview for a type of DICOM series (e.g. DICOM-SR)
*/ */
altImageText: PropTypes.string, altImageText: PropTypes.string,
SeriesDescription: PropTypes.string, SeriesDescription: PropTypes.string,
SeriesNumber: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), SeriesNumber: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
InstanceNumber: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), InstanceNumber: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
hasWarnings: PropTypes.instanceOf(Promise),
numImageFrames: PropTypes.number, numImageFrames: PropTypes.number,
onDoubleClick: PropTypes.func, onDoubleClick: PropTypes.func,
onClick: PropTypes.func, onClick: PropTypes.func,
@@ -78,6 +78,17 @@
height: 11px height: 11px
width: 11px width: 11px
.warning
margin: auto 0;
opacity: 1
color: #e29e4a;
svg
width: 16px;
height: 14px;
pointer-events: inherit;
.value .value
color: var(--text-secondary-color); color: var(--text-secondary-color);
display: inline-block display: inline-block
@@ -0,0 +1,104 @@
import React, { useState, createContext, useContext, useEffect } from 'react';
import PropTypes from 'prop-types';
const LoggerContext = createContext(null);
const { Provider } = LoggerContext;
export const useLogger = () => useContext(LoggerContext);
const LoggerProvider = ({ children, service }) => {
const [state, setState] = useState({
errors: [],
infos: [],
});
useEffect(() => {
const onErrorHandler = ({ error: errorObject, message }) => {
error({ error: errorObject, message });
};
window.addEventListener('error', onErrorHandler);
return () => {
window.removeEventListener('error', onErrorHandler);
};
}, []);
/**
* Logs an error
*
* @param {object} props { error, stack, message, displayOnConsole }
* @returns void
*/
const error = ({
error = {},
stack = '',
message = '',
displayOnConsole = true,
}) => {
const errorObject = { error, stack, message, displayOnConsole };
setState(state => ({ ...state, errors: [...state.errors, errorObject] }));
if (displayOnConsole) {
console.error(error);
}
};
/**
* Logs an info
*
* @param {object} props { message, displayOnConsole }
* @returns void
*/
const info = ({ message = '', displayOnConsole = true }) => {
setState(state => ({
...state,
infos: state.infos.push({ message, displayOnConsole }),
}));
if (displayOnConsole) {
console.info(message);
}
};
/**
* Sets the implementation of a log service that can be used by extensions
*
* @returns void
*/
useEffect(() => {
if (service) {
service.setServiceImplementation({ error, info });
}
}, [error, service, info]);
return <Provider value={{ info, error, state }}>{children}</Provider>;
};
/**
* Higher Order Component to use the log methods through a Class Component
*
* @returns
*/
export const withLogger = Component => {
return function WrappedComponent(props) {
const { error, info, state } = useLogger();
return <Component {...props} logger={{ error, info, state }} />;
};
};
LoggerProvider.defaultProps = {
service: null,
};
LoggerProvider.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]).isRequired,
service: PropTypes.shape({
setServiceImplementation: PropTypes.func,
}),
};
export default LoggerProvider;
export const LogConsumer = LoggerContext.Consumer;
@@ -18,3 +18,8 @@ export {
withDialog, withDialog,
useDialog, useDialog,
} from './DialogProvider.js'; } from './DialogProvider.js';
export {
default as LoggerProvider,
withLogger,
useLogger,
} from './LoggerProvider.js';
+8 -2
View File
@@ -30,7 +30,7 @@ import {
AboutContent, AboutContent,
OHIFModal, OHIFModal,
ErrorBoundary, ErrorBoundary,
ErrorPage ErrorPage,
} from './components'; } from './components';
import { useDebounce, useMedia } from './hooks'; import { useDebounce, useMedia } from './hooks';
@@ -66,6 +66,9 @@ import {
ModalConsumer, ModalConsumer,
useModal, useModal,
withModal, withModal,
LoggerProvider,
withLogger,
useLogger,
} from './contextProviders'; } from './contextProviders';
export { export {
@@ -127,11 +130,14 @@ export {
useDialog, useDialog,
ErrorBoundary, ErrorBoundary,
ErrorPage, ErrorPage,
LoggerProvider,
withLogger,
useLogger,
// Hooks // Hooks
useDebounce, useDebounce,
useMedia, useMedia,
// Utils // Utils
ViewerbaseDragDropContext, ViewerbaseDragDropContext,
asyncComponent, asyncComponent,
retryImport retryImport,
}; };
+110
View File
@@ -3,6 +3,116 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [4.9.9](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.9.8...@ohif/viewer@4.9.9) (2021-04-15)
**Note:** Version bump only for package @ohif/viewer
## [4.9.8](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.9.7...@ohif/viewer@4.9.8) (2021-03-31)
**Note:** Version bump only for package @ohif/viewer
## [4.9.7](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.9.6...@ohif/viewer@4.9.7) (2021-03-26)
**Note:** Version bump only for package @ohif/viewer
## [4.9.6](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.9.5...@ohif/viewer@4.9.6) (2021-03-26)
**Note:** Version bump only for package @ohif/viewer
## [4.9.5](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.9.4...@ohif/viewer@4.9.5) (2021-03-25)
### Bug Fixes
* IDC-2288: Update toolbar tabs after derived displayset loaded ([#2307](https://github.com/OHIF/Viewers/issues/2307)) ([6e723eb](https://github.com/OHIF/Viewers/commit/6e723ebced58852007ca553792c740976cfc4201))
## [4.9.4](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.9.3...@ohif/viewer@4.9.4) (2021-03-19)
**Note:** Version bump only for package @ohif/viewer
## [4.9.3](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.9.2...@ohif/viewer@4.9.3) (2021-03-15)
**Note:** Version bump only for package @ohif/viewer
## [4.9.2](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.9.1...@ohif/viewer@4.9.2) (2021-03-09)
**Note:** Version bump only for package @ohif/viewer
## [4.9.1](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.9.0...@ohif/viewer@4.9.1) (2021-03-09)
**Note:** Version bump only for package @ohif/viewer
# [4.9.0](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.8.12...@ohif/viewer@4.9.0) (2021-03-04)
### Features
* **log:** add new log service ([14d6454](https://github.com/OHIF/Viewers/commit/14d6454eafaa2ccb50e133c2945c9558052ea27e))
## [4.8.12](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.8.11...@ohif/viewer@4.8.12) (2021-03-03)
**Note:** Version bump only for package @ohif/viewer
## [4.8.11](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.8.10...@ohif/viewer@4.8.11) (2021-02-25)
**Note:** Version bump only for package @ohif/viewer
## [4.8.10](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.8.9...@ohif/viewer@4.8.10) (2021-02-08)
**Note:** Version bump only for package @ohif/viewer
## [4.8.9](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.8.8...@ohif/viewer@4.8.9) (2021-02-05) ## [4.8.9](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.8.8...@ohif/viewer@4.8.9) (2021-02-05)
**Note:** Version bump only for package @ohif/viewer **Note:** Version bump only for package @ohif/viewer
+11 -11
View File
@@ -1,6 +1,6 @@
{ {
"name": "@ohif/viewer", "name": "@ohif/viewer",
"version": "4.8.9", "version": "4.9.9",
"description": "OHIF Viewer", "description": "OHIF Viewer",
"author": "OHIF Contributors", "author": "OHIF Contributors",
"license": "MIT", "license": "MIT",
@@ -49,18 +49,18 @@
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.5.5", "@babel/runtime": "^7.5.5",
"@ohif/core": "^2.12.3", "@ohif/core": "^2.13.4",
"@ohif/extension-cornerstone": "^2.10.1", "@ohif/extension-cornerstone": "^2.10.7",
"@ohif/extension-debugging": "^0.1.6", "@ohif/extension-debugging": "^0.2.1",
"@ohif/extension-dicom-html": "^1.3.1", "@ohif/extension-dicom-html": "^1.3.5",
"@ohif/extension-dicom-microscopy": "^0.51.4", "@ohif/extension-dicom-microscopy": "^0.52.0",
"@ohif/extension-dicom-pdf": "^1.0.6", "@ohif/extension-dicom-pdf": "^1.0.6",
"@ohif/extension-dicom-rt": "^0.6.4", "@ohif/extension-dicom-rt": "^0.6.8",
"@ohif/extension-dicom-segmentation": "^0.5.2", "@ohif/extension-dicom-segmentation": "^0.6.3",
"@ohif/extension-lesion-tracker": "^0.2.1", "@ohif/extension-lesion-tracker": "^0.2.1",
"@ohif/extension-vtk": "^1.10.4", "@ohif/extension-vtk": "^1.11.5",
"@ohif/i18n": "^0.53.0", "@ohif/i18n": "^0.53.0",
"@ohif/ui": "^1.8.2", "@ohif/ui": "^1.9.1",
"@tanem/react-nprogress": "^1.1.25", "@tanem/react-nprogress": "^1.1.25",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"core-js": "^3.2.1", "core-js": "^3.2.1",
@@ -68,7 +68,7 @@
"cornerstone-math": "^0.1.8", "cornerstone-math": "^0.1.8",
"cornerstone-tools": "^4.20.1", "cornerstone-tools": "^4.20.1",
"cornerstone-wado-image-loader": "^3.1.0", "cornerstone-wado-image-loader": "^3.1.0",
"dcmjs": "0.17.2", "dcmjs": "0.18.4",
"dicom-parser": "^1.8.3", "dicom-parser": "^1.8.3",
"dicomweb-client": "^0.4.4", "dicomweb-client": "^0.4.4",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
+30 -19
View File
@@ -13,6 +13,7 @@ import {
ModalProvider, ModalProvider,
DialogProvider, DialogProvider,
OHIFModal, OHIFModal,
LoggerProvider,
ErrorBoundary, ErrorBoundary,
} from '@ohif/ui'; } from '@ohif/ui';
@@ -24,6 +25,7 @@ import {
UINotificationService, UINotificationService,
UIModalService, UIModalService,
UIDialogService, UIDialogService,
LoggerService,
MeasurementService, MeasurementService,
utils, utils,
redux as reduxOHIF, redux as reduxOHIF,
@@ -141,6 +143,7 @@ class App extends Component {
UIModalService, UIModalService,
UIDialogService, UIDialogService,
MeasurementService, MeasurementService,
LoggerService,
]); ]);
_initExtensions( _initExtensions(
[...defaultExtensions, ...extensions], [...defaultExtensions, ...extensions],
@@ -164,6 +167,7 @@ class App extends Component {
UIDialogService, UIDialogService,
UIModalService, UIModalService,
MeasurementService, MeasurementService,
LoggerService,
} = servicesManager.services; } = servicesManager.services;
if (this._userManager) { if (this._userManager) {
@@ -176,18 +180,20 @@ class App extends Component {
<UserManagerContext.Provider value={this._userManager}> <UserManagerContext.Provider value={this._userManager}>
<Router basename={routerBasename}> <Router basename={routerBasename}>
<WhiteLabelingContext.Provider value={whiteLabeling}> <WhiteLabelingContext.Provider value={whiteLabeling}>
<SnackbarProvider service={UINotificationService}> <LoggerProvider service={LoggerService}>
<DialogProvider service={UIDialogService}> <SnackbarProvider service={UINotificationService}>
<ModalProvider <DialogProvider service={UIDialogService}>
modal={OHIFModal} <ModalProvider
service={UIModalService} modal={OHIFModal}
> service={UIModalService}
<OHIFStandaloneViewer >
userManager={this._userManager} <OHIFStandaloneViewer
/> userManager={this._userManager}
</ModalProvider> />
</DialogProvider> </ModalProvider>
</SnackbarProvider> </DialogProvider>
</SnackbarProvider>
</LoggerProvider>
</WhiteLabelingContext.Provider> </WhiteLabelingContext.Provider>
</Router> </Router>
</UserManagerContext.Provider> </UserManagerContext.Provider>
@@ -206,13 +212,18 @@ class App extends Component {
<I18nextProvider i18n={i18n}> <I18nextProvider i18n={i18n}>
<Router basename={routerBasename}> <Router basename={routerBasename}>
<WhiteLabelingContext.Provider value={whiteLabeling}> <WhiteLabelingContext.Provider value={whiteLabeling}>
<SnackbarProvider service={UINotificationService}> <LoggerProvider service={LoggerService}>
<DialogProvider service={UIDialogService}> <SnackbarProvider service={UINotificationService}>
<ModalProvider modal={OHIFModal} service={UIModalService}> <DialogProvider service={UIDialogService}>
<OHIFStandaloneViewer /> <ModalProvider
</ModalProvider> modal={OHIFModal}
</DialogProvider> service={UIModalService}
</SnackbarProvider> >
<OHIFStandaloneViewer />
</ModalProvider>
</DialogProvider>
</SnackbarProvider>
</LoggerProvider>
</WhiteLabelingContext.Provider> </WhiteLabelingContext.Provider>
</Router> </Router>
</I18nextProvider> </I18nextProvider>
@@ -4,7 +4,7 @@ import React, { useEffect } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classNames from 'classnames'; import classNames from 'classnames';
import { utils } from '@ohif/core'; import { utils } from '@ohif/core';
import { useSnackbarContext } from '@ohif/ui'; import { useSnackbarContext, useLogger } from '@ohif/ui';
// //
import ViewportPane from './ViewportPane.js'; import ViewportPane from './ViewportPane.js';
import DefaultViewport from './DefaultViewport.js'; import DefaultViewport from './DefaultViewport.js';
@@ -12,7 +12,7 @@ import EmptyViewport from './EmptyViewport.js';
const { loadAndCacheDerivedDisplaySets } = utils; const { loadAndCacheDerivedDisplaySets } = utils;
const ViewportGrid = function (props) { const ViewportGrid = function(props) {
const { const {
activeViewportIndex, activeViewportIndex,
availablePlugins, availablePlugins,
@@ -36,14 +36,15 @@ const ViewportGrid = function (props) {
} }
const snackbar = useSnackbarContext(); const snackbar = useSnackbarContext();
const logger = useLogger();
useEffect(() => { useEffect(() => {
if (isStudyLoaded) { if (isStudyLoaded) {
viewportData.forEach(displaySet => { viewportData.forEach(displaySet => {
const promises = loadAndCacheDerivedDisplaySets(displaySet, studies); const promises = loadAndCacheDerivedDisplaySets(displaySet, studies);
promises.forEach(promise => { promises.forEach(promise => {
promise.catch(error => { promise.catch(error => {
logger.error({ error, message: error.message });
snackbar.show({ snackbar.show({
title: 'Error loading derived display set:', title: 'Error loading derived display set:',
message: error.message, message: error.message,
@@ -59,6 +59,9 @@ class ToolbarRow extends Component {
this.seriesPerStudyCount = []; this.seriesPerStudyCount = [];
this._handleBuiltIn = _handleBuiltIn.bind(this); this._handleBuiltIn = _handleBuiltIn.bind(this);
this._onDerivedDisplaySetsLoadedAndCached = this._onDerivedDisplaySetsLoadedAndCached.bind(
this
);
this.updateButtonGroups(); this.updateButtonGroups();
} }
@@ -109,6 +112,32 @@ class ToolbarRow extends Component {
}); });
} }
componentDidMount() {
/*
* TODO: Improve the way we notify parts of the app
* that depends on derived display sets to be loaded.
* (Implement pubsub for better tracking of derived display sets)
*/
document.addEventListener(
'deriveddisplaysetsloadedandcached',
this._onDerivedDisplaySetsLoadedAndCached
);
}
componentWillUnmount() {
document.removeEventListener(
'deriveddisplaysetsloadedandcached',
this._onDerivedDisplaySetsLoadedAndCached
);
}
_onDerivedDisplaySetsLoadedAndCached() {
this.updateButtonGroups();
this.setState({
toolbarButtons: _getVisibleToolbarButtons.call(this),
});
}
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
const activeContextsChanged = const activeContextsChanged =
prevProps.activeContexts !== this.props.activeContexts; prevProps.activeContexts !== this.props.activeContexts;
@@ -12,6 +12,7 @@ import ConnectedViewerMain from './ConnectedViewerMain.js';
import SidePanel from './../components/SidePanel.js'; import SidePanel from './../components/SidePanel.js';
import ErrorBoundaryDialog from './../components/ErrorBoundaryDialog'; import ErrorBoundaryDialog from './../components/ErrorBoundaryDialog';
import { extensionManager } from './../App.js'; import { extensionManager } from './../App.js';
import { ReconstructionIssues } from './../../../core/src/enums.js';
// Contexts // Contexts
import WhiteLabelingContext from '../context/WhiteLabelingContext.js'; import WhiteLabelingContext from '../context/WhiteLabelingContext.js';
@@ -271,6 +272,7 @@ class Viewer extends Component {
activeViewport={ activeViewport={
this.props.viewports[this.props.activeViewportIndex] this.props.viewports[this.props.activeViewportIndex]
} }
isDerivedDisplaySetsLoaded={this.props.isDerivedDisplaySetsLoaded}
isLeftSidePanelOpen={this.state.isLeftSidePanelOpen} isLeftSidePanelOpen={this.state.isLeftSidePanelOpen}
isRightSidePanelOpen={this.state.isRightSidePanelOpen} isRightSidePanelOpen={this.state.isRightSidePanelOpen}
selectedLeftSidePanel={ selectedLeftSidePanel={
@@ -366,6 +368,62 @@ class Viewer extends Component {
export default withDialog(Viewer); export default withDialog(Viewer);
/**
* Async function to check if there are any inconsistences in the series
* (i.e. reconstructable to a 3D volume). If not reconstructable MPR is disabled.
* The actual computations are done in isDisplaySetReconstructable.
*
* 1) Is series multiframe?
* 2) Do the frames have different dimensions/numer of components/orientations?
* 3) Has the series any missing frames or irregular spacing?
* 4) Is the series 4D?
*
* @param {*object} displaySet
* @returns {[string]} an array of strings containing the warnings
*/
const _checkForSeriesInconsistencesWarnings = async function (displaySet) {
// NOTE: at the moment this function is async even if it does not perfom any heavy calculation.
// We may add or move here some of the computations
// done when creating the displaySet (see makeDisplaySet and isDisplaySetReconstructable).
// the thumbnail footnotes warning react element is already set up to handle a promise.
const warningsList = [];
if (displaySet.warningIssues && displaySet.warningIssues.length !== 0) {
displaySet.warningIssues.forEach(warning => {
switch (warning) {
case ReconstructionIssues.DATASET_4D:
warningsList.push("The dataset is 4D.");
break;
case ReconstructionIssues.VARYING_IMAGESDIMENSIONS:
warningsList.push("The dataset frames have different dimensions (rows, columns).");
break;
case ReconstructionIssues.VARYING_IMAGESCOMPONENTS:
warningsList.push("The dataset frames have different components (Sample per pixel).");
break;
case ReconstructionIssues.VARYING_IMAGESORIENTATION:
warningsList.push("The dataset frames have different orientation.");
break;
case ReconstructionIssues.IRREGULAR_SPACING:
warningsList.push("The dataset frames have different pixel spacing.");
break;
case ReconstructionIssues.MULTIFFRAMES:
warningsList.push("The dataset is a multiframes.");
break;
default:
break;
}
});
warningsList.push('The datasets is not a reconstructable 3D volume. MPR mode is not available.');
}
if (displaySet.missingFrames &&
(!displaySet.warningIssues ||
(displaySet.warningIssues && !displaySet.warningIssues.find(warn => warn === ReconstructionIssues.DATASET_4D)))) {
warningsList.push('The datasets is missing frames: ' + displaySet.missingFrames + '.');
}
return warningsList
}
/** /**
* What types are these? Why do we have "mapping" dropped in here instead of in * What types are these? Why do we have "mapping" dropped in here instead of in
* a mapping layer? * a mapping layer?
@@ -405,6 +463,8 @@ const _mapStudiesToThumbnails = function(studies) {
altImageText = displaySet.Modality ? displaySet.Modality : 'UN'; altImageText = displaySet.Modality ? displaySet.Modality : 'UN';
} }
const hasWarnings = _checkForSeriesInconsistencesWarnings(displaySet)
return { return {
imageId, imageId,
altImageText, altImageText,
@@ -413,6 +473,7 @@ const _mapStudiesToThumbnails = function(studies) {
InstanceNumber, InstanceNumber,
numImageFrames, numImageFrames,
SeriesNumber, SeriesNumber,
hasWarnings,
}; };
}); });
@@ -5,10 +5,11 @@ import usePrevious from '../customHooks/usePrevious';
import ConnectedViewer from './ConnectedViewer.js'; import ConnectedViewer from './ConnectedViewer.js';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { extensionManager } from './../App.js'; import { extensionManager } from './../App.js';
import { useSnackbarContext } from '@ohif/ui'; import { useSnackbarContext, ErrorPage } from '@ohif/ui';
// Contexts // Contexts
import AppContext from '../context/AppContext'; import AppContext from '../context/AppContext';
import NotFound from '../routes/NotFound';
const { OHIFStudyMetadata, OHIFSeriesMetadata } = metadata; const { OHIFStudyMetadata, OHIFSeriesMetadata } = metadata;
const { retrieveStudiesMetadata, deleteStudyMetadataPromise } = studies; const { retrieveStudiesMetadata, deleteStudyMetadataPromise } = studies;
@@ -291,7 +292,7 @@ function ViewerRetrieveStudyData({
}) })
.catch(error => { .catch(error => {
if (error && !error.isCanceled) { if (error && !error.isCanceled) {
setError(true); setError(error);
log.error(error); log.error(error);
} }
}); });
@@ -300,6 +301,7 @@ function ViewerRetrieveStudyData({
}); });
setStudies(studies); setStudies(studies);
setIsStudyLoaded(true);
} }
}; };
@@ -358,13 +360,13 @@ function ViewerRetrieveStudyData({
}) })
.catch(error => { .catch(error => {
if (error && !error.isCanceled) { if (error && !error.isCanceled) {
setError(true); setError(error);
log.error(error); log.error(error);
} }
}); });
} catch (error) { } catch (error) {
if (error) { if (error) {
setError(true); setError(error);
log.error(error); log.error(error);
} }
} }
@@ -411,7 +413,12 @@ function ViewerRetrieveStudyData({
}, []); }, []);
if (error) { if (error) {
return <div>Error: {JSON.stringify(error)}</div>; const content = JSON.stringify(error);
if (content.includes('404') || content.includes('NOT_FOUND')) {
return <NotFound />;
}
return <NotFound message="Failed to retrieve study data" />;
} }
return ( return (
-1
View File
@@ -41,7 +41,6 @@ let config = {};
if (window) { if (window) {
config = window.config || {}; config = window.config || {};
window.version = version; window.version = version;
} }
+8 -8
View File
@@ -6619,10 +6619,10 @@ dateformat@^3.0.0:
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
dcmjs@0.17.2: dcmjs@0.18.3:
version "0.17.2" version "0.18.3"
resolved "https://registry.yarnpkg.com/dcmjs/-/dcmjs-0.17.2.tgz#81d6e696119c25afbd26967a6250a32c25f06535" resolved "https://registry.yarnpkg.com/dcmjs/-/dcmjs-0.18.3.tgz#17d5a23d96b63264b8a1a859e4cb000b3e20495b"
integrity sha512-wM9AUWt9vM2S+owI/4UjoBCSV9Mfi/m5rykHH5WTDZVxQZUrL/ehOC/l7d7gkcMaOSD0C0r9X56Nn/562Jt1/Q== integrity sha512-nmG6wEBcIMnadXAZOTcXwacBv+lrh8bqPwIKZwdy7AkdihLEwI6/OnyP+PYjzcdltuPu9wOQcKZionvXuCteag==
dependencies: dependencies:
"@babel/polyfill" "^7.8.3" "@babel/polyfill" "^7.8.3"
"@babel/runtime" "^7.8.4" "@babel/runtime" "^7.8.4"
@@ -15698,10 +15698,10 @@ react-codemirror2@^6.0.0:
resolved "https://registry.yarnpkg.com/react-codemirror2/-/react-codemirror2-6.0.0.tgz#180065df57a64026026cde569a9708fdf7656525" resolved "https://registry.yarnpkg.com/react-codemirror2/-/react-codemirror2-6.0.0.tgz#180065df57a64026026cde569a9708fdf7656525"
integrity sha512-D7y9qZ05FbUh9blqECaJMdDwKluQiO3A9xB+fssd5jKM7YAXucRuEOlX32mJQumUvHUkHRHqXIPBjm6g0FW0Ag== integrity sha512-D7y9qZ05FbUh9blqECaJMdDwKluQiO3A9xB+fssd5jKM7YAXucRuEOlX32mJQumUvHUkHRHqXIPBjm6g0FW0Ag==
react-cornerstone-viewport@4.0.4: react-cornerstone-viewport@4.0.5:
version "4.0.4" version "4.0.5"
resolved "https://registry.yarnpkg.com/react-cornerstone-viewport/-/react-cornerstone-viewport-4.0.4.tgz#0e4291d9b0fe55c003e275175b0902ced61b0c80" resolved "https://registry.yarnpkg.com/react-cornerstone-viewport/-/react-cornerstone-viewport-4.0.5.tgz#3de83cdd3643980e0330f3743f631dbbb24d98a7"
integrity sha512-RjCqOtQep04dRoHtsju0USlxN/vGUI2WnEt1aN84iYU7eZ+AXnwJo1nAd0RMX2obcXaGCIqMDtMRkE/zm3oZHw== integrity sha512-uamDtFljWWEHe26kOBJJ1Bu//6hAgEra7BDVykOvtMC/W7kW34Q2fFX3ZwkL6TDdCQ94O6K98IXPS9HbrEJWYg==
dependencies: dependencies:
classnames "^2.2.6" classnames "^2.2.6"
date-fns "^2.2.1" date-fns "^2.2.1"