Compare commits

...
Author SHA1 Message Date
ohif-bot 92273b25b3 chore(version): Update package versions [skip ci] 2023-07-06 16:23:25 +00:00
ohif-bot 3f296bdeb5 chore(version): version.json [skip ci] 2023-07-06 16:23:22 +00:00
Attila Hornok 0600858055 docs(ohif): broken link in the docs (#3509) 2023-07-06 12:16:09 -04:00
Alireza 4a184d0be7 fix(invert): allows volume viewport to invert and sync their invert status (#3514) 2023-07-06 12:09:34 -04:00
ohif-bot f3a4f861b4 chore(version): Update package versions [skip ci] 2023-07-05 13:11:37 +00:00
ohif-bot fc19912162 chore(version): version.json [skip ci] 2023-07-05 13:11:33 +00:00
Joe Boccanfuso 61595ce7d6 feat(Docker): Facilitate the ability to run the OHIF docker image over SSL (#3511) 2023-07-05 09:03:43 -04:00
ohif-bot ffd53eff85 chore(version): Update package versions [skip ci] 2023-07-05 12:50:14 +00:00
ohif-bot 52a43c771a chore(version): version.json [skip ci] 2023-07-05 12:50:10 +00:00
Joe Boccanfuso c3c132d268 fix(tracked-measurement): SR viewports disable jump to measurement (#3518) 2023-07-05 08:43:01 -04:00
ohif-bot e742328ac1 chore(version): Update package versions [skip ci] 2023-07-04 18:46:19 +00:00
ohif-bot 90647b63a0 chore(version): version.json [skip ci] 2023-07-04 18:46:16 +00:00
Joe Boccanfuso ed44ad7f4b fix(segmentation): Use the series description for the segmentation label (#3517) 2023-07-04 14:39:39 -04:00
ohif-bot b0a456a46c chore(version): Update package versions [skip ci] 2023-07-04 16:41:18 +00:00
ohif-bot 8b7db45641 chore(version): version.json [skip ci] 2023-07-04 16:41:14 +00:00
Joe Boccanfuso b5599dde4e fix(utils): remove undefined/null values from the PerFrameFunctionalGroupsSequence in combineFrameInstance. (#3515) 2023-07-04 12:33:51 -04:00
ohif-bot f7b7131d70 chore(version): Update package versions [skip ci] 2023-07-04 16:05:36 +00:00
ohif-bot d646c15c27 chore(version): version.json [skip ci] 2023-07-04 16:05:32 +00:00
Bill WallaceandAlireza 64f8bb580a fix(colormap): update opacityMapping to opacity and use simple list renderer(#3464)
Co-authored-by: Alireza <ar.sedghi@gmail.com>
2023-07-04 11:57:59 -04:00
ohif-bot ce29bbe795 chore(version): Update package versions [skip ci] 2023-07-04 13:04:17 +00:00
ohif-bot 0bbcb4269d chore(version): version.json [skip ci] 2023-07-04 13:04:14 +00:00
Alireza 3efa793e60 fix(utils): remove undefined values in combineFrameInstance (#3513) 2023-07-04 08:57:14 -04:00
ohif-bot 3b50bd8cc4 chore(version): Update package versions [skip ci] 2023-07-03 14:41:24 +00:00
ohif-bot cd553e29b2 chore(version): version.json [skip ci] 2023-07-03 14:41:21 +00:00
mccle 12dd5a2619 fix(typeError): Address SliceThickness.toFixed TypeError (#3510) 2023-07-03 10:31:46 -04:00
ohif-bot f7a435c2f3 chore(version): Update package versions [skip ci] 2023-06-29 19:56:51 +00:00
ohif-bot 19f1da702f chore(version): version.json [skip ci] 2023-06-29 19:56:47 +00:00
Sofien-Sellami 14974b6973 fix(tmtv): Fusion_Viewport to allow displaySets to be changed (#3502)
Allows drag and drop of new sets of viewports to change them one at a time.
Co-authored-by: Bill Wallace <wayfarer3130@gmail.com>
2023-06-29 15:48:52 -04:00
ohif-bot b4dbe5656b chore(version): Update package versions [skip ci] 2023-06-29 15:24:35 +00:00
ohif-bot c6f7349fd7 chore(version): version.json [skip ci] 2023-06-29 15:24:32 +00:00
Sofien-Sellami abe939bd20 fix(hp): Remove filtered displaySets from parameter from study protocolEngine.findMatch() (#3343)
The changes look good and are running now successfully.
2023-06-29 11:17:08 -04:00
ohif-bot 4d4dd45c23 chore(version): Update package versions [skip ci] 2023-06-29 15:04:16 +00:00
ohif-bot 7671b9faf4 chore(version): version.json [skip ci] 2023-06-29 15:04:12 +00:00
Sofien-SellamiandBill Wallace e653961858 Add support for array input for all constraints in HangingProtocolService validator (#3322)
Co-authored-by: Bill Wallace <wayfarer3130@gmail.com>
2023-06-29 10:56:40 -04:00
ohif-bot aeb61f40da chore(version): Update package versions [skip ci] 2023-06-29 14:51:44 +00:00
ohif-bot b5fb2461dd chore(version): version.json [skip ci] 2023-06-29 14:51:41 +00:00
Joe Boccanfuso 15ad8f29cd fix(date formatting): Show study date as a fallback for an empty series date and show 'No Study Date' as a back up for both (#3483) 2023-06-29 10:43:56 -04:00
ohif-bot fa37593696 chore(version): Update package versions [skip ci] 2023-06-29 14:38:20 +00:00
ohif-bot 08eed4cdf9 chore(version): version.json [skip ci] 2023-06-29 14:38:15 +00:00
Sofien-Sellami b5b7d323c8 fix: allow volume3d viewport for SUV rendering (#3494)
Add checks to include volume3d viewports.
2023-06-29 10:30:41 -04:00
ohif-bot 8a8ae237d2 chore(version): Update package versions [skip ci] 2023-06-27 15:52:28 +00:00
ohif-bot cf1e00fee0 chore(version): version.json [skip ci] 2023-06-27 15:52:24 +00:00
Joe Boccanfuso ef4f28690a fix(DICOM Upload): use correct Accept header for upload (#3498) 2023-06-27 11:44:46 -04:00
ohif-bot c98211ccb5 chore(version): Update package versions [skip ci] 2023-06-23 00:55:55 +00:00
ohif-bot 71342fac8f chore(version): version.json [skip ci] 2023-06-23 00:55:52 +00:00
Alireza 52f419d188 feat(transferSyntax): Add customizable Transfer syntax through datasource config (#3406) 2023-06-22 20:47:50 -04:00
Salim Kanoun ca3a0b56f7 update old configs 2023-06-22 21:26:26 +02:00
Salim Kanoun 1a91f210ab rename 2023-06-20 22:18:14 +02:00
ohif-bot 3503e6e9f4 chore(version): Update package versions [skip ci] 2023-06-20 14:33:52 +00:00
ohif-bot 0c51444066 chore(version): version.json [skip ci] 2023-06-20 14:33:48 +00:00
Alireza 83c453d1f3 chore(version): update cs3d version and add iframe documentation (#3474) 2023-06-20 10:26:05 -04:00
Salim Kanoun fa73a458bd WIP (not tested yet) 2023-06-20 09:34:20 +00:00
ohif-bot 5670a1699d chore(version): Update package versions [skip ci] 2023-06-19 14:44:15 +00:00
ohif-bot c529c0da9c chore(version): version.json [skip ci] 2023-06-19 14:44:10 +00:00
dxlin d51211f6b9 fix(SR export): prevent empty sr description when export (#3173) 2023-06-19 10:35:53 -04:00
ohif-bot 2d8400f9d8 chore(version): Update package versions [skip ci] 2023-06-19 14:10:15 +00:00
ohif-bot e12242a15c chore(version): version.json [skip ci] 2023-06-19 14:10:11 +00:00
Davy 8baf9deaf0 fix(i18n): add more fields i18n (#3262) 2023-06-19 10:02:48 -04:00
ohif-bot a34a0b1a3a chore(version): Update package versions [skip ci] 2023-06-19 13:47:55 +00:00
ohif-bot e1545b67da chore(version): version.json [skip ci] 2023-06-19 13:47:52 +00:00
wangxuan d75305e70d fi(proptype): Invalid prop WhiteLabeling of type object supplied... (#3152) 2023-06-19 09:40:31 -04:00
ohif-bot 242beb7b46 chore(version): Update package versions [skip ci] 2023-06-19 13:39:11 +00:00
ohif-bot c5d4e97115 chore(version): version.json [skip ci] 2023-06-19 13:39:07 +00:00
Igor OctavianoandIgor Octaviano 59cdc4ba9a fix(SEG): Missing SpacingBetweenSlices prevents SEG rendering (#3344)
Co-authored-by: Igor Octaviano <igor.octaviano@radicalimaging.com>
2023-06-19 09:31:04 -04:00
ohif-bot 971c594791 chore(version): Update package versions [skip ci] 2023-06-19 13:22:44 +00:00
ohif-bot c55136f55e chore(version): version.json [skip ci] 2023-06-19 13:22:41 +00:00
Jemshith T K 63e12dd651 docs(ohif-cli): update ohif-cli.md (#3461) 2023-06-19 09:15:30 -04:00
ohif-bot c75c6af22f chore(version): Update package versions [skip ci] 2023-06-19 13:09:00 +00:00
ohif-bot 3c777ba58b chore(version): version.json [skip ci] 2023-06-19 13:08:56 +00:00
dxlin e6f73a2025 fix(RT) : Make ContourImageSequence check under ROIContourSequence->ContourImageSequence optional (#3476) 2023-06-19 09:01:23 -04:00
ohif-bot 652e61a417 chore(version): Update package versions [skip ci] 2023-06-15 17:08:06 +00:00
ohif-bot 48bcdd6b50 chore(version): version.json [skip ci] 2023-06-15 17:08:01 +00:00
Joe Boccanfuso cc73f15c8c fix(Button): redesign of existing Button component for consistency (#3473) 2023-06-15 12:58:21 -04:00
ohif-bot 3dce70e624 chore(version): Update package versions [skip ci] 2023-06-13 12:59:35 +00:00
ohif-bot 1d00893c49 chore(version): version.json [skip ci] 2023-06-13 12:59:31 +00:00
Sofien-Sellami 2890635675 fix(overlay): Fix undefined volumes in customizable viewport overlay (#3435) 2023-06-13 08:51:01 -04:00
ohif-bot a6d967a37e chore(version): Update package versions [skip ci] 2023-06-13 02:41:20 +00:00
ohif-bot f23a4500f5 chore(version): version.json [skip ci] 2023-06-13 02:41:17 +00:00
Alireza cadb559619 docs(readme): correct the docs images (#3470) 2023-06-12 22:33:54 -04:00
Salim Kanoun ad3ef3e8ef Merge branch 'master' into customizable-TS 2023-06-09 21:45:03 +02:00
Salim Kanoun 18c6a47dca Merge branch 'master' into customizable-TS 2023-06-07 13:08:49 +02:00
Salim Kanoun 93f30f06c2 Fix tests 2023-06-06 16:57:19 +02:00
Salim Kanoun 50d2640876 accept both accept header and transfer syntax uid 2023-06-05 22:32:29 +02:00
Salim Kanoun 10e399d7b8 Merge branch 'master' into customizable-TS 2023-06-04 12:43:16 +02:00
Salim Kanoun e4937e7473 update comments 2023-06-01 23:35:13 +02:00
Salim Kanoun 62dd2e78bd null safe 2023-06-01 23:32:16 +02:00
Salim Kanoun c3654b7ddf rework TS 2023-06-01 23:18:54 +02:00
Salim Kanoun de60586b71 fixes 2023-05-29 23:39:06 +02:00
Salim Kanoun f670678cf0 WIP accept header 2023-05-29 23:28:17 +02:00
Salim Kanoun 56633a67d9 Merge branch 'v3-stable' into customizable-TS 2023-05-29 23:26:36 +02:00
Salim Kanoun 8e2535a308 temp disabled of requested ts 2023-05-29 10:38:27 +02:00
Salim Kanoun 6da1734b6e Moving requested ts in createDicomWebApi (WIP) 2023-05-29 10:38:04 +02:00
Salim Kanoun 5ae6e9caf4 restaure config 2023-05-18 20:05:28 +02:00
Salim Kanoun 5e4043d99c add source of type correspondancies 2023-05-18 19:21:46 +02:00
Salim Kanoun 0e991d6bde config documentation 2023-05-18 19:13:36 +02:00
Salim Kanoun 2f63a9db80 init commit making TS customizable in OHIF settings 2023-05-18 19:06:26 +02:00
Salim Kanoun bedc379e97 Merge pull request #4 from OHIF/v3-stable
V3 stable
2023-05-18 17:35:16 +02:00
Salim Kanoun 5b7dc9e9c3 Merge pull request #3 from OHIF/v3-stable
V3 stable
2023-04-05 14:02:23 +02:00
Salim Kanoun 00099c0136 Merge remote-tracking branch 'upstream/v3-stable' into v3-stable 2023-03-12 08:01:06 +01:00
Salim Kanoun 799d648a90 Merge pull request #2 from OHIF/v3-stable
V3 stable
2022-12-28 21:25:05 +01:00
Salim Kanoun d5c347cecd Merge pull request #1 from OHIF/v3-stable
V3 stable
2022-11-24 17:01:48 +01:00
566 changed files with 3039 additions and 10594 deletions

No files matched your search

+2 -1
View File
@@ -1,5 +1,6 @@
server {
listen ${PORT};
listen ${PORT} default_server;
listen [::]:${PORT} default_server;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
@@ -0,0 +1,22 @@
server {
listen ${SSL_PORT} ssl http2 default_server;
listen [::]:${SSL_PORT} ssl http2 default_server;
ssl_certificate /etc/ssl/certs/ssl-certificate.crt;
ssl_certificate_key /etc/ssl/private/ssl-private-key.key;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
add_header Cross-Origin-Opener-Policy same-origin;
add_header Cross-Origin-Embedder-Policy require-corp;
add_header Cross-Origin-Resource-Policy same-origin;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
+11 -1
View File
@@ -1,6 +1,16 @@
#!/bin/sh
envsubst '${PORT}' < /usr/src/default.conf.template > /etc/nginx/conf.d/default.conf
if [ -n "$SSL_PORT" ]
then
envsubst '${SSL_PORT}:${PORT}' < /usr/src/default.ssl.conf.template > /etc/nginx/conf.d/default.conf
else
envsubst '${PORT}' < /usr/src/default.conf.template > /etc/nginx/conf.d/default.conf
fi
if [ -n "$APP_CONFIG" ]
then
echo "$APP_CONFIG" > /usr/share/nginx/html/app-config.js
fi
if [ -n "$CLIENT_ID" ] || [ -n "$HEALTHCARE_API_ENDPOINT" ]
then
-9
View File
@@ -73,15 +73,6 @@ module.exports = (env, argv, { SRC_DIR, ENTRY }) => {
children: false,
warnings: true,
},
devServer: {
open: true,
port: 3000,
historyApiFallback: true,
headers: {
'Cross-Origin-Embedder-Policy': 'require-corp',
'Cross-Origin-Opener-Policy': 'same-origin',
},
},
cache: {
type: 'filesystem',
},
+6 -1
View File
@@ -61,7 +61,7 @@ RUN yarn run build
# Stage 3: Bundle the built application into a Docker container
# which runs Nginx using Alpine Linux
FROM nginxinc/nginx-unprivileged:1.23.1-alpine as final
FROM nginxinc/nginx-unprivileged:1.25-alpine as final
#RUN apk add --no-cache bash
ENV PORT=80
RUN rm /etc/nginx/conf.d/default.conf
@@ -69,5 +69,10 @@ USER nginx
COPY --chown=nginx:nginx .docker/Viewer-v3.x /usr/src
RUN chmod 777 /usr/src/entrypoint.sh
COPY --from=builder /usr/src/app/platform/app/dist /usr/share/nginx/html
# In entrypoint.sh, app-config.js might be overwritten, so chmod it to be writeable.
# The nginx user cannot chmod it, so change to root.
USER root
RUN chmod 666 /usr/share/nginx/html/app-config.js
USER nginx
ENTRYPOINT ["/usr/src/entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]
+9 -7
View File
@@ -34,13 +34,15 @@ provided by the <a href="https://ohif.org/">Open Health Imaging Foundation (OHIF
<!-- [![All Contributors](https://img.shields.io/badge/all_contributors-10-orange.svg?style=flat-square)](#contributors) -->
<!-- prettier-ignore-end -->
| | |
| :-: | :--- |
| <img src="platform/docs/docs/assets/img/demo-measurements.jpg" alt="Measurement tracking" width="350"/> | Measurement Tracking |
| <img src="platform/docs/docs/assets/img/demo-segmentation.png" alt="Segmentations" width="350"/> | Labelmap Segmentations |
| <img src="platform/docs/docs/assets/img/demo-ptct.png" alt="Hanging Protocols" width="350"/> | Fusion and Custom Hanging protocols |
| <img src="platform/docs/docs/assets/img/demo-microscopy.png" alt="Microscopy" width="350"/> | Slide Microscopy |
| <img src="platform/docs/docs/assets/img/demo-volumeRendering.png" alt="Volume Rendering" width="350"/> | Volume Rendering |
| | | |
| :-: | :--- | :--- |
| <img src="platform/docs/docs/assets/img/demo-measurements.jpg" alt="Measurement tracking" width="350"/> | Measurement Tracking | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5) |
| <img src="platform/docs/docs/assets/img/demo-segmentation.png" alt="Segmentations" width="350"/> | Labelmap Segmentations | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.12.2.1107.5.2.32.35162.30000015050317233592200000046) |
| <img src="platform/docs/docs/assets/img/demo-ptct.png" alt="Hanging Protocols" width="350"/> | Fusion and Custom Hanging protocols | [Demo](https://viewer.ohif.org/tmtv?StudyInstanceUIDs=1.3.6.1.4.1.14519.5.2.1.7009.2403.334240657131972136850343327463) |
| <img src="platform/docs/docs/assets/img/demo-microscopy.png" alt="Microscopy" width="350"/> | Slide Microscopy | [Demo](https://viewer.ohif.org/microscopy?StudyInstanceUIDs=2.25.275741864483510678566144889372061815320) |
| <img src="platform/docs/docs/assets/img/demo-volumeRendering.png" alt="Volume Rendering" width="350"/> | Volume Rendering | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&hangingprotocolId=mprAnd3DVolumeViewport) |
## About
+1 -1
View File
@@ -1 +1 @@
14369414cf0193f00243ae5c9f8415cf7079a753
060085805510a046da3f5a5bb7dd2952e40d9b91
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-cornerstone-dicom-rt",
"version": "3.7.0-beta.2",
"version": "3.7.0-beta.27",
"description": "DICOM RT read workflow",
"author": "OHIF",
"license": "MIT",
@@ -31,10 +31,10 @@
"start": "yarn run dev"
},
"peerDependencies": {
"@ohif/core": "3.7.0-beta.2",
"@ohif/extension-cornerstone": "3.7.0-beta.2",
"@ohif/extension-default": "3.7.0-beta.2",
"@ohif/i18n": "3.7.0-beta.2",
"@ohif/core": "3.7.0-beta.27",
"@ohif/extension-cornerstone": "3.7.0-beta.27",
"@ohif/extension-default": "3.7.0-beta.27",
"@ohif/i18n": "3.7.0-beta.27",
"prop-types": "^15.6.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
@@ -181,12 +181,6 @@ export default async function loadRTStruct(
ContourGeometricType,
} = ContourSequenceArray[c];
const sopInstanceUID = ContourImageSequence.ReferencedSOPInstanceUID;
const imageId = _getImageId(imageIdSopInstanceUidPairs, sopInstanceUID);
if (!imageId) {
continue;
}
let isSupported = false;
const points = [];
@@ -1,3 +1,4 @@
import { ButtonEnums } from '@ohif/ui';
import hydrateRTDisplaySet from './_hydrateRT';
const RESPONSE = {
@@ -38,12 +39,12 @@ function _askHydrate(uiViewportDialogService, viewportIndex) {
const message = 'Do you want to open this Segmentation?';
const actions = [
{
type: 'secondary',
type: ButtonEnums.type.secondary,
text: 'No',
value: RESPONSE.CANCEL,
},
{
type: 'primary',
type: ButtonEnums.type.primary,
text: 'Yes',
value: RESPONSE.HYDRATE_SEG,
},
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-cornerstone-dicom-seg",
"version": "3.7.0-beta.2",
"version": "3.7.0-beta.27",
"description": "DICOM SEG read workflow",
"author": "OHIF",
"license": "MIT",
@@ -31,10 +31,10 @@
"start": "yarn run dev"
},
"peerDependencies": {
"@ohif/core": "3.7.0-beta.2",
"@ohif/extension-cornerstone": "3.7.0-beta.2",
"@ohif/extension-default": "3.7.0-beta.2",
"@ohif/i18n": "3.7.0-beta.2",
"@ohif/core": "3.7.0-beta.27",
"@ohif/extension-cornerstone": "3.7.0-beta.27",
"@ohif/extension-default": "3.7.0-beta.27",
"@ohif/i18n": "3.7.0-beta.27",
"prop-types": "^15.6.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
@@ -1,5 +1,5 @@
import React from 'react';
import { Input, Dialog } from '@ohif/ui';
import { Input, Dialog, ButtonEnums } from '@ohif/ui';
function callInputDialog(uiDialogService, label, callback) {
const dialogId = 'enter-segment-label';
@@ -29,8 +29,8 @@ function callInputDialog(uiDialogService, label, callback) {
noCloseButton: true,
onClose: () => uiDialogService.dismiss({ id: dialogId }),
actions: [
{ id: 'cancel', text: 'Cancel', type: 'primary' },
{ id: 'save', text: 'Confirm', type: 'secondary' },
{ id: 'cancel', text: 'Cancel', type: ButtonEnums.type.secondary },
{ id: 'save', text: 'Confirm', type: ButtonEnums.type.primary },
],
onSubmit: onSubmitHandler,
body: ({ value, setValue }) => {
@@ -1,3 +1,4 @@
import { ButtonEnums } from '@ohif/ui';
import hydrateSEGDisplaySet from './_hydrateSEG';
const RESPONSE = {
@@ -6,11 +7,7 @@ const RESPONSE = {
HYDRATE_SEG: 5,
};
function promptHydrateSEG({
servicesManager,
segDisplaySet,
viewportIndex,
}) {
function promptHydrateSEG({ servicesManager, segDisplaySet, viewportIndex }) {
const { uiViewportDialogService } = servicesManager.services;
return new Promise(async function(resolve, reject) {
@@ -36,12 +33,12 @@ function _askHydrate(uiViewportDialogService, viewportIndex) {
const message = 'Do you want to open this Segmentation?';
const actions = [
{
type: 'secondary',
type: ButtonEnums.type.secondary,
text: 'No',
value: RESPONSE.CANCEL,
},
{
type: 'primary',
type: ButtonEnums.type.primary,
text: 'Yes',
value: RESPONSE.HYDRATE_SEG,
},
@@ -71,7 +71,8 @@ function OHIFCornerstoneSEGViewport(props) {
const referencedDisplaySet = segDisplaySet.getReferenceDisplaySet();
const referencedDisplaySetMetadata = _getReferencedDisplaySetMetadata(
referencedDisplaySet
referencedDisplaySet,
segDisplaySet
);
referencedDisplaySetRef.current = {
@@ -343,10 +344,10 @@ function OHIFCornerstoneSEGViewport(props) {
patientSex: PatientSex || '',
patientAge: PatientAge || '',
MRN: PatientID || '',
thickness: SliceThickness ? `${SliceThickness.toFixed(2)}mm` : '',
thickness: SliceThickness ? `${parseFloat(SliceThickness).toFixed(2)}mm` : '',
spacing:
SpacingBetweenSlices !== undefined
? `${SpacingBetweenSlices.toFixed(2)}mm`
? `${parseFloat(SpacingBetweenSlices).toFixed(2)}mm`
: '',
scanner: ManufacturerModelName || '',
},
@@ -381,20 +382,28 @@ OHIFCornerstoneSEGViewport.defaultProps = {
customProps: {},
};
function _getReferencedDisplaySetMetadata(referencedDisplaySet) {
function _getReferencedDisplaySetMetadata(referencedDisplaySet, segDisplaySet) {
const {
SharedFunctionalGroupsSequence: [SharedFunctionalGroup],
} = segDisplaySet.instance;
const {
PixelMeasuresSequence: [PixelMeasures],
} = SharedFunctionalGroup;
const { SpacingBetweenSlices, SliceThickness } = PixelMeasures;
const image0 = referencedDisplaySet.images[0];
const referencedDisplaySetMetadata = {
PatientID: image0.PatientID,
PatientName: image0.PatientName,
PatientSex: image0.PatientSex,
PatientAge: image0.PatientAge,
SliceThickness: image0.SliceThickness,
SliceThickness: image0.SliceThickness || SliceThickness,
StudyDate: image0.StudyDate,
SeriesDescription: image0.SeriesDescription,
SeriesInstanceUID: image0.SeriesInstanceUID,
SeriesNumber: image0.SeriesNumber,
ManufacturerModelName: image0.ManufacturerModelName,
SpacingBetweenSlices: image0.SpacingBetweenSlices,
SpacingBetweenSlices: image0.SpacingBetweenSlices || SpacingBetweenSlices,
};
return referencedDisplaySetMetadata;
+8 -8
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-cornerstone-dicom-sr",
"version": "3.7.0-beta.2",
"version": "3.7.0-beta.27",
"description": "OHIF extension for an SR Cornerstone Viewport",
"author": "OHIF",
"license": "MIT",
@@ -32,10 +32,10 @@
"test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests"
},
"peerDependencies": {
"@ohif/core": "3.7.0-beta.2",
"@ohif/extension-cornerstone": "3.7.0-beta.2",
"@ohif/extension-measurement-tracking": "3.7.0-beta.2",
"@ohif/ui": "3.7.0-beta.2",
"@ohif/core": "3.7.0-beta.27",
"@ohif/extension-cornerstone": "3.7.0-beta.27",
"@ohif/extension-measurement-tracking": "3.7.0-beta.27",
"@ohif/ui": "3.7.0-beta.27",
"dcmjs": "^0.29.5",
"dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8",
@@ -44,9 +44,9 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^1.1.8",
"@cornerstonejs/core": "^1.1.8",
"@cornerstonejs/tools": "^1.1.8",
"@cornerstonejs/adapters": "^1.4.1",
"@cornerstonejs/core": "^1.4.1",
"@cornerstonejs/tools": "^1.4.1",
"classnames": "^2.3.2"
}
}
@@ -225,6 +225,7 @@ function OHIFCornerstoneSRViewport(props) {
}}
onElementEnabled={onElementEnabled}
initialImageIndex={initialImageIndex}
isJumpToMeasurementDisabled={true}
></Component>
);
}, [activeImageDisplaySetData, viewportIndex, measurementSelected]);
+8 -8
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-cornerstone",
"version": "3.7.0-beta.2",
"version": "3.7.0-beta.27",
"description": "OHIF extension for Cornerstone",
"author": "OHIF",
"license": "MIT",
@@ -36,9 +36,9 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.2",
"@cornerstonejs/codec-openjph": "^2.4.2",
"@cornerstonejs/dicom-image-loader": "^1.1.8",
"@ohif/core": "3.7.0-beta.2",
"@ohif/ui": "3.7.0-beta.2",
"@cornerstonejs/dicom-image-loader": "^1.4.1",
"@ohif/core": "3.7.0-beta.27",
"@ohif/ui": "3.7.0-beta.27",
"dcmjs": "^0.29.6",
"dicom-parser": "^1.8.21",
"hammerjs": "^2.0.8",
@@ -52,10 +52,10 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^1.1.8",
"@cornerstonejs/core": "^1.1.8",
"@cornerstonejs/streaming-image-volume-loader": "^1.1.8",
"@cornerstonejs/tools": "^1.1.8",
"@cornerstonejs/adapters": "^1.4.1",
"@cornerstonejs/core": "^1.4.1",
"@cornerstonejs/streaming-image-volume-loader": "^1.4.1",
"@cornerstonejs/tools": "^1.4.1",
"@kitware/vtk.js": "27.3.1",
"html2canvas": "^1.4.1",
"lodash.debounce": "4.0.8",
@@ -119,6 +119,7 @@ const OHIFCornerstoneViewport = React.memo(props => {
servicesManager,
onElementEnabled,
onElementDisabled,
isJumpToMeasurementDisabled,
// Note: you SHOULD NOT use the initialImageIdOrIndex for manipulation
// of the imageData in the OHIFCornerstoneViewport. This prop is used
// to set the initial state of the viewport's first image to render
@@ -454,6 +455,10 @@ const OHIFCornerstoneViewport = React.memo(props => {
* the cache for jumping to see if there is any jump queued, then we jump to the correct slice.
*/
useEffect(() => {
if (isJumpToMeasurementDisabled) {
return;
}
const unsubscribeFromJumpToMeasurementEvents = _subscribeToJumpToMeasurementEvents(
measurementService,
displaySetService,
@@ -716,6 +721,10 @@ function _jumpToMeasurement(
// Component displayName
OHIFCornerstoneViewport.displayName = 'OHIFCornerstoneViewport';
OHIFCornerstoneViewport.defaultProps = {
isJumpToMeasurementDisabled: false,
};
OHIFCornerstoneViewport.propTypes = {
viewportIndex: PropTypes.number.isRequired,
displaySets: PropTypes.array.isRequired,
@@ -724,6 +733,7 @@ OHIFCornerstoneViewport.propTypes = {
displaySetOptions: PropTypes.arrayOf(PropTypes.any),
servicesManager: PropTypes.object.isRequired,
onElementEnabled: PropTypes.func,
isJumpToMeasurementDisabled: PropTypes.bool,
// Note: you SHOULD NOT use the initialImageIdOrIndex for manipulation
// of the imageData in the OHIFCornerstoneViewport. This prop is used
// to set the initial state of the viewport's first image to render
@@ -379,7 +379,7 @@ function _getViewportInstance(viewportData, imageIndex) {
if (viewportData.viewportType === Enums.ViewportType.STACK) {
imageId = viewportData.data.imageIds[imageIndex];
} else if (viewportData.viewportType === Enums.ViewportType.ORTHOGRAPHIC) {
const volumes = viewportData.volumes;
const volumes = viewportData.data;
if (volumes && volumes.length == 1) {
const volume = volumes[0];
imageId = volume.imageIds[imageIndex];
+3 -5
View File
@@ -457,11 +457,9 @@ function commandsModule({
const { viewport } = enabledElement;
if (viewport instanceof StackViewport) {
const { invert } = viewport.getProperties();
viewport.setProperties({ invert: !invert });
viewport.render();
}
const { invert } = viewport.getProperties();
viewport.setProperties({ invert: !invert });
viewport.render();
},
resetViewport: () => {
const enabledElement = _getActiveViewportEnabledElement();
@@ -5,7 +5,7 @@ import PropTypes from 'prop-types';
import classNames from 'classnames';
import DicomFileUploader from '../../utils/DicomFileUploader';
import DicomUploadProgress from './DicomUploadProgress';
import { Button } from '@ohif/ui';
import { Button, ButtonEnums } from '@ohif/ui';
import './DicomUpload.css';
type DicomUploadProps = {
@@ -46,12 +46,7 @@ function DicomUpload({
<Dropzone onDrop={onDrop} noDrag>
{({ getRootProps, getInputProps }) => (
<div {...getRootProps()}>
<Button
variant="contained"
color="primary"
disabled={false}
onClick={() => {}}
>
<Button disabled={false} onClick={() => {}}>
{'Add files'}
<input {...getInputProps()} />
</Button>
@@ -62,9 +57,7 @@ function DicomUpload({
{({ getRootProps, getInputProps }) => (
<div {...getRootProps()}>
<Button
variant="contained"
color="primaryDark"
border="primaryActive"
type={ButtonEnums.type.secondary}
disabled={false}
onClick={() => {}}
>
@@ -308,13 +308,7 @@ function DicomUploadProgress({
} ${
dicomFileUploaderArr.length > 1 ? 'files' : 'file'
} completed.`}</span>
<Button
variant="contained"
color="primary"
disabled={false}
className="ml-auto"
onClick={onComplete}
>
<Button disabled={false} className="ml-auto" onClick={onComplete}>
{'Close'}
</Button>
</>
@@ -27,7 +27,6 @@ const DicomUploadProgressItem = memo(
const [failedReason, setFailedReason] = useState('');
const [status, setStatus] = useState(dicomFileUploader.getStatus());
console.info(`${dicomFileUploader.getFileId()}`);
const isComplete = useCallback(() => {
return (
status === UploadStatus.Failed ||
-1
View File
@@ -24,7 +24,6 @@ import { toolNames } from './initCornerstoneTools';
import { getEnabledElement, reset as enabledElementReset } from './state';
import dicomLoaderService from './utils/dicomLoaderService';
import getActiveViewportEnabledElement from './utils/getActiveViewportEnabledElement';
import { registerColormap } from './utils/colormap/transferFunctionHelpers';
import { id } from './id';
import * as csWADOImageLoader from './initWADOImageLoader.js';
+3 -5
View File
@@ -26,6 +26,7 @@ import nthLoader from './utils/nthLoader';
import interleaveTopToBottom from './utils/interleaveTopToBottom';
import initContextMenu from './initContextMenu';
import initDoubleClick from './initDoubleClick';
import { CornerstoneServices } from './types';
// TODO: Cypress tests are currently grabbing this from the window?
window.cornerstone = cornerstone;
@@ -69,10 +70,7 @@ export default async function init({
const {
userAuthenticationService,
measurementService,
customizationService,
displaySetService,
uiDialogService,
uiModalService,
uiNotificationService,
cineService,
@@ -81,7 +79,7 @@ export default async function init({
toolGroupService,
viewportGridService,
stateSyncService,
} = servicesManager.services;
} = servicesManager.services as CornerstoneServices;
window.services = servicesManager.services;
window.extensionManager = extensionManager;
@@ -166,7 +164,7 @@ export default async function init({
prefetch: appConfig?.maxNumRequests?.prefetch || 10,
};
initWADOImageLoader(userAuthenticationService, appConfig);
initWADOImageLoader(userAuthenticationService, appConfig, extensionManager);
/* Measurement Service */
this.measurementServiceSource = connectToolsToMeasurementService(
@@ -5,7 +5,7 @@ import dicomImageLoader, {
webWorkerManager,
} from '@cornerstonejs/dicom-image-loader';
import dicomParser from 'dicom-parser';
import { errorHandler } from '@ohif/core';
import { errorHandler, utils } from '@ohif/core';
const { registerVolumeLoader } = volumeLoader;
@@ -35,7 +35,8 @@ function initWebWorkers(appConfig) {
export default function initWADOImageLoader(
userAuthenticationService,
appConfig
appConfig,
extensionManager
) {
dicomImageLoader.external.cornerstone = cornerstone;
dicomImageLoader.external.dicomParser = dicomParser;
@@ -55,18 +56,18 @@ export default function initWADOImageLoader(
convertFloatPixelDataToInt: false,
},
beforeSend: function(xhr) {
//TODO should be removed in the future and request emitted by DicomWebDataSource
const sourceConfig =
extensionManager.getActiveDataSource()?.[0].getConfig() ?? {};
const headers = userAuthenticationService.getAuthorizationHeader();
const acceptHeader = utils.generateAcceptHeader(
sourceConfig.acceptHeader,
sourceConfig.requestTransferSyntaxUID,
sourceConfig.omitQuotationForMultipartRequest
);
// Request:
// JPEG-LS Lossless (1.2.840.10008.1.2.4.80) if available, otherwise accept
// whatever transfer-syntax the origin server provides.
// For now we use image/jls and image/x-jls because some servers still use the old type
// http://dicom.nema.org/medical/dicom/current/output/html/part18.html
const xhrRequestHeaders = {
Accept: appConfig.omitQuotationForMultipartRequest
? 'multipart/related; type=application/octet-stream'
: 'multipart/related; type="application/octet-stream"',
// 'multipart/related; type="image/x-jls", multipart/related; type="image/jls"; transfer-syntax="1.2.840.10008.1.2.4.80", multipart/related; type="image/x-jls", multipart/related; type="application/octet-stream"; transfer-syntax=*',
Accept: acceptHeader,
};
if (headers) {
@@ -542,6 +542,7 @@ class SegmentationService extends PubSubService {
id: segmentationId,
displaySetInstanceUID: segDisplaySet.displaySetInstanceUID,
type: representationType,
label: segDisplaySet.SeriesDescription,
representationData: {
[LABELMAP]: {
volumeId: segmentationId,
@@ -789,6 +790,7 @@ class SegmentationService extends PubSubService {
id: segmentationId,
displaySetInstanceUID: rtDisplaySetUID,
type: representationType,
label: rtDisplaySet.SeriesDescription,
representationData: {
[CONTOUR]: {
geometryIds,
@@ -816,45 +818,54 @@ class SegmentationService extends PubSubService {
const segmentsCachedStats = {};
const initializeContour = async rtStructData => {
const { data, id, color, segmentIndex, geometryId } = rtStructData;
const geometry = await geometryLoader.createAndCacheGeometry(geometryId, {
geometryData: {
data,
id,
color,
frameOfReferenceUID: structureSet.frameOfReferenceUID,
// catch error instead of failing to allow loading to continue
try {
const geometry = await geometryLoader.createAndCacheGeometry(
geometryId,
{
geometryData: {
data,
id,
color,
frameOfReferenceUID: structureSet.frameOfReferenceUID,
segmentIndex,
},
type: csEnums.GeometryType.CONTOUR,
}
);
const contourSet = geometry.data;
const centroid = contourSet.getCentroid();
segmentsCachedStats[segmentIndex] = {
center: { world: centroid },
modifiedTime: rtDisplaySet.SeriesDate, // we use the SeriesDate as the modifiedTime since this is the first time we are creating the segmentation
};
segmentation.segments[segmentIndex] = {
label: id,
segmentIndex,
},
type: csEnums.GeometryType.CONTOUR,
});
color,
...SEGMENT_CONSTANT,
};
const contourSet = geometry.data;
const centroid = contourSet.getCentroid();
const numInitialized = Object.keys(segmentsCachedStats).length;
segmentsCachedStats[segmentIndex] = {
center: { world: centroid },
modifiedTime: rtDisplaySet.SeriesDate, // we use the SeriesDate as the modifiedTime since this is the first time we are creating the segmentation
};
// Calculate percentage completed
const percentComplete = Math.round(
(numInitialized / allRTStructData.length) * 100
);
segmentation.segments[segmentIndex] = {
label: id,
segmentIndex,
color,
...SEGMENT_CONSTANT,
};
const numInitialized = Object.keys(segmentsCachedStats).length;
// Calculate percentage completed
const percentComplete = Math.round(
(numInitialized / allRTStructData.length) * 100
);
this._broadcastEvent(EVENTS.SEGMENT_LOADING_COMPLETE, {
percentComplete,
// Note: this is not the geometryIds length since there might be
// some missing ROINumbers
numSegments: allRTStructData.length,
});
this._broadcastEvent(EVENTS.SEGMENT_LOADING_COMPLETE, {
percentComplete,
// Note: this is not the geometryIds length since there might be
// some missing ROINumbers
numSegments: allRTStructData.length,
});
} catch (e) {
console.warn(e);
}
};
const promiseArray = [];
@@ -15,7 +15,7 @@ const EVENTS = {
* sync group declared.
*/
export type SyncCreator = (
type: string,
id: string,
options?: Record<string, unknown>
) => Synchronizer;
@@ -83,7 +83,7 @@ export default class SyncGroupService {
* @param type is the type of the synchronizer to create
* @param creator
*/
public setSynchronizer(type: string, creator: SyncCreator): void {
public addSynchronizerType(type: string, creator: SyncCreator): void {
this.synchronizerCreators[type.toLowerCase()] = creator;
}
@@ -745,7 +745,7 @@ class CornerstoneViewportService extends PubSubService
const viewport = this.getCornerstoneViewport(viewportId);
const viewportCamera = viewport.getCamera();
if (viewport instanceof VolumeViewport) {
if (viewport instanceof VolumeViewport || viewport instanceof VolumeViewport3D) {
this._setVolumeViewport(viewport, viewportData, viewportInfo).then(() => {
if (keepCamera) {
viewport.setCamera(viewportCamera);
@@ -198,7 +198,9 @@ class ViewportInfo {
// via cornerstoneViewportService
let viewportData = this.getViewportData();
if (viewportData.viewportType === Enums.ViewportType.ORTHOGRAPHIC) {
if (viewportData.viewportType === Enums.ViewportType.ORTHOGRAPHIC ||
viewportData.viewportType === Enums.ViewportType.VOLUME_3D
) {
viewportData = viewportData as VolumeViewportData;
return viewportData.data.some(
({ displaySetInstanceUID: dsUID }) => dsUID === displaySetInstanceUID
@@ -1,9 +1,9 @@
import { Types } from '@ohif/core';
import ToolGroupService from './services/ToolGroupService';
import SyncGroupService from './services/SyncGroupService';
import SegmentationService from './services/SegmentationService';
import CornerstoneCacheService from './services/CornerstoneCacheService';
import CornerstoneViewportService from './services/ViewportService/CornerstoneViewportService';
import ToolGroupService from '../services/ToolGroupService';
import SyncGroupService from '../services/SyncGroupService';
import SegmentationService from '../services/SegmentationService';
import CornerstoneCacheService from '../services/CornerstoneCacheService';
import CornerstoneViewportService from '../services/ViewportService/CornerstoneViewportService';
interface CornerstoneServices extends Types.Services {
cornerstoneViewportService: CornerstoneViewportService;
@@ -1,5 +1,5 @@
import React from 'react';
import { Input, Dialog } from '@ohif/ui';
import { Input, Dialog, ButtonEnums } from '@ohif/ui';
/**
*
@@ -60,8 +60,8 @@ function callInputDialog(
noCloseButton: true,
onClose: () => uiDialogService.dismiss({ id: dialogId }),
actions: [
{ id: 'cancel', text: 'Cancel', type: 'primary' },
{ id: 'save', text: 'Save', type: 'secondary' },
{ id: 'cancel', text: 'Cancel', type: ButtonEnums.type.secondary },
{ id: 'save', text: 'Save', type: ButtonEnums.type.primary },
],
onSubmit: onSubmitHandler,
body: ({ value, setValue }) => {
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-default",
"version": "3.7.0-beta.2",
"version": "3.7.0-beta.27",
"description": "Common/default features and functionality for basic image viewing",
"author": "OHIF Core Team",
"license": "MIT",
@@ -30,8 +30,8 @@
"start": "yarn run dev"
},
"peerDependencies": {
"@ohif/core": "3.7.0-beta.2",
"@ohif/i18n": "3.7.0-beta.2",
"@ohif/core": "3.7.0-beta.27",
"@ohif/i18n": "3.7.0-beta.27",
"dcmjs": "^0.29.5",
"dicomweb-client": "^0.10.2",
"prop-types": "^15.6.2",
@@ -60,15 +60,42 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
supportsReject,
staticWado,
singlepart,
omitQuotationForMultipartRequest,
acceptHeader,
requestTransferSyntaxUID,
} = dicomWebConfig;
const dicomWebConfigCopy = JSON.parse(JSON.stringify(dicomWebConfig));
const getAuthrorizationHeader = () => {
const xhrRequestHeaders = {};
const authHeaders = userAuthenticationService.getAuthorizationHeader();
if (authHeaders && authHeaders.Authorization) {
xhrRequestHeaders.Authorization = authHeaders.Authorization;
}
return xhrRequestHeaders;
};
const generateWadoHeader = () => {
let authorizationHeader = getAuthrorizationHeader();
//Generate accept header depending on config params
let formattedAcceptHeader = utils.generateAcceptHeader(
acceptHeader,
requestTransferSyntaxUID,
omitQuotationForMultipartRequest
);
return {
...authorizationHeader,
Accept: formattedAcceptHeader,
};
};
const qidoConfig = {
url: qidoRoot,
staticWado,
singlepart,
headers: userAuthenticationService.getAuthorizationHeader(),
headers: getAuthrorizationHeader(),
errorInterceptor: errorHandler.getHTTPErrorHandler(),
};
@@ -76,7 +103,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
url: wadoRoot,
staticWado,
singlepart,
headers: userAuthenticationService.getAuthorizationHeader(),
headers: generateWadoHeader(),
errorInterceptor: errorHandler.getHTTPErrorHandler(),
};
@@ -110,11 +137,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
studies: {
mapParams: mapParams.bind(),
search: async function(origParams) {
const headers = userAuthenticationService.getAuthorizationHeader();
if (headers) {
qidoDicomWebClient.headers = headers;
}
qidoDicomWebClient.headers = getAuthrorizationHeader();
const { studyInstanceUid, seriesInstanceUid, ...mappedParams } =
mapParams(origParams, {
supportsFuzzyMatching,
@@ -135,11 +158,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
series: {
// mapParams: mapParams.bind(),
search: async function(studyInstanceUid) {
const headers = userAuthenticationService.getAuthorizationHeader();
if (headers) {
qidoDicomWebClient.headers = headers;
}
qidoDicomWebClient.headers = getAuthrorizationHeader();
const results = await seriesInStudy(
qidoDicomWebClient,
studyInstanceUid
@@ -151,11 +170,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
},
instances: {
search: (studyInstanceUid, queryParameters) => {
const headers = userAuthenticationService.getAuthorizationHeader();
if (headers) {
qidoDicomWebClient.headers = headers;
}
qidoDicomWebClient.headers = getAuthrorizationHeader();
qidoSearch.call(
undefined,
qidoDicomWebClient,
@@ -182,6 +197,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
return getDirectURL({ wadoRoot, singlepart }, params);
},
bulkDataURI: async ({ StudyInstanceUID, BulkDataURI }) => {
qidoDicomWebClient.headers = getAuthrorizationHeader();
const options = {
multipart: false,
BulkDataURI,
@@ -200,11 +216,6 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
sortFunction,
madeInClient = false,
} = {}) => {
const headers = userAuthenticationService.getAuthorizationHeader();
if (headers) {
wadoDicomWebClient.headers = headers;
}
if (!StudyInstanceUID) {
throw new Error(
'Unable to query for SeriesMetadata without StudyInstanceUID'
@@ -234,17 +245,12 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
store: {
dicom: async (dataset, request) => {
const headers = userAuthenticationService.getAuthorizationHeader();
if (headers) {
wadoDicomWebClient.headers = headers;
}
wadoDicomWebClient.headers = getAuthrorizationHeader();
if (dataset instanceof ArrayBuffer) {
const options = {
datasets: [dataset],
request,
};
await wadoDicomWebClient.storeInstances(options);
} else {
const meta = {
@@ -282,7 +288,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
madeInClient
) => {
const enableStudyLazyLoad = false;
wadoDicomWebClient.headers = generateWadoHeader();
// data is all SOPInstanceUIDs
const data = await retrieveStudyMetadata(
wadoDicomWebClient,
@@ -353,6 +359,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
madeInClient = false
) => {
const enableStudyLazyLoad = true;
wadoDicomWebClient.headers = generateWadoHeader();
// Get Series
const {
preLoadData: seriesSummaryMetadata,
@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next';
import { Button, ButtonGroup } from '@ohif/ui';
import { LegacyButton, ButtonGroup } from '@ohif/ui';
function ActionButtons({ onExportClick, onCreateReportClick }) {
const { t } = useTranslation('MeasurementTable');
@@ -10,12 +10,16 @@ function ActionButtons({ onExportClick, onCreateReportClick }) {
return (
<React.Fragment>
<ButtonGroup color="black" size="inherit">
<Button className="px-2 py-2 text-base" onClick={onExportClick}>
{/* TODO Revisit design of ButtonGroup later - for now use LegacyButton for its children.*/}
<LegacyButton className="px-2 py-2 text-base" onClick={onExportClick}>
{t('Export CSV')}
</Button>
<Button className="px-2 py-2 text-base" onClick={onCreateReportClick}>
</LegacyButton>
<LegacyButton
className="px-2 py-2 text-base"
onClick={onCreateReportClick}
>
{t('Create Report')}
</Button>
</LegacyButton>
</ButtonGroup>
</React.Fragment>
);
@@ -3,7 +3,7 @@ import classnames from 'classnames';
import { useNavigate } from 'react-router-dom';
import { useAppConfig } from '@state';
import { Button } from '@ohif/ui';
import { Button, ButtonEnums } from '@ohif/ui';
function DataSourceSelector() {
const [appConfig] = useAppConfig();
@@ -33,7 +33,8 @@ function DataSourceSelector() {
<div key={ds.sourceName}>
<h1 className="text-white">{ds.friendlyName}</h1>
<Button
className={classnames('font-bold', 'ml-2')}
type={ButtonEnums.type.primary}
className={classnames('ml-2')}
onClick={() => {
navigate({
pathname: '/',
@@ -1,7 +1,13 @@
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { utils, ServicesManager } from '@ohif/core';
import { MeasurementTable, Dialog, Input, useViewportGrid } from '@ohif/ui';
import {
MeasurementTable,
Dialog,
Input,
useViewportGrid,
ButtonEnums,
} from '@ohif/ui';
import ActionButtons from './ActionButtons';
import debounce from 'lodash.debounce';
@@ -189,9 +195,8 @@ export default function PanelMeasurementTable({
);
},
actions: [
// temp: swap button types until colors are updated
{ id: 'cancel', text: 'Cancel', type: 'primary' },
{ id: 'save', text: 'Save', type: 'secondary' },
{ id: 'cancel', text: 'Cancel', type: ButtonEnums.type.secondary },
{ id: 'save', text: 'Save', type: ButtonEnums.type.primary },
],
onSubmit: onSubmitHandler,
},
@@ -1,6 +1,6 @@
/* eslint-disable react/display-name */
import React from 'react';
import { Dialog, Input, Select } from '@ohif/ui';
import { ButtonEnums, Dialog, Input, Select } from '@ohif/ui';
export const CREATE_REPORT_DIALOG_RESPONSE = {
CANCEL: 0,
@@ -81,8 +81,8 @@ export default function createReportDialogPrompt(
noCloseButton: true,
onClose: _handleClose,
actions: [
{ id: 'cancel', text: 'Cancel', type: 'primary' },
{ id: 'save', text: 'Save', type: 'secondary' },
{ id: 'cancel', text: 'Cancel', type: ButtonEnums.type.secondary },
{ id: 'save', text: 'Save', type: ButtonEnums.type.primary },
],
// TODO: Should be on button press...
onSubmit: _handleFormSubmit,
+1 -1
View File
@@ -29,7 +29,7 @@ export default function Toolbar({ servicesManager }) {
return (
<>
{toolbarButtons.map((toolDef, index) => {
{toolbarButtons.map(toolDef => {
const { id, Component, componentProps } = toolDef;
// TODO: ...
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-dicom-microscopy",
"version": "3.7.0-beta.2",
"version": "3.7.0-beta.27",
"description": "OHIF extension for DICOM microscopy",
"author": "Bill Wallace, md-prog",
"license": "MIT",
@@ -28,10 +28,10 @@
"start": "yarn run dev"
},
"peerDependencies": {
"@ohif/core": "3.7.0-beta.2",
"@ohif/extension-default": "3.7.0-beta.2",
"@ohif/i18n": "3.7.0-beta.2",
"@ohif/ui": "3.7.0-beta.2",
"@ohif/core": "3.7.0-beta.27",
"@ohif/extension-default": "3.7.0-beta.27",
"@ohif/i18n": "3.7.0-beta.27",
"@ohif/ui": "3.7.0-beta.27",
"prop-types": "^15.6.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
@@ -1,5 +1,5 @@
import React from 'react';
import { Input, Dialog } from '@ohif/ui';
import { Input, Dialog, ButtonEnums } from '@ohif/ui';
/**
*
@@ -14,7 +14,7 @@ export default function callInputDialog({
uiDialogService,
title = 'Annotation',
defaultValue = '',
callback = (value: string, action: string) => {}
callback = (value: string, action: string) => {},
}) {
const dialogId = 'microscopy-input-dialog';
@@ -43,8 +43,8 @@ export default function callInputDialog({
noCloseButton: true,
onClose: () => uiDialogService.dismiss({ id: dialogId }),
actions: [
{ id: 'cancel', text: 'Cancel', type: 'primary' },
{ id: 'save', text: 'Save', type: 'secondary' },
{ id: 'cancel', text: 'Cancel', type: ButtonEnums.type.secondary },
{ id: 'save', text: 'Save', type: ButtonEnums.type.primary },
],
onSubmit: onSubmitHandler,
body: ({ value, setValue }) => {
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-dicom-pdf",
"version": "3.7.0-beta.2",
"version": "3.7.0-beta.27",
"description": "OHIF extension for PDF display",
"author": "OHIF",
"license": "MIT",
@@ -28,8 +28,8 @@
"test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests"
},
"peerDependencies": {
"@ohif/core": "3.7.0-beta.2",
"@ohif/ui": "3.7.0-beta.2",
"@ohif/core": "3.7.0-beta.27",
"@ohif/ui": "3.7.0-beta.27",
"dcmjs": "^0.29.5",
"dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8",
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-dicom-video",
"version": "3.7.0-beta.2",
"version": "3.7.0-beta.27",
"description": "OHIF extension for video display",
"author": "OHIF",
"license": "MIT",
@@ -28,8 +28,8 @@
"test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests"
},
"peerDependencies": {
"@ohif/core": "3.7.0-beta.2",
"@ohif/ui": "3.7.0-beta.2",
"@ohif/core": "3.7.0-beta.27",
"@ohif/ui": "3.7.0-beta.27",
"dcmjs": "^0.29.5",
"dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8",
+7 -7
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-measurement-tracking",
"version": "3.7.0-beta.2",
"version": "3.7.0-beta.27",
"description": "Tracking features and functionality for basic image viewing",
"author": "OHIF Core Team",
"license": "MIT",
@@ -30,11 +30,11 @@
"start": "yarn run dev"
},
"peerDependencies": {
"@cornerstonejs/core": "^1.1.8",
"@cornerstonejs/tools": "^1.1.8",
"@ohif/core": "3.7.0-beta.2",
"@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.2",
"@ohif/ui": "3.7.0-beta.2",
"@cornerstonejs/core": "^1.4.1",
"@cornerstonejs/tools": "^1.4.1",
"@ohif/core": "3.7.0-beta.27",
"@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.27",
"@ohif/ui": "3.7.0-beta.27",
"classnames": "^2.3.2",
"dcmjs": "^0.29.5",
"lodash.debounce": "^4.17.21",
@@ -46,7 +46,7 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@ohif/ui": "3.7.0-beta.2",
"@ohif/ui": "3.7.0-beta.27",
"@xstate/react": "^0.8.1",
"xstate": "^4.10.0"
}
@@ -1,6 +1,6 @@
/* eslint-disable react/display-name */
import React from 'react';
import { Dialog, Input } from '@ohif/ui';
import { ButtonEnums, Dialog, Input } from '@ohif/ui';
import RESPONSE from './PROMPT_RESPONSES';
export default function createReportDialogPrompt(uiDialogService) {
@@ -20,12 +20,19 @@ export default function createReportDialogPrompt(uiDialogService) {
* @param {string} param0.value - value from input field
*/
const _handleFormSubmit = ({ action, value }) => {
uiDialogService.dismiss({ id: dialogId });
switch (action.id) {
case 'save':
resolve({ action: RESPONSE.CREATE_REPORT, value: value.label });
// Only save if description is not blank otherwise ignore
if (value.label && value.label.trim() !== '') {
resolve({
action: RESPONSE.CREATE_REPORT,
value: value.label.trim(),
});
uiDialogService.dismiss({ id: dialogId });
}
break;
case 'cancel':
uiDialogService.dismiss({ id: dialogId });
resolve({ action: RESPONSE.CANCEL, value: undefined });
break;
}
@@ -43,8 +50,8 @@ export default function createReportDialogPrompt(uiDialogService) {
noCloseButton: true,
onClose: _handleClose,
actions: [
{ id: 'cancel', text: 'Cancel', type: 'primary' },
{ id: 'save', text: 'Save', type: 'secondary' },
{ id: 'cancel', text: 'Cancel', type: ButtonEnums.type.secondary },
{ id: 'save', text: 'Save', type: ButtonEnums.type.primary },
],
// TODO: Should be on button press...
onSubmit: _handleFormSubmit,
@@ -55,8 +62,8 @@ export default function createReportDialogPrompt(uiDialogService) {
};
const onKeyPressHandler = event => {
if (event.key === 'Enter') {
uiDialogService.dismiss({ id: dialogId });
resolve({ action: RESPONSE.CREATE_REPORT, value: value.label });
// Trigger form submit
_handleFormSubmit({ action: { id: 'save' }, value });
}
};
return (
@@ -1,3 +1,5 @@
import { ButtonEnums } from '@ohif/ui';
const RESPONSE = {
NO_NEVER: -1,
CANCEL: 0,
@@ -31,19 +33,19 @@ function _askTrackMeasurements(uiViewportDialogService, viewportIndex) {
const actions = [
{
id: 'prompt-begin-tracking-cancel',
type: 'cancel',
type: ButtonEnums.type.secondary,
text: 'No',
value: RESPONSE.CANCEL,
},
{
id: 'prompt-begin-tracking-no-do-not-ask-again',
type: 'secondary',
type: ButtonEnums.type.secondary,
text: 'No, do not ask again',
value: RESPONSE.NO_NEVER,
},
{
id: 'prompt-begin-tracking-yes',
type: 'primary',
type: ButtonEnums.type.primary,
text: 'Yes',
value: RESPONSE.SET_STUDY_AND_SERIES,
},
@@ -1,4 +1,5 @@
import { hydrateStructuredReport } from '@ohif/extension-cornerstone-dicom-sr';
import { ButtonEnums } from '@ohif/ui';
const RESPONSE = {
NO_NEVER: -1,
@@ -61,12 +62,12 @@ function _askTrackMeasurements(uiViewportDialogService, viewportIndex) {
'Do you want to continue tracking measurements for this study?';
const actions = [
{
type: 'secondary',
type: ButtonEnums.type.secondary,
text: 'No',
value: RESPONSE.CANCEL,
},
{
type: 'primary',
type: ButtonEnums.type.primary,
text: 'Yes',
value: RESPONSE.HYDRATE_REPORT,
},
@@ -1,3 +1,5 @@
import { ButtonEnums } from '@ohif/ui';
const RESPONSE = {
NO_NEVER: -1,
CANCEL: 0,
@@ -38,14 +40,18 @@ function _askShouldAddMeasurements(uiViewportDialogService, viewportIndex) {
const message =
'Do you want to add this measurement to the existing report?';
const actions = [
{ type: 'cancel', text: 'Cancel', value: RESPONSE.CANCEL },
{
type: 'secondary',
type: ButtonEnums.type.secondary,
text: 'Cancel',
value: RESPONSE.CANCEL,
},
{
type: ButtonEnums.type.primary,
text: 'Create new report',
value: RESPONSE.CREATE_REPORT,
},
{
type: 'primary',
type: ButtonEnums.type.primary,
text: 'Add to existing report',
value: RESPONSE.ADD_SERIES,
},
@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next';
import { Button, ButtonGroup } from '@ohif/ui';
import { Button, ButtonEnums } from '@ohif/ui';
function ActionButtons({ onExportClick, onCreateReportClick, disabled }) {
const { t } = useTranslation('MeasurementTable');
@@ -10,23 +10,18 @@ function ActionButtons({ onExportClick, onCreateReportClick, disabled }) {
return (
<React.Fragment>
<Button
className="text-base px-2 py-2"
size="initial"
variant={disabled ? 'disabled' : 'outlined'}
color="black"
border="primaryActive"
onClick={onExportClick}
disabled={disabled}
type={ButtonEnums.type.secondary}
size={ButtonEnums.size.small}
>
{t('Export')}
</Button>
<Button
className="ml-2 px-2 text-base"
variant={disabled ? 'disabled' : 'outlined'}
size="initial"
color="black"
border="primaryActive"
className="ml-2"
onClick={onCreateReportClick}
type={ButtonEnums.type.secondary}
size={ButtonEnums.size.small}
disabled={disabled}
>
{t('Create Report')}
@@ -6,6 +6,7 @@ import {
Dialog,
Input,
useViewportGrid,
ButtonEnums,
} from '@ohif/ui';
import { DicomMetadataStore, utils } from '@ohif/core';
import { useDebounce } from '@hooks';
@@ -217,9 +218,8 @@ function PanelMeasurementTableTracking({ servicesManager, extensionManager }) {
);
},
actions: [
// temp: swap button types until colors are updated
{ id: 'cancel', text: 'Cancel', type: 'primary' },
{ id: 'save', text: 'Save', type: 'secondary' },
{ id: 'cancel', text: 'Cancel', type: ButtonEnums.type.secondary },
{ id: 'save', text: 'Save', type: ButtonEnums.type.primary },
],
onSubmit: onSubmitHandler,
},
@@ -1,4 +1,5 @@
import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import PropTypes from 'prop-types';
import { utils } from '@ohif/core';
import {
@@ -6,6 +7,7 @@ import {
useImageViewer,
useViewportGrid,
Dialog,
ButtonEnums,
} from '@ohif/ui';
import { useTrackedMeasurements } from '../../getContextModule';
@@ -30,6 +32,8 @@ function PanelStudyBrowserTracking({
uiNotificationService,
} = servicesManager.services;
const { t } = useTranslation('Common');
// Normally you nest the components so the tree isn't so deep, and the data
// doesn't have to have such an intense shape. This works well enough for now.
// Tabs --> Studies --> DisplaySets --> Thumbnails
@@ -133,7 +137,7 @@ function PanelStudyBrowserTracking({
const actuallyMappedStudies = mappedStudies.map(qidoStudy => {
return {
studyInstanceUid: qidoStudy.StudyInstanceUID,
date: formatDate(qidoStudy.StudyDate),
date: formatDate(qidoStudy.StudyDate) || t('NoStudyDate'),
description: qidoStudy.StudyDescription,
modalities: qidoStudy.ModalitiesInStudy,
numInstances: qidoStudy.NumInstances,
@@ -507,11 +511,15 @@ function _mapDisplaySets(
</div>
),
actions: [
{ id: 'cancel', text: 'Cancel', type: 'secondary' },
{
id: 'cancel',
text: 'Cancel',
type: ButtonEnums.type.secondary,
},
{
id: 'yes',
text: 'Yes',
type: 'primary',
type: ButtonEnums.type.primary,
classes: ['reject-yes-button'],
},
],
@@ -22,7 +22,7 @@ function TrackedCornerstoneViewport(props) {
viewportOptions,
} = props;
const { t } = useTranslation('TrackedViewport');
const { t } = useTranslation('Common');
const {
measurementService,
@@ -54,6 +54,7 @@ function TrackedCornerstoneViewport(props) {
PatientAge,
SliceThickness,
SpacingBetweenSlices,
StudyDate,
ManufacturerModelName,
} = displaySet.images[0];
@@ -194,7 +195,8 @@ function TrackedCornerstoneViewport(props) {
getStatusComponent={() => _getStatusComponent(isTracked)}
studyData={{
label: viewportLabel,
studyDate: formatDate(SeriesDate), // TODO: This is series date. Is that ok?
studyDate:
formatDate(SeriesDate) || formatDate(StudyDate) || t('NoStudyDate'),
currentSeries: SeriesNumber, // TODO - switch entire currentSeries to be UID based or actual position based
seriesDescription: SeriesDescription,
patientInformation: {
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-test",
"version": "3.7.0-beta.2",
"version": "3.7.0-beta.27",
"description": "OHIF extension used inside e2e testing",
"author": "OHIF",
"license": "MIT",
@@ -28,8 +28,8 @@
"test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests"
},
"peerDependencies": {
"@ohif/core": "3.7.0-beta.2",
"@ohif/ui": "3.7.0-beta.2",
"@ohif/core": "3.7.0-beta.27",
"@ohif/ui": "3.7.0-beta.27",
"dcmjs": "0.29.4",
"dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8",
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-tmtv",
"version": "3.7.0-beta.2",
"version": "3.7.0-beta.27",
"description": "OHIF extension for Total Metabolic Tumor Volume",
"author": "OHIF",
"license": "MIT",
@@ -28,8 +28,8 @@
"test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests"
},
"peerDependencies": {
"@ohif/core": "3.7.0-beta.2",
"@ohif/ui": "3.7.0-beta.2",
"@ohif/core": "3.7.0-beta.27",
"@ohif/ui": "3.7.0-beta.27",
"dcmjs": "^0.29.5",
"dicom-parser": "^1.8.9",
"hammerjs": "^2.0.8",
+1 -3
View File
@@ -225,9 +225,7 @@ export default function PanelPetSUV({ servicesManager, commandsManager }) {
value={metadata.SeriesTime || ''}
onChange={() => {}}
/>
<Button color="primary" onClick={updateMetadata}>
Reload Data
</Button>
<Button onClick={updateMetadata}>Reload Data</Button>
</div>
</div>
}
@@ -1,5 +1,5 @@
import React from 'react';
import { Button, ButtonGroup } from '@ohif/ui';
import { LegacyButton, ButtonGroup } from '@ohif/ui';
import { useTranslation } from 'react-i18next';
function ExportReports({ segmentations, tmtvValue, config, commandsManager }) {
@@ -9,8 +9,9 @@ function ExportReports({ segmentations, tmtvValue, config, commandsManager }) {
<>
{segmentations?.length ? (
<div className="flex justify-center mt-4 space-x-2">
{/* TODO Revisit design of ButtonGroup later - for now use LegacyButton for its children.*/}
<ButtonGroup color="black" size="inherit">
<Button
<LegacyButton
className="px-2 py-2 text-base"
disabled={tmtvValue === null}
onClick={() => {
@@ -22,10 +23,10 @@ function ExportReports({ segmentations, tmtvValue, config, commandsManager }) {
}}
>
{t('Export CSV')}
</Button>
</LegacyButton>
</ButtonGroup>
<ButtonGroup color="black" size="inherit">
<Button
<LegacyButton
className="px-2 py-2 text-base"
onClick={() => {
commandsManager.runCommand('createTMTVRTReport');
@@ -33,7 +34,7 @@ function ExportReports({ segmentations, tmtvValue, config, commandsManager }) {
disabled={tmtvValue === null}
>
{t('Create RT Report')}
</Button>
</LegacyButton>
</ButtonGroup>
</div>
) : null}
@@ -181,7 +181,6 @@ export default function PanelRoiThresholdSegmentation({
<div className="overflow-x-hidden overflow-y-auto invisible-scrollbar">
<div className="flex mx-4 my-4 mb-4 space-x-4">
<Button
color="primary"
onClick={() => {
setLabelmapLoading(true);
setTimeout(() => {
@@ -194,9 +193,7 @@ export default function PanelRoiThresholdSegmentation({
>
{labelmapLoading ? 'loading ...' : 'New Label'}
</Button>
<Button color="primary" onClick={handleROIThresholding}>
Run
</Button>
<Button onClick={handleROIThresholding}>Run</Button>
</div>
<div
className="flex items-center justify-around h-8 mb-2 border-t outline-none cursor-pointer select-none bg-secondary-dark first:border-0 border-secondary-light"
@@ -1,5 +1,5 @@
import React from 'react';
import { Input, Label, Select, Button, ButtonGroup } from '@ohif/ui';
import { Input, Label, Select, LegacyButton, ButtonGroup } from '@ohif/ui';
import { useTranslation } from 'react-i18next';
export const ROI_STAT = 'roi_stat';
@@ -38,8 +38,9 @@ function ROIThresholdConfiguration({ config, dispatch, runCommand }) {
/>
</div>
<div className="w-1/2">
{/* TODO Revisit design of ButtonGroup later - for now use LegacyButton for its children.*/}
<ButtonGroup>
<Button
<LegacyButton
size="initial"
className="px-2 py-2 text-base text-white"
color="primaryLight"
@@ -47,8 +48,8 @@ function ROIThresholdConfiguration({ config, dispatch, runCommand }) {
onClick={() => runCommand('setStartSliceForROIThresholdTool')}
>
{t('Start')}
</Button>
<Button
</LegacyButton>
<LegacyButton
size="initial"
color="primaryLight"
variant="outlined"
@@ -56,7 +57,7 @@ function ROIThresholdConfiguration({ config, dispatch, runCommand }) {
onClick={() => runCommand('setEndSliceForROIThresholdTool')}
>
{t('End')}
</Button>
</LegacyButton>
</ButtonGroup>
</div>
</div>
@@ -1,5 +1,5 @@
import React from 'react';
import { Input, Dialog } from '@ohif/ui';
import { Input, Dialog, ButtonEnums } from '@ohif/ui';
function segmentationItemEditHandler({ id, servicesManager }) {
const { segmentationService, uiDialogService } = servicesManager.services;
@@ -44,23 +44,20 @@ function segmentationItemEditHandler({ id, servicesManager }) {
}
};
return (
<div className="p-4 bg-primary-dark">
<Input
autoFocus
className="mt-2 bg-black border-primary-main"
type="text"
containerClassName="mr-2"
value={value.label}
onChange={onChangeHandler}
onKeyPress={onKeyPressHandler}
/>
</div>
<Input
autoFocus
className="bg-black border-primary-main"
type="text"
containerClassName="mr-2"
value={value.label}
onChange={onChangeHandler}
onKeyPress={onKeyPressHandler}
/>
);
},
actions: [
// temp: swap button types until colors are updated
{ id: 'cancel', text: 'Cancel', type: 'primary' },
{ id: 'save', text: 'Save', type: 'secondary' },
{ id: 'cancel', text: 'Cancel', type: ButtonEnums.type.secondary },
{ id: 'save', text: 'Save', type: ButtonEnums.type.primary },
],
onSubmit: onSubmitHandler,
},
+10 -1
View File
@@ -553,7 +553,16 @@ const commandsModule = ({
commandsManager.runCommand('setViewportColormap', {
viewportIndex,
displaySetInstanceUID: ptDisplaySet.displaySetInstanceUID,
colormap,
colormap: {
name: colormap,
// TODO: This opacity mapping matches that in hpViewports, but
// ideally making this editable in a side panel would be useful
opacity: [
{ value: 0, opacity: 0 },
{ value: 0.1, opacity: 0.9 },
{ value: 1, opacity: 0.95 },
],
},
});
viewports.push(
+18 -6
View File
@@ -254,16 +254,20 @@ const fusionAXIAL = {
id: 'ctDisplaySet',
},
{
id: 'ptDisplaySet',
options: {
colormap: {
name: 'hsv',
opacityMapping: [{ value: 0.1, opacity: 0.9 }],
opacity: [
{ value: 0, opacity: 0 },
{ value: 0.1, opacity: 0.9 },
{ value: 1, opacity: 0.95 },
],
},
voi: {
custom: 'getPTVOIRange',
},
},
id: 'ptDisplaySet',
},
],
};
@@ -310,16 +314,20 @@ const fusionSAGITTAL = {
id: 'ctDisplaySet',
},
{
id: 'ptDisplaySet',
options: {
colormap: {
name: 'hsv',
opacityMapping: [{ value: 0.1, opacity: 0.9 }],
opacity: [
{ value: 0, opacity: 0 },
{ value: 0.1, opacity: 0.9 },
{ value: 1, opacity: 0.95 },
],
},
voi: {
custom: 'getPTVOIRange',
},
},
id: 'ptDisplaySet',
},
],
};
@@ -366,16 +374,20 @@ const fusionCORONAL = {
id: 'ctDisplaySet',
},
{
id: 'ptDisplaySet',
options: {
colormap: {
name: 'hsv',
opacityMapping: [{ value: 0.1, opacity: 0.9 }],
opacity: [
{ value: 0, opacity: 0 },
{ value: 0.1, opacity: 0.9 },
{ value: 1, opacity: 0.95 },
],
},
voi: {
custom: 'getPTVOIRange',
},
},
id: 'ptDisplaySet',
},
],
};
+1 -1
View File
@@ -1,5 +1,5 @@
{
"version": "3.7.0-beta.2",
"version": "3.7.0-beta.27",
"packages": ["extensions/*", "platform/*", "modes/*"],
"npmClient": "yarn",
"useWorkspaces": true
+7 -7
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/mode-basic-dev-mode",
"version": "3.7.0-beta.2",
"version": "3.7.0-beta.27",
"description": "Basic OHIF Viewer Using Cornerstone",
"author": "OHIF",
"license": "MIT",
@@ -29,12 +29,12 @@
"test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests"
},
"peerDependencies": {
"@ohif/core": "3.7.0-beta.2",
"@ohif/extension-cornerstone": "3.7.0-beta.2",
"@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.2",
"@ohif/extension-default": "3.7.0-beta.2",
"@ohif/extension-dicom-pdf": "3.7.0-beta.2",
"@ohif/extension-dicom-video": "3.7.0-beta.2"
"@ohif/core": "3.7.0-beta.27",
"@ohif/extension-cornerstone": "3.7.0-beta.27",
"@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.27",
"@ohif/extension-default": "3.7.0-beta.27",
"@ohif/extension-dicom-pdf": "3.7.0-beta.27",
"@ohif/extension-dicom-video": "3.7.0-beta.27"
},
"dependencies": {
"@babel/runtime": "^7.20.13"
+9 -9
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/mode-test",
"version": "3.7.0-beta.2",
"version": "3.7.0-beta.27",
"description": "Basic mode for testing",
"author": "OHIF",
"license": "MIT",
@@ -32,14 +32,14 @@
"test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests"
},
"peerDependencies": {
"@ohif/core": "3.7.0-beta.2",
"@ohif/extension-cornerstone": "3.7.0-beta.2",
"@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.2",
"@ohif/extension-default": "3.7.0-beta.2",
"@ohif/extension-dicom-pdf": "3.7.0-beta.2",
"@ohif/extension-dicom-video": "3.7.0-beta.2",
"@ohif/extension-measurement-tracking": "3.7.0-beta.2",
"@ohif/extension-test": "3.7.0-beta.2"
"@ohif/core": "3.7.0-beta.27",
"@ohif/extension-cornerstone": "3.7.0-beta.27",
"@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.27",
"@ohif/extension-default": "3.7.0-beta.27",
"@ohif/extension-dicom-pdf": "3.7.0-beta.27",
"@ohif/extension-dicom-video": "3.7.0-beta.27",
"@ohif/extension-measurement-tracking": "3.7.0-beta.27",
"@ohif/extension-test": "3.7.0-beta.27"
},
"dependencies": {
"@babel/runtime": "^7.20.13"
+10 -10
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/mode-longitudinal",
"version": "3.7.0-beta.2",
"version": "3.7.0-beta.27",
"description": "Longitudinal Workflow",
"author": "OHIF",
"license": "MIT",
@@ -32,15 +32,15 @@
"test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests"
},
"peerDependencies": {
"@ohif/core": "3.7.0-beta.2",
"@ohif/extension-cornerstone": "3.7.0-beta.2",
"@ohif/extension-cornerstone-dicom-rt": "3.7.0-beta.2",
"@ohif/extension-cornerstone-dicom-seg": "3.7.0-beta.2",
"@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.2",
"@ohif/extension-default": "3.7.0-beta.2",
"@ohif/extension-dicom-pdf": "3.7.0-beta.2",
"@ohif/extension-dicom-video": "3.7.0-beta.2",
"@ohif/extension-measurement-tracking": "3.7.0-beta.2"
"@ohif/core": "3.7.0-beta.27",
"@ohif/extension-cornerstone": "3.7.0-beta.27",
"@ohif/extension-cornerstone-dicom-rt": "3.7.0-beta.27",
"@ohif/extension-cornerstone-dicom-seg": "3.7.0-beta.27",
"@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.27",
"@ohif/extension-default": "3.7.0-beta.27",
"@ohif/extension-dicom-pdf": "3.7.0-beta.27",
"@ohif/extension-dicom-video": "3.7.0-beta.27",
"@ohif/extension-measurement-tracking": "3.7.0-beta.27"
},
"dependencies": {
"@babel/runtime": "^7.20.13"
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/mode-microscopy",
"version": "3.7.0-beta.2",
"version": "3.7.0-beta.27",
"description": "OHIF mode for DICOM microscopy",
"author": "OHIF",
"license": "MIT",
@@ -33,8 +33,8 @@
"test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests"
},
"peerDependencies": {
"@ohif/core": "3.7.0-beta.2",
"@ohif/extension-dicom-microscopy": "3.7.0-beta.2"
"@ohif/core": "3.7.0-beta.27",
"@ohif/extension-dicom-microscopy": "3.7.0-beta.27"
},
"dependencies": {
"@babel/runtime": "^7.20.13"
+8 -8
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/mode-tmtv",
"version": "3.7.0-beta.2",
"version": "3.7.0-beta.27",
"description": "Total Metabolic Tumor Volume Workflow",
"author": "OHIF",
"license": "MIT",
@@ -32,13 +32,13 @@
"test:unit:ci": "jest --ci --runInBand --collectCoverage --passWithNoTests"
},
"peerDependencies": {
"@ohif/core": "3.7.0-beta.2",
"@ohif/extension-cornerstone": "3.7.0-beta.2",
"@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.2",
"@ohif/extension-default": "3.7.0-beta.2",
"@ohif/extension-dicom-pdf": "3.7.0-beta.2",
"@ohif/extension-dicom-video": "3.7.0-beta.2",
"@ohif/extension-measurement-tracking": "3.7.0-beta.2"
"@ohif/core": "3.7.0-beta.27",
"@ohif/extension-cornerstone": "3.7.0-beta.27",
"@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.27",
"@ohif/extension-default": "3.7.0-beta.27",
"@ohif/extension-dicom-pdf": "3.7.0-beta.27",
"@ohif/extension-dicom-video": "3.7.0-beta.27",
"@ohif/extension-measurement-tracking": "3.7.0-beta.27"
},
"dependencies": {
"@babel/runtime": "^7.20.13"
+2 -1
View File
@@ -220,7 +220,8 @@ function modeFactory({ modeConfiguration }) {
return {
id: ohif.layout,
props: {
// leftPanels: [ohif.thumbnailList],
leftPanels: [ohif.thumbnailList],
leftPanelDefaultClosed: true,
rightPanels: [tmtv.ROIThresholdPanel, tmtv.petSUV],
viewports: [
{
+4 -12
View File
@@ -24,9 +24,8 @@ function _createButton(type, id, icon, label, commands, tooltip) {
function _createColormap(label, colormap) {
return {
id: label.toString(),
title: label,
subtitle: label,
id: label,
label,
type: 'action',
commands: [
{
@@ -36,13 +35,6 @@ function _createColormap(label, colormap) {
colormap,
},
},
{
commandName: 'setFusionPTColormap',
commandOptions: {
toolGroupId: toolGroupIds.Fusion,
colormap,
},
},
],
};
}
@@ -313,7 +305,8 @@ const toolbarButtons = [
commandName: 'displayNotification',
commandOptions: {
title: 'RectangleROI Threshold Tip',
text: 'RectangleROI Threshold tool should be used on PT Axial Viewport',
text:
'RectangleROI Threshold tool should be used on PT Axial Viewport',
type: 'info',
},
},
@@ -345,7 +338,6 @@ const toolbarButtons = [
tooltip: 'PET Image Colormap',
},
isAction: true, // ?
renderer: WindowLevelMenuItem,
items: [
_createColormap('HSV', 'hsv'),
_createColormap('Hot Iron', 'hot_iron'),
-1
View File
@@ -149,7 +149,6 @@
]
},
"resolutions": {
"@cornerstonejs/core": "^1.1.8",
"**/@babel/runtime": "^7.20.13",
"commander": "8.3.0",
"nth-check": "^2.1.1",
@@ -1,5 +1,5 @@
describe('OHIF Context Menu', function () {
beforeEach(function () {
describe('OHIF Context Menu', function() {
beforeEach(function() {
cy.checkStudyRouteInViewer(
'1.2.840.113619.2.5.1762583153.215519.978957063.78'
);
@@ -10,10 +10,10 @@ describe('OHIF Context Menu', function () {
cy.resetViewport().wait(50);
});
it('checks context menu customization', function () {
it('checks context menu customization', function() {
// Add length measurement
cy.addLengthMeasurement();
cy.get('[data-cy="prompt-begin-tracking-yes"]').click();
cy.get('[data-cy="prompt-begin-tracking-yes-btn"]').click();
cy.get('[data-cy="measurement-item"]').click();
const [x1, y1] = [150, 100];
@@ -113,7 +113,7 @@ describe('OHIF Cornerstone Toolbar', () => {
cy.addLengthMeasurement();
cy.get('[data-cy="viewport-notification"]').should('exist');
cy.get('[data-cy="viewport-notification"]').should('be.visible');
cy.get('[data-cy="prompt-begin-tracking-yes"]').click();
cy.get('[data-cy="prompt-begin-tracking-yes-btn"]').click();
//Verify the measurement exists in the table
cy.get('@measurementsPanel').should('be.visible');
@@ -27,7 +27,7 @@ describe('OHIF Measurement Panel', function() {
cy.addLengthMeasurement();
cy.get('[data-cy="viewport-notification"]').should('exist');
cy.get('[data-cy="viewport-notification"]').should('be.visible');
cy.get('[data-cy="prompt-begin-tracking-yes"]').click();
cy.get('[data-cy="prompt-begin-tracking-yes-btn"]').click();
cy.get('[data-cy="measurement-item"]').click();
cy.get('[data-cy="measurement-item"]')
@@ -46,7 +46,7 @@ describe('OHIF Measurement Panel', function() {
it('checks if image would jump when clicked on a measurement item', function() {
// Add length measurement
cy.addLengthMeasurement();
cy.get('[data-cy="prompt-begin-tracking-yes"]').click();
cy.get('[data-cy="prompt-begin-tracking-yes-btn"]').click();
cy.scrollToIndex(13);
+2
View File
@@ -43,3 +43,5 @@
# COMMENT: For sharedArrayBuffer, see https://developer.chrome.com/blog/enabling-shared-array-buffer/
Cross-Origin-Embedder-Policy = "require-corp"
Cross-Origin-Opener-Policy = "same-origin"
# set CORP to cross-origin for anyone who wants to use the viewer in an iframe
Cross-Origin-Resource-Policy = "cross-origin"
+18 -18
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/app",
"version": "3.7.0-beta.2",
"version": "3.7.0-beta.27",
"productVersion": "3.4.0",
"description": "OHIF Viewer",
"author": "OHIF Contributors",
@@ -51,23 +51,23 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.2",
"@cornerstonejs/codec-openjph": "^2.4.2",
"@cornerstonejs/dicom-image-loader": "^1.1.8",
"@ohif/core": "3.7.0-beta.2",
"@ohif/extension-cornerstone": "3.7.0-beta.2",
"@ohif/extension-cornerstone-dicom-rt": "3.7.0-beta.2",
"@ohif/extension-cornerstone-dicom-seg": "3.7.0-beta.2",
"@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.2",
"@ohif/extension-default": "3.7.0-beta.2",
"@ohif/extension-dicom-microscopy": "3.7.0-beta.2",
"@ohif/extension-dicom-pdf": "3.7.0-beta.2",
"@ohif/extension-dicom-video": "3.7.0-beta.2",
"@ohif/extension-test": "3.7.0-beta.2",
"@ohif/i18n": "3.7.0-beta.2",
"@ohif/mode-basic-dev-mode": "3.7.0-beta.2",
"@ohif/mode-longitudinal": "3.7.0-beta.2",
"@ohif/mode-microscopy": "3.7.0-beta.2",
"@ohif/mode-test": "3.7.0-beta.2",
"@ohif/ui": "3.7.0-beta.2",
"@cornerstonejs/dicom-image-loader": "^1.4.1",
"@ohif/core": "3.7.0-beta.27",
"@ohif/extension-cornerstone": "3.7.0-beta.27",
"@ohif/extension-cornerstone-dicom-rt": "3.7.0-beta.27",
"@ohif/extension-cornerstone-dicom-seg": "3.7.0-beta.27",
"@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.27",
"@ohif/extension-default": "3.7.0-beta.27",
"@ohif/extension-dicom-microscopy": "3.7.0-beta.27",
"@ohif/extension-dicom-pdf": "3.7.0-beta.27",
"@ohif/extension-dicom-video": "3.7.0-beta.27",
"@ohif/extension-test": "3.7.0-beta.27",
"@ohif/i18n": "3.7.0-beta.27",
"@ohif/mode-basic-dev-mode": "3.7.0-beta.27",
"@ohif/mode-longitudinal": "3.7.0-beta.27",
"@ohif/mode-microscopy": "3.7.0-beta.27",
"@ohif/mode-test": "3.7.0-beta.27",
"@ohif/ui": "3.7.0-beta.27",
"@types/react": "^17.0.38",
"classnames": "^2.3.2",
"core-js": "^3.16.1",
+2 -1
View File
@@ -4,7 +4,7 @@ window.config = {
modes: [],
showStudyList: true,
// below flag is for performance reasons, but it might not work for all servers
omitQuotationForMultipartRequest: true,
showWarningMessageForCrossOrigin: true,
showCPUFallbackMessage: true,
showLoadingIndicator: true,
@@ -30,6 +30,7 @@ window.config = {
supportsFuzzyMatching: false,
supportsWildcard: false,
staticWado: true,
omitQuotationForMultipartRequest: true,
},
},
{
+1 -2
View File
@@ -11,7 +11,6 @@ window.config = {
// some windows systems have issues with more than 3 web workers
maxNumberOfWebWorkers: 3,
// below flag is for performance reasons, but it might not work for all servers
omitQuotationForMultipartRequest: true,
showWarningMessageForCrossOrigin: true,
showCPUFallbackMessage: true,
showLoadingIndicator: true,
@@ -51,7 +50,6 @@ window.config = {
wadoUriRoot: 'https://d33do7qe4w26qo.cloudfront.net/dicomweb',
qidoRoot: 'https://d33do7qe4w26qo.cloudfront.net/dicomweb',
wadoRoot: 'https://d33do7qe4w26qo.cloudfront.net/dicomweb',
qidoSupportsIncludeField: false,
supportsReject: false,
imageRendering: 'wadors',
@@ -68,6 +66,7 @@ window.config = {
enabled: true,
relativeResolution: 'studies',
},
omitQuotationForMultipartRequest: true,
},
},
{
+1 -1
View File
@@ -4,7 +4,6 @@ window.config = {
extensions: [],
showStudyList: true,
// below flag is for performance reasons, but it might not work for all servers
omitQuotationForMultipartRequest: true,
showWarningMessageForCrossOrigin: true,
strictZSpacingForVolumeViewport: true,
showCPUFallbackMessage: true,
@@ -25,6 +24,7 @@ window.config = {
bulkDataURI: {
enabled: false,
},
omitQuotationForMultipartRequest: true,
},
},
],
@@ -4,7 +4,6 @@ window.config = {
modes: [],
showStudyList: true,
// below flag is for performance reasons, but it might not work for all servers
omitQuotationForMultipartRequest: true,
showWarningMessageForCrossOrigin: true,
showCPUFallbackMessage: true,
showLoadingIndicator: true,
@@ -28,6 +27,7 @@ window.config = {
enableStudyLazyLoad: true,
supportsFuzzyMatching: false,
supportsWildcard: false,
omitQuotationForMultipartRequest: true,
},
},
{
@@ -5,7 +5,6 @@ window.config = {
showStudyList: true,
maxNumberOfWebWorkers: 3,
// below flag is for performance reasons, but it might not work for all servers
omitQuotationForMultipartRequest: true,
showWarningMessageForCrossOrigin: true,
showCPUFallbackMessage: true,
showLoadingIndicator: true,
@@ -31,6 +30,7 @@ window.config = {
supportsWildcard: true,
staticWado: true,
singlepart: 'bulkdata,video,pdf',
omitQuotationForMultipartRequest: true,
},
},
{
@@ -4,7 +4,6 @@ window.config = {
extensions: [],
modes: [],
// below flag is for performance reasons, but it might not work for all servers
omitQuotationForMultipartRequest: true,
showWarningMessageForCrossOrigin: true,
showCPUFallbackMessage: true,
showLoadingIndicator: true,
@@ -23,6 +22,7 @@ window.config = {
qidoSupportsIncludeField: false,
imageRendering: 'wadors',
thumbnailRendering: 'wadors',
omitQuotationForMultipartRequest: true,
},
},
{
@@ -2,7 +2,6 @@ window.config = {
routerBasename: '/',
showStudyList: true,
// below flag is for performance reasons, but it might not work for all servers
omitQuotationForMultipartRequest: true,
showWarningMessageForCrossOrigin: true,
showCPUFallbackMessage: true,
showLoadingIndicator: true,
@@ -18,6 +17,7 @@ window.config = {
qidoSupportsIncludeField: false,
imageRendering: 'wadors',
thumbnailRendering: 'wadors',
omitQuotationForMultipartRequest: true,
// REQUIRED TAG:
// TODO: Remove tag after https://github.com/OHIF/ohif-core/pull/19 is merged and we bump version
// requestOptions: {
@@ -4,7 +4,7 @@ window.config = {
extensions: [],
modes: [],
// below flag is for performance reasons, but it might not work for all servers
omitQuotationForMultipartRequest: true,
showWarningMessageForCrossOrigin: true,
showCPUFallbackMessage: true,
showLoadingIndicator: true,
@@ -23,6 +23,7 @@ window.config = {
qidoSupportsIncludeField: false,
imageRendering: 'wadors',
thumbnailRendering: 'wadors',
omitQuotationForMultipartRequest: true,
},
},
{
+1 -1
View File
@@ -4,7 +4,6 @@ window.config = {
modes: ['@ohif/mode-test'],
showStudyList: true,
// below flag is for performance reasons, but it might not work for all servers
omitQuotationForMultipartRequest: true,
maxNumberOfWebWorkers: 3,
showWarningMessageForCrossOrigin: false,
showCPUFallbackMessage: false,
@@ -31,6 +30,7 @@ window.config = {
supportsFuzzyMatching: false,
supportsWildcard: true,
singlepart: 'video,thumbnail,pdf',
omitQuotationForMultipartRequest: true,
},
},
{
+1 -1
View File
@@ -6,7 +6,6 @@ window.config = {
},
enableGoogleCloudAdapter: false,
// below flag is for performance reasons, but it might not work for all servers
omitQuotationForMultipartRequest: true,
showWarningMessageForCrossOrigin: true,
showCPUFallbackMessage: true,
showLoadingIndicator: true,
@@ -55,6 +54,7 @@ window.config = {
supportsFuzzyMatching: true,
supportsWildcard: false,
dicomUploadEnabled: true,
omitQuotationForMultipartRequest: true,
},
},
{
-1
View File
@@ -2,7 +2,6 @@ window.config = {
routerBasename: '/',
enableGoogleCloudAdapter: true,
// below flag is for performance reasons, but it might not work for all servers
omitQuotationForMultipartRequest: true,
showWarningMessageForCrossOrigin: true,
showCPUFallbackMessage: true,
showLoadingIndicator: true,
+1 -1
View File
@@ -8,7 +8,6 @@ window.config = {
extensions: [],
modes: [],
// below flag is for performance reasons, but it might not work for all servers
omitQuotationForMultipartRequest: true,
showWarningMessageForCrossOrigin: true,
showCPUFallbackMessage: true,
showLoadingIndicator: true,
@@ -39,6 +38,7 @@ window.config = {
bulkDataURI: {
enabled: true,
},
omitQuotationForMultipartRequest: true,
},
},
{
+1 -1
View File
@@ -8,7 +8,6 @@ window.config = {
showStudyList: true,
maxNumberOfWebWorkers: 4,
// below flag is for performance reasons, but it might not work for all servers
omitQuotationForMultipartRequest: true,
showWarningMessageForCrossOrigin: true,
showCPUFallbackMessage: true,
showLoadingIndicator: true,
@@ -33,6 +32,7 @@ window.config = {
supportsWildcard: true,
staticWado: true,
singlepart: 'bulkdata,video,pdf',
omitQuotationForMultipartRequest: true,
},
},
{
+1 -1
View File
@@ -16,7 +16,6 @@ window.config = {
showStudyList: true,
maxNumberOfWebWorkers: 4,
// below flag is for performance reasons, but it might not work for all servers
omitQuotationForMultipartRequest: true,
showWarningMessageForCrossOrigin: true,
showCPUFallbackMessage: true,
showLoadingIndicator: true,
@@ -42,6 +41,7 @@ window.config = {
supportsWildcard: true,
staticWado: true,
singlepart: 'bulkdata,video,pdf',
omitQuotationForMultipartRequest: true,
},
},
{
+1 -1
View File
@@ -4,7 +4,6 @@ window.config = {
modes: [],
showStudyList: true,
// below flag is for performance reasons, but it might not work for all servers
omitQuotationForMultipartRequest: true,
showWarningMessageForCrossOrigin: true,
showCPUFallbackMessage: true,
showLoadingIndicator: true,
@@ -38,6 +37,7 @@ window.config = {
enabled: true,
relativeResolution: 'studies',
},
omitQuotationForMultipartRequest: true,
},
},
{
@@ -2,7 +2,6 @@ window.config = {
routerBasename: '/',
showStudyList: true,
// below flag is for performance reasons, but it might not work for all servers
omitQuotationForMultipartRequest: true,
showWarningMessageForCrossOrigin: true,
showCPUFallbackMessage: true,
showLoadingIndicator: true,
@@ -18,6 +17,7 @@ window.config = {
imageRendering: 'wadors',
thumbnailRendering: 'wadors',
supportsFuzzyMatching: true,
omitQuotationForMultipartRequest: true,
},
],
},
@@ -15,7 +15,7 @@ import { utils, hotkeys, ServicesManager } from '@ohif/core';
import {
Icon,
StudyListExpandedRow,
Button,
LegacyButton,
EmptyStudies,
StudyListTable,
StudyListPagination,
@@ -363,16 +363,17 @@ function WorkList({
''}?${query.toString()}`}
// to={`${mode.routeName}/dicomweb?StudyInstanceUIDs=${studyInstanceUid}`}
>
<Button
{/* TODO revisit the completely rounded style of buttons used for launching a mode from the worklist later - for now use LegacyButton*/}
<LegacyButton
rounded="full"
variant={isValidMode ? 'contained' : 'disabled'}
disabled={!isValidMode}
endIcon={<Icon name="launch-arrow" />} // launch-arrow | launch-info
className={classnames('font-medium ', { 'ml-2': !isFirst })}
className={classnames({ 'ml-2': !isFirst })}
onClick={() => {}}
>
{t(`Modes:${mode.displayName}`)}
</Button>
</LegacyButton>
</Link>
);
})}
+7
View File
@@ -74,9 +74,16 @@ module.exports = {
},
customblue: {
10: '#0A163F',
20: '#0B1F54',
30: '#09286e',
40: '#0E307F',
50: '#0F3A94',
80: '#1454D4',
100: '#c4fdff',
200: '#38daff',
300: '#1D204D',
400: '#90A0C1',
},
customgray: {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/cli",
"version": "3.7.0-beta.2",
"version": "3.7.0-beta.27",
"description": "A CLI to bootstrap new OHIF extension or mode",
"type": "module",
"main": "src/index.js",
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/core",
"version": "3.7.0-beta.2",
"version": "3.7.0-beta.27",
"description": "Generic business logic for web-based medical imaging applications",
"author": "OHIF Core Team",
"license": "MIT",
@@ -35,8 +35,8 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.2",
"@cornerstonejs/codec-openjph": "^2.4.2",
"@cornerstonejs/dicom-image-loader": "^1.1.8",
"@ohif/ui": "3.7.0-beta.2",
"@cornerstonejs/dicom-image-loader": "^1.4.1",
"@ohif/ui": "3.7.0-beta.27",
"cornerstone-math": "0.1.9",
"dicom-parser": "^1.8.21"
},
+25 -24
View File
@@ -173,30 +173,31 @@ const bindings = [
label: 'W/L Preset 5',
keys: ['5'],
},
{
commandName: 'setWindowLevel',
commandOptions: windowLevelPresets[6],
label: 'W/L Preset 6',
keys: ['6'],
},
{
commandName: 'setWindowLevel',
commandOptions: windowLevelPresets[7],
label: 'W/L Preset 7',
keys: ['7'],
},
{
commandName: 'setWindowLevel',
commandOptions: windowLevelPresets[8],
label: 'W/L Preset 8',
keys: ['8'],
},
{
commandName: 'setWindowLevel',
commandOptions: windowLevelPresets[9],
label: 'W/L Preset 9',
keys: ['9'],
},
// These don't exist, so don't try applying them....
// {
// commandName: 'setWindowLevel',
// commandOptions: windowLevelPresets[6],
// label: 'W/L Preset 6',
// keys: ['6'],
// },
// {
// commandName: 'setWindowLevel',
// commandOptions: windowLevelPresets[7],
// label: 'W/L Preset 7',
// keys: ['7'],
// },
// {
// commandName: 'setWindowLevel',
// commandOptions: windowLevelPresets[8],
// label: 'W/L Preset 8',
// keys: ['8'],
// },
// {
// commandName: 'setWindowLevel',
// commandOptions: windowLevelPresets[9],
// label: 'W/L Preset 9',
// keys: ['9'],
// },
];
export default bindings;
@@ -695,15 +695,18 @@ export default class HangingProtocolService extends PubSubService {
) {
viewport.displaySets.forEach(displaySet => {
const { id } = displaySet;
const {
displaySetInstanceUID: oldDisplaySetInstanceUID,
} = displaySetMatchDetails.get(id);
const displaySetMatchDetail = displaySetMatchDetails.get(id);
displaySetInstanceUIDs.push(
const { displaySetInstanceUID: oldDisplaySetInstanceUID } = displaySetMatchDetail;
const displaySetInstanceUID =
displaySet.id === displaySetSelectorId
? newDisplaySetInstanceUID
: oldDisplaySetInstanceUID
);
: oldDisplaySetInstanceUID;
displaySetMatchDetail.displaySetInstanceUID = displaySetInstanceUID;
displaySetInstanceUIDs.push(displaySetInstanceUID);
displaySetOptions.push(displaySet);
});
}
@@ -1389,17 +1392,20 @@ export default class HangingProtocolService extends PubSubService {
this.studies.forEach(study => {
// Skip non-active if active only
if (matchActiveOnly && this.activeStudy !== study) return;
const studyDisplaySets = this.displaySets.filter(
it => it.StudyInstanceUID === study.StudyInstanceUID
it => it.StudyInstanceUID === study.StudyInstanceUID
);
const studyMatchDetails = this.protocolEngine.findMatch(
study,
studyMatchingRules,
{
studies: this.studies,
displaySets: studyDisplaySets,
displaySetMatchDetails: this.displaySetMatchDetails,
}
study,
studyMatchingRules,
{
studies: this.studies,
displaySets: studyDisplaySets,
allDisplaySets: this.displaySets,
displaySetMatchDetails: this.displaySetMatchDetails,
}
);
// Prevent bestMatch from being updated if the matchDetails' required attribute check has failed
@@ -1408,10 +1414,10 @@ export default class HangingProtocolService extends PubSubService {
}
this.debug(
'study',
study.StudyInstanceUID,
'display sets #',
studyDisplaySets.length
'study',
study.StudyInstanceUID,
'display sets #',
studyDisplaySets.length
);
studyDisplaySets.forEach(displaySet => {
const {
@@ -1420,15 +1426,15 @@ export default class HangingProtocolService extends PubSubService {
displaySetInstanceUID,
} = displaySet;
const seriesMatchDetails = this.protocolEngine.findMatch(
displaySet,
seriesMatchingRules,
// Todo: why we have images here since the matching type does not have it
{
studies: this.studies,
instance: displaySet.images?.[0],
displaySetMatchDetails: this.displaySetMatchDetails,
displaySets: studyDisplaySets,
}
displaySet,
seriesMatchingRules,
// Todo: why we have images here since the matching type does not have it
{
studies: this.studies,
instance: displaySet.images?.[0],
displaySetMatchDetails: this.displaySetMatchDetails,
displaySets: studyDisplaySets,
}
);
// Prevent bestMatch from being updated if the matchDetails' required attribute check has failed
@@ -1,69 +1,240 @@
import validate from 'validate.js';
/**
* check if the value is strictly equal to options
*
* @example
* value = ['abc', 'def', 'GHI']
* testValue = 'abc' (Fail)
* = ['abc'] (Fail)
* = ['abc', 'def', 'GHI'] (Valid)
* = ['abc', 'GHI', 'def'] (Fail)
* = ['abc', 'def'] (Fail)
*
* value = 'Attenuation Corrected'
* testValue = 'Attenuation Corrected' (Valid)
* testValue = 'Attenuation' (Fail)
*
* value = ['Attenuation Corrected']
* testValue = ['Attenuation Corrected'] (Valid)
* = 'Attenuation Corrected' (Valid)
* = 'Attenuation' (Fail)
*
* */
validate.validators.equals = function(value, options, key) {
const testValue = getTestValue(options);
const dicomArrayValue = dicomTagToArray(value);
validate.validators.equals = function(value, options, key, attributes) {
const testValue = options?.value ?? options;
if (value !== testValue) {
return key + 'must equal ' + testValue;
// If options is an array, then we need to validate each element in the array
if (Array.isArray(testValue)) {
// If the array has only one element, then we need to compare the value to that element
if (testValue.length !== dicomArrayValue.length) {
return `${key} must be an array of length ${testValue.length}`;
} else {
for (let i = 0; i < testValue.length; i++) {
if (testValue[i] !== dicomArrayValue[i]) {
return `${key} ${testValue[i]} must equal ${dicomArrayValue[i]}`;
}
}
}
} else if (testValue !== dicomArrayValue[0]) {
return `${key} must equal ${testValue}`;
}
};
/**
* check if the value is not equal to options
*
* @example
* value = ['abc', 'def', 'GHI']
* testValue = 'abc' (Valid)
* = ['abc'] (Valid)
* = ['abc', 'def', 'GHI'] (Fail)
* = ['abc', 'GHI', 'def'] (Valid)
* = ['abc', 'def'] (Valid)
*
* value = 'Attenuation Corrected'
* = 'Attenuation Corrected' (Fail)
* = 'Attenuation' (Valid)
*
* value = ['Attenuation Corrected']
* testValue = ['Attenuation Corrected'] (Fail)
* = 'Attenuation Corrected' (Fail)
* = 'Attenuation' (Fail)
* */
validate.validators.doesNotEqual = function(value, options, key) {
const testValue = options?.value ?? options;
if (value === testValue) {
return key + 'cannot equal ' + testValue;
const testValue = getTestValue(options);
const dicomArrayValue = dicomTagToArray(value);
if (Array.isArray(testValue)) {
if (testValue.length === dicomArrayValue.length) {
let score = 0;
testValue.forEach((x, i) => {
if (x === dicomArrayValue[i]) {
score++;
}
});
if (score === testValue.length) {
return `${key} must not equal to ${testValue}`;
}
}
} else if (testValue === dicomArrayValue[0]) {
console.debug(dicomArrayValue, testValue);
return `${key} must not equal to ${testValue}`;
}
};
/**
* Check if a value includes one or more specified options.
*
* @example
* value = ['abc', 'def', 'GHI']
* testValue = ‘abc’ (Fail)
* = ‘dog’ (Fail)
* = [‘abc’] (Valid)
* = [‘att’, ‘abc’] (Valid)
* = ['abc', 'def', 'dog'] (Valid)
* = ['cat', 'dog'] (Fail)
*
* value = ['Attenuation Corrected']
* testValue = 'Attenuation Corrected' (Fail)
* = ['Attenuation Corrected', 'Corrected'] (Valid)
* = ['Attenuation', 'Corrected'] (Fail)
*
* value = 'Attenuation Corrected'
* testValue = ['Attenuation Corrected', 'Corrected'] (Valid)
* = ['Attenuation', 'Corrected'] (Fail)
* */
validate.validators.includes = function(value, options, key) {
const testValue = getTestValue(options);
const dicomArrayValue = dicomTagToArray(value);
if (Array.isArray(testValue)) {
const includedValues = testValue.filter(el => dicomArrayValue.includes(el));
if (includedValues.length === 0) {
return `${key} must include at least one of the following values: ${testValue.join(
', '
)}`;
}
} else return `${key} ${testValue} must be an array`;
// else if (!value.includes(testValue)) {
// return `${key} ${value} must include ${testValue}`;
// }
};
/**
* Check if a value does not include one or more specified options.
*
* @example
* value = ['abc', 'def', 'GHI']
* testValue = ['Corr'] (Valid)
* = 'abc' (Fail)
* = ['abc'] (Fail)
* = [‘att’, ‘cor’] (Valid)
* = ['abc', 'def', 'dog'] (Fail)
*
* value = ['Attenuation Corrected']
* testValue = 'Attenuation Corrected' (Fail)
* = ['Attenuation Corrected', 'Corrected'] (Fail)
* = ['Attenuation', 'Corrected'] (Valid)
*
* value = 'Attenuation Corrected'
* testValue = ['Attenuation Corrected', 'Corrected'] (Fail)
* = ['Attenuation', 'Corrected'] (Valid)
* */
validate.validators.doesNotInclude = function(value, options, key) {
const testValue = getTestValue(options);
const dicomArrayValue = dicomTagToArray(value);
// if (!Array.isArray(value) || value.length === 1) {
// return `${key} is not allowed as a single value`;
// }
if (Array.isArray(testValue)) {
const includedValues = testValue.filter(el => dicomArrayValue.includes(el));
if (includedValues.length > 0) {
return `${key} must not include the following value: ${includedValues}`;
}
} else return `${key} ${testValue} must be an array`;
};
// Ignore case contains.
// options testValue MUST be in lower case already, otherwise it won't match
validate.validators.containsI = function (value, options, key) {
const testValue = options?.value ?? options;
/**
* @example
* value = 'Attenuation Corrected'
* testValue = ‘Corr’ (Valid)
* = ‘corr’ (Valid)
* = [‘att’, ‘cor’] (Valid)
* = [‘Att’, ‘Wall’] (Valid)
* = [‘cat’, ‘dog’] (Fail)
*
* value = ['abc', 'def', 'GHI']
* testValue = 'def' (Valid)
* = 'dog' (Fail)
* = ['gh', 'de'] (Valid)
* = ['cat', 'dog'] (Fail)
*
* */
validate.validators.containsI = function(value, options, key) {
const testValue = getTestValue(options);
if (Array.isArray(value)) {
if (
value.some(
item => !validate.validators.containsI(item.toLowerCase(), options, key)
)
value.some(
item => !validate.validators.containsI(item.toLowerCase(), options, key)
)
) {
return undefined;
}
return `No item of ${value.join(',')} contains ${JSON.stringify(
testValue
testValue
)}`;
}
if (Array.isArray(testValue)) {
if (
testValue.some(
subTest => !validate.validators.containsI(value, subTest, key)
)
testValue.some(
subTest =>
!validate.validators.containsI(value, subTest.toLowerCase(), key)
)
) {
return;
}
return `${key} must contain at least one of ${testValue.join(',')}`;
}
if (
testValue &&
value.indexOf &&
value.toLowerCase().indexOf(testValue) === -1
testValue &&
value.indexOf &&
value.toLowerCase().indexOf(testValue.toLowerCase()) === -1
) {
return key + 'must contain any case of' + testValue;
}
};
/**
* @example
* value = 'Attenuation Corrected'
* testValue = ‘Corr’ (Valid)
* = ‘corr’ (Fail)
* = [‘att’, ‘cor’] (Fail)
* = [‘Att’, ‘Wall’] (Valid)
* = [‘cat’, ‘dog’] (Fail)
*
* value = ['abc', 'def', 'GHI']
* testValue = 'def' (Valid)
* = 'dog' (Fail)
* = ['cat', 'de'] (Valid)
* = ['cat', 'dog'] (Fail)
*
* */
validate.validators.contains = function(value, options, key) {
const testValue = options?.value ?? options;
const testValue = getTestValue(options);
if (Array.isArray(value)) {
if (value.some(item => !validate.validators.contains(item, options, key))) {
return undefined;
}
return `No item of ${value.join(',')} contains ${JSON.stringify(
testValue
testValue
)}`;
}
if (Array.isArray(testValue)) {
if (
testValue.some(
subTest => !validate.validators.contains(value, subTest, key)
)
testValue.some(
subTest => !validate.validators.contains(value, subTest, key)
)
) {
return;
}
@@ -73,50 +244,235 @@ validate.validators.contains = function(value, options, key) {
return key + 'must contain ' + testValue;
}
};
/**
* @example
* value = 'Attenuation Corrected'
* testValue = ‘Corr’ (Fail)
* = ‘corr’ (Valid)
* = [‘att’, ‘cor’] (Valid)
* = [‘Att’, ‘Wall’] (Fail)
* = [‘cat’, ‘dog’] (Valid)
*
* value = ['abc', 'def', 'GHI']
* testValue = 'def' (Fail)
* = 'dog' (Valid)
* = ['cat', 'de'] (Fail)
* = ['cat', 'dog'] (Valid)
*
* */
validate.validators.doesNotContain = function(value, options, key) {
if (options && value.indexOf && value.indexOf(options.value) !== -1) {
return key + 'cannot contain ' + options.value;
const containsResult = validate.validators.contains(value, options, key);
if (!containsResult) {
return `No item of ${value} should contain ${getTestValue(options)}`;
}
};
/**
* @example
* value = 'Attenuation Corrected'
* testValue = ‘Corr’ (Fail)
* = ‘corr’ (Fail)
* = [‘att’, ‘cor’] (Fail)
* = [‘Att’, ‘Wall’] (Fail)
* = [‘cat’, ‘dog’] (Valid)
*
* value = ['abc', 'def', 'GHI']
* testValue = 'DEF' (Fail)
* = 'dog' (Valid)
* = ['cat', 'gh'] (Fail)
* = ['cat', 'dog'] (Valid)
*
* */
validate.validators.doesNotContainI = function(value, options, key) {
const containsResult = validate.validators.containsI(value, options, key);
if (!containsResult) {
return `No item of ${value} should not contain ${getTestValue(options)}`;
}
};
/**
* @example
* value = 'Attenuation Corrected'
* testValue = ‘Corr’ (Fail)
* = ‘Att’ (Fail)
* = ['cat', 'dog', 'Att'] (Valid)
* = [‘cat’, ‘dog’] (Fail)
*
* value = ['abc', 'def', 'GHI']
* testValue = 'deg' (Valid)
* = ['cat', 'GH'] (Valid)
* = ['cat', 'gh'] (Fail)
* = ['cat', 'dog'] (Fail)
*
* */
validate.validators.startsWith = function(value, options, key) {
if (options && value.startsWith && !value.startsWith(options.value)) {
return key + 'must start with ' + options.value;
let testValues = getTestValue(options);
if (typeof testValues === 'string') {
testValues = [testValues];
}
if (typeof value === 'string') {
if (!testValues.some(testValue => value.startsWith(testValue))) {
return key + ' must start with any of these values: ' + testValues;
}
} else if (Array.isArray(value)) {
let valid = false;
for (let i = 0; i < value.length; i++) {
for (let j = 0; j < testValues.length; j++) {
if (value[i].startsWith(testValues[j])) {
valid = true; // set valid flag to true if a match is found
break;
}
}
if (valid) {
return undefined; // break out of loop if a match is found
}
}
if (!valid) {
return key + ' must start with any of these values: ' + testValues; // return undefined if no match is found
}
} else {
return 'Value must be a string or an array';
}
};
/**
* @example
* value = 'Attenuation Corrected'
* testValue = ‘TED’ (Fail)
* = ‘ted’ (Valid)
* = ['cat', 'dog', 'ted'] (Valid)
* = [‘cat’, ‘dog’] (Fail)
*
* value = ['abc', 'def', 'GHI']
* testValue = 'deg' (Valid)
* = ['cat', 'HI'] (Valid)
* = ['cat', 'hi'] (Fail)
* = ['cat', 'dog'] (Fail)
*
* */
validate.validators.endsWith = function(value, options, key) {
if (options && value.endsWith && !value.endsWith(options.value)) {
return key + 'must end with ' + options.value;
let testValues = getTestValue(options);
if (typeof testValues === 'string') {
testValues = [testValues];
}
if (typeof value === 'string') {
if (!testValues.some(testValue => value.endsWith(testValue))) {
return key + ' must end with any of these values: ' + testValues;
}
} else if (Array.isArray(value)) {
let valid = false;
for (let i = 0; i < value.length; i++) {
for (let j = 0; j < testValues.length; j++) {
if (value[i].endsWith(testValues[j])) {
valid = true; // set valid flag to true if a match is found
break;
}
}
if (valid) {
return undefined; // break out of loop if a match is found
}
}
if (!valid) {
return key + ' must end with any of these values: ' + testValues; // return undefined if no match is found
}
} else {
return key + ' must be a string or an array';
}
};
const getTestValue = options => options?.value ?? options;
/**
* @example
* value = 30
* testValue = 20 (Valid)
* = 40 (Fail)
*
* */
validate.validators.greaterThan = function(value, options, key) {
const testValue = getTestValue(options);
if (value === undefined || value === null || value <= testValue) {
return key + 'with value ' + value + ' must be greater than ' + testValue;
if (Array.isArray(value) || typeof value === 'string') {
return `${key} is not allowed as an array or string`;
}
if (Array.isArray(testValue)) {
if (testValue.length === 1) {
if (!(value >= testValue[0])) {
return `${key} must be greater than or equal to ${testValue[0]}, but was ${value}`;
}
} else if (testValue.length > 1) {
return key + ' must be an array of length 1';
}
} else {
if (!(value >= testValue)) {
return key + ' must be greater than ' + testValue;
}
}
};
/**
* @example
* value = 30
* testValue = 40 (Valid)
* = 20 (Fail)
*
* */
validate.validators.lessThan = function(value, options, key) {
const testValue = getTestValue(options);
if (Array.isArray(testValue)) {
if (testValue.length === 1) {
if (!(value <= testValue[0])) {
return `${key} must be less than or equal to ${testValue[0]}, but was ${value}`;
}
} else if (testValue.length > 1) {
return key + ' must be an array of length 1';
}
} else {
if (!(value <= testValue)) {
return key + ' must be less than ' + testValue;
}
}
};
/**
* @example
*
* value = 50
* testValue = [10,60] (Valid)
* = [60, 10] (Valid)
* = [0, 10] (Fail)
* = [70, 80] (Fail)
* = 45 (Fail)
* = [45] (Fail)
*
* */
validate.validators.range = function(value, options, key) {
const testValue = getTestValue(options);
if (value === undefined || value < testValue[0] || value > testValue[1]) {
return (
key +
'with value ' +
value +
' must be between ' +
testValue[0] +
' and ' +
testValue[1]
);
}
if (Array.isArray(testValue) && testValue.length === 2) {
const min = Math.min(testValue[0], testValue[1]);
const max = Math.max(testValue[0], testValue[1]);
if (value === undefined || value < min || value > max) {
return `${key} with value ${value} must be between ${min} and ${max}`;
}
} else return `${key} must be an array of length 2`;
};
validate.validators.notNull = value =>
value === null || value === undefined ? 'Value is null' : undefined;
value === null || value === undefined ? 'Value is null' : undefined;
const getTestValue = options => {
if (Array.isArray(options)) {
return options.map(option => option?.value ?? option);
} else {
return options?.value ?? options;
}
};
const dicomTagToArray = value => {
let dicomArrayValue;
if (!Array.isArray(value)) {
dicomArrayValue = [value];
} else {
dicomArrayValue = [...value];
}
return dicomArrayValue;
};
export default validate;
@@ -1,139 +1,570 @@
import validate from './validator.js';
describe('validator', () => {
const attributeMap = {
str: 'string',
upper: 'UPPER',
num: 3,
nullValue: null,
list: ['abc', 'def', 'GHI'],
};
const attributeMap = {
str: 'Attenuation Corrected',
upper: 'UPPER',
num: 3,
nullValue: null,
list: ['abc', 'def', 'GHI'],
listStr: ['Attenuation Corrected'],
};
const options = {
format: 'grouped',
};
const options = {
format: 'grouped',
};
describe('contains', () => {
it('returns match any list contains', () => {
expect(
validate(attributeMap, { list: { contains: 'a' } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { str: { contains: 'i' } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { str: { contains: ['i'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { contains: ['a'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { contains: ['z', 'd'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { contains: ['z'] } }, [options])
).not.toBeUndefined();
describe('equals', () => {
it('returned undefined on strictly equals', () => {
expect(
validate(attributeMap, { listStr: { equals: ['Attenuation'] } }, [
options,
])
).not.toBeUndefined();
expect(
validate(attributeMap, { listStr: { equals: 'Attenuation' } }, [
options,
])
).not.toBeUndefined();
expect(
validate(
attributeMap,
{ listStr: { equals: 'Attenuation Corrected' } },
[options]
)
).toBeUndefined();
expect(
validate(
attributeMap,
{ listStr: { equals: ['Attenuation Corrected'] } },
[options]
)
).toBeUndefined();
expect(
validate(attributeMap, { str: { equals: 'Attenuation Corrected' } }, [
options,
])
).toBeUndefined();
expect(
validate(
attributeMap,
{ str: { equals: { value: 'Attenuation Corrected' } } },
[options]
)
).toBeUndefined();
expect(
validate(attributeMap, { str: { equals: ['Attenuation Corrected'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { str: { equals: ['Attenuation'] } }, [options])
).not.toBeUndefined();
expect(
validate(attributeMap, { list: { equals: ['abc', 'def', 'GHI'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { equals: ['abc', 'GHI', 'def'] } }, [
options,
])
).not.toBeUndefined();
expect(
validate(
attributeMap,
{ list: { equals: { value: ['abc', 'def', 'GHI'] } } },
[options]
)
).toBeUndefined();
});
});
});
describe('doesNotEqual', () => {
it('returns undefined if value does not equal ', () => {
expect(
validate(
attributeMap,
{ listStr: { doesNotEqual: 'Attenuation Corrected' } },
[options]
)
).not.toBeUndefined();
expect(
validate(
attributeMap,
{ listStr: { doesNotEqual: ['Attenuation Corrected'] } },
[options]
)
).not.toBeUndefined();
expect(
validate(attributeMap, { listStr: { doesNotEqual: 'Attenuation' } }, [
options,
])
).toBeUndefined();
describe('containsI', () => {
it('returns match any list contains case insensitive', () => {
expect(
validate(attributeMap, { upper: { containsI: ['bye', 'pre'] } }, [
options,
])
).not.toBeUndefined();
expect(
validate(attributeMap, { list: { containsI: 'hi' } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { containsI: ['hi', 'bye'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { containsI: ['bye', 'hi'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { containsI: ['ig', 'hi'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { upper: { containsI: ['bye', 'per'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotEqual: 'Attenuation' } }, [
options,
])
).toBeUndefined();
expect(
validate(
attributeMap,
{ str: { doesNotEqual: { value: 'Attenuation' } } },
[options]
)
).toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotEqual: ['Attenuation'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotEqual: ['abc', 'def'] } }, [
options,
])
).toBeUndefined();
expect(
validate(
attributeMap,
{ list: { doesNotEqual: ['abc', 'GHI', 'def'] } },
[options]
)
).toBeUndefined();
expect(
validate(
attributeMap,
{ list: { doesNotEqual: ['abc', 'def', 'GHI'] } },
[options]
)
).not.toBeUndefined();
});
});
});
describe('includes', () => {
it('returns match any list includes', () => {
expect(
validate(
attributeMap,
{ listStr: { includes: 'Attenuation Corrected' } },
[options]
)
).not.toBeUndefined();
expect(
validate(
attributeMap,
{ listStr: { includes: ['Attenuation Corrected'] } },
[options]
)
).toBeUndefined();
expect(
validate(
attributeMap,
{ listStr: { includes: ['Attenuation Corrected', 'Corrected'] } },
[options]
)
).toBeUndefined();
expect(
validate(
attributeMap,
{ listStr: { includes: ['Attenuation', 'Corrected'] } },
[options]
)
).not.toBeUndefined();
expect(
validate(
attributeMap,
{ str: { includes: ['Attenuation Corrected', 'Corrected'] } },
[options]
)
).toBeUndefined();
expect(
validate(
attributeMap,
{ str: { includes: ['Attenuation', 'Corrected'] } },
[options]
)
).not.toBeUndefined();
expect(
validate(attributeMap, { list: { includes: ['abc'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { includes: ['GHI', 'HI'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { includes: ['HI', 'bye'] } }, [options])
).not.toBeUndefined();
});
});
describe('doesNotInclude', () => {
it('returns undefined if list does not includes', () => {
expect(
validate(
attributeMap,
{ listStr: { doesNotInclude: 'Attenuation Corrected' } },
[options]
)
).not.toBeUndefined();
expect(
validate(
attributeMap,
{
listStr: { doesNotInclude: ['Attenuation Corrected', 'Corrected'] },
},
[options]
)
).not.toBeUndefined();
expect(
validate(
attributeMap,
{ listStr: { doesNotInclude: ['Attenuation', 'Corrected'] } },
[options]
)
).toBeUndefined();
expect(
validate(
attributeMap,
{ str: { doesNotInclude: ['Attenuation Corrected', 'Corrected'] } },
[options]
)
).not.toBeUndefined();
expect(
validate(
attributeMap,
{ str: { doesNotInclude: ['Attenuation', 'Corrected'] } },
[options]
)
).toBeUndefined();
expect(
validate(attributeMap, { list: { doesNotInclude: ['Corr'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { doesNotInclude: 'abc' } }, [options])
).not.toBeUndefined();
expect(
validate(
attributeMap,
{ list: { doesNotInclude: { value: ['abc'] } } },
[options]
)
).not.toBeUndefined();
expect(
validate(
attributeMap,
{ list: { doesNotInclude: { value: ['att', 'cor'] } } },
[options]
)
).toBeUndefined();
expect(
validate(
attributeMap,
{ list: { doesNotInclude: { value: ['abc', 'def', 'dog'] } } },
[options]
)
).not.toBeUndefined();
});
});
describe('containsI', () => {
it('returns match any list contains case insensitive', () => {
expect(
validate(attributeMap, { upper: { containsI: ['hi', 'pre'] } }, [
options,
])
).not.toBeUndefined();
expect(
validate(attributeMap, { list: { containsI: 'hi' } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { containsI: ['ghi', 'bye'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { containsI: ['bye', 'hi'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { containsI: ['ig', 'hi'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { upper: { containsI: ['bye', 'per'] } }, [
options,
])
).toBeUndefined();
});
});
describe('contains', () => {
it('returns match any list contains', () => {
expect(
validate(attributeMap, { str: { contains: 'Corr' } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { str: { contains: { value: 'Corr' } } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { str: { contains: ['Corr'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { str: { contains: ['corr'] } }, [options])
).not.toBeUndefined();
expect(
validate(attributeMap, { str: { contains: ['Att', 'Wall'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { contains: 'GH' } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { contains: ['ab'] } }, [options])
).toBeUndefined();
describe('equals', () => {
it('returned undefined on equals', () => {
expect(
validate(attributeMap, { str: { equals: attributeMap.str } }, [options])
).toBeUndefined();
expect(
validate(
attributeMap,
{ num: { equals: { value: attributeMap.num } } },
[options]
)
).toBeUndefined();
expect(
validate(attributeMap, { list: { contains: ['z', 'bc'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { contains: ['z'] } }, [options])
).not.toBeUndefined();
});
});
it('returns error on not equals', () => {
expect(
validate(attributeMap, { str: { equals: 'abc' } }, [options])
).not.toBeUndefined();
expect(
validate(
attributeMap,
{ num: { equals: { value: 1 + attributeMap.num } } },
[options]
)
).not.toBeUndefined();
describe('doesNotContain', () => {
it('returns undefined if string does not contain specified value', () => {
expect(
validate(attributeMap, { str: { doesNotContain: ['att', 'wall'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotContain: 'Corr' } }, [options])
).not.toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotContain: 'corr' } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotContain: { value: 'corr' } } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotContain: ['att', 'cor'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotContain: ['Att', 'cor'] } }, [
options,
])
).not.toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotContain: ['bye', 'hi'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { doesNotContain: ['GHI', 'hi'] } }, [
options,
])
).not.toBeUndefined();
expect(
validate(attributeMap, { list: { doesNotContain: ['hi'] } }, [options])
).toBeUndefined();
});
});
});
describe('greaterThan', () => {
it('returns undefined on greaterThan', () => {
expect(
validate(
attributeMap,
{ num: { greaterThan: { value: attributeMap.num - 1 } } },
[options]
)
).toBeUndefined();
expect(
validate(attributeMap, { num: { greaterThan: attributeMap.num - 1 } }, [
options,
])
).toBeUndefined();
describe('doesNotContainI', () => {
it('returns undefined if string does not contain specified value', () => {
expect(
validate(attributeMap, { str: { doesNotContainI: 'corr' } }, [options])
).not.toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotContainI: 'Corr' } }, [options])
).not.toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotContainI: ['att', 'cor'] } }, [
options,
])
).not.toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotContainI: ['Att', 'wall'] } }, [
options,
])
).not.toBeUndefined();
expect(
validate(attributeMap, { str: { doesNotContainI: ['bye', 'hi'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { doesNotContainI: ['bye', 'ABC'] } }, [
options,
])
).not.toBeUndefined();
expect(
validate(attributeMap, { list: { doesNotContainI: 'bye' } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { doesNotContainI: ['bye', 'ABC'] } }, [
options,
])
).not.toBeUndefined();
});
});
describe('startsWith', () => {
it('returns undefined if string starts with specified value', () => {
expect(
validate(attributeMap, { str: { startsWith: { value: 'Atte' } } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { str: { startsWith: 'Att' } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { str: { startsWith: ['cat', 'dog', 'Att'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { str: { startsWith: ['cat', 'dog'] } }, [
options,
])
).not.toBeUndefined();
expect(
validate(attributeMap, { list: { startsWith: ['GH'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { startsWith: ['de', 'bye'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { startsWith: ['hi', 'bye'] } }, [
options,
])
).not.toBeUndefined();
});
});
describe('endsWith', () => {
it('returns undefined if string ends with specified value', () => {
expect(
validate(attributeMap, { str: { endsWith: 'ted' } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { str: { endsWith: { value: 'ted' } } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { str: { endsWith: ['ted'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { str: { endsWith: ['Att'] } }, [options])
).not.toBeUndefined();
expect(
validate(attributeMap, { str: { endsWith: ['cat', 'dog', 'ted'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { endsWith: ['HI'] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { list: { endsWith: ['bc', 'dog', 'ted'] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { list: { endsWith: ['bye', 'dog'] } }, [
options,
])
).not.toBeUndefined();
});
});
it('returns error on not greater than', () => {
expect(
validate(
attributeMap,
{ num: { greaterThan: { value: attributeMap.num } } },
[options]
)
).not.toBeUndefined();
expect(
validate(attributeMap, { num: { greaterThan: attributeMap.num } }, [
options,
])
).not.toBeUndefined();
describe('greaterThan', () => {
it('returns undefined on greaterThan', () => {
expect(
validate(
attributeMap,
{ num: { greaterThan: { value: attributeMap.num - 1 } } },
[options]
)
).toBeUndefined();
expect(
validate(attributeMap, { num: { greaterThan: attributeMap.num - 1 } }, [
options,
])
).toBeUndefined();
expect(
validate(
attributeMap,
{ num: { greaterThan: [attributeMap.num - 1] } },
[options]
)
).toBeUndefined();
expect(
validate(
attributeMap,
{ num: { greaterThan: [attributeMap.num + 1] } },
[options]
)
).not.toBeUndefined();
});
});
it('returns error on undefined value', () => {
expect(
validate(
attributeMap,
{ numUndefined: { greaterThan: { value: 3 } } },
[options]
)
).not.toBeUndefined();
describe('lessThan', () => {
it('returns undefined on lessThan', () => {
expect(
validate(
attributeMap,
{ num: { lessThan: { value: attributeMap.num + 1 } } },
[options]
)
).toBeUndefined();
expect(
validate(attributeMap, { num: { lessThan: attributeMap.num + 1 } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { num: { lessThan: [attributeMap.num + 1] } }, [
options,
])
).toBeUndefined();
expect(
validate(attributeMap, { num: { lessThan: [attributeMap.num - 1] } }, [
options,
])
).not.toBeUndefined();
});
});
describe('range', () => {
it('returns undefined if the value is between', () => {
expect(
validate(
attributeMap,
{ num: { range: [attributeMap.num + 1, attributeMap.num - 1] } },
[options]
)
).toBeUndefined();
expect(
validate(attributeMap, { num: { range: [1, 4] } }, [options])
).toBeUndefined();
expect(
validate(attributeMap, { num: { range: [1, 2] } }, [options])
).not.toBeUndefined();
expect(
validate(attributeMap, { num: { range: [4, 5] } }, [options])
).not.toBeUndefined();
expect(
validate(attributeMap, { num: { range: [5] } }, [options])
).not.toBeUndefined();
expect(
validate(attributeMap, { num: { range: 5 } }, [options])
).not.toBeUndefined();
});
});
});
});
+12 -12
View File
@@ -14,23 +14,23 @@ import {
* The interface for the services object
*/
export default interface Services {
userAuthenticationService?: Record<string, unknown>;
hangingProtocolService?: HangingProtocolService;
customizationService?: CustomizationService;
measurementService?: MeasurementService;
displaySetService?: DisplaySetService;
cineService?: Record<string, unknown>;
toolbarService?: ToolbarService;
cornerstoneViewportService?: Record<string, unknown>;
uiDialogService?: Record<string, unknown>;
toolGroupService?: Record<string, unknown>;
uiNotificationService?: UINotificationService;
uiModalService?: UIModalService;
uiViewportDialogService?: Record<string, unknown>;
viewportGridService?: ViewportGridService;
syncGroupService?: Record<string, unknown>;
cornerstoneCacheService?: Record<string, unknown>;
segmentationService?: Record<string, unknown>;
uiModalService?: UIModalService;
uiNotificationService?: UINotificationService;
stateSyncService?: StateSyncService;
panelService?: Record<string, unknown>;
cineService?: unknown;
userAuthenticationService?: unknown;
cornerstoneViewportService?: unknown;
uiDialogService?: unknown;
toolGroupService?: unknown;
uiViewportDialogService?: unknown;
syncGroupService?: unknown;
cornerstoneCacheService?: unknown;
segmentationService?: unknown;
panelService?: unknown;
}
Loaded 100 of 566 files, more files were not shown because too many files have changed in this diff. Show more