Compare commits
76
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7a435c2f3 | ||
|
|
19f1da702f | ||
|
|
14974b6973 | ||
|
|
b4dbe5656b | ||
|
|
c6f7349fd7 | ||
|
|
abe939bd20 | ||
|
|
4d4dd45c23 | ||
|
|
7671b9faf4 | ||
|
|
e653961858 | ||
|
|
aeb61f40da | ||
|
|
b5fb2461dd | ||
|
|
15ad8f29cd | ||
|
|
fa37593696 | ||
|
|
08eed4cdf9 | ||
|
|
b5b7d323c8 | ||
|
|
8a8ae237d2 | ||
|
|
cf1e00fee0 | ||
|
|
ef4f28690a | ||
|
|
c98211ccb5 | ||
|
|
71342fac8f | ||
|
|
52f419d188 | ||
|
|
ca3a0b56f7 | ||
|
|
1a91f210ab | ||
|
|
3503e6e9f4 | ||
|
|
0c51444066 | ||
|
|
83c453d1f3 | ||
|
|
fa73a458bd | ||
|
|
5670a1699d | ||
|
|
c529c0da9c | ||
|
|
d51211f6b9 | ||
|
|
2d8400f9d8 | ||
|
|
e12242a15c | ||
|
|
8baf9deaf0 | ||
|
|
a34a0b1a3a | ||
|
|
e1545b67da | ||
|
|
d75305e70d | ||
|
|
242beb7b46 | ||
|
|
c5d4e97115 | ||
|
|
59cdc4ba9a | ||
|
|
971c594791 | ||
|
|
c55136f55e | ||
|
|
63e12dd651 | ||
|
|
c75c6af22f | ||
|
|
3c777ba58b | ||
|
|
e6f73a2025 | ||
|
|
652e61a417 | ||
|
|
48bcdd6b50 | ||
|
|
cc73f15c8c | ||
|
|
3dce70e624 | ||
|
|
1d00893c49 | ||
|
|
2890635675 | ||
|
|
a6d967a37e | ||
|
|
f23a4500f5 | ||
|
|
cadb559619 | ||
|
|
ad3ef3e8ef | ||
|
|
18c6a47dca | ||
|
|
93f30f06c2 | ||
|
|
50d2640876 | ||
|
|
10e399d7b8 | ||
|
|
e4937e7473 | ||
|
|
62dd2e78bd | ||
|
|
c3654b7ddf | ||
|
|
de60586b71 | ||
|
|
f670678cf0 | ||
|
|
56633a67d9 | ||
|
|
8e2535a308 | ||
|
|
6da1734b6e | ||
|
|
5ae6e9caf4 | ||
|
|
5e4043d99c | ||
|
|
0e991d6bde | ||
|
|
2f63a9db80 | ||
|
|
bedc379e97 | ||
|
|
5b7dc9e9c3 | ||
|
|
00099c0136 | ||
|
|
799d648a90 | ||
|
|
d5c347cecd |
No files matched your search
@@ -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',
|
||||
},
|
||||
|
||||
@@ -34,13 +34,15 @@ provided by the <a href="https://ohif.org/">Open Health Imaging Foundation (OHIF
|
||||
<!-- [](#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
@@ -1 +1 @@
|
||||
14369414cf0193f00243ae5c9f8415cf7079a753
|
||||
14974b6973aff7b8b4a8f485ecf9149523d3a14b
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-cornerstone-dicom-rt",
|
||||
"version": "3.7.0-beta.2",
|
||||
"version": "3.7.0-beta.19",
|
||||
"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.19",
|
||||
"@ohif/extension-cornerstone": "3.7.0-beta.19",
|
||||
"@ohif/extension-default": "3.7.0-beta.19",
|
||||
"@ohif/i18n": "3.7.0-beta.19",
|
||||
"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.19",
|
||||
"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.19",
|
||||
"@ohif/extension-cornerstone": "3.7.0-beta.19",
|
||||
"@ohif/extension-default": "3.7.0-beta.19",
|
||||
"@ohif/i18n": "3.7.0-beta.19",
|
||||
"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 = {
|
||||
@@ -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;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-cornerstone-dicom-sr",
|
||||
"version": "3.7.0-beta.2",
|
||||
"version": "3.7.0-beta.19",
|
||||
"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.19",
|
||||
"@ohif/extension-cornerstone": "3.7.0-beta.19",
|
||||
"@ohif/extension-measurement-tracking": "3.7.0-beta.19",
|
||||
"@ohif/ui": "3.7.0-beta.19",
|
||||
"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.2.4",
|
||||
"@cornerstonejs/core": "^1.2.4",
|
||||
"@cornerstonejs/tools": "^1.2.4",
|
||||
"classnames": "^2.3.2"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-cornerstone",
|
||||
"version": "3.7.0-beta.2",
|
||||
"version": "3.7.0-beta.19",
|
||||
"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.2.4",
|
||||
"@ohif/core": "3.7.0-beta.19",
|
||||
"@ohif/ui": "3.7.0-beta.19",
|
||||
"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.2.4",
|
||||
"@cornerstonejs/core": "^1.2.4",
|
||||
"@cornerstonejs/streaming-image-volume-loader": "^1.2.4",
|
||||
"@cornerstonejs/tools": "^1.2.4",
|
||||
"@kitware/vtk.js": "27.3.1",
|
||||
"html2canvas": "^1.4.1",
|
||||
"lodash.debounce": "4.0.8",
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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 ||
|
||||
|
||||
@@ -166,7 +166,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) {
|
||||
|
||||
@@ -816,45 +816,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 = [];
|
||||
|
||||
@@ -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,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 }) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-default",
|
||||
"version": "3.7.0-beta.2",
|
||||
"version": "3.7.0-beta.19",
|
||||
"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.19",
|
||||
"@ohif/i18n": "3.7.0-beta.19",
|
||||
"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,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-dicom-microscopy",
|
||||
"version": "3.7.0-beta.2",
|
||||
"version": "3.7.0-beta.19",
|
||||
"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.19",
|
||||
"@ohif/extension-default": "3.7.0-beta.19",
|
||||
"@ohif/i18n": "3.7.0-beta.19",
|
||||
"@ohif/ui": "3.7.0-beta.19",
|
||||
"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 }) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-dicom-pdf",
|
||||
"version": "3.7.0-beta.2",
|
||||
"version": "3.7.0-beta.19",
|
||||
"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.19",
|
||||
"@ohif/ui": "3.7.0-beta.19",
|
||||
"dcmjs": "^0.29.5",
|
||||
"dicom-parser": "^1.8.9",
|
||||
"hammerjs": "^2.0.8",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-dicom-video",
|
||||
"version": "3.7.0-beta.2",
|
||||
"version": "3.7.0-beta.19",
|
||||
"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.19",
|
||||
"@ohif/ui": "3.7.0-beta.19",
|
||||
"dcmjs": "^0.29.5",
|
||||
"dicom-parser": "^1.8.9",
|
||||
"hammerjs": "^2.0.8",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-measurement-tracking",
|
||||
"version": "3.7.0-beta.2",
|
||||
"version": "3.7.0-beta.19",
|
||||
"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.2.4",
|
||||
"@cornerstonejs/tools": "^1.2.4",
|
||||
"@ohif/core": "3.7.0-beta.19",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.19",
|
||||
"@ohif/ui": "3.7.0-beta.19",
|
||||
"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.19",
|
||||
"@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 (
|
||||
|
||||
+5
-3
@@ -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,
|
||||
},
|
||||
|
||||
+3
-2
@@ -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,
|
||||
},
|
||||
|
||||
+9
-3
@@ -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,
|
||||
},
|
||||
|
||||
+6
-11
@@ -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,
|
||||
},
|
||||
|
||||
+11
-3
@@ -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: {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-test",
|
||||
"version": "3.7.0-beta.2",
|
||||
"version": "3.7.0-beta.19",
|
||||
"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.19",
|
||||
"@ohif/ui": "3.7.0-beta.19",
|
||||
"dcmjs": "0.29.4",
|
||||
"dicom-parser": "^1.8.9",
|
||||
"hammerjs": "^2.0.8",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-tmtv",
|
||||
"version": "3.7.0-beta.2",
|
||||
"version": "3.7.0-beta.19",
|
||||
"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.19",
|
||||
"@ohif/ui": "3.7.0-beta.19",
|
||||
"dcmjs": "^0.29.5",
|
||||
"dicom-parser": "^1.8.9",
|
||||
"hammerjs": "^2.0.8",
|
||||
|
||||
@@ -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}
|
||||
|
||||
+1
-4
@@ -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"
|
||||
|
||||
+6
-5
@@ -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>
|
||||
|
||||
+12
-15
@@ -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,
|
||||
},
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "3.7.0-beta.2",
|
||||
"version": "3.7.0-beta.19",
|
||||
"packages": ["extensions/*", "platform/*", "modes/*"],
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/mode-basic-dev-mode",
|
||||
"version": "3.7.0-beta.2",
|
||||
"version": "3.7.0-beta.19",
|
||||
"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.19",
|
||||
"@ohif/extension-cornerstone": "3.7.0-beta.19",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.19",
|
||||
"@ohif/extension-default": "3.7.0-beta.19",
|
||||
"@ohif/extension-dicom-pdf": "3.7.0-beta.19",
|
||||
"@ohif/extension-dicom-video": "3.7.0-beta.19"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/mode-test",
|
||||
"version": "3.7.0-beta.2",
|
||||
"version": "3.7.0-beta.19",
|
||||
"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.19",
|
||||
"@ohif/extension-cornerstone": "3.7.0-beta.19",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.19",
|
||||
"@ohif/extension-default": "3.7.0-beta.19",
|
||||
"@ohif/extension-dicom-pdf": "3.7.0-beta.19",
|
||||
"@ohif/extension-dicom-video": "3.7.0-beta.19",
|
||||
"@ohif/extension-measurement-tracking": "3.7.0-beta.19",
|
||||
"@ohif/extension-test": "3.7.0-beta.19"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/mode-longitudinal",
|
||||
"version": "3.7.0-beta.2",
|
||||
"version": "3.7.0-beta.19",
|
||||
"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.19",
|
||||
"@ohif/extension-cornerstone": "3.7.0-beta.19",
|
||||
"@ohif/extension-cornerstone-dicom-rt": "3.7.0-beta.19",
|
||||
"@ohif/extension-cornerstone-dicom-seg": "3.7.0-beta.19",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.19",
|
||||
"@ohif/extension-default": "3.7.0-beta.19",
|
||||
"@ohif/extension-dicom-pdf": "3.7.0-beta.19",
|
||||
"@ohif/extension-dicom-video": "3.7.0-beta.19",
|
||||
"@ohif/extension-measurement-tracking": "3.7.0-beta.19"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/mode-microscopy",
|
||||
"version": "3.7.0-beta.2",
|
||||
"version": "3.7.0-beta.19",
|
||||
"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.19",
|
||||
"@ohif/extension-dicom-microscopy": "3.7.0-beta.19"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/mode-tmtv",
|
||||
"version": "3.7.0-beta.2",
|
||||
"version": "3.7.0-beta.19",
|
||||
"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.19",
|
||||
"@ohif/extension-cornerstone": "3.7.0-beta.19",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.19",
|
||||
"@ohif/extension-default": "3.7.0-beta.19",
|
||||
"@ohif/extension-dicom-pdf": "3.7.0-beta.19",
|
||||
"@ohif/extension-dicom-video": "3.7.0-beta.19",
|
||||
"@ohif/extension-measurement-tracking": "3.7.0-beta.19"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13"
|
||||
|
||||
@@ -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: [
|
||||
{
|
||||
|
||||
+1
-1
@@ -149,7 +149,7 @@
|
||||
]
|
||||
},
|
||||
"resolutions": {
|
||||
"@cornerstonejs/core": "^1.1.8",
|
||||
"@cornerstonejs/core": "^1.2.4",
|
||||
"**/@babel/runtime": "^7.20.13",
|
||||
"commander": "8.3.0",
|
||||
"nth-check": "^2.1.1",
|
||||
|
||||
+4
-4
@@ -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];
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/app",
|
||||
"version": "3.7.0-beta.2",
|
||||
"version": "3.7.0-beta.19",
|
||||
"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.2.4",
|
||||
"@ohif/core": "3.7.0-beta.19",
|
||||
"@ohif/extension-cornerstone": "3.7.0-beta.19",
|
||||
"@ohif/extension-cornerstone-dicom-rt": "3.7.0-beta.19",
|
||||
"@ohif/extension-cornerstone-dicom-seg": "3.7.0-beta.19",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.7.0-beta.19",
|
||||
"@ohif/extension-default": "3.7.0-beta.19",
|
||||
"@ohif/extension-dicom-microscopy": "3.7.0-beta.19",
|
||||
"@ohif/extension-dicom-pdf": "3.7.0-beta.19",
|
||||
"@ohif/extension-dicom-video": "3.7.0-beta.19",
|
||||
"@ohif/extension-test": "3.7.0-beta.19",
|
||||
"@ohif/i18n": "3.7.0-beta.19",
|
||||
"@ohif/mode-basic-dev-mode": "3.7.0-beta.19",
|
||||
"@ohif/mode-longitudinal": "3.7.0-beta.19",
|
||||
"@ohif/mode-microscopy": "3.7.0-beta.19",
|
||||
"@ohif/mode-test": "3.7.0-beta.19",
|
||||
"@ohif/ui": "3.7.0-beta.19",
|
||||
"@types/react": "^17.0.38",
|
||||
"classnames": "^2.3.2",
|
||||
"core-js": "^3.16.1",
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -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,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/cli",
|
||||
"version": "3.7.0-beta.2",
|
||||
"version": "3.7.0-beta.19",
|
||||
"description": "A CLI to bootstrap new OHIF extension or mode",
|
||||
"type": "module",
|
||||
"main": "src/index.js",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/core",
|
||||
"version": "3.7.0-beta.2",
|
||||
"version": "3.7.0-beta.19",
|
||||
"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.2.4",
|
||||
"@ohif/ui": "3.7.0-beta.19",
|
||||
"cornerstone-math": "0.1.9",
|
||||
"dicom-parser": "^1.8.21"
|
||||
},
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -8,5 +8,6 @@ import moment from 'moment';
|
||||
* @returns {string} Formatted date
|
||||
*/
|
||||
export default (date, format = 'DD-MMM-YYYY') => {
|
||||
return moment(date).format(format);
|
||||
// moment(undefined) returns the current date, so return the empty string instead
|
||||
return date ? moment(date).format(format) : '';
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
const generateAcceptHeader = (
|
||||
configAcceptHeader = [],
|
||||
requestTransferSyntaxUID = null,
|
||||
omitQuotationForMultipartRequest = false
|
||||
): string[] => {
|
||||
//if acceptedHeader is passed by config use it as it.
|
||||
if (configAcceptHeader.length > 0) {
|
||||
return configAcceptHeader;
|
||||
}
|
||||
|
||||
let acceptHeader = ['multipart/related'];
|
||||
if (requestTransferSyntaxUID && typeForTS[requestTransferSyntaxUID]) {
|
||||
const type = typeForTS[requestTransferSyntaxUID];
|
||||
acceptHeader.push('type=' + type);
|
||||
acceptHeader.push('transfer-syntax=' + requestTransferSyntaxUID);
|
||||
} else {
|
||||
acceptHeader.push('type=application/octet-stream');
|
||||
}
|
||||
|
||||
if (!omitQuotationForMultipartRequest) {
|
||||
//need to add quotation for each mime type of each accept entry
|
||||
acceptHeader = acceptHeader.map(mime => {
|
||||
if (mime.startsWith('type=')) {
|
||||
const quotedParam = 'type="' + mime.substring(5, mime.length) + '"';
|
||||
return quotedParam;
|
||||
}
|
||||
if (mime.startsWith('transfer-syntax=')) {
|
||||
const quotedParam =
|
||||
'transfer-syntax="' + mime.substring(16, mime.length) + '"';
|
||||
return quotedParam;
|
||||
} else {
|
||||
return mime;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return [acceptHeader.join('; ')];
|
||||
};
|
||||
|
||||
const typeForTS = {
|
||||
'*': 'application/octet-stream',
|
||||
'1.2.840.10008.1.2.1': 'application/octet-stream',
|
||||
'1.2.840.10008.1.2': 'application/octet-stream',
|
||||
'1.2.840.10008.1.2.2': 'application/octet-stream',
|
||||
'1.2.840.10008.1.2.4.70': 'image/jpeg',
|
||||
'1.2.840.10008.1.2.4.50': 'image/jpeg',
|
||||
'1.2.840.10008.1.2.4.51': 'image/dicom+jpeg',
|
||||
'1.2.840.10008.1.2.4.57': 'image/jpeg',
|
||||
'1.2.840.10008.1.2.5': 'image/dicom-rle',
|
||||
'1.2.840.10008.1.2.4.80': 'image/jls',
|
||||
'1.2.840.10008.1.2.4.81': 'image/jls',
|
||||
'1.2.840.10008.1.2.4.90': 'image/jp2',
|
||||
'1.2.840.10008.1.2.4.91': 'image/jp2',
|
||||
'1.2.840.10008.1.2.4.92': 'image/jpx',
|
||||
'1.2.840.10008.1.2.4.93': 'image/jpx',
|
||||
};
|
||||
|
||||
export default generateAcceptHeader;
|
||||
@@ -13,6 +13,7 @@ import Queue from './Queue';
|
||||
import isDicomUid from './isDicomUid';
|
||||
import formatDate from './formatDate';
|
||||
import formatPN from './formatPN';
|
||||
import generateAcceptHeader from './generateAcceptHeader';
|
||||
import resolveObjectPath from './resolveObjectPath';
|
||||
import hierarchicalListUtils from './hierarchicalListUtils';
|
||||
import progressTrackingUtils from './progressTrackingUtils';
|
||||
@@ -74,6 +75,7 @@ const utils = {
|
||||
subscribeToNextViewportGridChange,
|
||||
splitComma,
|
||||
getSplitParam,
|
||||
generateAcceptHeader,
|
||||
};
|
||||
|
||||
export {
|
||||
@@ -105,6 +107,7 @@ export {
|
||||
downloadCSVReport,
|
||||
splitComma,
|
||||
getSplitParam,
|
||||
generateAcceptHeader,
|
||||
};
|
||||
|
||||
export default utils;
|
||||
@@ -24,6 +24,7 @@ describe('Top level exports', () => {
|
||||
'b64toBlob',
|
||||
'formatDate',
|
||||
'formatPN',
|
||||
'generateAcceptHeader',
|
||||
'isEqualWithin',
|
||||
//'loadAndCacheDerivedDisplaySets',
|
||||
'isDisplaySetReconstructable',
|
||||
|
||||
@@ -31,16 +31,18 @@ Key features:
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
|
||||
| | |
|
||||
| :-: | :--- |
|
||||
| <img src="./assets/img/demo-measurements.jpg" alt="Measurement tracking" width="350"/> | Measurement Tracking |
|
||||
| <img src="./assets/img/demo-segmentation.png" alt="Segmentations" width="350"/> | Labelmap Segmentations |
|
||||
| <img src="./assets/img/demo-ptct.png" alt="Hanging Protocols" width="350"/> | Fusion and Custom Hanging protocols |
|
||||
| <img src="./assets/img/demo-microscopy.png" alt="Microscopy" width="350"/> | Slide Microscopy |
|
||||
| <img src="./assets/img/demo-volumeRendering.png" alt="Volume Rendering" width="350"/> | Volume Rendering |
|
||||
| | | |
|
||||
| :-: | :--- | :--- |
|
||||
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-measurements.jpg?raw=true" 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="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-segmentation.png?raw=true" 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="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-ptct.png?raw=true" 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="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-microscopy.png?raw=true" alt="Microscopy" width="350"/> | Slide Microscopy | [Demo](https://viewer.ohif.org/microscopy?StudyInstanceUIDs=2.25.275741864483510678566144889372061815320) |
|
||||
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-volumeRendering.png?raw=true" 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) |
|
||||
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 142 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 214 KiB |
@@ -48,6 +48,7 @@ window.config = {
|
||||
enableStudyLazyLoad: true,
|
||||
supportsFuzzyMatching: true,
|
||||
supportsWildcard: true,
|
||||
omitQuotationForMultipartRequest: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -97,6 +98,7 @@ window.config = ({ servicesManager } = {}) => {
|
||||
enableStudyLazyLoad: true,
|
||||
supportsFuzzyMatching: true,
|
||||
supportsWildcard: true,
|
||||
omitQuotationForMultipartRequest: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -112,6 +114,8 @@ Here are a list of some options available:
|
||||
- `maxNumberOfWebWorkers`: The maximum number of web workers to use for
|
||||
decoding. Defaults to minimum of `navigator.hardwareConcurrency` and
|
||||
what is specified by `maxNumberOfWebWorkers`. Some windows machines require smaller values.
|
||||
- `acceptHeader` : accept header to request specific dicom transfer syntax ex : [ 'multipart/related; type=image/jls; q=1', 'multipart/related; type=application/octet-stream; q=0.1' ]
|
||||
- `requestTransferSyntaxUID` : Request a specific Tansfer syntax from dicom web server ex: 1.2.840.10008.1.2.4.80 (applyed only if acceptHeader is not set)
|
||||
- `omitQuotationForMultipartRequest`: Some servers (e.g., .NET) require the `multipart/related` request to be sent without quotation marks. Defaults to `false`. If your server doesn't require this, then setting this flag to `true` might improve performance (by removing the need for preflight requests). Also note that
|
||||
if auth headers are used, a preflight request is required.
|
||||
- `maxNumRequests`: The maximum number of requests to allow in parallel. It is an object with keys of `interaction`, `thumbnail`, and `prefetch`. You can specify a specific number for each type.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 8
|
||||
sidebar_position: 7
|
||||
sidebar_label: Authorization
|
||||
---
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ and registered extension's features, are configured using this file.
|
||||
|
||||
The easiest way to apply your own configuration is to modify the `default.js`
|
||||
file. For more advanced configuration options, check out our
|
||||
[configuration essentials guide](../configuration/index.md).
|
||||
[configuration essentials guide](../configuration/configurationFiles.md).
|
||||
|
||||
## Next Steps
|
||||
|
||||
@@ -108,6 +108,10 @@ yarn global add http-server
|
||||
npx http-server ./dist
|
||||
```
|
||||
|
||||
:::caution
|
||||
In the video below notice that there is `platform/viewer` which has been renamed to `platform/app` in the latest version
|
||||
:::
|
||||
|
||||
<div style={{padding:"56.25% 0 0 0", position:"relative"}}>
|
||||
<iframe src="https://player.vimeo.com/video/551957266?badge=0&autopause=0&player_id=0&app_id=58479" frameBorder="0" allow="autoplay; fullscreen; picture-in-picture" allowFullScreen style= {{ position:"absolute",top:0,left:0,width:"100%",height:"100%"}} title="measurement-report"></iframe>
|
||||
</div>
|
||||
@@ -127,6 +131,6 @@ web application. For a starting point, check out this repository's own use of:
|
||||
[circleci]: https://circleci.com/gh/OHIF/Viewers
|
||||
[circleci-config]: https://github.com/OHIF/Viewers/blob/master/.circleci/config.yml
|
||||
[netlify]: https://app.netlify.com/sites/ohif/deploys
|
||||
[netlify.toml]: https://github.com/OHIF/Viewers/blob/master/netlify.toml
|
||||
[netlify.toml]: https://github.com/OHIF/Viewers/blob/master/platform/app/netlify.toml
|
||||
[build-deploy-preview.sh]: https://github.com/OHIF/Viewers/blob/master/.netlify/build-deploy-preview.sh
|
||||
<!-- prettier-ignore-end -->
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
sidebar_position: 7
|
||||
---
|
||||
|
||||
# Google Cloud Healthcare
|
||||
|
||||
> Coming soon - We are working on bringing Google Cloud Healthcare to OHIF-v3
|
||||
@@ -0,0 +1,163 @@
|
||||
---
|
||||
sidebar_position: 7
|
||||
sidebar_label: iframe
|
||||
---
|
||||
|
||||
# iframe
|
||||
|
||||
With the transition to more advanced visualization, loading, and rendering techniques using WebWorkers, WASM, and WebGL, the script tag usage of the OHIF viewer v3 has been deprecated.
|
||||
An alternative option for script tag usage is to employ an iframe. You can utilize the iframe element to load the OHIF viewer and establish communication with it using the postMessage API if needed.
|
||||
|
||||
We recommend utilizing modern development practices and incorporating OHIF viewer within your application using a more modular and integrated approach, such as leveraging bundlers, other UI
|
||||
components, and frameworks.
|
||||
|
||||
## Static Build
|
||||
|
||||
You can use the iframe element to load the OHIF viewer as a child element of your application if you need the
|
||||
viewer to be embedded within your application. The iframe element can be used as follows (use your own custom styles)
|
||||
|
||||
```html
|
||||
<iframe src="./path-to-ohif-build" style="width: 100%; height: 500px; border: none"/>
|
||||
```
|
||||
|
||||
The important thing to note here is that the iframe element is loading the OHIF viewer from the `./path-to-ohif-build`. This path can be
|
||||
named anything you want, but it should be the path to the OHIF viewer build directory. The build directory is the directory that
|
||||
contains the `index.html` file (See [build for production](./build-for-production.md) for more information).
|
||||
|
||||
It is also required that the PUBLIC_URL environment variable is set to the same path. For example, if the iframe is
|
||||
`<iframe src="./ohif" />` (which means there is a `ohif` folder containing the build in your main app), then you need to:
|
||||
|
||||
1. use a config (e.g. config/myConfig.js) file that is using the `routerBasename` of `/ohif` (note the one / - it is not /ohif/).
|
||||
2. build the viewer with `PUBLIC_URL=./ohif/ APP_CONFIG=config/myConfig.js yarn build` (note the one / - it is not /ohif/).
|
||||
|
||||
:::tip
|
||||
Check to make sure the `app-config.js` in the build is reflecting the correct routerBasename.
|
||||
:::
|
||||
|
||||
:::tip
|
||||
The PUBLIC_URL tells the application where to find the static assets and the routerBasename will tell the application how to handle the rouets
|
||||
:::
|
||||
|
||||
### Try it locally
|
||||
|
||||
Download the index.html and the build (against the /ohif/ path) from [here](https://ohif-assets.s3.us-east-2.amazonaws.com/iframe-basic/Archive.zip)
|
||||
|
||||
Then run the
|
||||
|
||||
```
|
||||
npx http-server unzipped-folder
|
||||
```
|
||||
|
||||
You should be able to see
|
||||
|
||||

|
||||
|
||||
:::info
|
||||
Notice the Cross Origin Isolation Warning. It is present to indicate that OHIF cannot render volumes because the volume viewports
|
||||
use SharedArrayBuffer which is not allowed for non cross origin isolated apps. You can read more about Cross Origin Isolation here
|
||||
https://web.dev/coop-coep/ or follow the steps below to enable it.
|
||||
:::
|
||||
|
||||
### Fixing the Cross Origin Isolation Warning to enable volume rendering
|
||||
|
||||
For that we need a more sophisticated setup, since we need to add the Cross Origin Embedder Policy and Cross Origin Opener Policy headers
|
||||
to make the parent app cross origin isolated. For that we can use an Express server. (Note: you can use any other method
|
||||
to add the headers, this is just one of the methods)
|
||||
|
||||
Download files from [here](https://ohif-assets.s3.us-east-2.amazonaws.com/iframe-express/Archive.zip)
|
||||
|
||||
```js
|
||||
const express = require("express")
|
||||
const app = express()
|
||||
|
||||
app.use((req, res, next) => {
|
||||
res.setHeader("Cross-Origin-Opener-Policy", "same-origin")
|
||||
res.setHeader("Cross-Origin-Embedder-Policy", "require-corp")
|
||||
next()
|
||||
})
|
||||
|
||||
app.use(express.static("public")) // 'public' should be the folder with the static OHIF build files
|
||||
|
||||
app.listen(8080, () => console.log("Listening on port 8080!"))
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
:::tip
|
||||
if you are using webpack with react you can set
|
||||
|
||||
```js
|
||||
devServer: {
|
||||
headers: {
|
||||
"Cross-Origin-Opener-Policy": "same-origin",
|
||||
"Cross-Origin-Embedder-Policy": "require-corp"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::tip
|
||||
If you are using Angular, you should modify the `angular.json` file to add the headers
|
||||
|
||||
```js
|
||||
"serve": {
|
||||
//
|
||||
"configurations": {
|
||||
//
|
||||
"development": {
|
||||
//
|
||||
"headers": {
|
||||
"Cross-Origin-Opener-Policy": "same-origin",
|
||||
"Cross-Origin-Embedder-Policy": "require-corp"
|
||||
}
|
||||
}
|
||||
},
|
||||
//
|
||||
},
|
||||
```
|
||||
:::
|
||||
|
||||
|
||||
|
||||
## Development Server
|
||||
|
||||
If you are not using the static build, you can use the iframe to load the viewer from the local development server. For example, if you are running the viewer locally on port 3000, you can use the following iframe element to load the viewer:
|
||||
|
||||
```html
|
||||
// e.g., app running on 3001 and iframe loading the viewer from 3000
|
||||
<iframe src="http://localhost:3000" style="width: 100%; height: 500px; border: none"/>
|
||||
```
|
||||
|
||||
Notice that not including the static build removes the need for
|
||||
the PUBLIC_URL and the routerBasename. However, the Cross Origin Resource Policy (CORP)
|
||||
headers must be set because the viewer will be loaded from a different port. You can read
|
||||
more about CORP [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cross-Origin_Resource_Policy).
|
||||
Basically in the development server that is serving the viewer, add the following headers:
|
||||
|
||||
```js
|
||||
// use this if the embedding app is running on the same site as OHIF
|
||||
// (e.g. parent/embedding app is http://localhost:3001 and OHIF is http://localhost:3000)
|
||||
"Cross-Origin-Resource-Policy": "same-site"
|
||||
or
|
||||
|
||||
// use this if the embedding app is a completely different origin than OHIF (e.g.
|
||||
// parent/embedding app is http://192.168.1.2 and OHIF is http://localhost:3000)
|
||||
"Cross-Origin-Resource-Policy": "cross-origin"
|
||||
```
|
||||
|
||||
:::info
|
||||
You can't set the `Cross-Origin-Resource-Policy` to `same-origin` since the viewer is loaded from a different port.
|
||||
:::
|
||||
|
||||
:::tip
|
||||
If you are using webpack to serve the viewer it would be
|
||||
|
||||
```js
|
||||
devServer: {
|
||||
headers: {
|
||||
"Cross-Origin-Resource-Policy": "same-site" // cross-origin is also valid
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -5,29 +5,21 @@ sidebar_label: Overview
|
||||
|
||||
# Deployment
|
||||
|
||||
The OHIF Viewer can be embedded in other web applications via it's [packaged
|
||||
script source][viewer-npm], or served up as a stand-alone PWA ([progressive web
|
||||
application][pwa-url]) by building and hosting a collection of static assets. In
|
||||
The OHIF Viewer can be served as a stand-alone PWA ([progressive web
|
||||
application][pwa-url]) by building and hosting a collection of static assets or be embedded in other web applications via an iframe if needed. In
|
||||
either case, you will need to configure your instance of the Viewer so that it
|
||||
can connect to your data source (the database or PACS that provides the data
|
||||
your Viewer will display).
|
||||
|
||||
## Overview
|
||||
|
||||
:::tip
|
||||
Our goal is to make deployment as simple and painless as possible; however,
|
||||
there is an inherent amount of complexity in configuring and deploying web
|
||||
applications. If you find yourself a little lost, please don't hesitate to
|
||||
[reach out for help](/help)
|
||||
reach out to for help.
|
||||
:::
|
||||
|
||||
## Deployment Scenarios
|
||||
|
||||
### Embedded Viewer (deprecated)
|
||||
|
||||
`OHIF-v3` has deprecated deploying the viewer as an embedded viewer the number
|
||||
of underlying libraries that run web workers are increasing for OHIF. An example
|
||||
of these libraries is OHIF's 3D rendering functionality that is provided by
|
||||
`vtk-js`.
|
||||
|
||||
### Stand-alone Viewer
|
||||
|
||||
Deploying the OHIF Viewer as a stand-alone web application provides many
|
||||
@@ -43,7 +35,6 @@ _Today:_
|
||||
_In the future:_
|
||||
|
||||
- The ability to package the viewer for [App Store distribution][app-store]
|
||||
- Leverage `service-workers` for offline support and speed benefits from caching
|
||||
|
||||
#### Hosted Static Assets
|
||||
|
||||
@@ -52,10 +43,6 @@ HTML, CSS, JS, Font Files, and Images. We "build" those files from our
|
||||
`source code` with configuration specific to our project. We then make those
|
||||
files publicly accessible by hosting them on a Web Server.
|
||||
|
||||
If you have not deployed a web application before, this may be a good time to
|
||||
[reach out for help](/help), as these steps assume prior web development and
|
||||
deployment experience.
|
||||
|
||||
##### Part 1 - Build Production Assets
|
||||
|
||||
"Building", or creating, the files you will need is the same regardless of the
|
||||
@@ -84,6 +71,16 @@ _Advanced_
|
||||
- [GCP + Cloudflare](./static-assets.md#gcp--cloudflare)
|
||||
- [Azure](./static-assets.md#azure)
|
||||
|
||||
### Embedded Viewer (iframe)
|
||||
|
||||
`OHIF-v3` has deprecated deploying the viewer as an embedded viewer via a script
|
||||
tag as the number of underlying libraries that run web workers are increasing for OHIF. An example of these libraries is OHIF's 3D rendering functionality that is provided by
|
||||
`vtk-js`.
|
||||
|
||||
However, you can still embed the viewer using an iframe. You can utilize the iframe element to load the OHIF viewer and establish communication with it using the postMessage API if needed.
|
||||
Read more about how to use the iframe [here](./iframe.md).
|
||||
|
||||
|
||||
## Data
|
||||
|
||||
The OHIF Viewer is able to connect to any data source that implements the [DICOM
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
sidebar_position: 6
|
||||
---
|
||||
|
||||
# User Account Control
|
||||
|
||||
> Coming soon - We are working on bringing the User Account Control to OHIF-v3
|
||||
@@ -113,7 +113,7 @@ files:
|
||||
|
||||
### create-extension
|
||||
|
||||
Similar to the `create-extension` command, you can use the `create-extension`
|
||||
Similar to the `create-mode` command, you can use the `create-extension`
|
||||
command to create a new extension template. This command will create a new
|
||||
extension template in the directory that you specify the path.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
sidebar_position: 10
|
||||
sidebar_label: 💥 Migration Guide (NEW)💥
|
||||
sidebar_label: Migration Guide (NEW)
|
||||
---
|
||||
|
||||
# Migration Guide
|
||||
|
||||
Loaded 100 of 539 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user