@ohif/app 3.7.0-beta.6 → 3.7.0-beta.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{917.bundle.57d86a03581296d2ee00.js → 12.bundle.c54b94d07d31f5716eb1.js} +6 -6
- package/dist/{295.bundle.957b1159fec14b9199a1.js → 125.bundle.1ae4c6313c31cd0502cc.js} +4 -4
- package/dist/{208.bundle.182a2d2827d0d8afce33.js → 128.bundle.b0a7aa9ae66c094c40b5.js} +6 -6
- package/dist/{616.bundle.0ab47fe1619e9ed278b9.js → 150.bundle.2075342642eddc35e924.js} +155 -104
- package/dist/{351.bundle.0742237651aef9694a65.js → 181.bundle.70c4340cbe29bd14aafc.js} +147 -129
- package/dist/{351.css → 181.css} +1 -1
- package/dist/{606.bundle.5d876f5f3dd8287f0a28.js → 202.bundle.8007de18c96daaceca7f.js} +1459 -811
- package/dist/{926.bundle.dbc9d0e591cb9217fda2.js → 220.bundle.f7e1c96c94245e70f2be.js} +990 -400
- package/dist/{664.bundle.09abae984223969d1bde.js → 23.bundle.e008ad788170f2ed5569.js} +5 -6
- package/dist/{976.bundle.d6c34ae072976b3d9c29.js → 236.bundle.4aab776fb3e7654f1f0c.js} +38 -24
- package/dist/{55.bundle.550a823e75eb608e8d5e.js → 250.bundle.0d497b1b8afb0cbbe02f.js} +37 -25
- package/dist/{973.bundle.1a5e3125446a7f22729b.js → 281.bundle.c35a76364b385ee72bfd.js} +18 -14
- package/dist/{744.bundle.2282095988d3a22f17eb.js → 30.bundle.777231cf20f408db12f1.js} +128 -119
- package/dist/{192.bundle.2ae9e68532962089836f.js → 348.bundle.be4810ac9ac67cd7d8c5.js} +18 -14
- package/dist/{404.bundle.dd49183aaac4294b003b.js → 359.bundle.d723d31672f7fe575501.js} +13 -19
- package/dist/{82.bundle.0b649d84e313e1928590.js → 362.bundle.9d4d81eab3e31314a932.js} +1274 -287
- package/dist/{50.bundle.5eb258e72b39b2216560.js → 378.bundle.3069476ee6501c83ad44.js} +10 -8
- package/dist/{790.bundle.d362d0c4b8cdf0493e73.js → 410.bundle.f973e56e3a7d8165d87a.js} +6 -6
- package/dist/{151.bundle.31ea35044218837bf73f.js → 417.bundle.720dc8f3a6e99f378aa9.js} +9 -11
- package/dist/{569.bundle.21f8ad57c06a210448b5.js → 451.bundle.a573877dff7b43382138.js} +63 -81
- package/dist/{581.bundle.dc6197189f7c88c27d4c.js → 471.bundle.e9ecd59867a19e323234.js} +44 -72
- package/dist/{199.bundle.ec85a189dbc481dc980b.js → 506.bundle.8b2c661a99271b31663c.js} +79 -10
- package/dist/{935.bundle.deeffff0e4f7b528e3c3.js → 604.bundle.a51f83e64004bca5f497.js} +2 -3
- package/dist/{984.bundle.e48272bf3c41816e19fc.js → 663.bundle.80190c7364dd4095010b.js} +67 -37
- package/dist/{531.bundle.2a82fb1d69e5b57cc72b.js → 677.bundle.ec5f2b4707db33bd4d8e.js} +731 -447
- package/dist/{707.bundle.7fd06edc9852075913ec.js → 678.bundle.adc83cac2fd0ea4f19f2.js} +209 -216
- package/dist/{205.bundle.b5a473c200dcf2bbcdb4.js → 686.bundle.70565410179f1e7d22e6.js} +4 -4
- package/dist/{331.bundle.bd0c13931a21d53086c9.js → 754.bundle.1884c227b361aefa66b4.js} +12383 -7530
- package/dist/{728.bundle.d13856835357400fef82.js → 774.bundle.8ba82ee206266eb2da5e.js} +90 -63
- package/dist/{381.bundle.0905e683605fcbc0895f.js → 775.bundle.2285e7e0e67878948c0d.js} +16 -16
- package/dist/{283.bundle.426df6a7412bc2932775.js → 782.bundle.fc7e353f1dce39953254.js} +57 -26
- package/dist/{642.bundle.0a98bca321a959b489f2.js → 814.bundle.9218ffc353490526c320.js} +6 -6
- package/dist/{799.bundle.758558e64147e5aad612.js → 822.bundle.99bf759483aa32086346.js} +66 -17
- package/dist/{953.bundle.3b0189ebc11cf0946f18.js → 886.bundle.c5a6b96760ea43352375.js} +17 -11
- package/dist/{270.bundle.4564621556b0f963a004.js → 925.bundle.7b06521fc75e0d3f71c3.js} +770 -607
- package/dist/945.min.worker.js +1 -1
- package/dist/945.min.worker.js.map +1 -1
- package/dist/app-config.js +7 -7
- package/dist/{app.bundle.3f8ce0b8b48882f2ff10.js → app.bundle.2a91a8b9b9e61b42cc21.js} +70344 -68432
- package/dist/app.bundle.css +9 -9
- package/dist/cornerstoneDICOMImageLoader.min.js +1 -1
- package/dist/cornerstoneDICOMImageLoader.min.js.map +1 -1
- package/dist/{dicom-microscopy-viewer.bundle.aa60bdf008c32c39cfd7.js → dicom-microscopy-viewer.bundle.2c146384eb9466d02ff8.js} +5 -4
- package/dist/google.js +7 -5
- package/dist/index.html +1 -1
- package/dist/{index.worker.1c69152d710fa7b84bce.worker.js → index.worker.e62ecca63f1a2e124230.worker.js} +2 -2
- package/dist/index.worker.e62ecca63f1a2e124230.worker.js.map +1 -0
- package/dist/sw.js +1 -1
- package/package.json +19 -20
- package/dist/780.bundle.fd0f13dc92e9caa0581e.js +0 -4769
- package/dist/index.worker.1c69152d710fa7b84bce.worker.js.map +0 -1
- /package/dist/{55.css → 250.css} +0 -0
- /package/dist/{806.css → 579.css} +0 -0
- /package/dist/{707.css → 678.css} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
(
|
|
2
|
+
(self["webpackChunk"] = self["webpackChunk"] || []).push([[362],{
|
|
3
3
|
|
|
4
|
-
/***/
|
|
4
|
+
/***/ 13362:
|
|
5
5
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
6
6
|
|
|
7
7
|
// ESM COMPAT FLAG
|
|
@@ -28,11 +28,11 @@ __webpack_require__.d(utils_namespaceObject, {
|
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
// EXTERNAL MODULE: ../../../node_modules/dicomweb-client/build/dicomweb-client.es.js
|
|
31
|
-
var dicomweb_client_es = __webpack_require__(
|
|
32
|
-
// EXTERNAL MODULE: ../../core/src/index.ts +
|
|
33
|
-
var src = __webpack_require__(
|
|
31
|
+
var dicomweb_client_es = __webpack_require__(97604);
|
|
32
|
+
// EXTERNAL MODULE: ../../core/src/index.ts + 106 modules
|
|
33
|
+
var src = __webpack_require__(38930);
|
|
34
34
|
// EXTERNAL MODULE: ../../core/src/utils/sortStudy.ts
|
|
35
|
-
var sortStudy = __webpack_require__(
|
|
35
|
+
var sortStudy = __webpack_require__(62971);
|
|
36
36
|
;// CONCATENATED MODULE: ../../../extensions/default/src/DicomWebDataSource/qido.js
|
|
37
37
|
/**
|
|
38
38
|
* QIDO - Query based on ID for DICOM Objects
|
|
@@ -378,7 +378,7 @@ function getImageId(_ref) {
|
|
|
378
378
|
}
|
|
379
379
|
}
|
|
380
380
|
// EXTERNAL MODULE: ../../../node_modules/dcmjs/build/dcmjs.es.js
|
|
381
|
-
var dcmjs_es = __webpack_require__(
|
|
381
|
+
var dcmjs_es = __webpack_require__(67540);
|
|
382
382
|
;// CONCATENATED MODULE: ../../../extensions/default/src/DicomWebDataSource/wado/retrieveMetadataLoader.js
|
|
383
383
|
/**
|
|
384
384
|
* Class to define inheritance of load retrieve strategy.
|
|
@@ -708,12 +708,16 @@ class StaticWadoClient extends dicomweb_client_es.api.DICOMwebClient {
|
|
|
708
708
|
* @returns
|
|
709
709
|
*/
|
|
710
710
|
async searchForStudies(options) {
|
|
711
|
-
if (!this.staticWado)
|
|
711
|
+
if (!this.staticWado) {
|
|
712
|
+
return super.searchForStudies(options);
|
|
713
|
+
}
|
|
712
714
|
const searchResult = await super.searchForStudies(options);
|
|
713
715
|
const {
|
|
714
716
|
queryParams
|
|
715
717
|
} = options;
|
|
716
|
-
if (!queryParams)
|
|
718
|
+
if (!queryParams) {
|
|
719
|
+
return searchResult;
|
|
720
|
+
}
|
|
717
721
|
const lowerParams = this.toLowerParams(queryParams);
|
|
718
722
|
const filtered = searchResult.filter(study => {
|
|
719
723
|
for (const key of Object.keys(StaticWadoClient.studyFilterKeys)) {
|
|
@@ -726,12 +730,16 @@ class StaticWadoClient extends dicomweb_client_es.api.DICOMwebClient {
|
|
|
726
730
|
return filtered;
|
|
727
731
|
}
|
|
728
732
|
async searchForSeries(options) {
|
|
729
|
-
if (!this.staticWado)
|
|
733
|
+
if (!this.staticWado) {
|
|
734
|
+
return super.searchForSeries(options);
|
|
735
|
+
}
|
|
730
736
|
const searchResult = await super.searchForSeries(options);
|
|
731
737
|
const {
|
|
732
738
|
queryParams
|
|
733
739
|
} = options;
|
|
734
|
-
if (!queryParams)
|
|
740
|
+
if (!queryParams) {
|
|
741
|
+
return searchResult;
|
|
742
|
+
}
|
|
735
743
|
const lowerParams = this.toLowerParams(queryParams);
|
|
736
744
|
const filtered = searchResult.filter(series => {
|
|
737
745
|
for (const key of Object.keys(StaticWadoClient.seriesFilterKeys)) {
|
|
@@ -767,8 +775,12 @@ class StaticWadoClient extends dicomweb_client_es.api.DICOMwebClient {
|
|
|
767
775
|
actual = actual.Alphabetic;
|
|
768
776
|
}
|
|
769
777
|
if (typeof actual == 'string') {
|
|
770
|
-
if (actual.length === 0)
|
|
771
|
-
|
|
778
|
+
if (actual.length === 0) {
|
|
779
|
+
return true;
|
|
780
|
+
}
|
|
781
|
+
if (desired.length === 0 || desired === '*') {
|
|
782
|
+
return true;
|
|
783
|
+
}
|
|
772
784
|
if (desired[0] === '*' && desired[desired.length - 1] === '*') {
|
|
773
785
|
// console.log(`Comparing ${actual} to ${desired.substring(1, desired.length - 1)}`)
|
|
774
786
|
return actual.indexOf(desired.substring(1, desired.length - 1)) != -1;
|
|
@@ -783,9 +795,13 @@ class StaticWadoClient extends dicomweb_client_es.api.DICOMwebClient {
|
|
|
783
795
|
|
|
784
796
|
/** Compares a pair of dates to see if the value is within the range */
|
|
785
797
|
compareDateRange(range, value) {
|
|
786
|
-
if (!value)
|
|
798
|
+
if (!value) {
|
|
799
|
+
return true;
|
|
800
|
+
}
|
|
787
801
|
const dash = range.indexOf('-');
|
|
788
|
-
if (dash === -1)
|
|
802
|
+
if (dash === -1) {
|
|
803
|
+
return this.compareValues(range, value);
|
|
804
|
+
}
|
|
789
805
|
const start = range.substring(0, dash);
|
|
790
806
|
const end = range.substring(dash + 1);
|
|
791
807
|
return (!start || value >= start) && (!end || value <= end);
|
|
@@ -802,11 +818,17 @@ class StaticWadoClient extends dicomweb_client_es.api.DICOMwebClient {
|
|
|
802
818
|
*/
|
|
803
819
|
filterItem(key, queryParams, study, sourceFilterMap) {
|
|
804
820
|
const altKey = sourceFilterMap[key] || key;
|
|
805
|
-
if (!queryParams)
|
|
821
|
+
if (!queryParams) {
|
|
822
|
+
return true;
|
|
823
|
+
}
|
|
806
824
|
const testValue = queryParams[key] || queryParams[altKey];
|
|
807
|
-
if (!testValue)
|
|
825
|
+
if (!testValue) {
|
|
826
|
+
return true;
|
|
827
|
+
}
|
|
808
828
|
const valueElem = study[key] || study[altKey];
|
|
809
|
-
if (!valueElem)
|
|
829
|
+
if (!valueElem) {
|
|
830
|
+
return false;
|
|
831
|
+
}
|
|
810
832
|
if (valueElem.vr == 'DA') {
|
|
811
833
|
return this.compareDateRange(testValue, valueElem.Value[0]);
|
|
812
834
|
}
|
|
@@ -867,8 +889,12 @@ const getDirectURL = (config, params) => {
|
|
|
867
889
|
singlepart: fetchPart = 'video'
|
|
868
890
|
} = params;
|
|
869
891
|
const value = instance[tag];
|
|
870
|
-
if (!value)
|
|
871
|
-
|
|
892
|
+
if (!value) {
|
|
893
|
+
return undefined;
|
|
894
|
+
}
|
|
895
|
+
if (value.DirectRetrieveURL) {
|
|
896
|
+
return value.DirectRetrieveURL;
|
|
897
|
+
}
|
|
872
898
|
if (value.InlineBinary) {
|
|
873
899
|
const blob = src.utils.b64toBlob(value.InlineBinary, defaultType);
|
|
874
900
|
value.DirectRetrieveURL = URL.createObjectURL(blob);
|
|
@@ -991,65 +1017,69 @@ const metadataProvider = src.classes.MetadataProvider;
|
|
|
991
1017
|
* @param {string|bool} singlepart - indicates of the retrieves can fetch singlepart. Options are bulkdata, video, image or boolean true
|
|
992
1018
|
*/
|
|
993
1019
|
function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
994
|
-
|
|
995
|
-
qidoRoot,
|
|
996
|
-
wadoRoot,
|
|
997
|
-
enableStudyLazyLoad,
|
|
998
|
-
supportsFuzzyMatching,
|
|
999
|
-
supportsWildcard,
|
|
1000
|
-
supportsReject,
|
|
1001
|
-
staticWado,
|
|
1002
|
-
singlepart
|
|
1003
|
-
} = dicomWebConfig;
|
|
1004
|
-
const dicomWebConfigCopy = JSON.parse(JSON.stringify(dicomWebConfig));
|
|
1005
|
-
const qidoConfig = {
|
|
1006
|
-
url: qidoRoot,
|
|
1007
|
-
staticWado,
|
|
1008
|
-
singlepart,
|
|
1009
|
-
headers: userAuthenticationService.getAuthorizationHeader(),
|
|
1010
|
-
errorInterceptor: src/* errorHandler */.Po.getHTTPErrorHandler()
|
|
1011
|
-
};
|
|
1012
|
-
const wadoConfig = {
|
|
1013
|
-
url: wadoRoot,
|
|
1014
|
-
staticWado,
|
|
1015
|
-
singlepart,
|
|
1016
|
-
headers: userAuthenticationService.getAuthorizationHeader(),
|
|
1017
|
-
errorInterceptor: src/* errorHandler */.Po.getHTTPErrorHandler()
|
|
1018
|
-
};
|
|
1019
|
-
|
|
1020
|
-
// TODO -> Two clients sucks, but its better than 1000.
|
|
1021
|
-
// TODO -> We'll need to merge auth later.
|
|
1022
|
-
const qidoDicomWebClient = staticWado ? new StaticWadoClient(qidoConfig) : new dicomweb_client_es.api.DICOMwebClient(qidoConfig);
|
|
1023
|
-
const wadoDicomWebClient = staticWado ? new StaticWadoClient(wadoConfig) : new dicomweb_client_es.api.DICOMwebClient(wadoConfig);
|
|
1020
|
+
let dicomWebConfigCopy, qidoConfig, wadoConfig, qidoDicomWebClient, wadoDicomWebClient, getAuthrorizationHeader, generateWadoHeader;
|
|
1024
1021
|
const implementation = {
|
|
1025
1022
|
initialize: _ref => {
|
|
1026
1023
|
let {
|
|
1027
1024
|
params,
|
|
1028
1025
|
query
|
|
1029
1026
|
} = _ref;
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1027
|
+
if (dicomWebConfig.onConfiguration && typeof dicomWebConfig.onConfiguration === 'function') {
|
|
1028
|
+
dicomWebConfig = dicomWebConfig.onConfiguration(dicomWebConfig, {
|
|
1029
|
+
params,
|
|
1030
|
+
query
|
|
1031
|
+
});
|
|
1032
|
+
}
|
|
1033
|
+
dicomWebConfigCopy = JSON.parse(JSON.stringify(dicomWebConfig));
|
|
1034
|
+
getAuthrorizationHeader = () => {
|
|
1035
|
+
const xhrRequestHeaders = {};
|
|
1036
|
+
const authHeaders = userAuthenticationService.getAuthorizationHeader();
|
|
1037
|
+
if (authHeaders && authHeaders.Authorization) {
|
|
1038
|
+
xhrRequestHeaders.Authorization = authHeaders.Authorization;
|
|
1039
|
+
}
|
|
1040
|
+
return xhrRequestHeaders;
|
|
1041
|
+
};
|
|
1042
|
+
generateWadoHeader = () => {
|
|
1043
|
+
let authorizationHeader = getAuthrorizationHeader();
|
|
1044
|
+
//Generate accept header depending on config params
|
|
1045
|
+
let formattedAcceptHeader = src.utils.generateAcceptHeader(dicomWebConfig.acceptHeader, dicomWebConfig.requestTransferSyntaxUID, dicomWebConfig.omitQuotationForMultipartRequest);
|
|
1046
|
+
return {
|
|
1047
|
+
...authorizationHeader,
|
|
1048
|
+
Accept: formattedAcceptHeader
|
|
1049
|
+
};
|
|
1050
|
+
};
|
|
1051
|
+
qidoConfig = {
|
|
1052
|
+
url: dicomWebConfig.qidoRoot,
|
|
1053
|
+
staticWado: dicomWebConfig.staticWado,
|
|
1054
|
+
singlepart: dicomWebConfig.singlepart,
|
|
1055
|
+
headers: userAuthenticationService.getAuthorizationHeader(),
|
|
1056
|
+
errorInterceptor: src/* errorHandler */.Po.getHTTPErrorHandler()
|
|
1057
|
+
};
|
|
1058
|
+
wadoConfig = {
|
|
1059
|
+
url: dicomWebConfig.wadoRoot,
|
|
1060
|
+
staticWado: dicomWebConfig.staticWado,
|
|
1061
|
+
singlepart: dicomWebConfig.singlepart,
|
|
1062
|
+
headers: userAuthenticationService.getAuthorizationHeader(),
|
|
1063
|
+
errorInterceptor: src/* errorHandler */.Po.getHTTPErrorHandler()
|
|
1064
|
+
};
|
|
1065
|
+
|
|
1066
|
+
// TODO -> Two clients sucks, but its better than 1000.
|
|
1067
|
+
// TODO -> We'll need to merge auth later.
|
|
1068
|
+
qidoDicomWebClient = dicomWebConfig.staticWado ? new StaticWadoClient(qidoConfig) : new dicomweb_client_es.api.DICOMwebClient(qidoConfig);
|
|
1069
|
+
wadoDicomWebClient = dicomWebConfig.staticWado ? new StaticWadoClient(wadoConfig) : new dicomweb_client_es.api.DICOMwebClient(wadoConfig);
|
|
1037
1070
|
},
|
|
1038
1071
|
query: {
|
|
1039
1072
|
studies: {
|
|
1040
1073
|
mapParams: mapParams.bind(),
|
|
1041
1074
|
search: async function (origParams) {
|
|
1042
|
-
|
|
1043
|
-
if (headers) {
|
|
1044
|
-
qidoDicomWebClient.headers = headers;
|
|
1045
|
-
}
|
|
1075
|
+
qidoDicomWebClient.headers = getAuthrorizationHeader();
|
|
1046
1076
|
const {
|
|
1047
1077
|
studyInstanceUid,
|
|
1048
1078
|
seriesInstanceUid,
|
|
1049
1079
|
...mappedParams
|
|
1050
1080
|
} = mapParams(origParams, {
|
|
1051
|
-
supportsFuzzyMatching,
|
|
1052
|
-
supportsWildcard
|
|
1081
|
+
supportsFuzzyMatching: dicomWebConfig.supportsFuzzyMatching,
|
|
1082
|
+
supportsWildcard: dicomWebConfig.supportsWildcard
|
|
1053
1083
|
}) || {};
|
|
1054
1084
|
const results = await search(qidoDicomWebClient, undefined, undefined, mappedParams);
|
|
1055
1085
|
return processResults(results);
|
|
@@ -1059,10 +1089,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
|
1059
1089
|
series: {
|
|
1060
1090
|
// mapParams: mapParams.bind(),
|
|
1061
1091
|
search: async function (studyInstanceUid) {
|
|
1062
|
-
|
|
1063
|
-
if (headers) {
|
|
1064
|
-
qidoDicomWebClient.headers = headers;
|
|
1065
|
-
}
|
|
1092
|
+
qidoDicomWebClient.headers = getAuthrorizationHeader();
|
|
1066
1093
|
const results = await seriesInStudy(qidoDicomWebClient, studyInstanceUid);
|
|
1067
1094
|
return processSeriesResults(results);
|
|
1068
1095
|
}
|
|
@@ -1071,10 +1098,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
|
1071
1098
|
|
|
1072
1099
|
instances: {
|
|
1073
1100
|
search: (studyInstanceUid, queryParameters) => {
|
|
1074
|
-
|
|
1075
|
-
if (headers) {
|
|
1076
|
-
qidoDicomWebClient.headers = headers;
|
|
1077
|
-
}
|
|
1101
|
+
qidoDicomWebClient.headers = getAuthrorizationHeader();
|
|
1078
1102
|
search.call(undefined, qidoDicomWebClient, studyInstanceUid, null, queryParameters);
|
|
1079
1103
|
}
|
|
1080
1104
|
}
|
|
@@ -1093,8 +1117,8 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
|
1093
1117
|
*/
|
|
1094
1118
|
directURL: params => {
|
|
1095
1119
|
return utils_getDirectURL({
|
|
1096
|
-
wadoRoot,
|
|
1097
|
-
singlepart
|
|
1120
|
+
wadoRoot: dicomWebConfig.wadoRoot,
|
|
1121
|
+
singlepart: dicomWebConfig.singlepart
|
|
1098
1122
|
}, params);
|
|
1099
1123
|
},
|
|
1100
1124
|
bulkDataURI: async _ref2 => {
|
|
@@ -1102,6 +1126,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
|
1102
1126
|
StudyInstanceUID,
|
|
1103
1127
|
BulkDataURI
|
|
1104
1128
|
} = _ref2;
|
|
1129
|
+
qidoDicomWebClient.headers = getAuthrorizationHeader();
|
|
1105
1130
|
const options = {
|
|
1106
1131
|
multipart: false,
|
|
1107
1132
|
BulkDataURI,
|
|
@@ -1121,14 +1146,10 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
|
1121
1146
|
sortFunction,
|
|
1122
1147
|
madeInClient = false
|
|
1123
1148
|
} = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
1124
|
-
const headers = userAuthenticationService.getAuthorizationHeader();
|
|
1125
|
-
if (headers) {
|
|
1126
|
-
wadoDicomWebClient.headers = headers;
|
|
1127
|
-
}
|
|
1128
1149
|
if (!StudyInstanceUID) {
|
|
1129
1150
|
throw new Error('Unable to query for SeriesMetadata without StudyInstanceUID');
|
|
1130
1151
|
}
|
|
1131
|
-
if (enableStudyLazyLoad) {
|
|
1152
|
+
if (dicomWebConfig.enableStudyLazyLoad) {
|
|
1132
1153
|
return implementation._retrieveSeriesMetadataAsync(StudyInstanceUID, filters, sortCriteria, sortFunction, madeInClient);
|
|
1133
1154
|
}
|
|
1134
1155
|
return implementation._retrieveSeriesMetadataSync(StudyInstanceUID, filters, sortCriteria, sortFunction, madeInClient);
|
|
@@ -1137,10 +1158,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
|
1137
1158
|
},
|
|
1138
1159
|
store: {
|
|
1139
1160
|
dicom: async (dataset, request) => {
|
|
1140
|
-
|
|
1141
|
-
if (headers) {
|
|
1142
|
-
wadoDicomWebClient.headers = headers;
|
|
1143
|
-
}
|
|
1161
|
+
wadoDicomWebClient.headers = getAuthrorizationHeader();
|
|
1144
1162
|
if (dataset instanceof ArrayBuffer) {
|
|
1145
1163
|
const options = {
|
|
1146
1164
|
datasets: [dataset],
|
|
@@ -1170,7 +1188,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
|
1170
1188
|
},
|
|
1171
1189
|
_retrieveSeriesMetadataSync: async (StudyInstanceUID, filters, sortCriteria, sortFunction, madeInClient) => {
|
|
1172
1190
|
const enableStudyLazyLoad = false;
|
|
1173
|
-
|
|
1191
|
+
wadoDicomWebClient.headers = generateWadoHeader();
|
|
1174
1192
|
// data is all SOPInstanceUIDs
|
|
1175
1193
|
const data = await retrieveStudyMetadata(wadoDicomWebClient, StudyInstanceUID, enableStudyLazyLoad, filters, sortCriteria, sortFunction);
|
|
1176
1194
|
|
|
@@ -1215,6 +1233,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
|
1215
1233
|
_retrieveSeriesMetadataAsync: async function (StudyInstanceUID, filters, sortCriteria, sortFunction) {
|
|
1216
1234
|
let madeInClient = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
|
|
1217
1235
|
const enableStudyLazyLoad = true;
|
|
1236
|
+
wadoDicomWebClient.headers = generateWadoHeader();
|
|
1218
1237
|
// Get Series
|
|
1219
1238
|
const {
|
|
1220
1239
|
preLoadData: seriesSummaryMetadata,
|
|
@@ -1356,10 +1375,23 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
|
1356
1375
|
},
|
|
1357
1376
|
getConfig() {
|
|
1358
1377
|
return dicomWebConfigCopy;
|
|
1378
|
+
},
|
|
1379
|
+
getStudyInstanceUIDs(_ref4) {
|
|
1380
|
+
let {
|
|
1381
|
+
params,
|
|
1382
|
+
query
|
|
1383
|
+
} = _ref4;
|
|
1384
|
+
const {
|
|
1385
|
+
StudyInstanceUIDs: paramsStudyInstanceUIDs
|
|
1386
|
+
} = params;
|
|
1387
|
+
const queryStudyInstanceUIDs = src.utils.splitComma(query.getAll('StudyInstanceUIDs'));
|
|
1388
|
+
const StudyInstanceUIDs = queryStudyInstanceUIDs.length && queryStudyInstanceUIDs || paramsStudyInstanceUIDs;
|
|
1389
|
+
const StudyInstanceUIDsAsArray = StudyInstanceUIDs && Array.isArray(StudyInstanceUIDs) ? StudyInstanceUIDs : [StudyInstanceUIDs];
|
|
1390
|
+
return StudyInstanceUIDsAsArray;
|
|
1359
1391
|
}
|
|
1360
1392
|
};
|
|
1361
|
-
if (supportsReject) {
|
|
1362
|
-
implementation.reject = dcm4cheeReject(wadoRoot);
|
|
1393
|
+
if (dicomWebConfig.supportsReject) {
|
|
1394
|
+
implementation.reject = dcm4cheeReject(dicomWebConfig.wadoRoot);
|
|
1363
1395
|
}
|
|
1364
1396
|
return src/* IWebApiDataSource */.Is.create(implementation);
|
|
1365
1397
|
}
|
|
@@ -1375,7 +1407,8 @@ const mappings = {
|
|
|
1375
1407
|
patientId: 'PatientID'
|
|
1376
1408
|
};
|
|
1377
1409
|
let _store = {
|
|
1378
|
-
urls: []
|
|
1410
|
+
urls: [],
|
|
1411
|
+
studyInstanceUIDMap: new Map() // map of urls to array of study instance UIDs
|
|
1379
1412
|
// {
|
|
1380
1413
|
// url: url1
|
|
1381
1414
|
// studies: [Study1, Study2], // if multiple studies
|
|
@@ -1403,17 +1436,17 @@ const findStudies = (key, value) => {
|
|
|
1403
1436
|
};
|
|
1404
1437
|
function createDicomJSONApi(dicomJsonConfig) {
|
|
1405
1438
|
const {
|
|
1406
|
-
name,
|
|
1407
1439
|
wadoRoot
|
|
1408
1440
|
} = dicomJsonConfig;
|
|
1409
1441
|
const implementation = {
|
|
1410
1442
|
initialize: async _ref => {
|
|
1411
1443
|
let {
|
|
1412
|
-
params,
|
|
1413
1444
|
query,
|
|
1414
1445
|
url
|
|
1415
1446
|
} = _ref;
|
|
1416
|
-
if (!url)
|
|
1447
|
+
if (!url) {
|
|
1448
|
+
url = query.get('url');
|
|
1449
|
+
}
|
|
1417
1450
|
let metaData = getMetaDataByURL(url);
|
|
1418
1451
|
|
|
1419
1452
|
// if we have already cached the data from this specific url
|
|
@@ -1425,8 +1458,7 @@ function createDicomJSONApi(dicomJsonConfig) {
|
|
|
1425
1458
|
});
|
|
1426
1459
|
}
|
|
1427
1460
|
const response = await fetch(url);
|
|
1428
|
-
|
|
1429
|
-
const studyInstanceUIDs = data.studies.map(study => study.StudyInstanceUID);
|
|
1461
|
+
const data = await response.json();
|
|
1430
1462
|
let StudyInstanceUID;
|
|
1431
1463
|
let SeriesInstanceUID;
|
|
1432
1464
|
data.studies.forEach(study => {
|
|
@@ -1452,7 +1484,7 @@ function createDicomJSONApi(dicomJsonConfig) {
|
|
|
1452
1484
|
url,
|
|
1453
1485
|
studies: [...data.studies]
|
|
1454
1486
|
});
|
|
1455
|
-
|
|
1487
|
+
_store.studyInstanceUIDMap.set(url, data.studies.map(study => study.StudyInstanceUID));
|
|
1456
1488
|
},
|
|
1457
1489
|
query: {
|
|
1458
1490
|
studies: {
|
|
@@ -1561,7 +1593,9 @@ function createDicomJSONApi(dicomJsonConfig) {
|
|
|
1561
1593
|
return obj;
|
|
1562
1594
|
});
|
|
1563
1595
|
storeInstances(instances);
|
|
1564
|
-
if (index === numberOfSeries - 1)
|
|
1596
|
+
if (index === numberOfSeries - 1) {
|
|
1597
|
+
setSuccessFlag();
|
|
1598
|
+
}
|
|
1565
1599
|
});
|
|
1566
1600
|
}
|
|
1567
1601
|
}
|
|
@@ -1608,6 +1642,14 @@ function createDicomJSONApi(dicomJsonConfig) {
|
|
|
1608
1642
|
frame
|
|
1609
1643
|
});
|
|
1610
1644
|
return imageIds;
|
|
1645
|
+
},
|
|
1646
|
+
getStudyInstanceUIDs: _ref3 => {
|
|
1647
|
+
let {
|
|
1648
|
+
params,
|
|
1649
|
+
query
|
|
1650
|
+
} = _ref3;
|
|
1651
|
+
const url = query.get('url');
|
|
1652
|
+
return _store.studyInstanceUIDMap.get(url);
|
|
1611
1653
|
}
|
|
1612
1654
|
};
|
|
1613
1655
|
return src/* IWebApiDataSource */.Is.create(implementation);
|
|
@@ -1628,8 +1670,12 @@ const END_MODALITIES = {
|
|
|
1628
1670
|
};
|
|
1629
1671
|
const compareValue = function (v1, v2) {
|
|
1630
1672
|
let def = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
|
|
1631
|
-
if (v1 === v2)
|
|
1632
|
-
|
|
1673
|
+
if (v1 === v2) {
|
|
1674
|
+
return def;
|
|
1675
|
+
}
|
|
1676
|
+
if (v1 < v2) {
|
|
1677
|
+
return -1;
|
|
1678
|
+
}
|
|
1633
1679
|
return 1;
|
|
1634
1680
|
};
|
|
1635
1681
|
|
|
@@ -1660,19 +1706,6 @@ function createDicomLocalApi(dicomLocalConfig) {
|
|
|
1660
1706
|
params,
|
|
1661
1707
|
query
|
|
1662
1708
|
} = _ref;
|
|
1663
|
-
const {
|
|
1664
|
-
StudyInstanceUIDs: paramsStudyInstanceUIDs
|
|
1665
|
-
} = params;
|
|
1666
|
-
const queryStudyInstanceUIDs = query.getAll('StudyInstanceUIDs');
|
|
1667
|
-
const StudyInstanceUIDs = queryStudyInstanceUIDs || paramsStudyInstanceUIDs;
|
|
1668
|
-
const StudyInstanceUIDsAsArray = StudyInstanceUIDs && Array.isArray(StudyInstanceUIDs) ? StudyInstanceUIDs : [StudyInstanceUIDs];
|
|
1669
|
-
|
|
1670
|
-
// Put SRs at the end of series list to make sure images are loaded first
|
|
1671
|
-
StudyInstanceUIDsAsArray.forEach(StudyInstanceUID => {
|
|
1672
|
-
const study = src.DicomMetadataStore.getStudy(StudyInstanceUID);
|
|
1673
|
-
study.series = study.series.sort(customSort);
|
|
1674
|
-
});
|
|
1675
|
-
return StudyInstanceUIDsAsArray;
|
|
1676
1709
|
},
|
|
1677
1710
|
query: {
|
|
1678
1711
|
studies: {
|
|
@@ -1854,6 +1887,29 @@ function createDicomLocalApi(dicomLocalConfig) {
|
|
|
1854
1887
|
},
|
|
1855
1888
|
deleteStudyMetadataPromise() {
|
|
1856
1889
|
console.log('deleteStudyMetadataPromise not implemented');
|
|
1890
|
+
},
|
|
1891
|
+
getStudyInstanceUIDs: _ref3 => {
|
|
1892
|
+
let {
|
|
1893
|
+
params,
|
|
1894
|
+
query
|
|
1895
|
+
} = _ref3;
|
|
1896
|
+
const {
|
|
1897
|
+
StudyInstanceUIDs: paramsStudyInstanceUIDs
|
|
1898
|
+
} = params;
|
|
1899
|
+
const queryStudyInstanceUIDs = query.getAll('StudyInstanceUIDs');
|
|
1900
|
+
const StudyInstanceUIDs = queryStudyInstanceUIDs || paramsStudyInstanceUIDs;
|
|
1901
|
+
const StudyInstanceUIDsAsArray = StudyInstanceUIDs && Array.isArray(StudyInstanceUIDs) ? StudyInstanceUIDs : [StudyInstanceUIDs];
|
|
1902
|
+
|
|
1903
|
+
// Put SRs at the end of series list to make sure images are loaded first
|
|
1904
|
+
let isStudyInCache = false;
|
|
1905
|
+
StudyInstanceUIDsAsArray.forEach(StudyInstanceUID => {
|
|
1906
|
+
const study = src.DicomMetadataStore.getStudy(StudyInstanceUID);
|
|
1907
|
+
if (study) {
|
|
1908
|
+
study.series = study.series.sort(customSort);
|
|
1909
|
+
isStudyInCache = true;
|
|
1910
|
+
}
|
|
1911
|
+
});
|
|
1912
|
+
return isStudyInCache ? StudyInstanceUIDsAsArray : [];
|
|
1857
1913
|
}
|
|
1858
1914
|
};
|
|
1859
1915
|
return src/* IWebApiDataSource */.Is.create(implementation);
|
|
@@ -1882,13 +1938,6 @@ function createDicomWebProxyApi(dicomWebProxyConfig, UserAuthenticationService)
|
|
|
1882
1938
|
params,
|
|
1883
1939
|
query
|
|
1884
1940
|
} = _ref;
|
|
1885
|
-
let studyInstanceUIDs = [];
|
|
1886
|
-
|
|
1887
|
-
// there seem to be a couple of variations of the case for this parameter
|
|
1888
|
-
const queryStudyInstanceUIDs = query.get('studyInstanceUIDs') || query.get('studyInstanceUids');
|
|
1889
|
-
if (!queryStudyInstanceUIDs) {
|
|
1890
|
-
throw new Error(`No studyInstanceUids in request for '${name}'`);
|
|
1891
|
-
}
|
|
1892
1941
|
const url = query.get('url');
|
|
1893
1942
|
if (!url) {
|
|
1894
1943
|
throw new Error(`No url for '${name}'`);
|
|
@@ -1898,10 +1947,12 @@ function createDicomWebProxyApi(dicomWebProxyConfig, UserAuthenticationService)
|
|
|
1898
1947
|
if (!data.servers?.dicomWeb?.[0]) {
|
|
1899
1948
|
throw new Error('Invalid configuration returned by url');
|
|
1900
1949
|
}
|
|
1901
|
-
dicomWebDelegate = createDicomWebApi(data.servers.dicomWeb[0], UserAuthenticationService);
|
|
1902
|
-
|
|
1950
|
+
dicomWebDelegate = createDicomWebApi(data.servers.dicomWeb[0].configuration, UserAuthenticationService);
|
|
1951
|
+
dicomWebDelegate.initialize({
|
|
1952
|
+
params,
|
|
1953
|
+
query
|
|
1954
|
+
});
|
|
1903
1955
|
}
|
|
1904
|
-
return studyInstanceUIDs;
|
|
1905
1956
|
},
|
|
1906
1957
|
query: {
|
|
1907
1958
|
studies: {
|
|
@@ -1939,6 +1990,21 @@ function createDicomWebProxyApi(dicomWebProxyConfig, UserAuthenticationService)
|
|
|
1939
1990
|
},
|
|
1940
1991
|
getImageIdsForInstance: function () {
|
|
1941
1992
|
return dicomWebDelegate.getImageIdsForInstance(...arguments);
|
|
1993
|
+
},
|
|
1994
|
+
getStudyInstanceUIDs(_ref2) {
|
|
1995
|
+
let {
|
|
1996
|
+
params,
|
|
1997
|
+
query
|
|
1998
|
+
} = _ref2;
|
|
1999
|
+
let studyInstanceUIDs = [];
|
|
2000
|
+
|
|
2001
|
+
// there seem to be a couple of variations of the case for this parameter
|
|
2002
|
+
const queryStudyInstanceUIDs = query.get('studyInstanceUIDs') || query.get('studyInstanceUids');
|
|
2003
|
+
if (!queryStudyInstanceUIDs) {
|
|
2004
|
+
throw new Error(`No studyInstanceUids in request for '${name}'`);
|
|
2005
|
+
}
|
|
2006
|
+
studyInstanceUIDs = queryStudyInstanceUIDs.split(';');
|
|
2007
|
+
return studyInstanceUIDs;
|
|
1942
2008
|
}
|
|
1943
2009
|
};
|
|
1944
2010
|
return src/* IWebApiDataSource */.Is.create(implementation);
|
|
@@ -1978,24 +2044,24 @@ function getDataSourcesModule() {
|
|
|
1978
2044
|
}
|
|
1979
2045
|
/* harmony default export */ const src_getDataSourcesModule = (getDataSourcesModule);
|
|
1980
2046
|
// EXTERNAL MODULE: ../../../node_modules/react/index.js
|
|
1981
|
-
var react = __webpack_require__(
|
|
2047
|
+
var react = __webpack_require__(43001);
|
|
1982
2048
|
// EXTERNAL MODULE: ../../../node_modules/prop-types/index.js
|
|
1983
|
-
var prop_types = __webpack_require__(
|
|
2049
|
+
var prop_types = __webpack_require__(3827);
|
|
1984
2050
|
var prop_types_default = /*#__PURE__*/__webpack_require__.n(prop_types);
|
|
1985
2051
|
// EXTERNAL MODULE: ../node_modules/react-router-dom/dist/index.js
|
|
1986
|
-
var dist = __webpack_require__(
|
|
2052
|
+
var dist = __webpack_require__(62474);
|
|
1987
2053
|
// EXTERNAL MODULE: ../../../node_modules/react-i18next/dist/es/index.js + 15 modules
|
|
1988
|
-
var es = __webpack_require__(
|
|
2054
|
+
var es = __webpack_require__(69190);
|
|
1989
2055
|
// EXTERNAL MODULE: ../node_modules/react-router/dist/index.js
|
|
1990
|
-
var react_router_dist = __webpack_require__(
|
|
1991
|
-
// EXTERNAL MODULE: ../../ui/src/index.js +
|
|
1992
|
-
var ui_src = __webpack_require__(
|
|
1993
|
-
// EXTERNAL MODULE: ../../i18n/src/index.js +
|
|
1994
|
-
var i18n_src = __webpack_require__(
|
|
2056
|
+
var react_router_dist = __webpack_require__(85066);
|
|
2057
|
+
// EXTERNAL MODULE: ../../ui/src/index.js + 458 modules
|
|
2058
|
+
var ui_src = __webpack_require__(33570);
|
|
2059
|
+
// EXTERNAL MODULE: ../../i18n/src/index.js + 98 modules
|
|
2060
|
+
var i18n_src = __webpack_require__(43040);
|
|
1995
2061
|
// EXTERNAL MODULE: ./state/index.js + 1 modules
|
|
1996
|
-
var state = __webpack_require__(
|
|
2062
|
+
var state = __webpack_require__(62657);
|
|
1997
2063
|
// EXTERNAL MODULE: ../../../node_modules/classnames/index.js
|
|
1998
|
-
var classnames = __webpack_require__(
|
|
2064
|
+
var classnames = __webpack_require__(44921);
|
|
1999
2065
|
var classnames_default = /*#__PURE__*/__webpack_require__.n(classnames);
|
|
2000
2066
|
;// CONCATENATED MODULE: ../../../extensions/default/src/Toolbar/Toolbar.tsx
|
|
2001
2067
|
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
@@ -2030,7 +2096,7 @@ function Toolbar(_ref) {
|
|
|
2030
2096
|
unsub2();
|
|
2031
2097
|
};
|
|
2032
2098
|
}, [toolbarService]);
|
|
2033
|
-
return /*#__PURE__*/react.createElement(react.Fragment, null, toolbarButtons.map(
|
|
2099
|
+
return /*#__PURE__*/react.createElement(react.Fragment, null, toolbarButtons.map(toolDef => {
|
|
2034
2100
|
const {
|
|
2035
2101
|
id,
|
|
2036
2102
|
Component,
|
|
@@ -2116,8 +2182,10 @@ function ViewerLayout(_ref) {
|
|
|
2116
2182
|
// Todo: Handle parameters in a better way.
|
|
2117
2183
|
const query = new URLSearchParams(window.location.search);
|
|
2118
2184
|
const configUrl = query.get('configUrl');
|
|
2185
|
+
const dataSourceName = pathname.substring(dataSourceIdx + 1);
|
|
2186
|
+
const existingDataSource = extensionManager.getDataSources(dataSourceName);
|
|
2119
2187
|
const searchQuery = new URLSearchParams();
|
|
2120
|
-
if (dataSourceIdx !== -1) {
|
|
2188
|
+
if (dataSourceIdx !== -1 && existingDataSource) {
|
|
2121
2189
|
searchQuery.append('datasources', pathname.substring(dataSourceIdx + 1));
|
|
2122
2190
|
}
|
|
2123
2191
|
if (configUrl) {
|
|
@@ -2143,8 +2211,8 @@ function ViewerLayout(_ref) {
|
|
|
2143
2211
|
hotkeyDefinitions,
|
|
2144
2212
|
hotkeyDefaults
|
|
2145
2213
|
} = hotkeysManager;
|
|
2146
|
-
const versionNumber = "3.7.0-beta.
|
|
2147
|
-
const commitHash = "
|
|
2214
|
+
const versionNumber = "3.7.0-beta.61";
|
|
2215
|
+
const commitHash = "35fc30c5359d8199cc38ffa670c08687d2672f11";
|
|
2148
2216
|
const menuOptions = [{
|
|
2149
2217
|
title: t('Header:About'),
|
|
2150
2218
|
icon: 'info',
|
|
@@ -2364,6 +2432,7 @@ ViewerLayout.propTypes = {
|
|
|
2364
2432
|
|
|
2365
2433
|
|
|
2366
2434
|
|
|
2435
|
+
|
|
2367
2436
|
const {
|
|
2368
2437
|
sortStudyInstances,
|
|
2369
2438
|
formatDate
|
|
@@ -2386,6 +2455,8 @@ function PanelStudyBrowser(_ref) {
|
|
|
2386
2455
|
displaySetService,
|
|
2387
2456
|
uiNotificationService
|
|
2388
2457
|
} = servicesManager.services;
|
|
2458
|
+
const navigate = (0,dist/* useNavigate */.s0)();
|
|
2459
|
+
|
|
2389
2460
|
// Normally you nest the components so the tree isn't so deep, and the data
|
|
2390
2461
|
// doesn't have to have such an intense shape. This works well enough for now.
|
|
2391
2462
|
// Tabs --> Studies --> DisplaySets --> Thumbnails
|
|
@@ -2427,6 +2498,10 @@ function PanelStudyBrowser(_ref) {
|
|
|
2427
2498
|
const qidoForStudyUID = await dataSource.query.studies.search({
|
|
2428
2499
|
studyInstanceUid: StudyInstanceUID
|
|
2429
2500
|
});
|
|
2501
|
+
if (!qidoForStudyUID?.length) {
|
|
2502
|
+
navigate('/notfoundstudy', '_self');
|
|
2503
|
+
throw new Error('Invalid study URL');
|
|
2504
|
+
}
|
|
2430
2505
|
let qidoStudiesForPatient = qidoForStudyUID;
|
|
2431
2506
|
|
|
2432
2507
|
// try to fetch the prior studies based on the patientID if the
|
|
@@ -2470,7 +2545,7 @@ function PanelStudyBrowser(_ref) {
|
|
|
2470
2545
|
const imageId = imageIds[Math.floor(imageIds.length / 2)];
|
|
2471
2546
|
|
|
2472
2547
|
// TODO: Is it okay that imageIds are not returned here for SR displaySets?
|
|
2473
|
-
if (imageId) {
|
|
2548
|
+
if (imageId && !displaySet?.unsupported) {
|
|
2474
2549
|
// When the image arrives, render it and store the result in the thumbnailImgSrcMap
|
|
2475
2550
|
newImageSrcEntry[dSet.displaySetInstanceUID] = await getImageSrc(imageId);
|
|
2476
2551
|
if (isMounted.current) {
|
|
@@ -2509,20 +2584,22 @@ function PanelStudyBrowser(_ref) {
|
|
|
2509
2584
|
displaySetsAdded.forEach(async dSet => {
|
|
2510
2585
|
const newImageSrcEntry = {};
|
|
2511
2586
|
const displaySet = displaySetService.getDisplaySetByUID(dSet.displaySetInstanceUID);
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2587
|
+
if (!displaySet?.unsupported) {
|
|
2588
|
+
const imageIds = dataSource.getImageIdsForDisplaySet(displaySet);
|
|
2589
|
+
const imageId = imageIds[Math.floor(imageIds.length / 2)];
|
|
2590
|
+
|
|
2591
|
+
// TODO: Is it okay that imageIds are not returned here for SR displaysets?
|
|
2592
|
+
if (imageId) {
|
|
2593
|
+
// When the image arrives, render it and store the result in the thumbnailImgSrcMap
|
|
2594
|
+
newImageSrcEntry[dSet.displaySetInstanceUID] = await getImageSrc(imageId, dSet.initialViewport);
|
|
2595
|
+
if (isMounted.current) {
|
|
2596
|
+
setThumbnailImageSrcMap(prevState => {
|
|
2597
|
+
return {
|
|
2598
|
+
...prevState,
|
|
2599
|
+
...newImageSrcEntry
|
|
2600
|
+
};
|
|
2601
|
+
});
|
|
2602
|
+
}
|
|
2526
2603
|
}
|
|
2527
2604
|
}
|
|
2528
2605
|
});
|
|
@@ -2534,9 +2611,14 @@ function PanelStudyBrowser(_ref) {
|
|
|
2534
2611
|
const mappedDisplaySets = _mapDisplaySets(changedDisplaySets, thumbnailImageSrcMap);
|
|
2535
2612
|
setDisplaySets(mappedDisplaySets);
|
|
2536
2613
|
});
|
|
2614
|
+
const SubscriptionDisplaySetMetaDataInvalidated = displaySetService.subscribe(displaySetService.EVENTS.DISPLAY_SET_SERIES_METADATA_INVALIDATED, () => {
|
|
2615
|
+
const mappedDisplaySets = _mapDisplaySets(displaySetService.getActiveDisplaySets(), thumbnailImageSrcMap);
|
|
2616
|
+
setDisplaySets(mappedDisplaySets);
|
|
2617
|
+
});
|
|
2537
2618
|
return () => {
|
|
2538
2619
|
SubscriptionDisplaySetsAdded.unsubscribe();
|
|
2539
2620
|
SubscriptionDisplaySetsChanged.unsubscribe();
|
|
2621
|
+
SubscriptionDisplaySetMetaDataInvalidated.unsubscribe();
|
|
2540
2622
|
};
|
|
2541
2623
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2542
2624
|
}, []);
|
|
@@ -2605,7 +2687,7 @@ function _mapDisplaySets(displaySets, thumbnailImageSrcMap) {
|
|
|
2605
2687
|
const thumbnailNoImageDisplaySets = [];
|
|
2606
2688
|
displaySets.filter(ds => !ds.excludeFromThumbnailBrowser).forEach(ds => {
|
|
2607
2689
|
const imageSrc = thumbnailImageSrcMap[ds.displaySetInstanceUID];
|
|
2608
|
-
const componentType = _getComponentType(ds
|
|
2690
|
+
const componentType = _getComponentType(ds);
|
|
2609
2691
|
const array = componentType === 'thumbnail' ? thumbnailDisplaySets : thumbnailNoImageDisplaySets;
|
|
2610
2692
|
array.push({
|
|
2611
2693
|
displaySetInstanceUID: ds.displaySetInstanceUID,
|
|
@@ -2617,21 +2699,23 @@ function _mapDisplaySets(displaySets, thumbnailImageSrcMap) {
|
|
|
2617
2699
|
numInstances: ds.numImageFrames,
|
|
2618
2700
|
countIcon: ds.countIcon,
|
|
2619
2701
|
StudyInstanceUID: ds.StudyInstanceUID,
|
|
2702
|
+
messages: ds.messages,
|
|
2620
2703
|
componentType,
|
|
2621
2704
|
imageSrc,
|
|
2622
2705
|
dragData: {
|
|
2623
2706
|
type: 'displayset',
|
|
2624
2707
|
displaySetInstanceUID: ds.displaySetInstanceUID
|
|
2625
2708
|
// .. Any other data to pass
|
|
2626
|
-
}
|
|
2709
|
+
},
|
|
2710
|
+
|
|
2711
|
+
isHydratedForDerivedDisplaySet: ds.isHydrated
|
|
2627
2712
|
});
|
|
2628
2713
|
});
|
|
2629
|
-
|
|
2630
2714
|
return [...thumbnailDisplaySets, ...thumbnailNoImageDisplaySets];
|
|
2631
2715
|
}
|
|
2632
2716
|
const thumbnailNoImageModalities = ['SR', 'SEG', 'SM', 'RTSTRUCT', 'RTPLAN', 'RTDOSE'];
|
|
2633
|
-
function _getComponentType(
|
|
2634
|
-
if (thumbnailNoImageModalities.includes(Modality)) {
|
|
2717
|
+
function _getComponentType(ds) {
|
|
2718
|
+
if (thumbnailNoImageModalities.includes(ds.Modality) || ds?.unsupported) {
|
|
2635
2719
|
// TODO probably others.
|
|
2636
2720
|
return 'thumbnailNoImage';
|
|
2637
2721
|
}
|
|
@@ -2819,7 +2903,7 @@ ActionButtons.defaultProps = {
|
|
|
2819
2903
|
};
|
|
2820
2904
|
/* harmony default export */ const Panels_ActionButtons = (ActionButtons);
|
|
2821
2905
|
// EXTERNAL MODULE: ../../../node_modules/lodash.debounce/index.js
|
|
2822
|
-
var lodash_debounce = __webpack_require__(
|
|
2906
|
+
var lodash_debounce = __webpack_require__(8324);
|
|
2823
2907
|
var lodash_debounce_default = /*#__PURE__*/__webpack_require__.n(lodash_debounce);
|
|
2824
2908
|
;// CONCATENATED MODULE: ../../../extensions/default/src/Panels/createReportDialogPrompt.tsx
|
|
2825
2909
|
/* eslint-disable react/display-name */
|
|
@@ -3336,7 +3420,9 @@ function _mapMeasurementToDisplay(measurement, index, types) {
|
|
|
3336
3420
|
if (findingSites) {
|
|
3337
3421
|
const siteText = [];
|
|
3338
3422
|
findingSites.forEach(site => {
|
|
3339
|
-
if (site?.text !== label)
|
|
3423
|
+
if (site?.text !== label) {
|
|
3424
|
+
siteText.push(site.text);
|
|
3425
|
+
}
|
|
3340
3426
|
});
|
|
3341
3427
|
displayText = [...siteText, ...displayText];
|
|
3342
3428
|
}
|
|
@@ -3403,119 +3489,424 @@ function getPanelModule(_ref) {
|
|
|
3403
3489
|
}
|
|
3404
3490
|
/* harmony default export */ const src_getPanelModule = (getPanelModule);
|
|
3405
3491
|
// EXTERNAL MODULE: ../../core/src/utils/isImage.js
|
|
3406
|
-
var isImage = __webpack_require__(
|
|
3492
|
+
var isImage = __webpack_require__(11835);
|
|
3407
3493
|
// EXTERNAL MODULE: ../../core/src/utils/sopClassDictionary.js
|
|
3408
|
-
var sopClassDictionary = __webpack_require__(
|
|
3494
|
+
var sopClassDictionary = __webpack_require__(24369);
|
|
3409
3495
|
// EXTERNAL MODULE: ../../core/src/classes/ImageSet.ts
|
|
3410
|
-
var ImageSet = __webpack_require__(
|
|
3496
|
+
var ImageSet = __webpack_require__(13950);
|
|
3411
3497
|
// EXTERNAL MODULE: ../../core/src/utils/isDisplaySetReconstructable.js
|
|
3412
|
-
var isDisplaySetReconstructable = __webpack_require__(
|
|
3498
|
+
var isDisplaySetReconstructable = __webpack_require__(89359);
|
|
3413
3499
|
;// CONCATENATED MODULE: ../../../extensions/default/package.json
|
|
3414
3500
|
const package_namespaceObject = JSON.parse('{"u2":"@ohif/extension-default"}');
|
|
3415
3501
|
;// CONCATENATED MODULE: ../../../extensions/default/src/id.js
|
|
3416
3502
|
|
|
3417
3503
|
const id = package_namespaceObject.u2;
|
|
3418
3504
|
|
|
3419
|
-
|
|
3505
|
+
// EXTERNAL MODULE: ../../core/src/utils/sortInstancesByPosition.ts
|
|
3506
|
+
var sortInstancesByPosition = __webpack_require__(87425);
|
|
3507
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/validations/checkMultiframe.ts
|
|
3420
3508
|
|
|
3421
3509
|
|
|
3422
3510
|
|
|
3511
|
+
/**
|
|
3512
|
+
* Check various multi frame issues. It calls OHIF core functions
|
|
3513
|
+
* @param {*} multiFrameInstance
|
|
3514
|
+
* @param {*} warnings
|
|
3515
|
+
*/
|
|
3516
|
+
function checkMultiFrame(multiFrameInstance, messages) {
|
|
3517
|
+
if (!(0,isDisplaySetReconstructable/* hasPixelMeasurements */.hu)(multiFrameInstance)) {
|
|
3518
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.MULTIFRAME_NO_PIXEL_MEASUREMENTS);
|
|
3519
|
+
}
|
|
3520
|
+
if (!(0,isDisplaySetReconstructable/* hasOrientation */.sb)(multiFrameInstance)) {
|
|
3521
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.MULTIFRAME_NO_ORIENTATION);
|
|
3522
|
+
}
|
|
3523
|
+
if (!(0,isDisplaySetReconstructable/* hasPosition */.kN)(multiFrameInstance)) {
|
|
3524
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.MULTIFRAME_NO_POSITION_INFORMATION);
|
|
3525
|
+
}
|
|
3526
|
+
}
|
|
3527
|
+
// EXTERNAL MODULE: ../../core/src/utils/toNumber.js
|
|
3528
|
+
var toNumber = __webpack_require__(94972);
|
|
3529
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/validations/areAllImageDimensionsEqual.ts
|
|
3423
3530
|
|
|
3424
3531
|
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3532
|
+
/**
|
|
3533
|
+
* Check if the frames in a series has different dimensions
|
|
3534
|
+
* @param {*} instances
|
|
3535
|
+
* @returns
|
|
3536
|
+
*/
|
|
3537
|
+
function areAllImageDimensionsEqual(instances) {
|
|
3538
|
+
if (!instances?.length) {
|
|
3539
|
+
return false;
|
|
3540
|
+
}
|
|
3541
|
+
const firstImage = instances[0];
|
|
3542
|
+
const firstImageRows = (0,toNumber/* default */.Z)(firstImage.Rows);
|
|
3543
|
+
const firstImageColumns = (0,toNumber/* default */.Z)(firstImage.Columns);
|
|
3544
|
+
for (let i = 1; i < instances.length; i++) {
|
|
3545
|
+
const instance = instances[i];
|
|
3546
|
+
const {
|
|
3547
|
+
Rows,
|
|
3548
|
+
Columns
|
|
3549
|
+
} = instance;
|
|
3550
|
+
if (Rows !== firstImageRows || Columns !== firstImageColumns) {
|
|
3551
|
+
return false;
|
|
3552
|
+
}
|
|
3553
|
+
}
|
|
3554
|
+
return true;
|
|
3555
|
+
}
|
|
3556
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/validations/areAllImageComponentsEqual.ts
|
|
3436
3557
|
|
|
3437
|
-
// set appropriate attributes to image set...
|
|
3438
|
-
imageSet.setAttributes({
|
|
3439
|
-
displaySetInstanceUID: imageSet.uid,
|
|
3440
|
-
// create a local alias for the imageSet UID
|
|
3441
|
-
SeriesDate: instance.SeriesDate,
|
|
3442
|
-
SeriesTime: instance.SeriesTime,
|
|
3443
|
-
SeriesInstanceUID: instance.SeriesInstanceUID,
|
|
3444
|
-
StudyInstanceUID: instance.StudyInstanceUID,
|
|
3445
|
-
SeriesNumber: instance.SeriesNumber || 0,
|
|
3446
|
-
FrameRate: instance.FrameTime,
|
|
3447
|
-
SOPClassUID: instance.SOPClassUID,
|
|
3448
|
-
SeriesDescription: instance.SeriesDescription || '',
|
|
3449
|
-
Modality: instance.Modality,
|
|
3450
|
-
isMultiFrame: isMultiFrame(instance),
|
|
3451
|
-
countIcon: isReconstructable ? 'icon-mpr' : undefined,
|
|
3452
|
-
numImageFrames: instances.length,
|
|
3453
|
-
SOPClassHandlerId: `${id}.sopClassHandlerModule.${sopClassHandlerName}`,
|
|
3454
|
-
isReconstructable,
|
|
3455
|
-
averageSpacingBetweenFrames: averageSpacingBetweenFrames || null
|
|
3456
|
-
});
|
|
3457
3558
|
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3559
|
+
/**
|
|
3560
|
+
* Check if all voxels in series images has same number of components (samplesPerPixel)
|
|
3561
|
+
* @param {*} instances
|
|
3562
|
+
* @returns
|
|
3563
|
+
*/
|
|
3564
|
+
function areAllImageComponentsEqual(instances) {
|
|
3565
|
+
if (!instances?.length) {
|
|
3566
|
+
return false;
|
|
3567
|
+
}
|
|
3568
|
+
const firstImage = instances[0];
|
|
3569
|
+
const firstImageSamplesPerPixel = (0,toNumber/* default */.Z)(firstImage.SamplesPerPixel);
|
|
3570
|
+
for (let i = 1; i < instances.length; i++) {
|
|
3571
|
+
const instance = instances[i];
|
|
3572
|
+
const {
|
|
3573
|
+
SamplesPerPixel
|
|
3574
|
+
} = instance;
|
|
3575
|
+
if (SamplesPerPixel !== firstImageSamplesPerPixel) {
|
|
3576
|
+
return false;
|
|
3577
|
+
}
|
|
3465
3578
|
}
|
|
3579
|
+
return true;
|
|
3580
|
+
}
|
|
3581
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/validations/areAllImageOrientationsEqual.ts
|
|
3466
3582
|
|
|
3467
|
-
// Include the first image instance number (after sorted)
|
|
3468
|
-
/*imageSet.setAttribute(
|
|
3469
|
-
'instanceNumber',
|
|
3470
|
-
imageSet.getImage(0).InstanceNumber
|
|
3471
|
-
);*/
|
|
3472
3583
|
|
|
3473
|
-
/*const isReconstructable = isDisplaySetReconstructable(series, instances);
|
|
3474
|
-
imageSet.isReconstructable = isReconstructable.value;
|
|
3475
|
-
if (isReconstructable.missingFrames) {
|
|
3476
|
-
// TODO -> This is currently unused, but may be used for reconstructing
|
|
3477
|
-
// Volumes with gaps later on.
|
|
3478
|
-
imageSet.missingFrames = isReconstructable.missingFrames;
|
|
3479
|
-
}*/
|
|
3480
3584
|
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
function
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
const
|
|
3492
|
-
|
|
3585
|
+
/**
|
|
3586
|
+
* Check is the series has frames with different orientations
|
|
3587
|
+
* @param {*} instances
|
|
3588
|
+
* @returns
|
|
3589
|
+
*/
|
|
3590
|
+
function areAllImageOrientationsEqual(instances) {
|
|
3591
|
+
if (!instances?.length) {
|
|
3592
|
+
return false;
|
|
3593
|
+
}
|
|
3594
|
+
const firstImage = instances[0];
|
|
3595
|
+
const firstImageOrientationPatient = (0,toNumber/* default */.Z)(firstImage.ImageOrientationPatient);
|
|
3596
|
+
for (let i = 1; i < instances.length; i++) {
|
|
3597
|
+
const instance = instances[i];
|
|
3598
|
+
const imageOrientationPatient = (0,toNumber/* default */.Z)(instance.ImageOrientationPatient);
|
|
3599
|
+
if (!(0,isDisplaySetReconstructable/* _isSameOrientation */.NB)(imageOrientationPatient, firstImageOrientationPatient)) {
|
|
3600
|
+
return false;
|
|
3601
|
+
}
|
|
3602
|
+
}
|
|
3603
|
+
return true;
|
|
3493
3604
|
}
|
|
3605
|
+
// EXTERNAL MODULE: ../../../node_modules/gl-matrix/esm/index.js + 10 modules
|
|
3606
|
+
var esm = __webpack_require__(45451);
|
|
3607
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/calculateScanAxisNormal.ts
|
|
3608
|
+
|
|
3494
3609
|
|
|
3495
3610
|
/**
|
|
3496
|
-
*
|
|
3497
|
-
*
|
|
3498
|
-
*
|
|
3499
|
-
*
|
|
3500
|
-
* @param {Array} sopClassHandlerModules List of SOP Class Modules
|
|
3501
|
-
* @param {SeriesMetadata} series The series metadata object from which the display sets will be created
|
|
3502
|
-
* @returns {Array} The list of display sets created for the given series object
|
|
3611
|
+
* Calculates the scanAxisNormal based on a image orientation vector extract from a frame
|
|
3612
|
+
* @param {*} imageOrientation
|
|
3613
|
+
* @returns
|
|
3503
3614
|
*/
|
|
3504
|
-
function
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
const sopClassUids = getSopClassUids(instances);
|
|
3615
|
+
function calculateScanAxisNormal(imageOrientation) {
|
|
3616
|
+
const rowCosineVec = esm/* vec3.fromValues */.R3.fromValues(imageOrientation[0], imageOrientation[1], imageOrientation[2]);
|
|
3617
|
+
const colCosineVec = esm/* vec3.fromValues */.R3.fromValues(imageOrientation[3], imageOrientation[4], imageOrientation[5]);
|
|
3618
|
+
return esm/* vec3.cross */.R3.cross(esm/* vec3.create */.R3.create(), rowCosineVec, colCosineVec);
|
|
3619
|
+
}
|
|
3620
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/validations/areAllImagePositionsEqual.ts
|
|
3511
3621
|
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3622
|
+
|
|
3623
|
+
|
|
3624
|
+
|
|
3625
|
+
|
|
3626
|
+
/**
|
|
3627
|
+
* Checks if there is a position shift between consecutive frames
|
|
3628
|
+
* @param {*} previousPosition
|
|
3629
|
+
* @param {*} actualPosition
|
|
3630
|
+
* @param {*} scanAxisNormal
|
|
3631
|
+
* @param {*} averageSpacingBetweenFrames
|
|
3632
|
+
* @returns
|
|
3633
|
+
*/
|
|
3634
|
+
function _checkSeriesPositionShift(previousPosition, actualPosition, scanAxisNormal, averageSpacingBetweenFrames) {
|
|
3635
|
+
// predicted position should be the previous position added by the multiplication
|
|
3636
|
+
// of the scanAxisNormal and the average spacing between frames
|
|
3637
|
+
const predictedPosition = esm/* vec3.scaleAndAdd */.R3.scaleAndAdd(esm/* vec3.create */.R3.create(), previousPosition, scanAxisNormal, averageSpacingBetweenFrames);
|
|
3638
|
+
return esm/* vec3.distance */.R3.distance(actualPosition, predictedPosition) > averageSpacingBetweenFrames;
|
|
3639
|
+
}
|
|
3640
|
+
|
|
3641
|
+
/**
|
|
3642
|
+
* Checks if a series has position shifts between consecutive frames
|
|
3643
|
+
* @param {*} instances
|
|
3644
|
+
* @returns
|
|
3645
|
+
*/
|
|
3646
|
+
function areAllImagePositionsEqual(instances) {
|
|
3647
|
+
if (!instances?.length) {
|
|
3648
|
+
return false;
|
|
3649
|
+
}
|
|
3650
|
+
const firstImageOrientationPatient = (0,toNumber/* default */.Z)(instances[0].ImageOrientationPatient);
|
|
3651
|
+
const scanAxisNormal = calculateScanAxisNormal(firstImageOrientationPatient);
|
|
3652
|
+
const firstImagePositionPatient = (0,toNumber/* default */.Z)(instances[0].ImagePositionPatient);
|
|
3653
|
+
const lastIpp = (0,toNumber/* default */.Z)(instances[instances.length - 1].ImagePositionPatient);
|
|
3654
|
+
const averageSpacingBetweenFrames = (0,isDisplaySetReconstructable/* _getPerpendicularDistance */.Xn)(firstImagePositionPatient, lastIpp) / (instances.length - 1);
|
|
3655
|
+
let previousImagePositionPatient = firstImagePositionPatient;
|
|
3656
|
+
for (let i = 1; i < instances.length; i++) {
|
|
3657
|
+
const instance = instances[i];
|
|
3658
|
+
const imagePositionPatient = (0,toNumber/* default */.Z)(instance.ImagePositionPatient);
|
|
3659
|
+
if (_checkSeriesPositionShift(previousImagePositionPatient, imagePositionPatient, scanAxisNormal, averageSpacingBetweenFrames)) {
|
|
3660
|
+
return false;
|
|
3661
|
+
}
|
|
3662
|
+
previousImagePositionPatient = imagePositionPatient;
|
|
3663
|
+
}
|
|
3664
|
+
return true;
|
|
3665
|
+
}
|
|
3666
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/validations/areAllImageSpacingEqual.ts
|
|
3667
|
+
|
|
3668
|
+
|
|
3669
|
+
|
|
3670
|
+
/**
|
|
3671
|
+
* Checks if series has spacing issues
|
|
3672
|
+
* @param {*} instances
|
|
3673
|
+
* @param {*} warnings
|
|
3674
|
+
*/
|
|
3675
|
+
function areAllImageSpacingEqual(instances, messages) {
|
|
3676
|
+
if (!instances?.length) {
|
|
3677
|
+
return;
|
|
3678
|
+
}
|
|
3679
|
+
const firstImagePositionPatient = (0,toNumber/* default */.Z)(instances[0].ImagePositionPatient);
|
|
3680
|
+
const lastIpp = (0,toNumber/* default */.Z)(instances[instances.length - 1].ImagePositionPatient);
|
|
3681
|
+
const averageSpacingBetweenFrames = (0,isDisplaySetReconstructable/* _getPerpendicularDistance */.Xn)(firstImagePositionPatient, lastIpp) / (instances.length - 1);
|
|
3682
|
+
let previousImagePositionPatient = firstImagePositionPatient;
|
|
3683
|
+
const issuesFound = [];
|
|
3684
|
+
for (let i = 1; i < instances.length; i++) {
|
|
3685
|
+
const instance = instances[i];
|
|
3686
|
+
const imagePositionPatient = (0,toNumber/* default */.Z)(instance.ImagePositionPatient);
|
|
3687
|
+
const spacingBetweenFrames = (0,isDisplaySetReconstructable/* _getPerpendicularDistance */.Xn)(imagePositionPatient, previousImagePositionPatient);
|
|
3688
|
+
const spacingIssue = (0,isDisplaySetReconstructable/* _getSpacingIssue */.bg)(spacingBetweenFrames, averageSpacingBetweenFrames);
|
|
3689
|
+
if (spacingIssue) {
|
|
3690
|
+
const issue = spacingIssue.issue;
|
|
3691
|
+
|
|
3692
|
+
// avoid multiple warning of the same thing
|
|
3693
|
+
if (!issuesFound.includes(issue)) {
|
|
3694
|
+
issuesFound.push(issue);
|
|
3695
|
+
if (issue === isDisplaySetReconstructable/* reconstructionIssues */.e1.MISSING_FRAMES) {
|
|
3696
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.MISSING_FRAMES);
|
|
3697
|
+
} else if (issue === isDisplaySetReconstructable/* reconstructionIssues */.e1.IRREGULAR_SPACING) {
|
|
3698
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.IRREGULAR_SPACING);
|
|
3699
|
+
}
|
|
3700
|
+
}
|
|
3701
|
+
// we just want to find issues not how many
|
|
3702
|
+
if (issuesFound.length > 1) {
|
|
3703
|
+
break;
|
|
3704
|
+
}
|
|
3705
|
+
}
|
|
3706
|
+
previousImagePositionPatient = imagePositionPatient;
|
|
3707
|
+
}
|
|
3708
|
+
}
|
|
3709
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/validations/checkSingleFrames.ts
|
|
3710
|
+
|
|
3711
|
+
|
|
3712
|
+
|
|
3713
|
+
|
|
3714
|
+
|
|
3715
|
+
|
|
3716
|
+
|
|
3717
|
+
/**
|
|
3718
|
+
* Runs various checks in a single frame series
|
|
3719
|
+
* @param {*} instances
|
|
3720
|
+
* @param {*} warnings
|
|
3721
|
+
*/
|
|
3722
|
+
function checkSingleFrames(instances, messages) {
|
|
3723
|
+
if (instances.length > 2) {
|
|
3724
|
+
if (!areAllImageDimensionsEqual(instances)) {
|
|
3725
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.INCONSISTENT_DIMENSIONS);
|
|
3726
|
+
}
|
|
3727
|
+
if (!areAllImageComponentsEqual(instances)) {
|
|
3728
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.INCONSISTENT_COMPONENTS);
|
|
3729
|
+
}
|
|
3730
|
+
if (!areAllImageOrientationsEqual(instances)) {
|
|
3731
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.INCONSISTENT_ORIENTATIONS);
|
|
3732
|
+
}
|
|
3733
|
+
if (!areAllImagePositionsEqual(instances)) {
|
|
3734
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.INCONSISTENT_POSITION_INFORMATION);
|
|
3735
|
+
}
|
|
3736
|
+
areAllImageSpacingEqual(instances, messages);
|
|
3737
|
+
}
|
|
3738
|
+
}
|
|
3739
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/getDisplaySetMessages.ts
|
|
3740
|
+
|
|
3741
|
+
|
|
3742
|
+
|
|
3743
|
+
|
|
3744
|
+
|
|
3745
|
+
/**
|
|
3746
|
+
* Checks if a series is reconstructable to a 3D volume.
|
|
3747
|
+
*
|
|
3748
|
+
* @param {Object[]} instances An array of `OHIFInstanceMetadata` objects.
|
|
3749
|
+
*/
|
|
3750
|
+
function getDisplaySetMessages(instances, isReconstructable) {
|
|
3751
|
+
const messages = new src/* DisplaySetMessageList */.iK();
|
|
3752
|
+
if (!instances.length) {
|
|
3753
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.NO_VALID_INSTANCES);
|
|
3754
|
+
}
|
|
3755
|
+
const firstInstance = instances[0];
|
|
3756
|
+
// Due to current requirements, LOCALIZER series doesn't have any messages
|
|
3757
|
+
if (firstInstance.ImageType.includes('LOCALIZER')) {
|
|
3758
|
+
return messages;
|
|
3759
|
+
}
|
|
3760
|
+
const Modality = firstInstance.Modality;
|
|
3761
|
+
if (!isDisplaySetReconstructable/* constructableModalities */.M6.includes(Modality)) {
|
|
3762
|
+
return messages;
|
|
3763
|
+
}
|
|
3764
|
+
const isMultiframe = firstInstance.NumberOfFrames > 1;
|
|
3765
|
+
// Can't reconstruct if all instances don't have the ImagePositionPatient.
|
|
3766
|
+
if (!isMultiframe && !instances.every(instance => instance.ImagePositionPatient)) {
|
|
3767
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.NO_POSITION_INFORMATION);
|
|
3768
|
+
}
|
|
3769
|
+
const sortedInstances = (0,sortInstancesByPosition/* default */.Z)(instances);
|
|
3770
|
+
isMultiframe ? checkMultiFrame(sortedInstances[0], messages) : checkSingleFrames(sortedInstances, messages);
|
|
3771
|
+
if (!isReconstructable) {
|
|
3772
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.NOT_RECONSTRUCTABLE);
|
|
3773
|
+
}
|
|
3774
|
+
return messages;
|
|
3775
|
+
}
|
|
3776
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/getDisplaySetsFromUnsupportedSeries.js
|
|
3777
|
+
|
|
3778
|
+
|
|
3779
|
+
/**
|
|
3780
|
+
* Default handler for a instance list with an unsupported sopClassUID
|
|
3781
|
+
*/
|
|
3782
|
+
function getDisplaySetsFromUnsupportedSeries(instances) {
|
|
3783
|
+
const imageSet = new ImageSet/* default */.Z(instances);
|
|
3784
|
+
const messages = new src/* DisplaySetMessageList */.iK();
|
|
3785
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.UNSUPPORTED_DISPLAYSET);
|
|
3786
|
+
const instance = instances[0];
|
|
3787
|
+
imageSet.setAttributes({
|
|
3788
|
+
displaySetInstanceUID: imageSet.uid,
|
|
3789
|
+
// create a local alias for the imageSet UID
|
|
3790
|
+
SeriesDate: instance.SeriesDate,
|
|
3791
|
+
SeriesTime: instance.SeriesTime,
|
|
3792
|
+
SeriesInstanceUID: instance.SeriesInstanceUID,
|
|
3793
|
+
StudyInstanceUID: instance.StudyInstanceUID,
|
|
3794
|
+
SeriesNumber: instance.SeriesNumber || 0,
|
|
3795
|
+
FrameRate: instance.FrameTime,
|
|
3796
|
+
SOPClassUID: instance.SOPClassUID,
|
|
3797
|
+
SeriesDescription: instance.SeriesDescription || '',
|
|
3798
|
+
Modality: instance.Modality,
|
|
3799
|
+
numImageFrames: instances.length,
|
|
3800
|
+
unsupported: true,
|
|
3801
|
+
SOPClassHandlerId: 'unsupported',
|
|
3802
|
+
isReconstructable: false,
|
|
3803
|
+
messages
|
|
3804
|
+
});
|
|
3805
|
+
return [imageSet];
|
|
3806
|
+
}
|
|
3807
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/getSopClassHandlerModule.js
|
|
3808
|
+
|
|
3809
|
+
|
|
3810
|
+
|
|
3811
|
+
|
|
3812
|
+
|
|
3813
|
+
|
|
3814
|
+
|
|
3815
|
+
const sopClassHandlerName = 'stack';
|
|
3816
|
+
const isMultiFrame = instance => {
|
|
3817
|
+
return instance.NumberOfFrames > 1;
|
|
3818
|
+
};
|
|
3819
|
+
const makeDisplaySet = instances => {
|
|
3820
|
+
const instance = instances[0];
|
|
3821
|
+
const imageSet = new ImageSet/* default */.Z(instances);
|
|
3822
|
+
const {
|
|
3823
|
+
value: isReconstructable,
|
|
3824
|
+
averageSpacingBetweenFrames
|
|
3825
|
+
} = (0,isDisplaySetReconstructable/* default */.ZP)(instances);
|
|
3826
|
+
// set appropriate attributes to image set...
|
|
3827
|
+
const messages = getDisplaySetMessages(instances, isReconstructable);
|
|
3828
|
+
imageSet.setAttributes({
|
|
3829
|
+
displaySetInstanceUID: imageSet.uid,
|
|
3830
|
+
// create a local alias for the imageSet UID
|
|
3831
|
+
SeriesDate: instance.SeriesDate,
|
|
3832
|
+
SeriesTime: instance.SeriesTime,
|
|
3833
|
+
SeriesInstanceUID: instance.SeriesInstanceUID,
|
|
3834
|
+
StudyInstanceUID: instance.StudyInstanceUID,
|
|
3835
|
+
SeriesNumber: instance.SeriesNumber || 0,
|
|
3836
|
+
FrameRate: instance.FrameTime,
|
|
3837
|
+
SOPClassUID: instance.SOPClassUID,
|
|
3838
|
+
SeriesDescription: instance.SeriesDescription || '',
|
|
3839
|
+
Modality: instance.Modality,
|
|
3840
|
+
isMultiFrame: isMultiFrame(instance),
|
|
3841
|
+
countIcon: isReconstructable ? 'icon-mpr' : undefined,
|
|
3842
|
+
numImageFrames: instances.length,
|
|
3843
|
+
SOPClassHandlerId: `${id}.sopClassHandlerModule.${sopClassHandlerName}`,
|
|
3844
|
+
isReconstructable,
|
|
3845
|
+
messages,
|
|
3846
|
+
averageSpacingBetweenFrames: averageSpacingBetweenFrames || null
|
|
3847
|
+
});
|
|
3848
|
+
|
|
3849
|
+
// Sort the images in this series if needed
|
|
3850
|
+
const shallSort = true; //!OHIF.utils.ObjectPath.get(Meteor, 'settings.public.ui.sortSeriesByIncomingOrder');
|
|
3851
|
+
if (shallSort) {
|
|
3852
|
+
imageSet.sortBy((a, b) => {
|
|
3853
|
+
// Sort by InstanceNumber (0020,0013)
|
|
3854
|
+
return (parseInt(a.InstanceNumber) || 0) - (parseInt(b.InstanceNumber) || 0);
|
|
3855
|
+
});
|
|
3856
|
+
}
|
|
3857
|
+
|
|
3858
|
+
// Include the first image instance number (after sorted)
|
|
3859
|
+
/*imageSet.setAttribute(
|
|
3860
|
+
'instanceNumber',
|
|
3861
|
+
imageSet.getImage(0).InstanceNumber
|
|
3862
|
+
);*/
|
|
3863
|
+
|
|
3864
|
+
/*const isReconstructable = isDisplaySetReconstructable(series, instances);
|
|
3865
|
+
imageSet.isReconstructable = isReconstructable.value;
|
|
3866
|
+
if (isReconstructable.missingFrames) {
|
|
3867
|
+
// TODO -> This is currently unused, but may be used for reconstructing
|
|
3868
|
+
// Volumes with gaps later on.
|
|
3869
|
+
imageSet.missingFrames = isReconstructable.missingFrames;
|
|
3870
|
+
}*/
|
|
3871
|
+
|
|
3872
|
+
return imageSet;
|
|
3873
|
+
};
|
|
3874
|
+
const isSingleImageModality = modality => {
|
|
3875
|
+
return modality === 'CR' || modality === 'MG' || modality === 'DX';
|
|
3876
|
+
};
|
|
3877
|
+
function getSopClassUids(instances) {
|
|
3878
|
+
const uniqueSopClassUidsInSeries = new Set();
|
|
3879
|
+
instances.forEach(instance => {
|
|
3880
|
+
uniqueSopClassUidsInSeries.add(instance.SOPClassUID);
|
|
3881
|
+
});
|
|
3882
|
+
const sopClassUids = Array.from(uniqueSopClassUidsInSeries);
|
|
3883
|
+
return sopClassUids;
|
|
3884
|
+
}
|
|
3885
|
+
|
|
3886
|
+
/**
|
|
3887
|
+
* Basic SOPClassHandler:
|
|
3888
|
+
* - For all Image types that are stackable, create
|
|
3889
|
+
* a displaySet with a stack of images
|
|
3890
|
+
*
|
|
3891
|
+
* @param {Array} sopClassHandlerModules List of SOP Class Modules
|
|
3892
|
+
* @param {SeriesMetadata} series The series metadata object from which the display sets will be created
|
|
3893
|
+
* @returns {Array} The list of display sets created for the given series object
|
|
3894
|
+
*/
|
|
3895
|
+
function getDisplaySetsFromSeries(instances) {
|
|
3896
|
+
// If the series has no instances, stop here
|
|
3897
|
+
if (!instances || !instances.length) {
|
|
3898
|
+
throw new Error('No instances were provided');
|
|
3899
|
+
}
|
|
3900
|
+
const displaySets = [];
|
|
3901
|
+
const sopClassUids = getSopClassUids(instances);
|
|
3902
|
+
|
|
3903
|
+
// Search through the instances (InstanceMetadata object) of this series
|
|
3904
|
+
// Split Multi-frame instances and Single-image modalities
|
|
3905
|
+
// into their own specific display sets. Place the rest of each
|
|
3906
|
+
// series into another display set.
|
|
3907
|
+
const stackableInstances = [];
|
|
3908
|
+
instances.forEach(instance => {
|
|
3909
|
+
// All imaging modalities must have a valid value for sopClassUid (x00080016) or rows (x00280010)
|
|
3519
3910
|
if (!(0,isImage/* isImage */.O)(instance.SOPClassUID) && !instance.Rows) {
|
|
3520
3911
|
return;
|
|
3521
3912
|
}
|
|
@@ -3558,6 +3949,10 @@ function getSopClassHandlerModule() {
|
|
|
3558
3949
|
name: sopClassHandlerName,
|
|
3559
3950
|
sopClassUids,
|
|
3560
3951
|
getDisplaySetsFromSeries
|
|
3952
|
+
}, {
|
|
3953
|
+
name: 'not-supported-display-sets-handler',
|
|
3954
|
+
sopClassUids: [],
|
|
3955
|
+
getDisplaySetsFromSeries: getDisplaySetsFromUnsupportedSeries
|
|
3561
3956
|
}];
|
|
3562
3957
|
}
|
|
3563
3958
|
/* harmony default export */ const src_getSopClassHandlerModule = (getSopClassHandlerModule);
|
|
@@ -3856,7 +4251,7 @@ function adaptItem(item, subProps) {
|
|
|
3856
4251
|
return newItem;
|
|
3857
4252
|
}
|
|
3858
4253
|
// EXTERNAL MODULE: ../../ui/src/components/ContextMenu/ContextMenu.tsx
|
|
3859
|
-
var ContextMenu = __webpack_require__(
|
|
4254
|
+
var ContextMenu = __webpack_require__(5638);
|
|
3860
4255
|
;// CONCATENATED MODULE: ../../../extensions/default/src/CustomizableContextMenu/ContextMenuController.tsx
|
|
3861
4256
|
|
|
3862
4257
|
|
|
@@ -4065,10 +4460,10 @@ const defaultContextMenu = {
|
|
|
4065
4460
|
|
|
4066
4461
|
|
|
4067
4462
|
// EXTERNAL MODULE: ../../../node_modules/moment/moment.js
|
|
4068
|
-
var moment = __webpack_require__(
|
|
4463
|
+
var moment = __webpack_require__(71271);
|
|
4069
4464
|
var moment_default = /*#__PURE__*/__webpack_require__.n(moment);
|
|
4070
4465
|
// EXTERNAL MODULE: ../../../node_modules/react-window/dist/index.esm.js
|
|
4071
|
-
var index_esm = __webpack_require__(
|
|
4466
|
+
var index_esm = __webpack_require__(94614);
|
|
4072
4467
|
;// CONCATENATED MODULE: ../../../extensions/default/src/DicomTagBrowser/DicomTagTable.tsx
|
|
4073
4468
|
|
|
4074
4469
|
|
|
@@ -4266,7 +4661,6 @@ function DicomTagTable(_ref2) {
|
|
|
4266
4661
|
|
|
4267
4662
|
|
|
4268
4663
|
|
|
4269
|
-
|
|
4270
4664
|
const {
|
|
4271
4665
|
ImageSet: DicomTagBrowser_ImageSet
|
|
4272
4666
|
} = src.classes;
|
|
@@ -4295,7 +4689,6 @@ const DicomTagBrowser = _ref => {
|
|
|
4295
4689
|
setSelectedDisplaySetInstanceUID(value.value);
|
|
4296
4690
|
setInstanceNumber(1);
|
|
4297
4691
|
};
|
|
4298
|
-
const searchInputRef = (0,react.useRef)(null);
|
|
4299
4692
|
const activeDisplaySet = displaySets.find(ds => ds.displaySetInstanceUID === selectedDisplaySetInstanceUID);
|
|
4300
4693
|
const isImageStack = _isImageStack(activeDisplaySet);
|
|
4301
4694
|
const showInstanceList = isImageStack && activeDisplaySet.images.length > 1;
|
|
@@ -4399,29 +4792,11 @@ const DicomTagBrowser = _ref => {
|
|
|
4399
4792
|
className: "w-full h-1 bg-black"
|
|
4400
4793
|
}), /*#__PURE__*/react.createElement("div", {
|
|
4401
4794
|
className: "flex flex-row my-3 w-1/2"
|
|
4402
|
-
}, /*#__PURE__*/react.createElement(
|
|
4403
|
-
className: "
|
|
4404
|
-
}, /*#__PURE__*/react.createElement("span", {
|
|
4405
|
-
className: "absolute inset-y-0 left-0 flex items-center pl-2"
|
|
4406
|
-
}, /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
4407
|
-
name: "icon-search"
|
|
4408
|
-
})), /*#__PURE__*/react.createElement("input", {
|
|
4409
|
-
ref: searchInputRef,
|
|
4410
|
-
type: "text",
|
|
4411
|
-
className: "block bg-black w-full shadow transition duration-300 appearance-none border border-inputfield-main focus:border-inputfield-focus focus:outline-none disabled:border-inputfield-disabled rounded w-full py-2 px-9 text-base leading-tight placeholder:text-inputfield-placeholder",
|
|
4795
|
+
}, /*#__PURE__*/react.createElement(ui_src/* InputFilterText */.Xe, {
|
|
4796
|
+
className: "block w-full mr-8",
|
|
4412
4797
|
placeholder: "Search metadata...",
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
}), /*#__PURE__*/react.createElement("span", {
|
|
4416
|
-
className: "absolute inset-y-0 right-0 flex items-center pr-2"
|
|
4417
|
-
}, /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
4418
|
-
name: "icon-clear-field",
|
|
4419
|
-
className: classnames_default()('cursor-pointer', filterValue ? '' : 'hidden'),
|
|
4420
|
-
onClick: () => {
|
|
4421
|
-
searchInputRef.current.value = '';
|
|
4422
|
-
debouncedSetFilterValue('');
|
|
4423
|
-
}
|
|
4424
|
-
})))), /*#__PURE__*/react.createElement(DicomTagBrowser_DicomTagTable, {
|
|
4798
|
+
onDebounceChange: setFilterValue
|
|
4799
|
+
})), /*#__PURE__*/react.createElement(DicomTagBrowser_DicomTagTable, {
|
|
4425
4800
|
rows: filteredRows
|
|
4426
4801
|
}));
|
|
4427
4802
|
};
|
|
@@ -4637,10 +5012,14 @@ const reuseCachedLayout = (state, hangingProtocolService, syncService) => {
|
|
|
4637
5012
|
displaySetOptions,
|
|
4638
5013
|
displaySetInstanceUIDs
|
|
4639
5014
|
} = viewport;
|
|
4640
|
-
if (!displaySetOptions)
|
|
5015
|
+
if (!displaySetOptions) {
|
|
5016
|
+
continue;
|
|
5017
|
+
}
|
|
4641
5018
|
for (let i = 0; i < displaySetOptions.length; i++) {
|
|
4642
5019
|
const displaySetUID = displaySetInstanceUIDs[i];
|
|
4643
|
-
if (!displaySetUID)
|
|
5020
|
+
if (!displaySetUID) {
|
|
5021
|
+
continue;
|
|
5022
|
+
}
|
|
4644
5023
|
if (idx === activeViewportIndex && i === 0) {
|
|
4645
5024
|
displaySetSelectorMap[`${activeStudyUID}:activeDisplaySet:0`] = displaySetUID;
|
|
4646
5025
|
}
|
|
@@ -4673,9 +5052,11 @@ const reuseCachedLayout = (state, hangingProtocolService, syncService) => {
|
|
|
4673
5052
|
*/
|
|
4674
5053
|
const findViewportsByPosition_findOrCreateViewport = (hangingProtocolService, viewportsByPosition, viewportIndex, positionId, options) => {
|
|
4675
5054
|
const byPositionViewport = viewportsByPosition?.[positionId];
|
|
4676
|
-
if (byPositionViewport)
|
|
4677
|
-
|
|
4678
|
-
|
|
5055
|
+
if (byPositionViewport) {
|
|
5056
|
+
return {
|
|
5057
|
+
...byPositionViewport
|
|
5058
|
+
};
|
|
5059
|
+
}
|
|
4679
5060
|
const {
|
|
4680
5061
|
protocolId,
|
|
4681
5062
|
stageIndex
|
|
@@ -4756,8 +5137,8 @@ const findViewportsByPosition = (state, _ref, syncService) => {
|
|
|
4756
5137
|
};
|
|
4757
5138
|
};
|
|
4758
5139
|
/* harmony default export */ const src_findViewportsByPosition = (findViewportsByPosition);
|
|
4759
|
-
// EXTERNAL MODULE: ./index.js +
|
|
4760
|
-
var index = __webpack_require__(
|
|
5140
|
+
// EXTERNAL MODULE: ./index.js + 33 modules
|
|
5141
|
+
var index = __webpack_require__(59754);
|
|
4761
5142
|
;// CONCATENATED MODULE: ../../../extensions/default/src/commandsModule.ts
|
|
4762
5143
|
|
|
4763
5144
|
|
|
@@ -4859,7 +5240,9 @@ const commandsModule = _ref => {
|
|
|
4859
5240
|
stage
|
|
4860
5241
|
} = hangingProtocolService.getActiveProtocol();
|
|
4861
5242
|
const enableListener = button => {
|
|
4862
|
-
if (!button.id)
|
|
5243
|
+
if (!button.id) {
|
|
5244
|
+
return;
|
|
5245
|
+
}
|
|
4863
5246
|
const {
|
|
4864
5247
|
commands,
|
|
4865
5248
|
items
|
|
@@ -4868,7 +5251,9 @@ const commandsModule = _ref => {
|
|
|
4868
5251
|
items.forEach(enableListener);
|
|
4869
5252
|
}
|
|
4870
5253
|
const hpCommand = commands?.find?.(isHangingProtocolCommand);
|
|
4871
|
-
if (!hpCommand)
|
|
5254
|
+
if (!hpCommand) {
|
|
5255
|
+
return;
|
|
5256
|
+
}
|
|
4872
5257
|
const {
|
|
4873
5258
|
protocolId,
|
|
4874
5259
|
stageIndex,
|
|
@@ -5397,7 +5782,6 @@ const commandsModule = _ref => {
|
|
|
5397
5782
|
* It is not included in the viewer mode by default.
|
|
5398
5783
|
*/
|
|
5399
5784
|
const hpMN = {
|
|
5400
|
-
hasUpdatedPriorsInformation: false,
|
|
5401
5785
|
id: '@ohif/mnGrid',
|
|
5402
5786
|
description: 'Has various hanging protocol grid layouts',
|
|
5403
5787
|
name: '2x2',
|
|
@@ -5606,15 +5990,182 @@ const hpMN = {
|
|
|
5606
5990
|
numberOfPriorsReferenced: -1
|
|
5607
5991
|
};
|
|
5608
5992
|
/* harmony default export */ const hpMNGrid = (hpMN);
|
|
5993
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/hpCompare.ts
|
|
5994
|
+
const defaultDisplaySetSelector = {
|
|
5995
|
+
studyMatchingRules: [{
|
|
5996
|
+
// The priorInstance is a study counter that indicates what position this study is in
|
|
5997
|
+
// and the value comes from the options parameter.
|
|
5998
|
+
attribute: 'studyInstanceUIDsIndex',
|
|
5999
|
+
from: 'options',
|
|
6000
|
+
required: true,
|
|
6001
|
+
constraint: {
|
|
6002
|
+
equals: {
|
|
6003
|
+
value: 0
|
|
6004
|
+
}
|
|
6005
|
+
}
|
|
6006
|
+
}],
|
|
6007
|
+
seriesMatchingRules: [{
|
|
6008
|
+
attribute: 'numImageFrames',
|
|
6009
|
+
constraint: {
|
|
6010
|
+
greaterThan: {
|
|
6011
|
+
value: 0
|
|
6012
|
+
}
|
|
6013
|
+
}
|
|
6014
|
+
},
|
|
6015
|
+
// This display set will select the specified items by preference
|
|
6016
|
+
// It has no affect if nothing is specified in the URL.
|
|
6017
|
+
{
|
|
6018
|
+
attribute: 'isDisplaySetFromUrl',
|
|
6019
|
+
weight: 10,
|
|
6020
|
+
constraint: {
|
|
6021
|
+
equals: true
|
|
6022
|
+
}
|
|
6023
|
+
}]
|
|
6024
|
+
};
|
|
6025
|
+
const priorDisplaySetSelector = {
|
|
6026
|
+
studyMatchingRules: [{
|
|
6027
|
+
// The priorInstance is a study counter that indicates what position this study is in
|
|
6028
|
+
// and the value comes from the options parameter.
|
|
6029
|
+
attribute: 'studyInstanceUIDsIndex',
|
|
6030
|
+
from: 'options',
|
|
6031
|
+
required: true,
|
|
6032
|
+
constraint: {
|
|
6033
|
+
equals: {
|
|
6034
|
+
value: 1
|
|
6035
|
+
}
|
|
6036
|
+
}
|
|
6037
|
+
}],
|
|
6038
|
+
seriesMatchingRules: [{
|
|
6039
|
+
attribute: 'numImageFrames',
|
|
6040
|
+
constraint: {
|
|
6041
|
+
greaterThan: {
|
|
6042
|
+
value: 0
|
|
6043
|
+
}
|
|
6044
|
+
}
|
|
6045
|
+
},
|
|
6046
|
+
// This display set will select the specified items by preference
|
|
6047
|
+
// It has no affect if nothing is specified in the URL.
|
|
6048
|
+
{
|
|
6049
|
+
attribute: 'isDisplaySetFromUrl',
|
|
6050
|
+
weight: 10,
|
|
6051
|
+
constraint: {
|
|
6052
|
+
equals: true
|
|
6053
|
+
}
|
|
6054
|
+
}]
|
|
6055
|
+
};
|
|
6056
|
+
const currentDisplaySet = {
|
|
6057
|
+
id: 'defaultDisplaySetId'
|
|
6058
|
+
};
|
|
6059
|
+
const priorDisplaySet = {
|
|
6060
|
+
id: 'priorDisplaySetId'
|
|
6061
|
+
};
|
|
6062
|
+
const currentViewport0 = {
|
|
6063
|
+
viewportOptions: {
|
|
6064
|
+
toolGroupId: 'default',
|
|
6065
|
+
allowUnmatchedView: true
|
|
6066
|
+
},
|
|
6067
|
+
displaySets: [currentDisplaySet]
|
|
6068
|
+
};
|
|
6069
|
+
const currentViewport1 = {
|
|
6070
|
+
...currentViewport0,
|
|
6071
|
+
displaySets: [{
|
|
6072
|
+
...currentDisplaySet,
|
|
6073
|
+
matchedDisplaySetsIndex: 1
|
|
6074
|
+
}]
|
|
6075
|
+
};
|
|
6076
|
+
const priorViewport0 = {
|
|
6077
|
+
...currentViewport0,
|
|
6078
|
+
displaySets: [priorDisplaySet]
|
|
6079
|
+
};
|
|
6080
|
+
const priorViewport1 = {
|
|
6081
|
+
...priorViewport0,
|
|
6082
|
+
displaySets: [{
|
|
6083
|
+
...priorDisplaySet,
|
|
6084
|
+
matchedDisplaySetsIndex: 1
|
|
6085
|
+
}]
|
|
6086
|
+
};
|
|
6087
|
+
|
|
6088
|
+
/**
|
|
6089
|
+
* This hanging protocol can be activated on the primary mode by directly
|
|
6090
|
+
* referencing it in a URL or by directly including it within a mode, e.g.:
|
|
6091
|
+
* `&hangingProtocolId=@ohif/mnGrid` added to the viewer URL
|
|
6092
|
+
* It is not included in the viewer mode by default.
|
|
6093
|
+
*/
|
|
6094
|
+
const hpMNCompare = {
|
|
6095
|
+
id: '@ohif/hpCompare',
|
|
6096
|
+
description: 'Compare two studies in various layouts',
|
|
6097
|
+
name: 'Compare Two Studies',
|
|
6098
|
+
numberOfPriorsReferenced: 1,
|
|
6099
|
+
protocolMatchingRules: [{
|
|
6100
|
+
id: 'Two Studies',
|
|
6101
|
+
weight: 1000,
|
|
6102
|
+
attribute: 'StudyInstanceUID',
|
|
6103
|
+
// The 'from' attribute says where to get the 'attribute' value from. In this case
|
|
6104
|
+
// prior means the second study in the study list.
|
|
6105
|
+
from: 'prior',
|
|
6106
|
+
required: true,
|
|
6107
|
+
constraint: {
|
|
6108
|
+
notNull: true
|
|
6109
|
+
}
|
|
6110
|
+
}],
|
|
6111
|
+
toolGroupIds: ['default'],
|
|
6112
|
+
displaySetSelectors: {
|
|
6113
|
+
defaultDisplaySetId: defaultDisplaySetSelector,
|
|
6114
|
+
priorDisplaySetId: priorDisplaySetSelector
|
|
6115
|
+
},
|
|
6116
|
+
defaultViewport: {
|
|
6117
|
+
viewportOptions: {
|
|
6118
|
+
viewportType: 'stack',
|
|
6119
|
+
toolGroupId: 'default',
|
|
6120
|
+
allowUnmatchedView: true
|
|
6121
|
+
},
|
|
6122
|
+
displaySets: [{
|
|
6123
|
+
id: 'defaultDisplaySetId',
|
|
6124
|
+
matchedDisplaySetsIndex: -1
|
|
6125
|
+
}]
|
|
6126
|
+
},
|
|
6127
|
+
stages: [{
|
|
6128
|
+
name: '2x2',
|
|
6129
|
+
stageActivation: {
|
|
6130
|
+
enabled: {
|
|
6131
|
+
minViewportsMatched: 4
|
|
6132
|
+
}
|
|
6133
|
+
},
|
|
6134
|
+
viewportStructure: {
|
|
6135
|
+
layoutType: 'grid',
|
|
6136
|
+
properties: {
|
|
6137
|
+
rows: 2,
|
|
6138
|
+
columns: 2
|
|
6139
|
+
}
|
|
6140
|
+
},
|
|
6141
|
+
viewports: [currentViewport0, priorViewport0, currentViewport1, priorViewport1]
|
|
6142
|
+
}, {
|
|
6143
|
+
name: '2x1',
|
|
6144
|
+
stageActivation: {
|
|
6145
|
+
enabled: {
|
|
6146
|
+
minViewportsMatched: 2
|
|
6147
|
+
}
|
|
6148
|
+
},
|
|
6149
|
+
viewportStructure: {
|
|
6150
|
+
layoutType: 'grid',
|
|
6151
|
+
properties: {
|
|
6152
|
+
rows: 1,
|
|
6153
|
+
columns: 2
|
|
6154
|
+
}
|
|
6155
|
+
},
|
|
6156
|
+
viewports: [currentViewport0, priorViewport0]
|
|
6157
|
+
}]
|
|
6158
|
+
};
|
|
6159
|
+
/* harmony default export */ const hpCompare = (hpMNCompare);
|
|
5609
6160
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getHangingProtocolModule.js
|
|
5610
6161
|
|
|
6162
|
+
|
|
5611
6163
|
const defaultProtocol = {
|
|
5612
6164
|
id: 'default',
|
|
5613
6165
|
locked: true,
|
|
5614
6166
|
// Don't store this hanging protocol as it applies to the currently active
|
|
5615
6167
|
// display set by default
|
|
5616
6168
|
// cacheId: null,
|
|
5617
|
-
hasUpdatedPriorsInformation: false,
|
|
5618
6169
|
name: 'Default',
|
|
5619
6170
|
createdDate: '2021-02-23T19:22:08.894Z',
|
|
5620
6171
|
modifiedDate: '2023-04-01',
|
|
@@ -5708,6 +6259,11 @@ function getHangingProtocolModule() {
|
|
|
5708
6259
|
{
|
|
5709
6260
|
name: hpMNGrid.id,
|
|
5710
6261
|
protocol: hpMNGrid
|
|
6262
|
+
},
|
|
6263
|
+
// Create a MxN comparison hanging protocol available by default
|
|
6264
|
+
{
|
|
6265
|
+
name: hpCompare.id,
|
|
6266
|
+
protocol: hpCompare
|
|
5711
6267
|
}];
|
|
5712
6268
|
}
|
|
5713
6269
|
/* harmony default export */ const src_getHangingProtocolModule = (getHangingProtocolModule);
|
|
@@ -5743,7 +6299,7 @@ function DataSourceSelector() {
|
|
|
5743
6299
|
key: ds.sourceName
|
|
5744
6300
|
}, /*#__PURE__*/react.createElement("h1", {
|
|
5745
6301
|
className: "text-white"
|
|
5746
|
-
}, ds.friendlyName), /*#__PURE__*/react.createElement(ui_src/* Button */.zx, {
|
|
6302
|
+
}, ds.configuration?.friendlyName || ds.friendlyName), /*#__PURE__*/react.createElement(ui_src/* Button */.zx, {
|
|
5747
6303
|
type: ui_src/* ButtonEnums.type */.LZ.U.primary,
|
|
5748
6304
|
className: classnames_default()('ml-2'),
|
|
5749
6305
|
onClick: () => {
|
|
@@ -5755,10 +6311,419 @@ function DataSourceSelector() {
|
|
|
5755
6311
|
}, ds.sourceName), /*#__PURE__*/react.createElement("br", null)))))));
|
|
5756
6312
|
}
|
|
5757
6313
|
/* harmony default export */ const Panels_DataSourceSelector = (DataSourceSelector);
|
|
6314
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/Components/ItemListComponent.tsx
|
|
6315
|
+
|
|
6316
|
+
|
|
6317
|
+
|
|
6318
|
+
|
|
6319
|
+
function ItemListComponent(_ref) {
|
|
6320
|
+
let {
|
|
6321
|
+
itemLabel,
|
|
6322
|
+
itemList,
|
|
6323
|
+
onItemClicked
|
|
6324
|
+
} = _ref;
|
|
6325
|
+
const {
|
|
6326
|
+
t
|
|
6327
|
+
} = (0,es/* useTranslation */.$G)('DataSourceConfiguration');
|
|
6328
|
+
const [filterValue, setFilterValue] = (0,react.useState)('');
|
|
6329
|
+
(0,react.useEffect)(() => {
|
|
6330
|
+
setFilterValue('');
|
|
6331
|
+
}, [itemList]);
|
|
6332
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6333
|
+
className: "flex flex-col gap-4 min-h-[1px] grow"
|
|
6334
|
+
}, /*#__PURE__*/react.createElement("div", {
|
|
6335
|
+
className: "flex justify-between items-center"
|
|
6336
|
+
}, /*#__PURE__*/react.createElement("div", {
|
|
6337
|
+
className: "text-primary-light text-[20px]"
|
|
6338
|
+
}, t(`Select ${itemLabel}`)), /*#__PURE__*/react.createElement(ui_src/* InputFilterText */.Xe, {
|
|
6339
|
+
className: "grow max-w-[40%]",
|
|
6340
|
+
value: filterValue,
|
|
6341
|
+
onDebounceChange: setFilterValue,
|
|
6342
|
+
placeholder: t(`Search ${itemLabel} list`)
|
|
6343
|
+
})), /*#__PURE__*/react.createElement("div", {
|
|
6344
|
+
className: "flex flex-col relative min-h-[1px] grow text-[14px] bg-black"
|
|
6345
|
+
}, itemList == null ? /*#__PURE__*/react.createElement(ui_src/* LoadingIndicatorProgress */.LE, {
|
|
6346
|
+
className: 'w-full h-full'
|
|
6347
|
+
}) : itemList.length === 0 ? /*#__PURE__*/react.createElement("div", {
|
|
6348
|
+
className: "flex flex-col h-full px-6 py-4 items-center justify-center text-primary-light"
|
|
6349
|
+
}, /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
6350
|
+
name: "magnifier",
|
|
6351
|
+
className: "mb-4"
|
|
6352
|
+
}), /*#__PURE__*/react.createElement("span", null, t(`No ${itemLabel} available`))) : /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
|
|
6353
|
+
className: "bg-secondary-dark text-white px-3 py-1.5"
|
|
6354
|
+
}, t(itemLabel)), /*#__PURE__*/react.createElement("div", {
|
|
6355
|
+
className: "overflow-auto ohif-scrollbar"
|
|
6356
|
+
}, itemList.filter(item => !filterValue || item.name.toLowerCase().includes(filterValue.toLowerCase())).map(item => {
|
|
6357
|
+
const border = 'rounded border-transparent border-b-secondary-light border-[1px] hover:border-primary-light';
|
|
6358
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6359
|
+
className: classnames_default()('group mx-2 px-6 py-2 flex justify-between items-center hover:text-primary-light hover:bg-primary-dark', border),
|
|
6360
|
+
key: item.id
|
|
6361
|
+
}, /*#__PURE__*/react.createElement("div", null, item.name), /*#__PURE__*/react.createElement(ui_src/* Button */.zx, {
|
|
6362
|
+
onClick: () => onItemClicked(item),
|
|
6363
|
+
className: "invisible group-hover:visible",
|
|
6364
|
+
endIcon: /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
6365
|
+
name: "arrow-left"
|
|
6366
|
+
})
|
|
6367
|
+
}, t('Select')));
|
|
6368
|
+
})))));
|
|
6369
|
+
}
|
|
6370
|
+
/* harmony default export */ const Components_ItemListComponent = (ItemListComponent);
|
|
6371
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/Components/DataSourceConfigurationModalComponent.tsx
|
|
6372
|
+
|
|
6373
|
+
|
|
6374
|
+
|
|
6375
|
+
|
|
6376
|
+
|
|
6377
|
+
const NO_WRAP_ELLIPSIS_CLASS_NAMES = 'text-ellipsis whitespace-nowrap overflow-hidden';
|
|
6378
|
+
function DataSourceConfigurationModalComponent(_ref) {
|
|
6379
|
+
let {
|
|
6380
|
+
configurationAPI,
|
|
6381
|
+
configuredItems,
|
|
6382
|
+
onHide
|
|
6383
|
+
} = _ref;
|
|
6384
|
+
const {
|
|
6385
|
+
t
|
|
6386
|
+
} = (0,es/* useTranslation */.$G)('DataSourceConfiguration');
|
|
6387
|
+
const [itemList, setItemList] = (0,react.useState)();
|
|
6388
|
+
const [selectedItems, setSelectedItems] = (0,react.useState)(configuredItems);
|
|
6389
|
+
|
|
6390
|
+
// Determines whether to show the full configuration for the data source.
|
|
6391
|
+
// This typically occurs when the configuration component is first displayed.
|
|
6392
|
+
const [showFullConfig, setShowFullConfig] = (0,react.useState)(true);
|
|
6393
|
+
const [errorMessage, setErrorMessage] = (0,react.useState)();
|
|
6394
|
+
const [itemLabels] = (0,react.useState)(configurationAPI.getItemLabels());
|
|
6395
|
+
|
|
6396
|
+
/**
|
|
6397
|
+
* The index of the selected item that is considered current and for which
|
|
6398
|
+
* its sub-items should be displayed in the items list component. When the
|
|
6399
|
+
* full/existing configuration for a data source is to be shown, the current
|
|
6400
|
+
* selected item is the second to last in the `selectedItems` list.
|
|
6401
|
+
*/
|
|
6402
|
+
const currentSelectedItemIndex = showFullConfig ? selectedItems.length - 2 : selectedItems.length - 1;
|
|
6403
|
+
(0,react.useEffect)(() => {
|
|
6404
|
+
let shouldUpdate = true;
|
|
6405
|
+
setErrorMessage(null);
|
|
6406
|
+
|
|
6407
|
+
// Clear out the former/old list while we fetch the next sub item list.
|
|
6408
|
+
setItemList(null);
|
|
6409
|
+
if (selectedItems.length === 0) {
|
|
6410
|
+
configurationAPI.initialize().then(items => {
|
|
6411
|
+
if (shouldUpdate) {
|
|
6412
|
+
setItemList(items);
|
|
6413
|
+
}
|
|
6414
|
+
}).catch(error => setErrorMessage(error.message));
|
|
6415
|
+
} else if (!showFullConfig && selectedItems.length === itemLabels.length) {
|
|
6416
|
+
// The last item to configure the data source (path) has been selected.
|
|
6417
|
+
configurationAPI.setCurrentItem(selectedItems[selectedItems.length - 1]);
|
|
6418
|
+
// We can hide the modal dialog now.
|
|
6419
|
+
onHide();
|
|
6420
|
+
} else {
|
|
6421
|
+
configurationAPI.setCurrentItem(selectedItems[currentSelectedItemIndex]).then(items => {
|
|
6422
|
+
if (shouldUpdate) {
|
|
6423
|
+
setItemList(items);
|
|
6424
|
+
}
|
|
6425
|
+
}).catch(error => setErrorMessage(error.message));
|
|
6426
|
+
}
|
|
6427
|
+
return () => {
|
|
6428
|
+
shouldUpdate = false;
|
|
6429
|
+
};
|
|
6430
|
+
}, [selectedItems, configurationAPI, onHide, itemLabels, showFullConfig, currentSelectedItemIndex]);
|
|
6431
|
+
const getSelectedItemCursorClasses = itemIndex => itemIndex !== itemLabels.length - 1 && itemIndex < selectedItems.length ? 'cursor-pointer' : 'cursor-auto';
|
|
6432
|
+
const getSelectedItemBackgroundClasses = itemIndex => itemIndex < selectedItems.length ? classnames_default()('bg-black/[.4]', itemIndex !== itemLabels.length - 1 ? 'hover:bg-transparent active:bg-secondary-dark' : '') : 'bg-transparent';
|
|
6433
|
+
const getSelectedItemBorderClasses = itemIndex => itemIndex === currentSelectedItemIndex + 1 ? classnames_default()('border-2', 'border-solid', 'border-primary-light') : itemIndex < selectedItems.length ? 'border border-solid border-primary-active hover:border-primary-light active:border-white' : 'border border-dashed border-secondary-light';
|
|
6434
|
+
const getSelectedItemTextClasses = itemIndex => itemIndex <= selectedItems.length ? 'text-primary-light' : 'text-primary-active';
|
|
6435
|
+
const getErrorComponent = () => {
|
|
6436
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6437
|
+
className: "flex flex-col gap-4 min-h-[1px] grow"
|
|
6438
|
+
}, /*#__PURE__*/react.createElement("div", {
|
|
6439
|
+
className: "text-primary-light text-[20px]"
|
|
6440
|
+
}, t(`Error fetching ${itemLabels[selectedItems.length]} list`)), /*#__PURE__*/react.createElement("div", {
|
|
6441
|
+
className: "bg-black text-[14px] grow p-4"
|
|
6442
|
+
}, errorMessage));
|
|
6443
|
+
};
|
|
6444
|
+
const getSelectedItemsComponent = () => {
|
|
6445
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6446
|
+
className: "flex gap-4"
|
|
6447
|
+
}, itemLabels.map((itemLabel, itemLabelIndex) => {
|
|
6448
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6449
|
+
key: itemLabel,
|
|
6450
|
+
className: classnames_default()('rounded-md p-3.5 flex flex-col gap-1 shrink min-w-[1px] basis-[200px]', getSelectedItemCursorClasses(itemLabelIndex), getSelectedItemBackgroundClasses(itemLabelIndex), getSelectedItemBorderClasses(itemLabelIndex), getSelectedItemTextClasses(itemLabelIndex)),
|
|
6451
|
+
onClick: showFullConfig && itemLabelIndex < currentSelectedItemIndex || itemLabelIndex <= currentSelectedItemIndex ? () => {
|
|
6452
|
+
setShowFullConfig(false);
|
|
6453
|
+
setSelectedItems(theList => theList.slice(0, itemLabelIndex));
|
|
6454
|
+
} : undefined
|
|
6455
|
+
}, /*#__PURE__*/react.createElement("div", {
|
|
6456
|
+
className: "flex gap-2 items-center text-"
|
|
6457
|
+
}, itemLabelIndex < selectedItems.length ? /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
6458
|
+
name: "status-tracked"
|
|
6459
|
+
}) : /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
6460
|
+
name: "status-untracked"
|
|
6461
|
+
}), /*#__PURE__*/react.createElement("div", {
|
|
6462
|
+
className: classnames_default()(NO_WRAP_ELLIPSIS_CLASS_NAMES)
|
|
6463
|
+
}, t(itemLabel))), itemLabelIndex < selectedItems.length ? /*#__PURE__*/react.createElement("div", {
|
|
6464
|
+
className: classnames_default()('text-white text-[14px]', NO_WRAP_ELLIPSIS_CLASS_NAMES)
|
|
6465
|
+
}, selectedItems[itemLabelIndex].name) : /*#__PURE__*/react.createElement("br", null));
|
|
6466
|
+
}));
|
|
6467
|
+
};
|
|
6468
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6469
|
+
className: "h-[calc(100vh-300px)] flex flex-col pt-0.5 gap-4 select-none"
|
|
6470
|
+
}, getSelectedItemsComponent(), /*#__PURE__*/react.createElement("div", {
|
|
6471
|
+
className: "w-full h-0.5 shrink-0 bg-black"
|
|
6472
|
+
}), errorMessage ? getErrorComponent() : /*#__PURE__*/react.createElement(Components_ItemListComponent, {
|
|
6473
|
+
itemLabel: itemLabels[currentSelectedItemIndex + 1],
|
|
6474
|
+
itemList: itemList,
|
|
6475
|
+
onItemClicked: item => {
|
|
6476
|
+
setShowFullConfig(false);
|
|
6477
|
+
setSelectedItems(theList => [...theList.slice(0, currentSelectedItemIndex + 1), item]);
|
|
6478
|
+
}
|
|
6479
|
+
}));
|
|
6480
|
+
}
|
|
6481
|
+
/* harmony default export */ const Components_DataSourceConfigurationModalComponent = (DataSourceConfigurationModalComponent);
|
|
6482
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/Components/DataSourceConfigurationComponent.tsx
|
|
6483
|
+
|
|
6484
|
+
|
|
6485
|
+
|
|
6486
|
+
|
|
6487
|
+
function DataSourceConfigurationComponent(_ref) {
|
|
6488
|
+
let {
|
|
6489
|
+
servicesManager,
|
|
6490
|
+
extensionManager
|
|
6491
|
+
} = _ref;
|
|
6492
|
+
const {
|
|
6493
|
+
t
|
|
6494
|
+
} = (0,es/* useTranslation */.$G)('DataSourceConfiguration');
|
|
6495
|
+
const {
|
|
6496
|
+
show,
|
|
6497
|
+
hide
|
|
6498
|
+
} = (0,ui_src/* useModal */.dd)();
|
|
6499
|
+
const {
|
|
6500
|
+
customizationService
|
|
6501
|
+
} = servicesManager.services;
|
|
6502
|
+
const [configurationAPI, setConfigurationAPI] = (0,react.useState)();
|
|
6503
|
+
const [configuredItems, setConfiguredItems] = (0,react.useState)();
|
|
6504
|
+
(0,react.useEffect)(() => {
|
|
6505
|
+
let shouldUpdate = true;
|
|
6506
|
+
const dataSourceChangedCallback = async () => {
|
|
6507
|
+
const activeDataSourceDef = extensionManager.getActiveDataSourceDefinition();
|
|
6508
|
+
if (!activeDataSourceDef.configuration.configurationAPI) {
|
|
6509
|
+
return;
|
|
6510
|
+
}
|
|
6511
|
+
const {
|
|
6512
|
+
factory: configurationAPIFactory
|
|
6513
|
+
} = customizationService.get(activeDataSourceDef.configuration.configurationAPI) ?? {};
|
|
6514
|
+
if (!configurationAPIFactory) {
|
|
6515
|
+
return;
|
|
6516
|
+
}
|
|
6517
|
+
const configAPI = configurationAPIFactory(activeDataSourceDef.sourceName);
|
|
6518
|
+
setConfigurationAPI(configAPI);
|
|
6519
|
+
configAPI.getConfiguredItems().then(list => {
|
|
6520
|
+
if (shouldUpdate) {
|
|
6521
|
+
setConfiguredItems(list);
|
|
6522
|
+
}
|
|
6523
|
+
});
|
|
6524
|
+
};
|
|
6525
|
+
const sub = extensionManager.subscribe(extensionManager.EVENTS.ACTIVE_DATA_SOURCE_CHANGED, dataSourceChangedCallback);
|
|
6526
|
+
dataSourceChangedCallback();
|
|
6527
|
+
return () => {
|
|
6528
|
+
shouldUpdate = false;
|
|
6529
|
+
sub.unsubscribe();
|
|
6530
|
+
};
|
|
6531
|
+
}, []);
|
|
6532
|
+
return configuredItems ? /*#__PURE__*/react.createElement("div", {
|
|
6533
|
+
className: "flex text-aqua-pale overflow-hidden items-center"
|
|
6534
|
+
}, /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
6535
|
+
name: "settings",
|
|
6536
|
+
className: "cursor-pointer shrink-0 w-3.5 h-3.5 mr-2.5",
|
|
6537
|
+
onClick: () => show({
|
|
6538
|
+
content: Components_DataSourceConfigurationModalComponent,
|
|
6539
|
+
title: t('Configure Data Source'),
|
|
6540
|
+
contentProps: {
|
|
6541
|
+
configurationAPI,
|
|
6542
|
+
configuredItems,
|
|
6543
|
+
onHide: hide
|
|
6544
|
+
}
|
|
6545
|
+
})
|
|
6546
|
+
}), configuredItems.map((item, itemIndex) => {
|
|
6547
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6548
|
+
key: itemIndex,
|
|
6549
|
+
className: "flex overflow-hidden"
|
|
6550
|
+
}, /*#__PURE__*/react.createElement("div", {
|
|
6551
|
+
key: itemIndex,
|
|
6552
|
+
className: "text-ellipsis whitespace-nowrap overflow-hidden"
|
|
6553
|
+
}, item.name), itemIndex !== configuredItems.length - 1 && /*#__PURE__*/react.createElement("div", {
|
|
6554
|
+
className: "px-2.5"
|
|
6555
|
+
}, "|"));
|
|
6556
|
+
})) : /*#__PURE__*/react.createElement(react.Fragment, null);
|
|
6557
|
+
}
|
|
6558
|
+
/* harmony default export */ const Components_DataSourceConfigurationComponent = (DataSourceConfigurationComponent);
|
|
6559
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/DataSourceConfigurationAPI/GoogleCloudDataSourceConfigurationAPI.ts
|
|
6560
|
+
/**
|
|
6561
|
+
* This file contains the implementations of BaseDataSourceConfigurationAPIItem
|
|
6562
|
+
* and BaseDataSourceConfigurationAPI for the Google cloud healthcare API. To
|
|
6563
|
+
* better understand this implementation and/or to implement custom implementations,
|
|
6564
|
+
* see the platform\core\src\types\DataSourceConfigurationAPI.ts and its JS doc
|
|
6565
|
+
* comments as a guide.
|
|
6566
|
+
*/
|
|
6567
|
+
/**
|
|
6568
|
+
* The various Google Cloud Healthcare path item types.
|
|
6569
|
+
*/
|
|
6570
|
+
var ItemType = /*#__PURE__*/function (ItemType) {
|
|
6571
|
+
ItemType[ItemType["projects"] = 0] = "projects";
|
|
6572
|
+
ItemType[ItemType["locations"] = 1] = "locations";
|
|
6573
|
+
ItemType[ItemType["datasets"] = 2] = "datasets";
|
|
6574
|
+
ItemType[ItemType["dicomStores"] = 3] = "dicomStores";
|
|
6575
|
+
return ItemType;
|
|
6576
|
+
}(ItemType || {});
|
|
6577
|
+
const initialUrl = 'https://cloudresourcemanager.googleapis.com/v1';
|
|
6578
|
+
const baseHealthcareUrl = 'https://healthcare.googleapis.com/v1';
|
|
6579
|
+
class GoogleCloudDataSourceConfigurationAPIItem {
|
|
6580
|
+
constructor() {
|
|
6581
|
+
this.id = void 0;
|
|
6582
|
+
this.name = void 0;
|
|
6583
|
+
this.url = void 0;
|
|
6584
|
+
this.itemType = void 0;
|
|
6585
|
+
}
|
|
6586
|
+
}
|
|
6587
|
+
class GoogleCloudDataSourceConfigurationAPI {
|
|
6588
|
+
constructor(dataSourceName, servicesManager, extensionManager) {
|
|
6589
|
+
this._extensionManager = void 0;
|
|
6590
|
+
this._fetchOptions = void 0;
|
|
6591
|
+
this._dataSourceName = void 0;
|
|
6592
|
+
this.getItemLabels = () => ['Project', 'Location', 'Data set', 'DICOM store'];
|
|
6593
|
+
this._dataSourceName = dataSourceName;
|
|
6594
|
+
this._extensionManager = extensionManager;
|
|
6595
|
+
const userAuthenticationService = servicesManager.services.userAuthenticationService;
|
|
6596
|
+
this._fetchOptions = {
|
|
6597
|
+
method: 'GET',
|
|
6598
|
+
headers: userAuthenticationService.getAuthorizationHeader()
|
|
6599
|
+
};
|
|
6600
|
+
}
|
|
6601
|
+
async initialize() {
|
|
6602
|
+
const url = `${initialUrl}/projects`;
|
|
6603
|
+
const projects = await GoogleCloudDataSourceConfigurationAPI._doFetch(url, ItemType.projects, this._fetchOptions);
|
|
6604
|
+
if (!projects?.length) {
|
|
6605
|
+
return [];
|
|
6606
|
+
}
|
|
6607
|
+
const projectItems = projects.map(project => {
|
|
6608
|
+
return {
|
|
6609
|
+
id: project.projectId,
|
|
6610
|
+
name: project.name,
|
|
6611
|
+
itemType: ItemType.projects,
|
|
6612
|
+
url: `${baseHealthcareUrl}/projects/${project.projectId}`
|
|
6613
|
+
};
|
|
6614
|
+
});
|
|
6615
|
+
return projectItems;
|
|
6616
|
+
}
|
|
6617
|
+
async setCurrentItem(anItem) {
|
|
6618
|
+
const googleCloudItem = anItem;
|
|
6619
|
+
if (googleCloudItem.itemType === ItemType.dicomStores) {
|
|
6620
|
+
// Last configurable item, so update the data source configuration.
|
|
6621
|
+
const url = `${googleCloudItem.url}/dicomWeb`;
|
|
6622
|
+
const dataSourceDefCopy = JSON.parse(JSON.stringify(this._extensionManager.getDataSourceDefinition(this._dataSourceName)));
|
|
6623
|
+
dataSourceDefCopy.configuration = {
|
|
6624
|
+
...dataSourceDefCopy.configuration,
|
|
6625
|
+
wadoUriRoot: url,
|
|
6626
|
+
qidoRoot: url,
|
|
6627
|
+
wadoRoot: url
|
|
6628
|
+
};
|
|
6629
|
+
this._extensionManager.updateDataSourceConfiguration(dataSourceDefCopy.sourceName, dataSourceDefCopy.configuration);
|
|
6630
|
+
return [];
|
|
6631
|
+
}
|
|
6632
|
+
const subItemType = googleCloudItem.itemType + 1;
|
|
6633
|
+
const subItemField = `${ItemType[subItemType]}`;
|
|
6634
|
+
const url = `${googleCloudItem.url}/${subItemField}`;
|
|
6635
|
+
const fetchedSubItems = await GoogleCloudDataSourceConfigurationAPI._doFetch(url, subItemType, this._fetchOptions);
|
|
6636
|
+
if (!fetchedSubItems?.length) {
|
|
6637
|
+
return [];
|
|
6638
|
+
}
|
|
6639
|
+
const subItems = fetchedSubItems.map(subItem => {
|
|
6640
|
+
const nameSplit = subItem.name.split('/');
|
|
6641
|
+
return {
|
|
6642
|
+
id: subItem.name,
|
|
6643
|
+
name: nameSplit[nameSplit.length - 1],
|
|
6644
|
+
itemType: subItemType,
|
|
6645
|
+
url: `${baseHealthcareUrl}/${subItem.name}`
|
|
6646
|
+
};
|
|
6647
|
+
});
|
|
6648
|
+
return subItems;
|
|
6649
|
+
}
|
|
6650
|
+
async getConfiguredItems() {
|
|
6651
|
+
const dataSourceDefinition = this._extensionManager.getDataSourceDefinition(this._dataSourceName);
|
|
6652
|
+
const url = dataSourceDefinition.configuration.wadoUriRoot;
|
|
6653
|
+
const projectsIndex = url.indexOf('projects');
|
|
6654
|
+
const urlSplit = url.substring(projectsIndex).split('/');
|
|
6655
|
+
const configuredItems = [];
|
|
6656
|
+
for (let itemType = 0; itemType < 4; itemType += 1) {
|
|
6657
|
+
if (itemType === ItemType.projects) {
|
|
6658
|
+
const projectId = urlSplit[1];
|
|
6659
|
+
const projectUrl = `${initialUrl}/projects/${projectId}`;
|
|
6660
|
+
const data = await GoogleCloudDataSourceConfigurationAPI._doFetch(projectUrl, ItemType.projects, this._fetchOptions);
|
|
6661
|
+
const project = data[0];
|
|
6662
|
+
configuredItems.push({
|
|
6663
|
+
id: project.projectId,
|
|
6664
|
+
name: project.name,
|
|
6665
|
+
itemType: itemType,
|
|
6666
|
+
url: `${baseHealthcareUrl}/projects/${project.projectId}`
|
|
6667
|
+
});
|
|
6668
|
+
} else {
|
|
6669
|
+
const relativePath = urlSplit.slice(0, itemType * 2 + 2).join('/');
|
|
6670
|
+
configuredItems.push({
|
|
6671
|
+
id: relativePath,
|
|
6672
|
+
name: urlSplit[itemType * 2 + 1],
|
|
6673
|
+
itemType: itemType,
|
|
6674
|
+
url: `${baseHealthcareUrl}/${relativePath}`
|
|
6675
|
+
});
|
|
6676
|
+
}
|
|
6677
|
+
}
|
|
6678
|
+
return configuredItems;
|
|
6679
|
+
}
|
|
6680
|
+
|
|
6681
|
+
/**
|
|
6682
|
+
* Fetches an array of items the specified item type.
|
|
6683
|
+
* @param urlStr the fetch url
|
|
6684
|
+
* @param fetchItemType the type to fetch
|
|
6685
|
+
* @param fetchOptions the header options for the fetch (e.g. authorization header)
|
|
6686
|
+
* @param fetchSearchParams any search query params; currently only used for paging results
|
|
6687
|
+
* @returns an array of items of the specified type
|
|
6688
|
+
*/
|
|
6689
|
+
static async _doFetch(urlStr, fetchItemType) {
|
|
6690
|
+
let fetchOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
6691
|
+
let fetchSearchParams = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
6692
|
+
try {
|
|
6693
|
+
const url = new URL(urlStr);
|
|
6694
|
+
url.search = new URLSearchParams(fetchSearchParams).toString();
|
|
6695
|
+
const response = await fetch(url, fetchOptions);
|
|
6696
|
+
const data = await response.json();
|
|
6697
|
+
if (response.status >= 200 && response.status < 300 && data != null) {
|
|
6698
|
+
if (data.nextPageToken != null) {
|
|
6699
|
+
fetchSearchParams.pageToken = data.nextPageToken;
|
|
6700
|
+
const subPageData = await this._doFetch(urlStr, fetchItemType, fetchOptions, fetchSearchParams);
|
|
6701
|
+
data[ItemType[fetchItemType]] = data[ItemType[fetchItemType]].concat(subPageData);
|
|
6702
|
+
}
|
|
6703
|
+
if (data[ItemType[fetchItemType]]) {
|
|
6704
|
+
return data[ItemType[fetchItemType]];
|
|
6705
|
+
} else if (data.name) {
|
|
6706
|
+
return [data];
|
|
6707
|
+
} else {
|
|
6708
|
+
return [];
|
|
6709
|
+
}
|
|
6710
|
+
} else {
|
|
6711
|
+
const message = data?.error?.message || `Error returned from Google Cloud Healthcare: ${response.status} - ${response.statusText}`;
|
|
6712
|
+
throw new Error(message);
|
|
6713
|
+
}
|
|
6714
|
+
} catch (err) {
|
|
6715
|
+
const message = err?.message || 'Error occurred during fetch request.';
|
|
6716
|
+
throw new Error(message);
|
|
6717
|
+
}
|
|
6718
|
+
}
|
|
6719
|
+
}
|
|
6720
|
+
|
|
5758
6721
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getCustomizationModule.tsx
|
|
5759
6722
|
|
|
5760
6723
|
|
|
5761
6724
|
|
|
6725
|
+
|
|
6726
|
+
|
|
5762
6727
|
/**
|
|
5763
6728
|
*
|
|
5764
6729
|
* Note: this is an example of how the customization module can be used
|
|
@@ -5768,7 +6733,11 @@ function DataSourceSelector() {
|
|
|
5768
6733
|
* custom page for the user to view their profile, or to add a custom
|
|
5769
6734
|
* page for login etc.
|
|
5770
6735
|
*/
|
|
5771
|
-
function getCustomizationModule() {
|
|
6736
|
+
function getCustomizationModule(_ref) {
|
|
6737
|
+
let {
|
|
6738
|
+
servicesManager,
|
|
6739
|
+
extensionManager
|
|
6740
|
+
} = _ref;
|
|
5772
6741
|
return [{
|
|
5773
6742
|
name: 'helloPage',
|
|
5774
6743
|
value: {
|
|
@@ -5835,12 +6804,16 @@ function getCustomizationModule() {
|
|
|
5835
6804
|
{
|
|
5836
6805
|
id: 'ohif.overlayItem',
|
|
5837
6806
|
content: function (props) {
|
|
5838
|
-
if (this.condition && !this.condition(props))
|
|
6807
|
+
if (this.condition && !this.condition(props)) {
|
|
6808
|
+
return null;
|
|
6809
|
+
}
|
|
5839
6810
|
const {
|
|
5840
6811
|
instance
|
|
5841
6812
|
} = props;
|
|
5842
6813
|
const value = instance && this.attribute ? instance[this.attribute] : this.contentF && typeof this.contentF === 'function' ? this.contentF(props) : null;
|
|
5843
|
-
if (!value)
|
|
6814
|
+
if (!value) {
|
|
6815
|
+
return null;
|
|
6816
|
+
}
|
|
5844
6817
|
return /*#__PURE__*/react.createElement("span", {
|
|
5845
6818
|
className: "overlay-item flex flex-row",
|
|
5846
6819
|
style: {
|
|
@@ -5878,11 +6851,22 @@ function getCustomizationModule() {
|
|
|
5878
6851
|
}
|
|
5879
6852
|
return clonedObject;
|
|
5880
6853
|
}
|
|
6854
|
+
}, {
|
|
6855
|
+
// the generic GUI component to configure a data source using an instance of a BaseDataSourceConfigurationAPI
|
|
6856
|
+
id: 'ohif.dataSourceConfigurationComponent',
|
|
6857
|
+
component: Components_DataSourceConfigurationComponent.bind(null, {
|
|
6858
|
+
servicesManager,
|
|
6859
|
+
extensionManager
|
|
6860
|
+
})
|
|
6861
|
+
}, {
|
|
6862
|
+
// The factory for creating an instance of a BaseDataSourceConfigurationAPI for Google Cloud Healthcare
|
|
6863
|
+
id: 'ohif.dataSourceConfigurationAPI.google',
|
|
6864
|
+
factory: dataSourceName => new GoogleCloudDataSourceConfigurationAPI(dataSourceName, servicesManager, extensionManager)
|
|
5881
6865
|
}]
|
|
5882
6866
|
}];
|
|
5883
6867
|
}
|
|
5884
6868
|
// EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/calculate-suv/dist/calculate-suv.esm.js
|
|
5885
|
-
var calculate_suv_esm = __webpack_require__(
|
|
6869
|
+
var calculate_suv_esm = __webpack_require__(15747);
|
|
5886
6870
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getPTImageIdInstanceMetadata.ts
|
|
5887
6871
|
|
|
5888
6872
|
const getPTImageIdInstanceMetadata_metadataProvider = src["default"].classes.MetadataProvider;
|
|
@@ -5891,9 +6875,12 @@ function getPTImageIdInstanceMetadata(imageId) {
|
|
|
5891
6875
|
if (!dicomMetaData) {
|
|
5892
6876
|
throw new Error('dicom metadata are required');
|
|
5893
6877
|
}
|
|
5894
|
-
if (dicomMetaData.SeriesDate === undefined || dicomMetaData.SeriesTime === undefined || dicomMetaData.
|
|
6878
|
+
if (dicomMetaData.SeriesDate === undefined || dicomMetaData.SeriesTime === undefined || dicomMetaData.CorrectedImage === undefined || dicomMetaData.Units === undefined || !dicomMetaData.RadiopharmaceuticalInformationSequence || dicomMetaData.RadiopharmaceuticalInformationSequence[0].RadionuclideHalfLife === undefined || dicomMetaData.RadiopharmaceuticalInformationSequence[0].RadionuclideTotalDose === undefined || dicomMetaData.DecayCorrection === undefined || dicomMetaData.AcquisitionDate === undefined || dicomMetaData.AcquisitionTime === undefined || dicomMetaData.RadiopharmaceuticalInformationSequence[0].RadiopharmaceuticalStartDateTime === undefined && dicomMetaData.RadiopharmaceuticalInformationSequence[0].RadiopharmaceuticalStartTime === undefined) {
|
|
5895
6879
|
throw new Error('required metadata are missing');
|
|
5896
6880
|
}
|
|
6881
|
+
if (dicomMetaData.PatientWeight === undefined) {
|
|
6882
|
+
console.warn('PatientWeight missing from PT instance metadata');
|
|
6883
|
+
}
|
|
5897
6884
|
const instanceMetadata = {
|
|
5898
6885
|
CorrectedImage: dicomMetaData.CorrectedImage,
|
|
5899
6886
|
Units: dicomMetaData.Units,
|