@ohif/app 3.7.0-beta.11 → 3.7.0-beta.110
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.b9983325adf849bff6fd.js → 12.bundle.5ea15cb6633d8028e47d.js} +6 -6
- package/dist/{295.bundle.957b1159fec14b9199a1.js → 125.bundle.253395f320b72180da63.js} +6 -6
- package/dist/{351.bundle.0742237651aef9694a65.js → 181.bundle.ceb057236403bcb630ac.js} +226 -204
- package/dist/{351.css → 181.css} +1 -1
- package/dist/{744.bundle.4c4b884f90eb70482821.js → 19.bundle.03f809886c36c388d05c.js} +240 -381
- package/dist/{606.bundle.5d876f5f3dd8287f0a28.js → 202.bundle.d3490836f71e001dd30f.js} +2089 -692
- package/dist/{926.bundle.dbc9d0e591cb9217fda2.js → 220.bundle.f7e1c96c94245e70f2be.js} +990 -400
- package/dist/221.bundle.dc6dac346d724d6baeae.js +1779 -0
- package/dist/221.css +2 -0
- package/dist/{664.bundle.09abae984223969d1bde.js → 23.bundle.e008ad788170f2ed5569.js} +5 -6
- package/dist/{976.bundle.9cc2382162214ea0af2b.js → 236.bundle.7b906cd27864d65f32c0.js} +89 -105
- package/dist/{55.bundle.550a823e75eb608e8d5e.js → 250.bundle.8084960e3318cda37317.js} +52 -36
- package/dist/{973.bundle.4584df05b320b94cace5.js → 281.bundle.c9854cc25c839e49c2c8.js} +18 -14
- package/dist/{82.bundle.9a0e7f08d4bce18d302f.js → 342.bundle.7d6c1e6bda1c67d729a7.js} +1802 -489
- package/dist/{404.bundle.3d65ff813eead20462d3.js → 359.bundle.72d017719489ff11057b.js} +47 -134
- package/dist/{192.bundle.950e5380ea63c6d635d5.js → 370.bundle.e55d75ff1bdccee16cde.js} +117 -103
- package/dist/{790.bundle.7327fec7833ceea2784b.js → 410.bundle.5b41c68cb0f210a83f13.js} +11 -9
- package/dist/{151.bundle.31ea35044218837bf73f.js → 417.bundle.af0a207c29b109f84159.js} +49 -17
- package/dist/{569.bundle.c8e771a8d28e237b32be.js → 451.bundle.9fd36f52ff69594f0669.js} +86 -106
- package/dist/{581.bundle.dc6197189f7c88c27d4c.js → 471.bundle.b3d77b83b1593c09a504.js} +78 -99
- package/dist/{199.bundle.f50ffd85a4334de2f5c1.js → 506.bundle.468dc6db2a9bfa96bb44.js} +11 -9
- package/dist/{531.bundle.2a82fb1d69e5b57cc72b.js → 530.bundle.a03b6f942ace3e1baa1e.js} +726 -447
- package/dist/579.css +1 -0
- package/dist/{935.bundle.deeffff0e4f7b528e3c3.js → 604.bundle.a51f83e64004bca5f497.js} +2 -3
- package/dist/613.bundle.74d59dec1983ef3efcdc.js +532 -0
- package/dist/{984.bundle.119557c018e6371b4628.js → 663.bundle.a6196baf5853e7d3f7c7.js} +68 -38
- package/dist/{205.bundle.b5a473c200dcf2bbcdb4.js → 686.bundle.dccef1f36e4bc79bcc48.js} +6 -6
- package/dist/{50.bundle.65ff60818862eda39d12.js → 687.bundle.e2c9c42ad3989a14d513.js} +218 -9
- package/dist/{331.bundle.bd0c13931a21d53086c9.js → 743.bundle.489f7df3a089d4d374e1.js} +26294 -21326
- package/dist/757.bundle.ec8301d8e70d2b990f65.js +17067 -0
- package/dist/{728.bundle.d13856835357400fef82.js → 774.bundle.4b2dc46a35012b898e1a.js} +95 -64
- package/dist/{381.bundle.0905e683605fcbc0895f.js → 775.bundle.2285e7e0e67878948c0d.js} +16 -16
- package/dist/{283.bundle.1015e87c3a47b1f1379c.js → 788.bundle.f4493409508bdffa7af8.js} +120 -370
- package/dist/{642.bundle.8905e515ce593e57ceb1.js → 814.bundle.10a2cbf02b044387e68b.js} +6 -6
- package/dist/{707.bundle.f774f3e4a687ddd60a32.js → 82.bundle.9c6461625afd2e38b997.js} +1203 -804
- package/dist/{799.bundle.758558e64147e5aad612.js → 822.bundle.891f2e57b1b7bc2f4cb4.js} +81 -34
- package/dist/{953.bundle.3b0189ebc11cf0946f18.js → 886.bundle.4b3a7f2079d085fdbcb3.js} +34 -29
- package/dist/945.min.worker.js +1 -1
- package/dist/945.min.worker.js.map +1 -1
- package/dist/{270.bundle.4564621556b0f963a004.js → 957.bundle.9ea4506963ef8b2d84ba.js} +7095 -979
- package/dist/{208.bundle.7f610a302dc54c4924da.js → 99.bundle.334c4bd4e4e81aaf45ad.js} +86 -105
- package/dist/_redirects +1 -1
- package/dist/app-config.js +35 -17
- package/dist/app.bundle.css +13 -12
- package/dist/{app.bundle.3d598a4738bdc22950d3.js → app.bundle.fd6ac18b8874825722a0.js} +72771 -67313
- package/dist/assets/yandex-browser-manifest.json +1 -1
- 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/es6-shim.min.js +3569 -2
- package/dist/google.js +8 -7
- package/dist/index.html +2 -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/init-service-worker.js +3 -5
- package/dist/oidc-client.min.js +10857 -39
- package/dist/polyfill.min.js +184 -1
- package/dist/silent-refresh.html +18 -9
- package/dist/sw.js +1 -1
- package/package.json +21 -22
- package/dist/616.bundle.de530ae226dfa5573f6e.js +0 -685
- package/dist/780.bundle.fd0f13dc92e9caa0581e.js +0 -4769
- package/dist/index.worker.1c69152d710fa7b84bce.worker.js.map +0 -1
- /package/dist/{806.css → 19.css} +0 -0
- /package/dist/{55.css → 250.css} +0 -0
- /package/dist/{707.css → 82.css} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
(
|
|
2
|
+
(self["webpackChunk"] = self["webpackChunk"] || []).push([[342],{
|
|
3
3
|
|
|
4
|
-
/***/
|
|
4
|
+
/***/ 56342:
|
|
5
5
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
6
6
|
|
|
7
7
|
// ESM COMPAT FLAG
|
|
@@ -11,6 +11,8 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
11
11
|
__webpack_require__.d(__webpack_exports__, {
|
|
12
12
|
ContextMenuController: () => (/* reexport */ ContextMenuController),
|
|
13
13
|
CustomizableContextMenuTypes: () => (/* reexport */ types_namespaceObject),
|
|
14
|
+
createReportAsync: () => (/* reexport */ Actions_createReportAsync),
|
|
15
|
+
createReportDialogPrompt: () => (/* reexport */ CreateReportDialogPrompt),
|
|
14
16
|
"default": () => (/* binding */ default_src),
|
|
15
17
|
dicomWebUtils: () => (/* reexport */ utils_namespaceObject),
|
|
16
18
|
getStudiesForPatientByMRN: () => (/* reexport */ Panels_getStudiesForPatientByMRN)
|
|
@@ -28,11 +30,11 @@ __webpack_require__.d(utils_namespaceObject, {
|
|
|
28
30
|
});
|
|
29
31
|
|
|
30
32
|
// 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__(
|
|
33
|
+
var dicomweb_client_es = __webpack_require__(97604);
|
|
34
|
+
// EXTERNAL MODULE: ../../core/src/index.ts + 65 modules
|
|
35
|
+
var src = __webpack_require__(71771);
|
|
34
36
|
// EXTERNAL MODULE: ../../core/src/utils/sortStudy.ts
|
|
35
|
-
var sortStudy = __webpack_require__(
|
|
37
|
+
var sortStudy = __webpack_require__(62971);
|
|
36
38
|
;// CONCATENATED MODULE: ../../../extensions/default/src/DicomWebDataSource/qido.js
|
|
37
39
|
/**
|
|
38
40
|
* QIDO - Query based on ID for DICOM Objects
|
|
@@ -378,7 +380,7 @@ function getImageId(_ref) {
|
|
|
378
380
|
}
|
|
379
381
|
}
|
|
380
382
|
// EXTERNAL MODULE: ../../../node_modules/dcmjs/build/dcmjs.es.js
|
|
381
|
-
var dcmjs_es = __webpack_require__(
|
|
383
|
+
var dcmjs_es = __webpack_require__(67540);
|
|
382
384
|
;// CONCATENATED MODULE: ../../../extensions/default/src/DicomWebDataSource/wado/retrieveMetadataLoader.js
|
|
383
385
|
/**
|
|
384
386
|
* Class to define inheritance of load retrieve strategy.
|
|
@@ -638,7 +640,7 @@ const StudyMetaDataPromises = new Map();
|
|
|
638
640
|
*
|
|
639
641
|
* @param {Object} server Object with server configuration parameters
|
|
640
642
|
* @param {string} StudyInstanceUID The UID of the Study to be retrieved
|
|
641
|
-
* @param {boolean} enabledStudyLazyLoad Whether the study metadata should be loaded
|
|
643
|
+
* @param {boolean} enabledStudyLazyLoad Whether the study metadata should be loaded asynchronously.
|
|
642
644
|
* @param {function} storeInstancesCallback A callback used to store the retrieved instance metadata.
|
|
643
645
|
* @param {Object} [filters] - Object containing filters to be applied on retrieve metadata process
|
|
644
646
|
* @param {string} [filter.seriesInstanceUID] - series instance uid to filter results against
|
|
@@ -708,12 +710,16 @@ class StaticWadoClient extends dicomweb_client_es.api.DICOMwebClient {
|
|
|
708
710
|
* @returns
|
|
709
711
|
*/
|
|
710
712
|
async searchForStudies(options) {
|
|
711
|
-
if (!this.staticWado)
|
|
713
|
+
if (!this.staticWado) {
|
|
714
|
+
return super.searchForStudies(options);
|
|
715
|
+
}
|
|
712
716
|
const searchResult = await super.searchForStudies(options);
|
|
713
717
|
const {
|
|
714
718
|
queryParams
|
|
715
719
|
} = options;
|
|
716
|
-
if (!queryParams)
|
|
720
|
+
if (!queryParams) {
|
|
721
|
+
return searchResult;
|
|
722
|
+
}
|
|
717
723
|
const lowerParams = this.toLowerParams(queryParams);
|
|
718
724
|
const filtered = searchResult.filter(study => {
|
|
719
725
|
for (const key of Object.keys(StaticWadoClient.studyFilterKeys)) {
|
|
@@ -726,12 +732,16 @@ class StaticWadoClient extends dicomweb_client_es.api.DICOMwebClient {
|
|
|
726
732
|
return filtered;
|
|
727
733
|
}
|
|
728
734
|
async searchForSeries(options) {
|
|
729
|
-
if (!this.staticWado)
|
|
735
|
+
if (!this.staticWado) {
|
|
736
|
+
return super.searchForSeries(options);
|
|
737
|
+
}
|
|
730
738
|
const searchResult = await super.searchForSeries(options);
|
|
731
739
|
const {
|
|
732
740
|
queryParams
|
|
733
741
|
} = options;
|
|
734
|
-
if (!queryParams)
|
|
742
|
+
if (!queryParams) {
|
|
743
|
+
return searchResult;
|
|
744
|
+
}
|
|
735
745
|
const lowerParams = this.toLowerParams(queryParams);
|
|
736
746
|
const filtered = searchResult.filter(series => {
|
|
737
747
|
for (const key of Object.keys(StaticWadoClient.seriesFilterKeys)) {
|
|
@@ -767,8 +777,12 @@ class StaticWadoClient extends dicomweb_client_es.api.DICOMwebClient {
|
|
|
767
777
|
actual = actual.Alphabetic;
|
|
768
778
|
}
|
|
769
779
|
if (typeof actual == 'string') {
|
|
770
|
-
if (actual.length === 0)
|
|
771
|
-
|
|
780
|
+
if (actual.length === 0) {
|
|
781
|
+
return true;
|
|
782
|
+
}
|
|
783
|
+
if (desired.length === 0 || desired === '*') {
|
|
784
|
+
return true;
|
|
785
|
+
}
|
|
772
786
|
if (desired[0] === '*' && desired[desired.length - 1] === '*') {
|
|
773
787
|
// console.log(`Comparing ${actual} to ${desired.substring(1, desired.length - 1)}`)
|
|
774
788
|
return actual.indexOf(desired.substring(1, desired.length - 1)) != -1;
|
|
@@ -783,9 +797,13 @@ class StaticWadoClient extends dicomweb_client_es.api.DICOMwebClient {
|
|
|
783
797
|
|
|
784
798
|
/** Compares a pair of dates to see if the value is within the range */
|
|
785
799
|
compareDateRange(range, value) {
|
|
786
|
-
if (!value)
|
|
800
|
+
if (!value) {
|
|
801
|
+
return true;
|
|
802
|
+
}
|
|
787
803
|
const dash = range.indexOf('-');
|
|
788
|
-
if (dash === -1)
|
|
804
|
+
if (dash === -1) {
|
|
805
|
+
return this.compareValues(range, value);
|
|
806
|
+
}
|
|
789
807
|
const start = range.substring(0, dash);
|
|
790
808
|
const end = range.substring(dash + 1);
|
|
791
809
|
return (!start || value >= start) && (!end || value <= end);
|
|
@@ -802,12 +820,18 @@ class StaticWadoClient extends dicomweb_client_es.api.DICOMwebClient {
|
|
|
802
820
|
*/
|
|
803
821
|
filterItem(key, queryParams, study, sourceFilterMap) {
|
|
804
822
|
const altKey = sourceFilterMap[key] || key;
|
|
805
|
-
if (!queryParams)
|
|
823
|
+
if (!queryParams) {
|
|
824
|
+
return true;
|
|
825
|
+
}
|
|
806
826
|
const testValue = queryParams[key] || queryParams[altKey];
|
|
807
|
-
if (!testValue)
|
|
827
|
+
if (!testValue) {
|
|
828
|
+
return true;
|
|
829
|
+
}
|
|
808
830
|
const valueElem = study[key] || study[altKey];
|
|
809
|
-
if (!valueElem)
|
|
810
|
-
|
|
831
|
+
if (!valueElem) {
|
|
832
|
+
return false;
|
|
833
|
+
}
|
|
834
|
+
if (valueElem.vr === 'DA' && valueElem.Value?.[0]) {
|
|
811
835
|
return this.compareDateRange(testValue, valueElem.Value[0]);
|
|
812
836
|
}
|
|
813
837
|
const value = valueElem.Value;
|
|
@@ -867,8 +891,12 @@ const getDirectURL = (config, params) => {
|
|
|
867
891
|
singlepart: fetchPart = 'video'
|
|
868
892
|
} = params;
|
|
869
893
|
const value = instance[tag];
|
|
870
|
-
if (!value)
|
|
871
|
-
|
|
894
|
+
if (!value) {
|
|
895
|
+
return undefined;
|
|
896
|
+
}
|
|
897
|
+
if (value.DirectRetrieveURL) {
|
|
898
|
+
return value.DirectRetrieveURL;
|
|
899
|
+
}
|
|
872
900
|
if (value.InlineBinary) {
|
|
873
901
|
const blob = src.utils.b64toBlob(value.InlineBinary, defaultType);
|
|
874
902
|
value.DirectRetrieveURL = URL.createObjectURL(blob);
|
|
@@ -991,65 +1019,69 @@ const metadataProvider = src.classes.MetadataProvider;
|
|
|
991
1019
|
* @param {string|bool} singlepart - indicates of the retrieves can fetch singlepart. Options are bulkdata, video, image or boolean true
|
|
992
1020
|
*/
|
|
993
1021
|
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);
|
|
1022
|
+
let dicomWebConfigCopy, qidoConfig, wadoConfig, qidoDicomWebClient, wadoDicomWebClient, getAuthrorizationHeader, generateWadoHeader;
|
|
1024
1023
|
const implementation = {
|
|
1025
1024
|
initialize: _ref => {
|
|
1026
1025
|
let {
|
|
1027
1026
|
params,
|
|
1028
1027
|
query
|
|
1029
1028
|
} = _ref;
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1029
|
+
if (dicomWebConfig.onConfiguration && typeof dicomWebConfig.onConfiguration === 'function') {
|
|
1030
|
+
dicomWebConfig = dicomWebConfig.onConfiguration(dicomWebConfig, {
|
|
1031
|
+
params,
|
|
1032
|
+
query
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
dicomWebConfigCopy = JSON.parse(JSON.stringify(dicomWebConfig));
|
|
1036
|
+
getAuthrorizationHeader = () => {
|
|
1037
|
+
const xhrRequestHeaders = {};
|
|
1038
|
+
const authHeaders = userAuthenticationService.getAuthorizationHeader();
|
|
1039
|
+
if (authHeaders && authHeaders.Authorization) {
|
|
1040
|
+
xhrRequestHeaders.Authorization = authHeaders.Authorization;
|
|
1041
|
+
}
|
|
1042
|
+
return xhrRequestHeaders;
|
|
1043
|
+
};
|
|
1044
|
+
generateWadoHeader = () => {
|
|
1045
|
+
let authorizationHeader = getAuthrorizationHeader();
|
|
1046
|
+
//Generate accept header depending on config params
|
|
1047
|
+
let formattedAcceptHeader = src.utils.generateAcceptHeader(dicomWebConfig.acceptHeader, dicomWebConfig.requestTransferSyntaxUID, dicomWebConfig.omitQuotationForMultipartRequest);
|
|
1048
|
+
return {
|
|
1049
|
+
...authorizationHeader,
|
|
1050
|
+
Accept: formattedAcceptHeader
|
|
1051
|
+
};
|
|
1052
|
+
};
|
|
1053
|
+
qidoConfig = {
|
|
1054
|
+
url: dicomWebConfig.qidoRoot,
|
|
1055
|
+
staticWado: dicomWebConfig.staticWado,
|
|
1056
|
+
singlepart: dicomWebConfig.singlepart,
|
|
1057
|
+
headers: userAuthenticationService.getAuthorizationHeader(),
|
|
1058
|
+
errorInterceptor: src/* errorHandler */.Po.getHTTPErrorHandler()
|
|
1059
|
+
};
|
|
1060
|
+
wadoConfig = {
|
|
1061
|
+
url: dicomWebConfig.wadoRoot,
|
|
1062
|
+
staticWado: dicomWebConfig.staticWado,
|
|
1063
|
+
singlepart: dicomWebConfig.singlepart,
|
|
1064
|
+
headers: userAuthenticationService.getAuthorizationHeader(),
|
|
1065
|
+
errorInterceptor: src/* errorHandler */.Po.getHTTPErrorHandler()
|
|
1066
|
+
};
|
|
1067
|
+
|
|
1068
|
+
// TODO -> Two clients sucks, but its better than 1000.
|
|
1069
|
+
// TODO -> We'll need to merge auth later.
|
|
1070
|
+
qidoDicomWebClient = dicomWebConfig.staticWado ? new StaticWadoClient(qidoConfig) : new dicomweb_client_es.api.DICOMwebClient(qidoConfig);
|
|
1071
|
+
wadoDicomWebClient = dicomWebConfig.staticWado ? new StaticWadoClient(wadoConfig) : new dicomweb_client_es.api.DICOMwebClient(wadoConfig);
|
|
1037
1072
|
},
|
|
1038
1073
|
query: {
|
|
1039
1074
|
studies: {
|
|
1040
1075
|
mapParams: mapParams.bind(),
|
|
1041
1076
|
search: async function (origParams) {
|
|
1042
|
-
|
|
1043
|
-
if (headers) {
|
|
1044
|
-
qidoDicomWebClient.headers = headers;
|
|
1045
|
-
}
|
|
1077
|
+
qidoDicomWebClient.headers = getAuthrorizationHeader();
|
|
1046
1078
|
const {
|
|
1047
1079
|
studyInstanceUid,
|
|
1048
1080
|
seriesInstanceUid,
|
|
1049
1081
|
...mappedParams
|
|
1050
1082
|
} = mapParams(origParams, {
|
|
1051
|
-
supportsFuzzyMatching,
|
|
1052
|
-
supportsWildcard
|
|
1083
|
+
supportsFuzzyMatching: dicomWebConfig.supportsFuzzyMatching,
|
|
1084
|
+
supportsWildcard: dicomWebConfig.supportsWildcard
|
|
1053
1085
|
}) || {};
|
|
1054
1086
|
const results = await search(qidoDicomWebClient, undefined, undefined, mappedParams);
|
|
1055
1087
|
return processResults(results);
|
|
@@ -1059,10 +1091,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
|
1059
1091
|
series: {
|
|
1060
1092
|
// mapParams: mapParams.bind(),
|
|
1061
1093
|
search: async function (studyInstanceUid) {
|
|
1062
|
-
|
|
1063
|
-
if (headers) {
|
|
1064
|
-
qidoDicomWebClient.headers = headers;
|
|
1065
|
-
}
|
|
1094
|
+
qidoDicomWebClient.headers = getAuthrorizationHeader();
|
|
1066
1095
|
const results = await seriesInStudy(qidoDicomWebClient, studyInstanceUid);
|
|
1067
1096
|
return processSeriesResults(results);
|
|
1068
1097
|
}
|
|
@@ -1071,10 +1100,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
|
1071
1100
|
|
|
1072
1101
|
instances: {
|
|
1073
1102
|
search: (studyInstanceUid, queryParameters) => {
|
|
1074
|
-
|
|
1075
|
-
if (headers) {
|
|
1076
|
-
qidoDicomWebClient.headers = headers;
|
|
1077
|
-
}
|
|
1103
|
+
qidoDicomWebClient.headers = getAuthrorizationHeader();
|
|
1078
1104
|
search.call(undefined, qidoDicomWebClient, studyInstanceUid, null, queryParameters);
|
|
1079
1105
|
}
|
|
1080
1106
|
}
|
|
@@ -1093,8 +1119,8 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
|
1093
1119
|
*/
|
|
1094
1120
|
directURL: params => {
|
|
1095
1121
|
return utils_getDirectURL({
|
|
1096
|
-
wadoRoot,
|
|
1097
|
-
singlepart
|
|
1122
|
+
wadoRoot: dicomWebConfig.wadoRoot,
|
|
1123
|
+
singlepart: dicomWebConfig.singlepart
|
|
1098
1124
|
}, params);
|
|
1099
1125
|
},
|
|
1100
1126
|
bulkDataURI: async _ref2 => {
|
|
@@ -1102,6 +1128,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
|
1102
1128
|
StudyInstanceUID,
|
|
1103
1129
|
BulkDataURI
|
|
1104
1130
|
} = _ref2;
|
|
1131
|
+
qidoDicomWebClient.headers = getAuthrorizationHeader();
|
|
1105
1132
|
const options = {
|
|
1106
1133
|
multipart: false,
|
|
1107
1134
|
BulkDataURI,
|
|
@@ -1121,14 +1148,10 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
|
1121
1148
|
sortFunction,
|
|
1122
1149
|
madeInClient = false
|
|
1123
1150
|
} = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
1124
|
-
const headers = userAuthenticationService.getAuthorizationHeader();
|
|
1125
|
-
if (headers) {
|
|
1126
|
-
wadoDicomWebClient.headers = headers;
|
|
1127
|
-
}
|
|
1128
1151
|
if (!StudyInstanceUID) {
|
|
1129
1152
|
throw new Error('Unable to query for SeriesMetadata without StudyInstanceUID');
|
|
1130
1153
|
}
|
|
1131
|
-
if (enableStudyLazyLoad) {
|
|
1154
|
+
if (dicomWebConfig.enableStudyLazyLoad) {
|
|
1132
1155
|
return implementation._retrieveSeriesMetadataAsync(StudyInstanceUID, filters, sortCriteria, sortFunction, madeInClient);
|
|
1133
1156
|
}
|
|
1134
1157
|
return implementation._retrieveSeriesMetadataSync(StudyInstanceUID, filters, sortCriteria, sortFunction, madeInClient);
|
|
@@ -1137,10 +1160,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
|
1137
1160
|
},
|
|
1138
1161
|
store: {
|
|
1139
1162
|
dicom: async (dataset, request) => {
|
|
1140
|
-
|
|
1141
|
-
if (headers) {
|
|
1142
|
-
wadoDicomWebClient.headers = headers;
|
|
1143
|
-
}
|
|
1163
|
+
wadoDicomWebClient.headers = getAuthrorizationHeader();
|
|
1144
1164
|
if (dataset instanceof ArrayBuffer) {
|
|
1145
1165
|
const options = {
|
|
1146
1166
|
datasets: [dataset],
|
|
@@ -1149,7 +1169,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
|
1149
1169
|
await wadoDicomWebClient.storeInstances(options);
|
|
1150
1170
|
} else {
|
|
1151
1171
|
const meta = {
|
|
1152
|
-
FileMetaInformationVersion: dataset._meta
|
|
1172
|
+
FileMetaInformationVersion: dataset._meta?.FileMetaInformationVersion?.Value,
|
|
1153
1173
|
MediaStorageSOPClassUID: dataset.SOPClassUID,
|
|
1154
1174
|
MediaStorageSOPInstanceUID: dataset.SOPInstanceUID,
|
|
1155
1175
|
TransferSyntaxUID: EXPLICIT_VR_LITTLE_ENDIAN,
|
|
@@ -1170,7 +1190,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
|
1170
1190
|
},
|
|
1171
1191
|
_retrieveSeriesMetadataSync: async (StudyInstanceUID, filters, sortCriteria, sortFunction, madeInClient) => {
|
|
1172
1192
|
const enableStudyLazyLoad = false;
|
|
1173
|
-
|
|
1193
|
+
wadoDicomWebClient.headers = generateWadoHeader();
|
|
1174
1194
|
// data is all SOPInstanceUIDs
|
|
1175
1195
|
const data = await retrieveStudyMetadata(wadoDicomWebClient, StudyInstanceUID, enableStudyLazyLoad, filters, sortCriteria, sortFunction);
|
|
1176
1196
|
|
|
@@ -1199,6 +1219,8 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
|
1199
1219
|
instance
|
|
1200
1220
|
});
|
|
1201
1221
|
instance.imageId = imageId;
|
|
1222
|
+
instance.wadoRoot = dicomWebConfig.wadoRoot;
|
|
1223
|
+
instance.wadoUri = dicomWebConfig.wadoUri;
|
|
1202
1224
|
metadataProvider.addImageIdToUIDs(imageId, {
|
|
1203
1225
|
StudyInstanceUID,
|
|
1204
1226
|
SeriesInstanceUID: instance.SeriesInstanceUID,
|
|
@@ -1215,6 +1237,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
|
1215
1237
|
_retrieveSeriesMetadataAsync: async function (StudyInstanceUID, filters, sortCriteria, sortFunction) {
|
|
1216
1238
|
let madeInClient = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
|
|
1217
1239
|
const enableStudyLazyLoad = true;
|
|
1240
|
+
wadoDicomWebClient.headers = generateWadoHeader();
|
|
1218
1241
|
// Get Series
|
|
1219
1242
|
const {
|
|
1220
1243
|
preLoadData: seriesSummaryMetadata,
|
|
@@ -1230,7 +1253,7 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
|
1230
1253
|
const addRetrieveBulkData = instance => {
|
|
1231
1254
|
const naturalized = naturalizeDataset(instance);
|
|
1232
1255
|
|
|
1233
|
-
// if we
|
|
1256
|
+
// if we know the server doesn't use bulkDataURI, then don't
|
|
1234
1257
|
if (!dicomWebConfig.bulkDataURI?.enabled) {
|
|
1235
1258
|
return naturalized;
|
|
1236
1259
|
}
|
|
@@ -1356,10 +1379,23 @@ function createDicomWebApi(dicomWebConfig, userAuthenticationService) {
|
|
|
1356
1379
|
},
|
|
1357
1380
|
getConfig() {
|
|
1358
1381
|
return dicomWebConfigCopy;
|
|
1382
|
+
},
|
|
1383
|
+
getStudyInstanceUIDs(_ref4) {
|
|
1384
|
+
let {
|
|
1385
|
+
params,
|
|
1386
|
+
query
|
|
1387
|
+
} = _ref4;
|
|
1388
|
+
const {
|
|
1389
|
+
StudyInstanceUIDs: paramsStudyInstanceUIDs
|
|
1390
|
+
} = params;
|
|
1391
|
+
const queryStudyInstanceUIDs = src.utils.splitComma(query.getAll('StudyInstanceUIDs'));
|
|
1392
|
+
const StudyInstanceUIDs = queryStudyInstanceUIDs.length && queryStudyInstanceUIDs || paramsStudyInstanceUIDs;
|
|
1393
|
+
const StudyInstanceUIDsAsArray = StudyInstanceUIDs && Array.isArray(StudyInstanceUIDs) ? StudyInstanceUIDs : [StudyInstanceUIDs];
|
|
1394
|
+
return StudyInstanceUIDsAsArray;
|
|
1359
1395
|
}
|
|
1360
1396
|
};
|
|
1361
|
-
if (supportsReject) {
|
|
1362
|
-
implementation.reject = dcm4cheeReject(wadoRoot);
|
|
1397
|
+
if (dicomWebConfig.supportsReject) {
|
|
1398
|
+
implementation.reject = dcm4cheeReject(dicomWebConfig.wadoRoot);
|
|
1363
1399
|
}
|
|
1364
1400
|
return src/* IWebApiDataSource */.Is.create(implementation);
|
|
1365
1401
|
}
|
|
@@ -1375,7 +1411,8 @@ const mappings = {
|
|
|
1375
1411
|
patientId: 'PatientID'
|
|
1376
1412
|
};
|
|
1377
1413
|
let _store = {
|
|
1378
|
-
urls: []
|
|
1414
|
+
urls: [],
|
|
1415
|
+
studyInstanceUIDMap: new Map() // map of urls to array of study instance UIDs
|
|
1379
1416
|
// {
|
|
1380
1417
|
// url: url1
|
|
1381
1418
|
// studies: [Study1, Study2], // if multiple studies
|
|
@@ -1403,17 +1440,17 @@ const findStudies = (key, value) => {
|
|
|
1403
1440
|
};
|
|
1404
1441
|
function createDicomJSONApi(dicomJsonConfig) {
|
|
1405
1442
|
const {
|
|
1406
|
-
name,
|
|
1407
1443
|
wadoRoot
|
|
1408
1444
|
} = dicomJsonConfig;
|
|
1409
1445
|
const implementation = {
|
|
1410
1446
|
initialize: async _ref => {
|
|
1411
1447
|
let {
|
|
1412
|
-
params,
|
|
1413
1448
|
query,
|
|
1414
1449
|
url
|
|
1415
1450
|
} = _ref;
|
|
1416
|
-
if (!url)
|
|
1451
|
+
if (!url) {
|
|
1452
|
+
url = query.get('url');
|
|
1453
|
+
}
|
|
1417
1454
|
let metaData = getMetaDataByURL(url);
|
|
1418
1455
|
|
|
1419
1456
|
// if we have already cached the data from this specific url
|
|
@@ -1425,8 +1462,7 @@ function createDicomJSONApi(dicomJsonConfig) {
|
|
|
1425
1462
|
});
|
|
1426
1463
|
}
|
|
1427
1464
|
const response = await fetch(url);
|
|
1428
|
-
|
|
1429
|
-
const studyInstanceUIDs = data.studies.map(study => study.StudyInstanceUID);
|
|
1465
|
+
const data = await response.json();
|
|
1430
1466
|
let StudyInstanceUID;
|
|
1431
1467
|
let SeriesInstanceUID;
|
|
1432
1468
|
data.studies.forEach(study => {
|
|
@@ -1452,7 +1488,7 @@ function createDicomJSONApi(dicomJsonConfig) {
|
|
|
1452
1488
|
url,
|
|
1453
1489
|
studies: [...data.studies]
|
|
1454
1490
|
});
|
|
1455
|
-
|
|
1491
|
+
_store.studyInstanceUIDMap.set(url, data.studies.map(study => study.StudyInstanceUID));
|
|
1456
1492
|
},
|
|
1457
1493
|
query: {
|
|
1458
1494
|
studies: {
|
|
@@ -1479,18 +1515,18 @@ function createDicomJSONApi(dicomJsonConfig) {
|
|
|
1479
1515
|
});
|
|
1480
1516
|
},
|
|
1481
1517
|
processResults: () => {
|
|
1482
|
-
console.
|
|
1518
|
+
console.warn(' DICOMJson QUERY processResults not implemented');
|
|
1483
1519
|
}
|
|
1484
1520
|
},
|
|
1485
1521
|
series: {
|
|
1486
1522
|
// mapParams: mapParams.bind(),
|
|
1487
1523
|
search: () => {
|
|
1488
|
-
console.
|
|
1524
|
+
console.warn(' DICOMJson QUERY SERIES SEARCH not implemented');
|
|
1489
1525
|
}
|
|
1490
1526
|
},
|
|
1491
1527
|
instances: {
|
|
1492
1528
|
search: () => {
|
|
1493
|
-
console.
|
|
1529
|
+
console.warn(' DICOMJson QUERY instances SEARCH not implemented');
|
|
1494
1530
|
}
|
|
1495
1531
|
}
|
|
1496
1532
|
},
|
|
@@ -1512,7 +1548,7 @@ function createDicomJSONApi(dicomJsonConfig) {
|
|
|
1512
1548
|
return utils_getDirectURL(wadoRoot, params);
|
|
1513
1549
|
},
|
|
1514
1550
|
series: {
|
|
1515
|
-
metadata: function () {
|
|
1551
|
+
metadata: async function () {
|
|
1516
1552
|
let {
|
|
1517
1553
|
StudyInstanceUID,
|
|
1518
1554
|
madeInClient = false,
|
|
@@ -1561,14 +1597,16 @@ function createDicomJSONApi(dicomJsonConfig) {
|
|
|
1561
1597
|
return obj;
|
|
1562
1598
|
});
|
|
1563
1599
|
storeInstances(instances);
|
|
1564
|
-
if (index === numberOfSeries - 1)
|
|
1600
|
+
if (index === numberOfSeries - 1) {
|
|
1601
|
+
setSuccessFlag();
|
|
1602
|
+
}
|
|
1565
1603
|
});
|
|
1566
1604
|
}
|
|
1567
1605
|
}
|
|
1568
1606
|
},
|
|
1569
1607
|
store: {
|
|
1570
1608
|
dicom: () => {
|
|
1571
|
-
console.
|
|
1609
|
+
console.warn(' DICOMJson store dicom not implemented');
|
|
1572
1610
|
}
|
|
1573
1611
|
},
|
|
1574
1612
|
getImageIdsForDisplaySet(displaySet) {
|
|
@@ -1608,6 +1646,14 @@ function createDicomJSONApi(dicomJsonConfig) {
|
|
|
1608
1646
|
frame
|
|
1609
1647
|
});
|
|
1610
1648
|
return imageIds;
|
|
1649
|
+
},
|
|
1650
|
+
getStudyInstanceUIDs: _ref3 => {
|
|
1651
|
+
let {
|
|
1652
|
+
params,
|
|
1653
|
+
query
|
|
1654
|
+
} = _ref3;
|
|
1655
|
+
const url = query.get('url');
|
|
1656
|
+
return _store.studyInstanceUIDMap.get(url);
|
|
1611
1657
|
}
|
|
1612
1658
|
};
|
|
1613
1659
|
return src/* IWebApiDataSource */.Is.create(implementation);
|
|
@@ -1628,8 +1674,12 @@ const END_MODALITIES = {
|
|
|
1628
1674
|
};
|
|
1629
1675
|
const compareValue = function (v1, v2) {
|
|
1630
1676
|
let def = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
|
|
1631
|
-
if (v1 === v2)
|
|
1632
|
-
|
|
1677
|
+
if (v1 === v2) {
|
|
1678
|
+
return def;
|
|
1679
|
+
}
|
|
1680
|
+
if (v1 < v2) {
|
|
1681
|
+
return -1;
|
|
1682
|
+
}
|
|
1633
1683
|
return 1;
|
|
1634
1684
|
};
|
|
1635
1685
|
|
|
@@ -1660,19 +1710,6 @@ function createDicomLocalApi(dicomLocalConfig) {
|
|
|
1660
1710
|
params,
|
|
1661
1711
|
query
|
|
1662
1712
|
} = _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
1713
|
},
|
|
1677
1714
|
query: {
|
|
1678
1715
|
studies: {
|
|
@@ -1711,7 +1748,7 @@ function createDicomLocalApi(dicomLocalConfig) {
|
|
|
1711
1748
|
});
|
|
1712
1749
|
},
|
|
1713
1750
|
processResults: () => {
|
|
1714
|
-
console.
|
|
1751
|
+
console.warn(' DICOMLocal QUERY processResults not implemented');
|
|
1715
1752
|
}
|
|
1716
1753
|
},
|
|
1717
1754
|
series: {
|
|
@@ -1733,7 +1770,7 @@ function createDicomLocalApi(dicomLocalConfig) {
|
|
|
1733
1770
|
},
|
|
1734
1771
|
instances: {
|
|
1735
1772
|
search: () => {
|
|
1736
|
-
console.
|
|
1773
|
+
console.warn(' DICOMLocal QUERY instances SEARCH not implemented');
|
|
1737
1774
|
}
|
|
1738
1775
|
}
|
|
1739
1776
|
},
|
|
@@ -1854,6 +1891,29 @@ function createDicomLocalApi(dicomLocalConfig) {
|
|
|
1854
1891
|
},
|
|
1855
1892
|
deleteStudyMetadataPromise() {
|
|
1856
1893
|
console.log('deleteStudyMetadataPromise not implemented');
|
|
1894
|
+
},
|
|
1895
|
+
getStudyInstanceUIDs: _ref3 => {
|
|
1896
|
+
let {
|
|
1897
|
+
params,
|
|
1898
|
+
query
|
|
1899
|
+
} = _ref3;
|
|
1900
|
+
const {
|
|
1901
|
+
StudyInstanceUIDs: paramsStudyInstanceUIDs
|
|
1902
|
+
} = params;
|
|
1903
|
+
const queryStudyInstanceUIDs = query.getAll('StudyInstanceUIDs');
|
|
1904
|
+
const StudyInstanceUIDs = queryStudyInstanceUIDs || paramsStudyInstanceUIDs;
|
|
1905
|
+
const StudyInstanceUIDsAsArray = StudyInstanceUIDs && Array.isArray(StudyInstanceUIDs) ? StudyInstanceUIDs : [StudyInstanceUIDs];
|
|
1906
|
+
|
|
1907
|
+
// Put SRs at the end of series list to make sure images are loaded first
|
|
1908
|
+
let isStudyInCache = false;
|
|
1909
|
+
StudyInstanceUIDsAsArray.forEach(StudyInstanceUID => {
|
|
1910
|
+
const study = src.DicomMetadataStore.getStudy(StudyInstanceUID);
|
|
1911
|
+
if (study) {
|
|
1912
|
+
study.series = study.series.sort(customSort);
|
|
1913
|
+
isStudyInCache = true;
|
|
1914
|
+
}
|
|
1915
|
+
});
|
|
1916
|
+
return isStudyInCache ? StudyInstanceUIDsAsArray : [];
|
|
1857
1917
|
}
|
|
1858
1918
|
};
|
|
1859
1919
|
return src/* IWebApiDataSource */.Is.create(implementation);
|
|
@@ -1882,13 +1942,6 @@ function createDicomWebProxyApi(dicomWebProxyConfig, UserAuthenticationService)
|
|
|
1882
1942
|
params,
|
|
1883
1943
|
query
|
|
1884
1944
|
} = _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
1945
|
const url = query.get('url');
|
|
1893
1946
|
if (!url) {
|
|
1894
1947
|
throw new Error(`No url for '${name}'`);
|
|
@@ -1898,10 +1951,12 @@ function createDicomWebProxyApi(dicomWebProxyConfig, UserAuthenticationService)
|
|
|
1898
1951
|
if (!data.servers?.dicomWeb?.[0]) {
|
|
1899
1952
|
throw new Error('Invalid configuration returned by url');
|
|
1900
1953
|
}
|
|
1901
|
-
dicomWebDelegate = createDicomWebApi(data.servers.dicomWeb[0], UserAuthenticationService);
|
|
1902
|
-
|
|
1954
|
+
dicomWebDelegate = createDicomWebApi(data.servers.dicomWeb[0].configuration, UserAuthenticationService);
|
|
1955
|
+
dicomWebDelegate.initialize({
|
|
1956
|
+
params,
|
|
1957
|
+
query
|
|
1958
|
+
});
|
|
1903
1959
|
}
|
|
1904
|
-
return studyInstanceUIDs;
|
|
1905
1960
|
},
|
|
1906
1961
|
query: {
|
|
1907
1962
|
studies: {
|
|
@@ -1921,7 +1976,7 @@ function createDicomWebProxyApi(dicomWebProxyConfig, UserAuthenticationService)
|
|
|
1921
1976
|
return dicomWebDelegate.retrieve.directURL(...arguments);
|
|
1922
1977
|
},
|
|
1923
1978
|
series: {
|
|
1924
|
-
metadata: function () {
|
|
1979
|
+
metadata: async function () {
|
|
1925
1980
|
return dicomWebDelegate.retrieve.series.metadata(...arguments);
|
|
1926
1981
|
}
|
|
1927
1982
|
}
|
|
@@ -1939,6 +1994,21 @@ function createDicomWebProxyApi(dicomWebProxyConfig, UserAuthenticationService)
|
|
|
1939
1994
|
},
|
|
1940
1995
|
getImageIdsForInstance: function () {
|
|
1941
1996
|
return dicomWebDelegate.getImageIdsForInstance(...arguments);
|
|
1997
|
+
},
|
|
1998
|
+
getStudyInstanceUIDs(_ref2) {
|
|
1999
|
+
let {
|
|
2000
|
+
params,
|
|
2001
|
+
query
|
|
2002
|
+
} = _ref2;
|
|
2003
|
+
let studyInstanceUIDs = [];
|
|
2004
|
+
|
|
2005
|
+
// there seem to be a couple of variations of the case for this parameter
|
|
2006
|
+
const queryStudyInstanceUIDs = query.get('studyInstanceUIDs') || query.get('studyInstanceUids');
|
|
2007
|
+
if (!queryStudyInstanceUIDs) {
|
|
2008
|
+
throw new Error(`No studyInstanceUids in request for '${name}'`);
|
|
2009
|
+
}
|
|
2010
|
+
studyInstanceUIDs = queryStudyInstanceUIDs.split(';');
|
|
2011
|
+
return studyInstanceUIDs;
|
|
1942
2012
|
}
|
|
1943
2013
|
};
|
|
1944
2014
|
return src/* IWebApiDataSource */.Is.create(implementation);
|
|
@@ -1978,24 +2048,24 @@ function getDataSourcesModule() {
|
|
|
1978
2048
|
}
|
|
1979
2049
|
/* harmony default export */ const src_getDataSourcesModule = (getDataSourcesModule);
|
|
1980
2050
|
// EXTERNAL MODULE: ../../../node_modules/react/index.js
|
|
1981
|
-
var react = __webpack_require__(
|
|
2051
|
+
var react = __webpack_require__(43001);
|
|
1982
2052
|
// EXTERNAL MODULE: ../../../node_modules/prop-types/index.js
|
|
1983
|
-
var prop_types = __webpack_require__(
|
|
2053
|
+
var prop_types = __webpack_require__(3827);
|
|
1984
2054
|
var prop_types_default = /*#__PURE__*/__webpack_require__.n(prop_types);
|
|
2055
|
+
// EXTERNAL MODULE: ../../ui/src/index.js + 485 modules
|
|
2056
|
+
var ui_src = __webpack_require__(71783);
|
|
2057
|
+
// EXTERNAL MODULE: ./state/index.js + 1 modules
|
|
2058
|
+
var state = __webpack_require__(62657);
|
|
1985
2059
|
// EXTERNAL MODULE: ../node_modules/react-router-dom/dist/index.js
|
|
1986
|
-
var dist = __webpack_require__(
|
|
2060
|
+
var dist = __webpack_require__(62474);
|
|
1987
2061
|
// EXTERNAL MODULE: ../../../node_modules/react-i18next/dist/es/index.js + 15 modules
|
|
1988
|
-
var es = __webpack_require__(
|
|
2062
|
+
var es = __webpack_require__(69190);
|
|
1989
2063
|
// EXTERNAL MODULE: ../node_modules/react-router/dist/index.js
|
|
1990
|
-
var react_router_dist = __webpack_require__(
|
|
1991
|
-
// EXTERNAL MODULE: ../../
|
|
1992
|
-
var
|
|
1993
|
-
// EXTERNAL MODULE: ../../i18n/src/index.js + 95 modules
|
|
1994
|
-
var i18n_src = __webpack_require__(93058);
|
|
1995
|
-
// EXTERNAL MODULE: ./state/index.js + 1 modules
|
|
1996
|
-
var state = __webpack_require__(22896);
|
|
2064
|
+
var react_router_dist = __webpack_require__(85066);
|
|
2065
|
+
// EXTERNAL MODULE: ../../i18n/src/index.js + 134 modules
|
|
2066
|
+
var i18n_src = __webpack_require__(50376);
|
|
1997
2067
|
// EXTERNAL MODULE: ../../../node_modules/classnames/index.js
|
|
1998
|
-
var classnames = __webpack_require__(
|
|
2068
|
+
var classnames = __webpack_require__(44921);
|
|
1999
2069
|
var classnames_default = /*#__PURE__*/__webpack_require__.n(classnames);
|
|
2000
2070
|
;// CONCATENATED MODULE: ../../../extensions/default/src/Toolbar/Toolbar.tsx
|
|
2001
2071
|
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); }
|
|
@@ -2009,48 +2079,21 @@ function Toolbar(_ref) {
|
|
|
2009
2079
|
toolbarService
|
|
2010
2080
|
} = servicesManager.services;
|
|
2011
2081
|
const [toolbarButtons, setToolbarButtons] = (0,react.useState)([]);
|
|
2012
|
-
const [buttonState, setButtonState] = (0,react.useState)({
|
|
2013
|
-
primaryToolId: '',
|
|
2014
|
-
toggles: {},
|
|
2015
|
-
groups: {}
|
|
2016
|
-
});
|
|
2017
|
-
|
|
2018
|
-
// Could track buttons and state separately...?
|
|
2019
2082
|
(0,react.useEffect)(() => {
|
|
2020
2083
|
const {
|
|
2021
|
-
unsubscribe
|
|
2084
|
+
unsubscribe
|
|
2022
2085
|
} = toolbarService.subscribe(toolbarService.EVENTS.TOOL_BAR_MODIFIED, () => setToolbarButtons(toolbarService.getButtonSection('primary')));
|
|
2023
|
-
const {
|
|
2024
|
-
unsubscribe: unsub2
|
|
2025
|
-
} = toolbarService.subscribe(toolbarService.EVENTS.TOOL_BAR_STATE_MODIFIED, () => setButtonState({
|
|
2026
|
-
...toolbarService.state
|
|
2027
|
-
}));
|
|
2028
2086
|
return () => {
|
|
2029
|
-
|
|
2030
|
-
unsub2();
|
|
2087
|
+
unsubscribe();
|
|
2031
2088
|
};
|
|
2032
2089
|
}, [toolbarService]);
|
|
2033
|
-
|
|
2090
|
+
const onInteraction = (0,react.useCallback)(args => toolbarService.recordInteraction(args), [toolbarService]);
|
|
2091
|
+
return /*#__PURE__*/react.createElement(react.Fragment, null, toolbarButtons.map(toolDef => {
|
|
2034
2092
|
const {
|
|
2035
2093
|
id,
|
|
2036
2094
|
Component,
|
|
2037
2095
|
componentProps
|
|
2038
2096
|
} = toolDef;
|
|
2039
|
-
// TODO: ...
|
|
2040
|
-
|
|
2041
|
-
// isActive if:
|
|
2042
|
-
// - id is primary?
|
|
2043
|
-
// - id is in list of "toggled on"?
|
|
2044
|
-
let isActive;
|
|
2045
|
-
if (componentProps.type === 'toggle') {
|
|
2046
|
-
isActive = buttonState.toggles[id];
|
|
2047
|
-
}
|
|
2048
|
-
// Also need... to filter list for splitButton, and set primary based on most recently clicked
|
|
2049
|
-
// Also need to kill the radioGroup button's magic logic
|
|
2050
|
-
// Everything should be reactive off these props, so commands can inform ToolbarService
|
|
2051
|
-
|
|
2052
|
-
// These can... Trigger toolbar events based on updates?
|
|
2053
|
-
// Then sync using useEffect, or simply modify the state here?
|
|
2054
2097
|
return (
|
|
2055
2098
|
/*#__PURE__*/
|
|
2056
2099
|
// The margin for separating the tools on the toolbar should go here and NOT in each individual component (button) item.
|
|
@@ -2061,16 +2104,13 @@ function Toolbar(_ref) {
|
|
|
2061
2104
|
}, /*#__PURE__*/react.createElement(Component, _extends({
|
|
2062
2105
|
id: id
|
|
2063
2106
|
}, componentProps, {
|
|
2064
|
-
|
|
2065
|
-
isActive: isActive,
|
|
2066
|
-
onInteraction: args => toolbarService.recordInteraction(args),
|
|
2107
|
+
onInteraction: onInteraction,
|
|
2067
2108
|
servicesManager: servicesManager
|
|
2068
2109
|
})))
|
|
2069
2110
|
);
|
|
2070
2111
|
}));
|
|
2071
2112
|
}
|
|
2072
|
-
;// CONCATENATED MODULE: ../../../extensions/default/src/ViewerLayout/
|
|
2073
|
-
|
|
2113
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/ViewerLayout/ViewerHeader.tsx
|
|
2074
2114
|
|
|
2075
2115
|
|
|
2076
2116
|
|
|
@@ -2085,20 +2125,11 @@ const {
|
|
|
2085
2125
|
defaultLanguage,
|
|
2086
2126
|
currentLanguage
|
|
2087
2127
|
} = i18n_src["default"];
|
|
2088
|
-
function
|
|
2128
|
+
function ViewerHeader(_ref) {
|
|
2089
2129
|
let {
|
|
2090
|
-
// From Extension Module Params
|
|
2091
|
-
extensionManager,
|
|
2092
|
-
servicesManager,
|
|
2093
2130
|
hotkeysManager,
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
viewports,
|
|
2097
|
-
ViewportGridComp,
|
|
2098
|
-
leftPanels = [],
|
|
2099
|
-
rightPanels = [],
|
|
2100
|
-
leftPanelDefaultClosed = false,
|
|
2101
|
-
rightPanelDefaultClosed = false
|
|
2131
|
+
extensionManager,
|
|
2132
|
+
servicesManager
|
|
2102
2133
|
} = _ref;
|
|
2103
2134
|
const [appConfig] = (0,state/* useAppConfig */.M)();
|
|
2104
2135
|
const navigate = (0,dist/* useNavigate */.s0)();
|
|
@@ -2108,16 +2139,12 @@ function ViewerLayout(_ref) {
|
|
|
2108
2139
|
pathname
|
|
2109
2140
|
} = location;
|
|
2110
2141
|
const dataSourceIdx = pathname.indexOf('/', 1);
|
|
2111
|
-
// const search =
|
|
2112
|
-
// dataSourceIdx === -1
|
|
2113
|
-
// ? undefined
|
|
2114
|
-
// : `datasources=${pathname.substring(dataSourceIdx + 1)}`;
|
|
2115
|
-
|
|
2116
|
-
// Todo: Handle parameters in a better way.
|
|
2117
2142
|
const query = new URLSearchParams(window.location.search);
|
|
2118
2143
|
const configUrl = query.get('configUrl');
|
|
2144
|
+
const dataSourceName = pathname.substring(dataSourceIdx + 1);
|
|
2145
|
+
const existingDataSource = extensionManager.getDataSources(dataSourceName);
|
|
2119
2146
|
const searchQuery = new URLSearchParams();
|
|
2120
|
-
if (dataSourceIdx !== -1) {
|
|
2147
|
+
if (dataSourceIdx !== -1 && existingDataSource) {
|
|
2121
2148
|
searchQuery.append('datasources', pathname.substring(dataSourceIdx + 1));
|
|
2122
2149
|
}
|
|
2123
2150
|
if (configUrl) {
|
|
@@ -2135,16 +2162,12 @@ function ViewerLayout(_ref) {
|
|
|
2135
2162
|
show,
|
|
2136
2163
|
hide
|
|
2137
2164
|
} = (0,ui_src/* useModal */.dd)();
|
|
2138
|
-
const [showLoadingIndicator, setShowLoadingIndicator] = (0,react.useState)(appConfig.showLoadingIndicator);
|
|
2139
|
-
const {
|
|
2140
|
-
hangingProtocolService
|
|
2141
|
-
} = servicesManager.services;
|
|
2142
2165
|
const {
|
|
2143
2166
|
hotkeyDefinitions,
|
|
2144
2167
|
hotkeyDefaults
|
|
2145
2168
|
} = hotkeysManager;
|
|
2146
|
-
const versionNumber = "3.7.0-beta.
|
|
2147
|
-
const commitHash = "
|
|
2169
|
+
const versionNumber = "3.7.0-beta.110";
|
|
2170
|
+
const commitHash = "157b88c909d3289cb89ace731c1f9a19d40797ac";
|
|
2148
2171
|
const menuOptions = [{
|
|
2149
2172
|
title: t('Header:About'),
|
|
2150
2173
|
icon: 'info',
|
|
@@ -2178,7 +2201,9 @@ function ViewerLayout(_ref) {
|
|
|
2178
2201
|
hotkeyDefinitions,
|
|
2179
2202
|
language
|
|
2180
2203
|
} = _ref2;
|
|
2181
|
-
|
|
2204
|
+
if (language.value !== currentLanguage().value) {
|
|
2205
|
+
i18n_src["default"].changeLanguage(language.value);
|
|
2206
|
+
}
|
|
2182
2207
|
hotkeysManager.setHotkeys(hotkeyDefinitions);
|
|
2183
2208
|
hide();
|
|
2184
2209
|
},
|
|
@@ -2196,6 +2221,91 @@ function ViewerLayout(_ref) {
|
|
|
2196
2221
|
}
|
|
2197
2222
|
});
|
|
2198
2223
|
}
|
|
2224
|
+
return /*#__PURE__*/react.createElement(ui_src/* Header */.h4, {
|
|
2225
|
+
menuOptions: menuOptions,
|
|
2226
|
+
isReturnEnabled: !!appConfig.showStudyList,
|
|
2227
|
+
onClickReturnButton: onClickReturnButton,
|
|
2228
|
+
WhiteLabeling: appConfig.whiteLabeling
|
|
2229
|
+
}, /*#__PURE__*/react.createElement(ui_src/* ErrorBoundary */.SV, {
|
|
2230
|
+
context: "Primary Toolbar"
|
|
2231
|
+
}, /*#__PURE__*/react.createElement("div", {
|
|
2232
|
+
className: "relative flex justify-center"
|
|
2233
|
+
}, /*#__PURE__*/react.createElement(Toolbar, {
|
|
2234
|
+
servicesManager: servicesManager
|
|
2235
|
+
}))));
|
|
2236
|
+
}
|
|
2237
|
+
/* harmony default export */ const ViewerLayout_ViewerHeader = (ViewerHeader);
|
|
2238
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/Components/SidePanelWithServices.tsx
|
|
2239
|
+
|
|
2240
|
+
|
|
2241
|
+
const SidePanelWithServices = _ref => {
|
|
2242
|
+
let {
|
|
2243
|
+
servicesManager,
|
|
2244
|
+
side,
|
|
2245
|
+
className,
|
|
2246
|
+
activeTabIndex: activeTabIndexProp,
|
|
2247
|
+
tabs
|
|
2248
|
+
} = _ref;
|
|
2249
|
+
const panelService = servicesManager?.services?.panelService;
|
|
2250
|
+
|
|
2251
|
+
// Tracks whether this SidePanel has been opened at least once since this SidePanel was inserted into the DOM.
|
|
2252
|
+
// Thus going to the Study List page and back to the viewer resets this flag for a SidePanel.
|
|
2253
|
+
const [hasBeenOpened, setHasBeenOpened] = (0,react.useState)(false);
|
|
2254
|
+
const [activeTabIndex, setActiveTabIndex] = (0,react.useState)(activeTabIndexProp);
|
|
2255
|
+
(0,react.useEffect)(() => {
|
|
2256
|
+
if (panelService) {
|
|
2257
|
+
const activatePanelSubscription = panelService.subscribe(panelService.EVENTS.ACTIVATE_PANEL, activatePanelEvent => {
|
|
2258
|
+
if (!hasBeenOpened || activatePanelEvent.forceActive) {
|
|
2259
|
+
const tabIndex = tabs.findIndex(tab => tab.id === activatePanelEvent.panelId);
|
|
2260
|
+
if (tabIndex !== -1) {
|
|
2261
|
+
setActiveTabIndex(tabIndex);
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
});
|
|
2265
|
+
return () => {
|
|
2266
|
+
activatePanelSubscription.unsubscribe();
|
|
2267
|
+
};
|
|
2268
|
+
}
|
|
2269
|
+
}, [tabs, hasBeenOpened, panelService]);
|
|
2270
|
+
return /*#__PURE__*/react.createElement(ui_src/* SidePanel */.hs, {
|
|
2271
|
+
side: side,
|
|
2272
|
+
className: className,
|
|
2273
|
+
activeTabIndex: activeTabIndex,
|
|
2274
|
+
tabs: tabs,
|
|
2275
|
+
onOpen: () => {
|
|
2276
|
+
setHasBeenOpened(true);
|
|
2277
|
+
}
|
|
2278
|
+
});
|
|
2279
|
+
};
|
|
2280
|
+
/* harmony default export */ const Components_SidePanelWithServices = (SidePanelWithServices);
|
|
2281
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/ViewerLayout/index.tsx
|
|
2282
|
+
|
|
2283
|
+
|
|
2284
|
+
|
|
2285
|
+
|
|
2286
|
+
|
|
2287
|
+
|
|
2288
|
+
|
|
2289
|
+
function ViewerLayout(_ref) {
|
|
2290
|
+
let {
|
|
2291
|
+
// From Extension Module Params
|
|
2292
|
+
extensionManager,
|
|
2293
|
+
servicesManager,
|
|
2294
|
+
hotkeysManager,
|
|
2295
|
+
commandsManager,
|
|
2296
|
+
// From Modes
|
|
2297
|
+
viewports,
|
|
2298
|
+
ViewportGridComp,
|
|
2299
|
+
leftPanels = [],
|
|
2300
|
+
rightPanels = [],
|
|
2301
|
+
leftPanelDefaultClosed = false,
|
|
2302
|
+
rightPanelDefaultClosed = false
|
|
2303
|
+
} = _ref;
|
|
2304
|
+
const [appConfig] = (0,state/* useAppConfig */.M)();
|
|
2305
|
+
const {
|
|
2306
|
+
hangingProtocolService
|
|
2307
|
+
} = servicesManager.services;
|
|
2308
|
+
const [showLoadingIndicator, setShowLoadingIndicator] = (0,react.useState)(appConfig.showLoadingIndicator);
|
|
2199
2309
|
|
|
2200
2310
|
/**
|
|
2201
2311
|
* Set body classes (tailwindcss) that don't allow vertical
|
|
@@ -2213,7 +2323,7 @@ function ViewerLayout(_ref) {
|
|
|
2213
2323
|
const getComponent = id => {
|
|
2214
2324
|
const entry = extensionManager.getModuleEntry(id);
|
|
2215
2325
|
if (!entry) {
|
|
2216
|
-
throw new Error(`${id} is not
|
|
2326
|
+
throw new Error(`${id} is not valid for an extension module. Please verify your configuration or ensure that the extension is properly registered. It's also possible that your mode is utilizing a module from an extension that hasn't been included in its dependencies (add the extension to the "extensionDependencies" array in your mode's index.js file)`);
|
|
2217
2327
|
}
|
|
2218
2328
|
let content;
|
|
2219
2329
|
if (entry && entry.component) {
|
|
@@ -2266,19 +2376,12 @@ function ViewerLayout(_ref) {
|
|
|
2266
2376
|
const leftPanelComponents = leftPanels.map(getPanelData);
|
|
2267
2377
|
const rightPanelComponents = rightPanels.map(getPanelData);
|
|
2268
2378
|
const viewportComponents = viewports.map(getViewportComponentData);
|
|
2269
|
-
return /*#__PURE__*/react.createElement("div", null, /*#__PURE__*/react.createElement(
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
onClickReturnButton: onClickReturnButton,
|
|
2273
|
-
WhiteLabeling: appConfig.whiteLabeling
|
|
2274
|
-
}, /*#__PURE__*/react.createElement(ui_src/* ErrorBoundary */.SV, {
|
|
2275
|
-
context: "Primary Toolbar"
|
|
2276
|
-
}, /*#__PURE__*/react.createElement("div", {
|
|
2277
|
-
className: "relative flex justify-center"
|
|
2278
|
-
}, /*#__PURE__*/react.createElement(Toolbar, {
|
|
2379
|
+
return /*#__PURE__*/react.createElement("div", null, /*#__PURE__*/react.createElement(ViewerLayout_ViewerHeader, {
|
|
2380
|
+
hotkeysManager: hotkeysManager,
|
|
2381
|
+
extensionManager: extensionManager,
|
|
2279
2382
|
servicesManager: servicesManager
|
|
2280
|
-
})
|
|
2281
|
-
className: "
|
|
2383
|
+
}), /*#__PURE__*/react.createElement("div", {
|
|
2384
|
+
className: "relative flex w-full flex-row flex-nowrap items-stretch overflow-hidden bg-black",
|
|
2282
2385
|
style: {
|
|
2283
2386
|
height: 'calc(100vh - 52px'
|
|
2284
2387
|
}
|
|
@@ -2286,15 +2389,15 @@ function ViewerLayout(_ref) {
|
|
|
2286
2389
|
className: "h-full w-full bg-black"
|
|
2287
2390
|
}), leftPanelComponents.length ? /*#__PURE__*/react.createElement(ui_src/* ErrorBoundary */.SV, {
|
|
2288
2391
|
context: "Left Panel"
|
|
2289
|
-
}, /*#__PURE__*/react.createElement(
|
|
2392
|
+
}, /*#__PURE__*/react.createElement(Components_SidePanelWithServices, {
|
|
2290
2393
|
side: "left",
|
|
2291
2394
|
activeTabIndex: leftPanelDefaultClosed ? null : 0,
|
|
2292
2395
|
tabs: leftPanelComponents,
|
|
2293
2396
|
servicesManager: servicesManager
|
|
2294
2397
|
})) : null, /*#__PURE__*/react.createElement("div", {
|
|
2295
|
-
className: "flex
|
|
2398
|
+
className: "flex h-full flex-1 flex-col"
|
|
2296
2399
|
}, /*#__PURE__*/react.createElement("div", {
|
|
2297
|
-
className: "flex items-center justify-center
|
|
2400
|
+
className: "relative flex h-full flex-1 items-center justify-center overflow-hidden bg-black"
|
|
2298
2401
|
}, /*#__PURE__*/react.createElement(ui_src/* ErrorBoundary */.SV, {
|
|
2299
2402
|
context: "Grid"
|
|
2300
2403
|
}, /*#__PURE__*/react.createElement(ViewportGridComp, {
|
|
@@ -2303,7 +2406,7 @@ function ViewerLayout(_ref) {
|
|
|
2303
2406
|
commandsManager: commandsManager
|
|
2304
2407
|
})))), rightPanelComponents.length ? /*#__PURE__*/react.createElement(ui_src/* ErrorBoundary */.SV, {
|
|
2305
2408
|
context: "Right Panel"
|
|
2306
|
-
}, /*#__PURE__*/react.createElement(
|
|
2409
|
+
}, /*#__PURE__*/react.createElement(Components_SidePanelWithServices, {
|
|
2307
2410
|
side: "right",
|
|
2308
2411
|
activeTabIndex: rightPanelDefaultClosed ? null : 0,
|
|
2309
2412
|
tabs: rightPanelComponents,
|
|
@@ -2323,7 +2426,8 @@ ViewerLayout.propTypes = {
|
|
|
2323
2426
|
leftPanelDefaultClosed: (prop_types_default()).bool.isRequired,
|
|
2324
2427
|
rightPanelDefaultClosed: (prop_types_default()).bool.isRequired,
|
|
2325
2428
|
/** Responsible for rendering our grid of viewports; provided by consuming application */
|
|
2326
|
-
children: prop_types_default().oneOfType([(prop_types_default()).node, (prop_types_default()).func]).isRequired
|
|
2429
|
+
children: prop_types_default().oneOfType([(prop_types_default()).node, (prop_types_default()).func]).isRequired,
|
|
2430
|
+
viewports: (prop_types_default()).array
|
|
2327
2431
|
};
|
|
2328
2432
|
/* harmony default export */ const src_ViewerLayout = (ViewerLayout);
|
|
2329
2433
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getLayoutTemplateModule.js
|
|
@@ -2364,6 +2468,7 @@ ViewerLayout.propTypes = {
|
|
|
2364
2468
|
|
|
2365
2469
|
|
|
2366
2470
|
|
|
2471
|
+
|
|
2367
2472
|
const {
|
|
2368
2473
|
sortStudyInstances,
|
|
2369
2474
|
formatDate
|
|
@@ -2386,6 +2491,8 @@ function PanelStudyBrowser(_ref) {
|
|
|
2386
2491
|
displaySetService,
|
|
2387
2492
|
uiNotificationService
|
|
2388
2493
|
} = servicesManager.services;
|
|
2494
|
+
const navigate = (0,dist/* useNavigate */.s0)();
|
|
2495
|
+
|
|
2389
2496
|
// Normally you nest the components so the tree isn't so deep, and the data
|
|
2390
2497
|
// doesn't have to have such an intense shape. This works well enough for now.
|
|
2391
2498
|
// Tabs --> Studies --> DisplaySets --> Thumbnails
|
|
@@ -2393,7 +2500,7 @@ function PanelStudyBrowser(_ref) {
|
|
|
2393
2500
|
StudyInstanceUIDs
|
|
2394
2501
|
} = (0,ui_src/* useImageViewer */.zG)();
|
|
2395
2502
|
const [{
|
|
2396
|
-
|
|
2503
|
+
activeViewportId,
|
|
2397
2504
|
viewports
|
|
2398
2505
|
}, viewportGridService] = (0,ui_src/* useViewportGrid */.O_)();
|
|
2399
2506
|
const [activeTabName, setActiveTabName] = (0,react.useState)('primary');
|
|
@@ -2401,12 +2508,11 @@ function PanelStudyBrowser(_ref) {
|
|
|
2401
2508
|
const [studyDisplayList, setStudyDisplayList] = (0,react.useState)([]);
|
|
2402
2509
|
const [displaySets, setDisplaySets] = (0,react.useState)([]);
|
|
2403
2510
|
const [thumbnailImageSrcMap, setThumbnailImageSrcMap] = (0,react.useState)({});
|
|
2404
|
-
const isMounted = (0,react.useRef)(true);
|
|
2405
2511
|
const onDoubleClickThumbnailHandler = displaySetInstanceUID => {
|
|
2406
2512
|
let updatedViewports = [];
|
|
2407
|
-
const
|
|
2513
|
+
const viewportId = activeViewportId;
|
|
2408
2514
|
try {
|
|
2409
|
-
updatedViewports = hangingProtocolService.getViewportsRequireUpdate(
|
|
2515
|
+
updatedViewports = hangingProtocolService.getViewportsRequireUpdate(viewportId, displaySetInstanceUID);
|
|
2410
2516
|
} catch (error) {
|
|
2411
2517
|
console.warn(error);
|
|
2412
2518
|
uiNotificationService.show({
|
|
@@ -2427,6 +2533,10 @@ function PanelStudyBrowser(_ref) {
|
|
|
2427
2533
|
const qidoForStudyUID = await dataSource.query.studies.search({
|
|
2428
2534
|
studyInstanceUid: StudyInstanceUID
|
|
2429
2535
|
});
|
|
2536
|
+
if (!qidoForStudyUID?.length) {
|
|
2537
|
+
navigate('/notfoundstudy', '_self');
|
|
2538
|
+
throw new Error('Invalid study URL');
|
|
2539
|
+
}
|
|
2430
2540
|
let qidoStudiesForPatient = qidoForStudyUID;
|
|
2431
2541
|
|
|
2432
2542
|
// try to fetch the prior studies based on the patientID if the
|
|
@@ -2457,8 +2567,7 @@ function PanelStudyBrowser(_ref) {
|
|
|
2457
2567
|
});
|
|
2458
2568
|
}
|
|
2459
2569
|
StudyInstanceUIDs.forEach(sid => fetchStudiesForPatient(sid));
|
|
2460
|
-
|
|
2461
|
-
}, [StudyInstanceUIDs, getStudiesForPatientByMRN]);
|
|
2570
|
+
}, [StudyInstanceUIDs, dataSource, getStudiesForPatientByMRN, navigate]);
|
|
2462
2571
|
|
|
2463
2572
|
// // ~~ Initial Thumbnails
|
|
2464
2573
|
(0,react.useEffect)(() => {
|
|
@@ -2470,24 +2579,19 @@ function PanelStudyBrowser(_ref) {
|
|
|
2470
2579
|
const imageId = imageIds[Math.floor(imageIds.length / 2)];
|
|
2471
2580
|
|
|
2472
2581
|
// TODO: Is it okay that imageIds are not returned here for SR displaySets?
|
|
2473
|
-
if (imageId) {
|
|
2474
|
-
|
|
2475
|
-
newImageSrcEntry[dSet.displaySetInstanceUID] = await getImageSrc(imageId);
|
|
2476
|
-
if (isMounted.current) {
|
|
2477
|
-
setThumbnailImageSrcMap(prevState => {
|
|
2478
|
-
return {
|
|
2479
|
-
...prevState,
|
|
2480
|
-
...newImageSrcEntry
|
|
2481
|
-
};
|
|
2482
|
-
});
|
|
2483
|
-
}
|
|
2582
|
+
if (!imageId || displaySet?.unsupported) {
|
|
2583
|
+
return;
|
|
2484
2584
|
}
|
|
2585
|
+
// When the image arrives, render it and store the result in the thumbnailImgSrcMap
|
|
2586
|
+
newImageSrcEntry[dSet.displaySetInstanceUID] = await getImageSrc(imageId);
|
|
2587
|
+
setThumbnailImageSrcMap(prevState => {
|
|
2588
|
+
return {
|
|
2589
|
+
...prevState,
|
|
2590
|
+
...newImageSrcEntry
|
|
2591
|
+
};
|
|
2592
|
+
});
|
|
2485
2593
|
});
|
|
2486
|
-
|
|
2487
|
-
isMounted.current = false;
|
|
2488
|
-
};
|
|
2489
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2490
|
-
}, []);
|
|
2594
|
+
}, [StudyInstanceUIDs, dataSource, displaySetService, getImageSrc]);
|
|
2491
2595
|
|
|
2492
2596
|
// ~~ displaySets
|
|
2493
2597
|
(0,react.useEffect)(() => {
|
|
@@ -2496,50 +2600,59 @@ function PanelStudyBrowser(_ref) {
|
|
|
2496
2600
|
const mappedDisplaySets = _mapDisplaySets(currentDisplaySets, thumbnailImageSrcMap);
|
|
2497
2601
|
sortStudyInstances(mappedDisplaySets);
|
|
2498
2602
|
setDisplaySets(mappedDisplaySets);
|
|
2499
|
-
|
|
2500
|
-
}, [thumbnailImageSrcMap]);
|
|
2603
|
+
}, [StudyInstanceUIDs, thumbnailImageSrcMap, displaySetService]);
|
|
2501
2604
|
|
|
2502
2605
|
// ~~ subscriptions --> displaySets
|
|
2503
2606
|
(0,react.useEffect)(() => {
|
|
2504
2607
|
// DISPLAY_SETS_ADDED returns an array of DisplaySets that were added
|
|
2505
2608
|
const SubscriptionDisplaySetsAdded = displaySetService.subscribe(displaySetService.EVENTS.DISPLAY_SETS_ADDED, data => {
|
|
2506
2609
|
const {
|
|
2507
|
-
displaySetsAdded
|
|
2610
|
+
displaySetsAdded,
|
|
2611
|
+
options
|
|
2508
2612
|
} = data;
|
|
2509
2613
|
displaySetsAdded.forEach(async dSet => {
|
|
2510
2614
|
const newImageSrcEntry = {};
|
|
2511
2615
|
const displaySet = displaySetService.getDisplaySetByUID(dSet.displaySetInstanceUID);
|
|
2616
|
+
if (displaySet?.unsupported) {
|
|
2617
|
+
return;
|
|
2618
|
+
}
|
|
2512
2619
|
const imageIds = dataSource.getImageIdsForDisplaySet(displaySet);
|
|
2513
2620
|
const imageId = imageIds[Math.floor(imageIds.length / 2)];
|
|
2514
2621
|
|
|
2515
2622
|
// TODO: Is it okay that imageIds are not returned here for SR displaysets?
|
|
2516
|
-
if (imageId) {
|
|
2517
|
-
|
|
2518
|
-
newImageSrcEntry[dSet.displaySetInstanceUID] = await getImageSrc(imageId, dSet.initialViewport);
|
|
2519
|
-
if (isMounted.current) {
|
|
2520
|
-
setThumbnailImageSrcMap(prevState => {
|
|
2521
|
-
return {
|
|
2522
|
-
...prevState,
|
|
2523
|
-
...newImageSrcEntry
|
|
2524
|
-
};
|
|
2525
|
-
});
|
|
2526
|
-
}
|
|
2623
|
+
if (!imageId) {
|
|
2624
|
+
return;
|
|
2527
2625
|
}
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2626
|
+
// When the image arrives, render it and store the result in the thumbnailImgSrcMap
|
|
2627
|
+
newImageSrcEntry[dSet.displaySetInstanceUID] = await getImageSrc(imageId, dSet.initialViewport);
|
|
2628
|
+
setThumbnailImageSrcMap(prevState => {
|
|
2629
|
+
return {
|
|
2630
|
+
...prevState,
|
|
2631
|
+
...newImageSrcEntry
|
|
2632
|
+
};
|
|
2633
|
+
});
|
|
2634
|
+
});
|
|
2635
|
+
});
|
|
2636
|
+
return () => {
|
|
2637
|
+
SubscriptionDisplaySetsAdded.unsubscribe();
|
|
2638
|
+
};
|
|
2639
|
+
}, [getImageSrc, dataSource, displaySetService]);
|
|
2640
|
+
(0,react.useEffect)(() => {
|
|
2531
2641
|
// TODO: Will this always hold _all_ the displaySets we care about?
|
|
2532
2642
|
// DISPLAY_SETS_CHANGED returns `DisplaySerService.activeDisplaySets`
|
|
2533
2643
|
const SubscriptionDisplaySetsChanged = displaySetService.subscribe(displaySetService.EVENTS.DISPLAY_SETS_CHANGED, changedDisplaySets => {
|
|
2534
2644
|
const mappedDisplaySets = _mapDisplaySets(changedDisplaySets, thumbnailImageSrcMap);
|
|
2535
2645
|
setDisplaySets(mappedDisplaySets);
|
|
2536
2646
|
});
|
|
2647
|
+
const SubscriptionDisplaySetMetaDataInvalidated = displaySetService.subscribe(displaySetService.EVENTS.DISPLAY_SET_SERIES_METADATA_INVALIDATED, () => {
|
|
2648
|
+
const mappedDisplaySets = _mapDisplaySets(displaySetService.getActiveDisplaySets(), thumbnailImageSrcMap);
|
|
2649
|
+
setDisplaySets(mappedDisplaySets);
|
|
2650
|
+
});
|
|
2537
2651
|
return () => {
|
|
2538
|
-
SubscriptionDisplaySetsAdded.unsubscribe();
|
|
2539
2652
|
SubscriptionDisplaySetsChanged.unsubscribe();
|
|
2653
|
+
SubscriptionDisplaySetMetaDataInvalidated.unsubscribe();
|
|
2540
2654
|
};
|
|
2541
|
-
|
|
2542
|
-
}, []);
|
|
2655
|
+
}, [StudyInstanceUIDs, thumbnailImageSrcMap, displaySetService]);
|
|
2543
2656
|
const tabs = _createStudyBrowserTabs(StudyInstanceUIDs, studyDisplayList, displaySets);
|
|
2544
2657
|
|
|
2545
2658
|
// TODO: Should not fire this on "close"
|
|
@@ -2554,7 +2667,7 @@ function PanelStudyBrowser(_ref) {
|
|
|
2554
2667
|
requestDisplaySetCreationForStudy(displaySetService, StudyInstanceUID, madeInClient);
|
|
2555
2668
|
}
|
|
2556
2669
|
}
|
|
2557
|
-
const activeDisplaySetInstanceUIDs = viewports
|
|
2670
|
+
const activeDisplaySetInstanceUIDs = viewports.get(activeViewportId)?.displaySetInstanceUIDs;
|
|
2558
2671
|
return /*#__PURE__*/react.createElement(ui_src/* StudyBrowser */.eX, {
|
|
2559
2672
|
tabs: tabs,
|
|
2560
2673
|
servicesManager: servicesManager,
|
|
@@ -2605,7 +2718,7 @@ function _mapDisplaySets(displaySets, thumbnailImageSrcMap) {
|
|
|
2605
2718
|
const thumbnailNoImageDisplaySets = [];
|
|
2606
2719
|
displaySets.filter(ds => !ds.excludeFromThumbnailBrowser).forEach(ds => {
|
|
2607
2720
|
const imageSrc = thumbnailImageSrcMap[ds.displaySetInstanceUID];
|
|
2608
|
-
const componentType = _getComponentType(ds
|
|
2721
|
+
const componentType = _getComponentType(ds);
|
|
2609
2722
|
const array = componentType === 'thumbnail' ? thumbnailDisplaySets : thumbnailNoImageDisplaySets;
|
|
2610
2723
|
array.push({
|
|
2611
2724
|
displaySetInstanceUID: ds.displaySetInstanceUID,
|
|
@@ -2617,21 +2730,23 @@ function _mapDisplaySets(displaySets, thumbnailImageSrcMap) {
|
|
|
2617
2730
|
numInstances: ds.numImageFrames,
|
|
2618
2731
|
countIcon: ds.countIcon,
|
|
2619
2732
|
StudyInstanceUID: ds.StudyInstanceUID,
|
|
2733
|
+
messages: ds.messages,
|
|
2620
2734
|
componentType,
|
|
2621
2735
|
imageSrc,
|
|
2622
2736
|
dragData: {
|
|
2623
2737
|
type: 'displayset',
|
|
2624
2738
|
displaySetInstanceUID: ds.displaySetInstanceUID
|
|
2625
2739
|
// .. Any other data to pass
|
|
2626
|
-
}
|
|
2740
|
+
},
|
|
2741
|
+
|
|
2742
|
+
isHydratedForDerivedDisplaySet: ds.isHydrated
|
|
2627
2743
|
});
|
|
2628
2744
|
});
|
|
2629
|
-
|
|
2630
2745
|
return [...thumbnailDisplaySets, ...thumbnailNoImageDisplaySets];
|
|
2631
2746
|
}
|
|
2632
2747
|
const thumbnailNoImageModalities = ['SR', 'SEG', 'SM', 'RTSTRUCT', 'RTPLAN', 'RTDOSE'];
|
|
2633
|
-
function _getComponentType(
|
|
2634
|
-
if (thumbnailNoImageModalities.includes(Modality)) {
|
|
2748
|
+
function _getComponentType(ds) {
|
|
2749
|
+
if (thumbnailNoImageModalities.includes(ds.Modality) || ds?.unsupported) {
|
|
2635
2750
|
// TODO probably others.
|
|
2636
2751
|
return 'thumbnailNoImage';
|
|
2637
2752
|
}
|
|
@@ -2798,7 +2913,7 @@ function ActionButtons(_ref) {
|
|
|
2798
2913
|
const {
|
|
2799
2914
|
t
|
|
2800
2915
|
} = (0,es/* useTranslation */.$G)('MeasurementTable');
|
|
2801
|
-
return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement(ui_src/*
|
|
2916
|
+
return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement(ui_src/* LegacyButtonGroup */.HO, {
|
|
2802
2917
|
color: "black",
|
|
2803
2918
|
size: "inherit"
|
|
2804
2919
|
}, /*#__PURE__*/react.createElement(ui_src/* LegacyButton */.mN, {
|
|
@@ -2819,17 +2934,16 @@ ActionButtons.defaultProps = {
|
|
|
2819
2934
|
};
|
|
2820
2935
|
/* harmony default export */ const Panels_ActionButtons = (ActionButtons);
|
|
2821
2936
|
// EXTERNAL MODULE: ../../../node_modules/lodash.debounce/index.js
|
|
2822
|
-
var lodash_debounce = __webpack_require__(
|
|
2937
|
+
var lodash_debounce = __webpack_require__(8324);
|
|
2823
2938
|
var lodash_debounce_default = /*#__PURE__*/__webpack_require__.n(lodash_debounce);
|
|
2824
2939
|
;// CONCATENATED MODULE: ../../../extensions/default/src/Panels/createReportDialogPrompt.tsx
|
|
2825
|
-
/* eslint-disable react/display-name */
|
|
2826
2940
|
|
|
2827
2941
|
|
|
2828
2942
|
const CREATE_REPORT_DIALOG_RESPONSE = {
|
|
2829
2943
|
CANCEL: 0,
|
|
2830
2944
|
CREATE_REPORT: 1
|
|
2831
2945
|
};
|
|
2832
|
-
function
|
|
2946
|
+
function CreateReportDialogPrompt(uiDialogService, _ref) {
|
|
2833
2947
|
let {
|
|
2834
2948
|
extensionManager
|
|
2835
2949
|
} = _ref;
|
|
@@ -2906,11 +3020,11 @@ function createReportDialogPrompt(uiDialogService, _ref) {
|
|
|
2906
3020
|
actions: [{
|
|
2907
3021
|
id: 'cancel',
|
|
2908
3022
|
text: 'Cancel',
|
|
2909
|
-
type: ui_src/* ButtonEnums.type */.LZ.
|
|
3023
|
+
type: ui_src/* ButtonEnums.type */.LZ.dt.secondary
|
|
2910
3024
|
}, {
|
|
2911
3025
|
id: 'save',
|
|
2912
3026
|
text: 'Save',
|
|
2913
|
-
type: ui_src/* ButtonEnums.type */.LZ.
|
|
3027
|
+
type: ui_src/* ButtonEnums.type */.LZ.dt.primary
|
|
2914
3028
|
}],
|
|
2915
3029
|
// TODO: Should be on button press...
|
|
2916
3030
|
onSubmit: _handleFormSubmit,
|
|
@@ -2937,9 +3051,11 @@ function createReportDialogPrompt(uiDialogService, _ref) {
|
|
|
2937
3051
|
});
|
|
2938
3052
|
}
|
|
2939
3053
|
};
|
|
2940
|
-
return /*#__PURE__*/react.createElement(react.Fragment, null, dataSourcesOpts.length > 1 && /*#__PURE__*/react.createElement(
|
|
3054
|
+
return /*#__PURE__*/react.createElement(react.Fragment, null, dataSourcesOpts.length > 1 && window.config?.allowMultiSelectExport && /*#__PURE__*/react.createElement("div", null, /*#__PURE__*/react.createElement("label", {
|
|
3055
|
+
className: "text-[14px] leading-[1.2] text-white"
|
|
3056
|
+
}, "Data Source"), /*#__PURE__*/react.createElement(ui_src/* Select */.Ph, {
|
|
2941
3057
|
closeMenuOnSelect: true,
|
|
2942
|
-
className: "
|
|
3058
|
+
className: "border-primary-main mt-2 bg-black",
|
|
2943
3059
|
options: dataSourcesOpts,
|
|
2944
3060
|
placeholder: dataSourcesOpts.find(option => option.value === value.dataSourceName).placeHolder,
|
|
2945
3061
|
value: value.dataSourceName,
|
|
@@ -2950,17 +3066,19 @@ function createReportDialogPrompt(uiDialogService, _ref) {
|
|
|
2950
3066
|
}));
|
|
2951
3067
|
},
|
|
2952
3068
|
isClearable: false
|
|
2953
|
-
}), /*#__PURE__*/react.createElement(
|
|
3069
|
+
})), /*#__PURE__*/react.createElement("div", {
|
|
3070
|
+
className: "mt-3"
|
|
3071
|
+
}, /*#__PURE__*/react.createElement(ui_src/* Input */.II, {
|
|
2954
3072
|
autoFocus: true,
|
|
2955
3073
|
label: "Enter the report name",
|
|
2956
3074
|
labelClassName: "text-white text-[14px] leading-[1.2]",
|
|
2957
|
-
className: "
|
|
3075
|
+
className: "border-primary-main bg-black",
|
|
2958
3076
|
type: "text",
|
|
2959
3077
|
value: value.label,
|
|
2960
3078
|
onChange: onChangeHandler,
|
|
2961
3079
|
onKeyPress: onKeyPressHandler,
|
|
2962
3080
|
required: true
|
|
2963
|
-
}));
|
|
3081
|
+
})));
|
|
2964
3082
|
}
|
|
2965
3083
|
}
|
|
2966
3084
|
});
|
|
@@ -2973,12 +3091,13 @@ function createReportDialogPrompt(uiDialogService, _ref) {
|
|
|
2973
3091
|
/**
|
|
2974
3092
|
*
|
|
2975
3093
|
* @param {*} servicesManager
|
|
2976
|
-
* @param {*} dataSource
|
|
2977
|
-
* @param {*} measurements
|
|
2978
|
-
* @param {*} options
|
|
2979
|
-
* @returns {string[]} displaySetInstanceUIDs
|
|
2980
3094
|
*/
|
|
2981
|
-
async function createReportAsync(
|
|
3095
|
+
async function createReportAsync(_ref) {
|
|
3096
|
+
let {
|
|
3097
|
+
servicesManager,
|
|
3098
|
+
getReport,
|
|
3099
|
+
reportType = 'measurement'
|
|
3100
|
+
} = _ref;
|
|
2982
3101
|
const {
|
|
2983
3102
|
displaySetService,
|
|
2984
3103
|
uiNotificationService,
|
|
@@ -2988,32 +3107,27 @@ async function createReportAsync(servicesManager, commandsManager, dataSource, m
|
|
|
2988
3107
|
showOverlay: true,
|
|
2989
3108
|
isDraggable: false,
|
|
2990
3109
|
centralize: true,
|
|
2991
|
-
// TODO: Create a loading indicator component + zeplin design?
|
|
2992
3110
|
content: Loading
|
|
2993
3111
|
});
|
|
2994
3112
|
try {
|
|
2995
|
-
const naturalizedReport = await
|
|
2996
|
-
measurementData: measurements,
|
|
2997
|
-
dataSource,
|
|
2998
|
-
additionalFindingTypes: ['ArrowAnnotate'],
|
|
2999
|
-
options
|
|
3000
|
-
}, 'CORNERSTONE_STRUCTURED_REPORT');
|
|
3113
|
+
const naturalizedReport = await getReport();
|
|
3001
3114
|
|
|
3002
3115
|
// The "Mode" route listens for DicomMetadataStore changes
|
|
3003
3116
|
// When a new instance is added, it listens and
|
|
3004
3117
|
// automatically calls makeDisplaySets
|
|
3005
3118
|
src.DicomMetadataStore.addInstances([naturalizedReport], true);
|
|
3006
|
-
const
|
|
3119
|
+
const displaySet = displaySetService.getMostRecentDisplaySet();
|
|
3120
|
+
const displaySetInstanceUID = displaySet.displaySetInstanceUID;
|
|
3007
3121
|
uiNotificationService.show({
|
|
3008
3122
|
title: 'Create Report',
|
|
3009
|
-
message:
|
|
3123
|
+
message: `${reportType} saved successfully`,
|
|
3010
3124
|
type: 'success'
|
|
3011
3125
|
});
|
|
3012
3126
|
return [displaySetInstanceUID];
|
|
3013
3127
|
} catch (error) {
|
|
3014
3128
|
uiNotificationService.show({
|
|
3015
3129
|
title: 'Create Report',
|
|
3016
|
-
message: error.message ||
|
|
3130
|
+
message: error.message || `Failed to store ${reportType}`,
|
|
3017
3131
|
type: 'error'
|
|
3018
3132
|
});
|
|
3019
3133
|
} finally {
|
|
@@ -3105,7 +3219,7 @@ function PanelMeasurementTable(_ref) {
|
|
|
3105
3219
|
} = _ref;
|
|
3106
3220
|
const [viewportGrid, viewportGridService] = (0,ui_src/* useViewportGrid */.O_)();
|
|
3107
3221
|
const {
|
|
3108
|
-
|
|
3222
|
+
activeViewportId,
|
|
3109
3223
|
viewports
|
|
3110
3224
|
} = viewportGrid;
|
|
3111
3225
|
const {
|
|
@@ -3148,7 +3262,7 @@ function PanelMeasurementTable(_ref) {
|
|
|
3148
3262
|
}
|
|
3149
3263
|
async function createReport() {
|
|
3150
3264
|
// filter measurements that are added to the active study
|
|
3151
|
-
const activeViewport = viewports
|
|
3265
|
+
const activeViewport = viewports.get(activeViewportId);
|
|
3152
3266
|
const measurements = measurementService.getMeasurements();
|
|
3153
3267
|
const displaySet = displaySetService.getDisplaySetByUID(activeViewport.displaySetInstanceUIDs[0]);
|
|
3154
3268
|
const trackedMeasurements = measurements.filter(m => displaySet.StudyInstanceUID === m.referenceStudyUID);
|
|
@@ -3161,7 +3275,7 @@ function PanelMeasurementTable(_ref) {
|
|
|
3161
3275
|
});
|
|
3162
3276
|
return;
|
|
3163
3277
|
}
|
|
3164
|
-
const promptResult = await
|
|
3278
|
+
const promptResult = await CreateReportDialogPrompt(uiDialogService, {
|
|
3165
3279
|
extensionManager
|
|
3166
3280
|
});
|
|
3167
3281
|
if (promptResult.action === CREATE_REPORT_DIALOG_RESPONSE.CREATE_REPORT) {
|
|
@@ -3172,10 +3286,21 @@ function PanelMeasurementTable(_ref) {
|
|
|
3172
3286
|
promptResult.value === undefined || promptResult.value === '' ? 'Research Derived Series' // default
|
|
3173
3287
|
: promptResult.value; // provided value
|
|
3174
3288
|
|
|
3175
|
-
//
|
|
3289
|
+
// Reuse an existing series having the same series description to avoid
|
|
3176
3290
|
// creating too many series instances.
|
|
3177
3291
|
const options = findSRWithSameSeriesDescription(SeriesDescription, displaySetService);
|
|
3178
|
-
|
|
3292
|
+
const getReport = async () => {
|
|
3293
|
+
return commandsManager.runCommand('storeMeasurements', {
|
|
3294
|
+
measurementData: trackedMeasurements,
|
|
3295
|
+
dataSource,
|
|
3296
|
+
additionalFindingTypes: ['ArrowAnnotate'],
|
|
3297
|
+
options
|
|
3298
|
+
}, 'CORNERSTONE_STRUCTURED_REPORT');
|
|
3299
|
+
};
|
|
3300
|
+
return Actions_createReportAsync({
|
|
3301
|
+
servicesManager,
|
|
3302
|
+
getReport
|
|
3303
|
+
});
|
|
3179
3304
|
}
|
|
3180
3305
|
}
|
|
3181
3306
|
const jumpToImage = _ref2 => {
|
|
@@ -3183,7 +3308,7 @@ function PanelMeasurementTable(_ref) {
|
|
|
3183
3308
|
uid,
|
|
3184
3309
|
isActive
|
|
3185
3310
|
} = _ref2;
|
|
3186
|
-
measurementService.jumpToMeasurement(viewportGrid.
|
|
3311
|
+
measurementService.jumpToMeasurement(viewportGrid.activeViewportId, uid);
|
|
3187
3312
|
onMeasurementItemClickHandler({
|
|
3188
3313
|
uid,
|
|
3189
3314
|
isActive
|
|
@@ -3255,7 +3380,7 @@ function PanelMeasurementTable(_ref) {
|
|
|
3255
3380
|
labelClassName: "text-white text-[14px] leading-[1.2]",
|
|
3256
3381
|
autoFocus: true,
|
|
3257
3382
|
id: "annotation",
|
|
3258
|
-
className: "
|
|
3383
|
+
className: "border-primary-main bg-black",
|
|
3259
3384
|
type: "text",
|
|
3260
3385
|
value: value.label,
|
|
3261
3386
|
onChange: onChangeHandler,
|
|
@@ -3265,11 +3390,11 @@ function PanelMeasurementTable(_ref) {
|
|
|
3265
3390
|
actions: [{
|
|
3266
3391
|
id: 'cancel',
|
|
3267
3392
|
text: 'Cancel',
|
|
3268
|
-
type: ui_src/* ButtonEnums.type */.LZ.
|
|
3393
|
+
type: ui_src/* ButtonEnums.type */.LZ.dt.secondary
|
|
3269
3394
|
}, {
|
|
3270
3395
|
id: 'save',
|
|
3271
3396
|
text: 'Save',
|
|
3272
|
-
type: ui_src/* ButtonEnums.type */.LZ.
|
|
3397
|
+
type: ui_src/* ButtonEnums.type */.LZ.dt.primary
|
|
3273
3398
|
}],
|
|
3274
3399
|
onSubmit: onSubmitHandler
|
|
3275
3400
|
}
|
|
@@ -3289,7 +3414,7 @@ function PanelMeasurementTable(_ref) {
|
|
|
3289
3414
|
}
|
|
3290
3415
|
};
|
|
3291
3416
|
return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
|
|
3292
|
-
className: "
|
|
3417
|
+
className: "ohif-scrollbar overflow-y-auto overflow-x-hidden",
|
|
3293
3418
|
"data-cy": 'measurements-panel'
|
|
3294
3419
|
}, /*#__PURE__*/react.createElement(ui_src/* MeasurementTable */.wt, {
|
|
3295
3420
|
title: "Measurements",
|
|
@@ -3316,7 +3441,7 @@ function _getMappedMeasurements(measurementService) {
|
|
|
3316
3441
|
|
|
3317
3442
|
/**
|
|
3318
3443
|
* Map the measurements to the display text.
|
|
3319
|
-
* Adds finding and site
|
|
3444
|
+
* Adds finding and site information to the displayText and/or label,
|
|
3320
3445
|
* and provides as 'displayText' and 'label', while providing the original
|
|
3321
3446
|
* values as baseDisplayText and baseLabel
|
|
3322
3447
|
*/
|
|
@@ -3336,7 +3461,9 @@ function _mapMeasurementToDisplay(measurement, index, types) {
|
|
|
3336
3461
|
if (findingSites) {
|
|
3337
3462
|
const siteText = [];
|
|
3338
3463
|
findingSites.forEach(site => {
|
|
3339
|
-
if (site?.text !== label)
|
|
3464
|
+
if (site?.text !== label) {
|
|
3465
|
+
siteText.push(site.text);
|
|
3466
|
+
}
|
|
3340
3467
|
});
|
|
3341
3468
|
displayText = [...siteText, ...displayText];
|
|
3342
3469
|
}
|
|
@@ -3360,6 +3487,7 @@ function _mapMeasurementToDisplay(measurement, index, types) {
|
|
|
3360
3487
|
|
|
3361
3488
|
|
|
3362
3489
|
|
|
3490
|
+
|
|
3363
3491
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getPanelModule.tsx
|
|
3364
3492
|
|
|
3365
3493
|
|
|
@@ -3384,7 +3512,7 @@ function getPanelModule(_ref) {
|
|
|
3384
3512
|
};
|
|
3385
3513
|
return [{
|
|
3386
3514
|
name: 'seriesList',
|
|
3387
|
-
iconName: '
|
|
3515
|
+
iconName: 'tab-studies',
|
|
3388
3516
|
iconLabel: 'Studies',
|
|
3389
3517
|
label: 'Studies',
|
|
3390
3518
|
component: Panels_WrappedPanelStudyBrowser.bind(null, {
|
|
@@ -3403,25 +3531,340 @@ function getPanelModule(_ref) {
|
|
|
3403
3531
|
}
|
|
3404
3532
|
/* harmony default export */ const src_getPanelModule = (getPanelModule);
|
|
3405
3533
|
// EXTERNAL MODULE: ../../core/src/utils/isImage.js
|
|
3406
|
-
var isImage = __webpack_require__(
|
|
3534
|
+
var isImage = __webpack_require__(11835);
|
|
3407
3535
|
// EXTERNAL MODULE: ../../core/src/utils/sopClassDictionary.js
|
|
3408
|
-
var sopClassDictionary = __webpack_require__(
|
|
3536
|
+
var sopClassDictionary = __webpack_require__(24369);
|
|
3409
3537
|
// EXTERNAL MODULE: ../../core/src/classes/ImageSet.ts
|
|
3410
|
-
var ImageSet = __webpack_require__(
|
|
3538
|
+
var ImageSet = __webpack_require__(13950);
|
|
3411
3539
|
// EXTERNAL MODULE: ../../core/src/utils/isDisplaySetReconstructable.js
|
|
3412
|
-
var isDisplaySetReconstructable = __webpack_require__(
|
|
3540
|
+
var isDisplaySetReconstructable = __webpack_require__(89359);
|
|
3413
3541
|
;// CONCATENATED MODULE: ../../../extensions/default/package.json
|
|
3414
3542
|
const package_namespaceObject = JSON.parse('{"u2":"@ohif/extension-default"}');
|
|
3415
3543
|
;// CONCATENATED MODULE: ../../../extensions/default/src/id.js
|
|
3416
3544
|
|
|
3417
3545
|
const id = package_namespaceObject.u2;
|
|
3418
3546
|
|
|
3547
|
+
// EXTERNAL MODULE: ../../core/src/utils/sortInstancesByPosition.ts
|
|
3548
|
+
var sortInstancesByPosition = __webpack_require__(87425);
|
|
3549
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/validations/checkMultiframe.ts
|
|
3550
|
+
|
|
3551
|
+
|
|
3552
|
+
|
|
3553
|
+
/**
|
|
3554
|
+
* Check various multi frame issues. It calls OHIF core functions
|
|
3555
|
+
* @param {*} multiFrameInstance
|
|
3556
|
+
* @param {*} warnings
|
|
3557
|
+
*/
|
|
3558
|
+
function checkMultiFrame(multiFrameInstance, messages) {
|
|
3559
|
+
if (!(0,isDisplaySetReconstructable/* hasPixelMeasurements */.hu)(multiFrameInstance)) {
|
|
3560
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.MULTIFRAME_NO_PIXEL_MEASUREMENTS);
|
|
3561
|
+
}
|
|
3562
|
+
if (!(0,isDisplaySetReconstructable/* hasOrientation */.sb)(multiFrameInstance)) {
|
|
3563
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.MULTIFRAME_NO_ORIENTATION);
|
|
3564
|
+
}
|
|
3565
|
+
if (!(0,isDisplaySetReconstructable/* hasPosition */.kN)(multiFrameInstance)) {
|
|
3566
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.MULTIFRAME_NO_POSITION_INFORMATION);
|
|
3567
|
+
}
|
|
3568
|
+
}
|
|
3569
|
+
// EXTERNAL MODULE: ../../core/src/utils/toNumber.js
|
|
3570
|
+
var toNumber = __webpack_require__(94972);
|
|
3571
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/validations/areAllImageDimensionsEqual.ts
|
|
3572
|
+
|
|
3573
|
+
|
|
3574
|
+
/**
|
|
3575
|
+
* Check if the frames in a series has different dimensions
|
|
3576
|
+
* @param {*} instances
|
|
3577
|
+
* @returns
|
|
3578
|
+
*/
|
|
3579
|
+
function areAllImageDimensionsEqual(instances) {
|
|
3580
|
+
if (!instances?.length) {
|
|
3581
|
+
return false;
|
|
3582
|
+
}
|
|
3583
|
+
const firstImage = instances[0];
|
|
3584
|
+
const firstImageRows = (0,toNumber/* default */.Z)(firstImage.Rows);
|
|
3585
|
+
const firstImageColumns = (0,toNumber/* default */.Z)(firstImage.Columns);
|
|
3586
|
+
for (let i = 1; i < instances.length; i++) {
|
|
3587
|
+
const instance = instances[i];
|
|
3588
|
+
const {
|
|
3589
|
+
Rows,
|
|
3590
|
+
Columns
|
|
3591
|
+
} = instance;
|
|
3592
|
+
if (Rows !== firstImageRows || Columns !== firstImageColumns) {
|
|
3593
|
+
return false;
|
|
3594
|
+
}
|
|
3595
|
+
}
|
|
3596
|
+
return true;
|
|
3597
|
+
}
|
|
3598
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/validations/areAllImageComponentsEqual.ts
|
|
3599
|
+
|
|
3600
|
+
|
|
3601
|
+
/**
|
|
3602
|
+
* Check if all voxels in series images has same number of components (samplesPerPixel)
|
|
3603
|
+
* @param {*} instances
|
|
3604
|
+
* @returns
|
|
3605
|
+
*/
|
|
3606
|
+
function areAllImageComponentsEqual(instances) {
|
|
3607
|
+
if (!instances?.length) {
|
|
3608
|
+
return false;
|
|
3609
|
+
}
|
|
3610
|
+
const firstImage = instances[0];
|
|
3611
|
+
const firstImageSamplesPerPixel = (0,toNumber/* default */.Z)(firstImage.SamplesPerPixel);
|
|
3612
|
+
for (let i = 1; i < instances.length; i++) {
|
|
3613
|
+
const instance = instances[i];
|
|
3614
|
+
const {
|
|
3615
|
+
SamplesPerPixel
|
|
3616
|
+
} = instance;
|
|
3617
|
+
if (SamplesPerPixel !== firstImageSamplesPerPixel) {
|
|
3618
|
+
return false;
|
|
3619
|
+
}
|
|
3620
|
+
}
|
|
3621
|
+
return true;
|
|
3622
|
+
}
|
|
3623
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/validations/areAllImageOrientationsEqual.ts
|
|
3624
|
+
|
|
3625
|
+
|
|
3626
|
+
|
|
3627
|
+
/**
|
|
3628
|
+
* Check is the series has frames with different orientations
|
|
3629
|
+
* @param {*} instances
|
|
3630
|
+
* @returns
|
|
3631
|
+
*/
|
|
3632
|
+
function areAllImageOrientationsEqual(instances) {
|
|
3633
|
+
if (!instances?.length) {
|
|
3634
|
+
return false;
|
|
3635
|
+
}
|
|
3636
|
+
const firstImage = instances[0];
|
|
3637
|
+
const firstImageOrientationPatient = (0,toNumber/* default */.Z)(firstImage.ImageOrientationPatient);
|
|
3638
|
+
for (let i = 1; i < instances.length; i++) {
|
|
3639
|
+
const instance = instances[i];
|
|
3640
|
+
const imageOrientationPatient = (0,toNumber/* default */.Z)(instance.ImageOrientationPatient);
|
|
3641
|
+
if (!(0,isDisplaySetReconstructable/* _isSameOrientation */.NB)(imageOrientationPatient, firstImageOrientationPatient)) {
|
|
3642
|
+
return false;
|
|
3643
|
+
}
|
|
3644
|
+
}
|
|
3645
|
+
return true;
|
|
3646
|
+
}
|
|
3647
|
+
// EXTERNAL MODULE: ../../../node_modules/gl-matrix/esm/index.js + 10 modules
|
|
3648
|
+
var esm = __webpack_require__(45451);
|
|
3649
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/calculateScanAxisNormal.ts
|
|
3650
|
+
|
|
3651
|
+
|
|
3652
|
+
/**
|
|
3653
|
+
* Calculates the scanAxisNormal based on a image orientation vector extract from a frame
|
|
3654
|
+
* @param {*} imageOrientation
|
|
3655
|
+
* @returns
|
|
3656
|
+
*/
|
|
3657
|
+
function calculateScanAxisNormal(imageOrientation) {
|
|
3658
|
+
const rowCosineVec = esm/* vec3.fromValues */.R3.fromValues(imageOrientation[0], imageOrientation[1], imageOrientation[2]);
|
|
3659
|
+
const colCosineVec = esm/* vec3.fromValues */.R3.fromValues(imageOrientation[3], imageOrientation[4], imageOrientation[5]);
|
|
3660
|
+
return esm/* vec3.cross */.R3.cross(esm/* vec3.create */.R3.create(), rowCosineVec, colCosineVec);
|
|
3661
|
+
}
|
|
3662
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/validations/areAllImagePositionsEqual.ts
|
|
3663
|
+
|
|
3664
|
+
|
|
3665
|
+
|
|
3666
|
+
|
|
3667
|
+
|
|
3668
|
+
/**
|
|
3669
|
+
* Checks if there is a position shift between consecutive frames
|
|
3670
|
+
* @param {*} previousPosition
|
|
3671
|
+
* @param {*} actualPosition
|
|
3672
|
+
* @param {*} scanAxisNormal
|
|
3673
|
+
* @param {*} averageSpacingBetweenFrames
|
|
3674
|
+
* @returns
|
|
3675
|
+
*/
|
|
3676
|
+
function _checkSeriesPositionShift(previousPosition, actualPosition, scanAxisNormal, averageSpacingBetweenFrames) {
|
|
3677
|
+
// predicted position should be the previous position added by the multiplication
|
|
3678
|
+
// of the scanAxisNormal and the average spacing between frames
|
|
3679
|
+
const predictedPosition = esm/* vec3.scaleAndAdd */.R3.scaleAndAdd(esm/* vec3.create */.R3.create(), previousPosition, scanAxisNormal, averageSpacingBetweenFrames);
|
|
3680
|
+
return esm/* vec3.distance */.R3.distance(actualPosition, predictedPosition) > averageSpacingBetweenFrames;
|
|
3681
|
+
}
|
|
3682
|
+
|
|
3683
|
+
/**
|
|
3684
|
+
* Checks if a series has position shifts between consecutive frames
|
|
3685
|
+
* @param {*} instances
|
|
3686
|
+
* @returns
|
|
3687
|
+
*/
|
|
3688
|
+
function areAllImagePositionsEqual(instances) {
|
|
3689
|
+
if (!instances?.length) {
|
|
3690
|
+
return false;
|
|
3691
|
+
}
|
|
3692
|
+
const firstImageOrientationPatient = (0,toNumber/* default */.Z)(instances[0].ImageOrientationPatient);
|
|
3693
|
+
if (!firstImageOrientationPatient) {
|
|
3694
|
+
return false;
|
|
3695
|
+
}
|
|
3696
|
+
const scanAxisNormal = calculateScanAxisNormal(firstImageOrientationPatient);
|
|
3697
|
+
const firstImagePositionPatient = (0,toNumber/* default */.Z)(instances[0].ImagePositionPatient);
|
|
3698
|
+
const lastIpp = (0,toNumber/* default */.Z)(instances[instances.length - 1].ImagePositionPatient);
|
|
3699
|
+
const averageSpacingBetweenFrames = (0,isDisplaySetReconstructable/* _getPerpendicularDistance */.Xn)(firstImagePositionPatient, lastIpp) / (instances.length - 1);
|
|
3700
|
+
let previousImagePositionPatient = firstImagePositionPatient;
|
|
3701
|
+
for (let i = 1; i < instances.length; i++) {
|
|
3702
|
+
const instance = instances[i];
|
|
3703
|
+
const imagePositionPatient = (0,toNumber/* default */.Z)(instance.ImagePositionPatient);
|
|
3704
|
+
if (_checkSeriesPositionShift(previousImagePositionPatient, imagePositionPatient, scanAxisNormal, averageSpacingBetweenFrames)) {
|
|
3705
|
+
return false;
|
|
3706
|
+
}
|
|
3707
|
+
previousImagePositionPatient = imagePositionPatient;
|
|
3708
|
+
}
|
|
3709
|
+
return true;
|
|
3710
|
+
}
|
|
3711
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/validations/areAllImageSpacingEqual.ts
|
|
3712
|
+
|
|
3713
|
+
|
|
3714
|
+
|
|
3715
|
+
/**
|
|
3716
|
+
* Checks if series has spacing issues
|
|
3717
|
+
* @param {*} instances
|
|
3718
|
+
* @param {*} warnings
|
|
3719
|
+
*/
|
|
3720
|
+
function areAllImageSpacingEqual(instances, messages) {
|
|
3721
|
+
if (!instances?.length) {
|
|
3722
|
+
return;
|
|
3723
|
+
}
|
|
3724
|
+
const firstImagePositionPatient = (0,toNumber/* default */.Z)(instances[0].ImagePositionPatient);
|
|
3725
|
+
if (!firstImagePositionPatient) {
|
|
3726
|
+
return;
|
|
3727
|
+
}
|
|
3728
|
+
const lastIpp = (0,toNumber/* default */.Z)(instances[instances.length - 1].ImagePositionPatient);
|
|
3729
|
+
const averageSpacingBetweenFrames = (0,isDisplaySetReconstructable/* _getPerpendicularDistance */.Xn)(firstImagePositionPatient, lastIpp) / (instances.length - 1);
|
|
3730
|
+
let previousImagePositionPatient = firstImagePositionPatient;
|
|
3731
|
+
const issuesFound = [];
|
|
3732
|
+
for (let i = 1; i < instances.length; i++) {
|
|
3733
|
+
const instance = instances[i];
|
|
3734
|
+
const imagePositionPatient = (0,toNumber/* default */.Z)(instance.ImagePositionPatient);
|
|
3735
|
+
const spacingBetweenFrames = (0,isDisplaySetReconstructable/* _getPerpendicularDistance */.Xn)(imagePositionPatient, previousImagePositionPatient);
|
|
3736
|
+
const spacingIssue = (0,isDisplaySetReconstructable/* _getSpacingIssue */.bg)(spacingBetweenFrames, averageSpacingBetweenFrames);
|
|
3737
|
+
if (spacingIssue) {
|
|
3738
|
+
const issue = spacingIssue.issue;
|
|
3739
|
+
|
|
3740
|
+
// avoid multiple warning of the same thing
|
|
3741
|
+
if (!issuesFound.includes(issue)) {
|
|
3742
|
+
issuesFound.push(issue);
|
|
3743
|
+
if (issue === isDisplaySetReconstructable/* reconstructionIssues */.e1.MISSING_FRAMES) {
|
|
3744
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.MISSING_FRAMES);
|
|
3745
|
+
} else if (issue === isDisplaySetReconstructable/* reconstructionIssues */.e1.IRREGULAR_SPACING) {
|
|
3746
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.IRREGULAR_SPACING);
|
|
3747
|
+
}
|
|
3748
|
+
}
|
|
3749
|
+
// we just want to find issues not how many
|
|
3750
|
+
if (issuesFound.length > 1) {
|
|
3751
|
+
break;
|
|
3752
|
+
}
|
|
3753
|
+
}
|
|
3754
|
+
previousImagePositionPatient = imagePositionPatient;
|
|
3755
|
+
}
|
|
3756
|
+
}
|
|
3757
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/validations/checkSingleFrames.ts
|
|
3758
|
+
|
|
3759
|
+
|
|
3760
|
+
|
|
3761
|
+
|
|
3762
|
+
|
|
3763
|
+
|
|
3764
|
+
|
|
3765
|
+
/**
|
|
3766
|
+
* Runs various checks in a single frame series
|
|
3767
|
+
* @param {*} instances
|
|
3768
|
+
* @param {*} warnings
|
|
3769
|
+
*/
|
|
3770
|
+
function checkSingleFrames(instances, messages) {
|
|
3771
|
+
if (instances.length > 2) {
|
|
3772
|
+
if (!areAllImageDimensionsEqual(instances)) {
|
|
3773
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.INCONSISTENT_DIMENSIONS);
|
|
3774
|
+
}
|
|
3775
|
+
if (!areAllImageComponentsEqual(instances)) {
|
|
3776
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.INCONSISTENT_COMPONENTS);
|
|
3777
|
+
}
|
|
3778
|
+
if (!areAllImageOrientationsEqual(instances)) {
|
|
3779
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.INCONSISTENT_ORIENTATIONS);
|
|
3780
|
+
}
|
|
3781
|
+
if (!areAllImagePositionsEqual(instances)) {
|
|
3782
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.INCONSISTENT_POSITION_INFORMATION);
|
|
3783
|
+
}
|
|
3784
|
+
areAllImageSpacingEqual(instances, messages);
|
|
3785
|
+
}
|
|
3786
|
+
}
|
|
3787
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/getDisplaySetMessages.ts
|
|
3788
|
+
|
|
3789
|
+
|
|
3790
|
+
|
|
3791
|
+
|
|
3792
|
+
|
|
3793
|
+
/**
|
|
3794
|
+
* Checks if a series is reconstructable to a 3D volume.
|
|
3795
|
+
*
|
|
3796
|
+
* @param {Object[]} instances An array of `OHIFInstanceMetadata` objects.
|
|
3797
|
+
*/
|
|
3798
|
+
function getDisplaySetMessages(instances, isReconstructable) {
|
|
3799
|
+
const messages = new src/* DisplaySetMessageList */.iK();
|
|
3800
|
+
if (!instances.length) {
|
|
3801
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.NO_VALID_INSTANCES);
|
|
3802
|
+
return;
|
|
3803
|
+
}
|
|
3804
|
+
const firstInstance = instances[0];
|
|
3805
|
+
const {
|
|
3806
|
+
Modality,
|
|
3807
|
+
ImageType,
|
|
3808
|
+
NumberOfFrames
|
|
3809
|
+
} = firstInstance;
|
|
3810
|
+
// Due to current requirements, LOCALIZER series doesn't have any messages
|
|
3811
|
+
if (ImageType?.includes('LOCALIZER')) {
|
|
3812
|
+
return messages;
|
|
3813
|
+
}
|
|
3814
|
+
if (!isDisplaySetReconstructable/* constructableModalities */.M6.includes(Modality)) {
|
|
3815
|
+
return messages;
|
|
3816
|
+
}
|
|
3817
|
+
const isMultiframe = NumberOfFrames > 1;
|
|
3818
|
+
// Can't reconstruct if all instances don't have the ImagePositionPatient.
|
|
3819
|
+
if (!isMultiframe && !instances.every(instance => instance.ImagePositionPatient)) {
|
|
3820
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.NO_POSITION_INFORMATION);
|
|
3821
|
+
}
|
|
3822
|
+
const sortedInstances = (0,sortInstancesByPosition/* default */.Z)(instances);
|
|
3823
|
+
isMultiframe ? checkMultiFrame(sortedInstances[0], messages) : checkSingleFrames(sortedInstances, messages);
|
|
3824
|
+
if (!isReconstructable) {
|
|
3825
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.NOT_RECONSTRUCTABLE);
|
|
3826
|
+
}
|
|
3827
|
+
return messages;
|
|
3828
|
+
}
|
|
3829
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/getDisplaySetsFromUnsupportedSeries.js
|
|
3830
|
+
|
|
3831
|
+
|
|
3832
|
+
/**
|
|
3833
|
+
* Default handler for a instance list with an unsupported sopClassUID
|
|
3834
|
+
*/
|
|
3835
|
+
function getDisplaySetsFromUnsupportedSeries(instances) {
|
|
3836
|
+
const imageSet = new ImageSet/* default */.Z(instances);
|
|
3837
|
+
const messages = new src/* DisplaySetMessageList */.iK();
|
|
3838
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.UNSUPPORTED_DISPLAYSET);
|
|
3839
|
+
const instance = instances[0];
|
|
3840
|
+
imageSet.setAttributes({
|
|
3841
|
+
displaySetInstanceUID: imageSet.uid,
|
|
3842
|
+
// create a local alias for the imageSet UID
|
|
3843
|
+
SeriesDate: instance.SeriesDate,
|
|
3844
|
+
SeriesTime: instance.SeriesTime,
|
|
3845
|
+
SeriesInstanceUID: instance.SeriesInstanceUID,
|
|
3846
|
+
StudyInstanceUID: instance.StudyInstanceUID,
|
|
3847
|
+
SeriesNumber: instance.SeriesNumber || 0,
|
|
3848
|
+
FrameRate: instance.FrameTime,
|
|
3849
|
+
SOPClassUID: instance.SOPClassUID,
|
|
3850
|
+
SeriesDescription: instance.SeriesDescription || '',
|
|
3851
|
+
Modality: instance.Modality,
|
|
3852
|
+
numImageFrames: instances.length,
|
|
3853
|
+
unsupported: true,
|
|
3854
|
+
SOPClassHandlerId: 'unsupported',
|
|
3855
|
+
isReconstructable: false,
|
|
3856
|
+
messages
|
|
3857
|
+
});
|
|
3858
|
+
return [imageSet];
|
|
3859
|
+
}
|
|
3419
3860
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getSopClassHandlerModule.js
|
|
3420
3861
|
|
|
3421
3862
|
|
|
3422
3863
|
|
|
3423
3864
|
|
|
3424
3865
|
|
|
3866
|
+
|
|
3867
|
+
|
|
3425
3868
|
const sopClassHandlerName = 'stack';
|
|
3426
3869
|
const isMultiFrame = instance => {
|
|
3427
3870
|
return instance.NumberOfFrames > 1;
|
|
@@ -3432,9 +3875,9 @@ const makeDisplaySet = instances => {
|
|
|
3432
3875
|
const {
|
|
3433
3876
|
value: isReconstructable,
|
|
3434
3877
|
averageSpacingBetweenFrames
|
|
3435
|
-
} = (0,isDisplaySetReconstructable/* default */.
|
|
3436
|
-
|
|
3878
|
+
} = (0,isDisplaySetReconstructable/* default */.ZP)(instances);
|
|
3437
3879
|
// set appropriate attributes to image set...
|
|
3880
|
+
const messages = getDisplaySetMessages(instances, isReconstructable);
|
|
3438
3881
|
imageSet.setAttributes({
|
|
3439
3882
|
displaySetInstanceUID: imageSet.uid,
|
|
3440
3883
|
// create a local alias for the imageSet UID
|
|
@@ -3452,6 +3895,7 @@ const makeDisplaySet = instances => {
|
|
|
3452
3895
|
numImageFrames: instances.length,
|
|
3453
3896
|
SOPClassHandlerId: `${id}.sopClassHandlerModule.${sopClassHandlerName}`,
|
|
3454
3897
|
isReconstructable,
|
|
3898
|
+
messages,
|
|
3455
3899
|
averageSpacingBetweenFrames: averageSpacingBetweenFrames || null
|
|
3456
3900
|
});
|
|
3457
3901
|
|
|
@@ -3558,6 +4002,10 @@ function getSopClassHandlerModule() {
|
|
|
3558
4002
|
name: sopClassHandlerName,
|
|
3559
4003
|
sopClassUids,
|
|
3560
4004
|
getDisplaySetsFromSeries
|
|
4005
|
+
}, {
|
|
4006
|
+
name: 'not-supported-display-sets-handler',
|
|
4007
|
+
sopClassUids: [],
|
|
4008
|
+
getDisplaySetsFromSeries: getDisplaySetsFromUnsupportedSeries
|
|
3561
4009
|
}];
|
|
3562
4010
|
}
|
|
3563
4011
|
/* harmony default export */ const src_getSopClassHandlerModule = (getSopClassHandlerModule);
|
|
@@ -3565,44 +4013,53 @@ function getSopClassHandlerModule() {
|
|
|
3565
4013
|
|
|
3566
4014
|
function ToolbarDivider() {
|
|
3567
4015
|
return /*#__PURE__*/react.createElement("span", {
|
|
3568
|
-
className: "
|
|
4016
|
+
className: "border-common-dark mx-2 h-8 w-4 self-center border-l"
|
|
3569
4017
|
});
|
|
3570
4018
|
}
|
|
3571
4019
|
;// CONCATENATED MODULE: ../../../extensions/default/src/Toolbar/ToolbarLayoutSelector.tsx
|
|
4020
|
+
function ToolbarLayoutSelector_extends() { ToolbarLayoutSelector_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 ToolbarLayoutSelector_extends.apply(this, arguments); }
|
|
3572
4021
|
|
|
3573
4022
|
|
|
3574
4023
|
|
|
3575
4024
|
|
|
3576
|
-
function
|
|
4025
|
+
function ToolbarLayoutSelectorWithServices(_ref) {
|
|
3577
4026
|
let {
|
|
3578
|
-
rows,
|
|
3579
|
-
columns,
|
|
3580
|
-
className,
|
|
3581
4027
|
servicesManager,
|
|
3582
|
-
...
|
|
4028
|
+
...props
|
|
3583
4029
|
} = _ref;
|
|
3584
|
-
const [isOpen, setIsOpen] = (0,react.useState)(false);
|
|
3585
4030
|
const {
|
|
3586
|
-
hangingProtocolService,
|
|
3587
4031
|
toolbarService
|
|
3588
4032
|
} = servicesManager.services;
|
|
4033
|
+
const onSelection = (0,react.useCallback)(props => {
|
|
4034
|
+
toolbarService.recordInteraction({
|
|
4035
|
+
interactionType: 'action',
|
|
4036
|
+
commands: [{
|
|
4037
|
+
commandName: 'setViewportGridLayout',
|
|
4038
|
+
commandOptions: {
|
|
4039
|
+
...props
|
|
4040
|
+
},
|
|
4041
|
+
context: 'DEFAULT'
|
|
4042
|
+
}]
|
|
4043
|
+
});
|
|
4044
|
+
}, [toolbarService]);
|
|
4045
|
+
return /*#__PURE__*/react.createElement(LayoutSelector, ToolbarLayoutSelector_extends({}, props, {
|
|
4046
|
+
onSelection: onSelection
|
|
4047
|
+
}));
|
|
4048
|
+
}
|
|
4049
|
+
function LayoutSelector(_ref2) {
|
|
4050
|
+
let {
|
|
4051
|
+
rows,
|
|
4052
|
+
columns,
|
|
4053
|
+
className,
|
|
4054
|
+
onSelection,
|
|
4055
|
+
...rest
|
|
4056
|
+
} = _ref2;
|
|
4057
|
+
const [isOpen, setIsOpen] = (0,react.useState)(false);
|
|
3589
4058
|
const closeOnOutsideClick = () => {
|
|
3590
4059
|
if (isOpen) {
|
|
3591
4060
|
setIsOpen(false);
|
|
3592
4061
|
}
|
|
3593
4062
|
};
|
|
3594
|
-
(0,react.useEffect)(() => {
|
|
3595
|
-
const {
|
|
3596
|
-
unsubscribe
|
|
3597
|
-
} = hangingProtocolService.subscribe(hangingProtocolService.EVENTS.PROTOCOL_CHANGED, evt => {
|
|
3598
|
-
const {
|
|
3599
|
-
protocol
|
|
3600
|
-
} = evt;
|
|
3601
|
-
});
|
|
3602
|
-
return () => {
|
|
3603
|
-
unsubscribe();
|
|
3604
|
-
};
|
|
3605
|
-
}, [hangingProtocolService]);
|
|
3606
4063
|
(0,react.useEffect)(() => {
|
|
3607
4064
|
window.addEventListener('click', closeOnOutsideClick);
|
|
3608
4065
|
return () => {
|
|
@@ -3611,18 +4068,6 @@ function LayoutSelector(_ref) {
|
|
|
3611
4068
|
}, [isOpen]);
|
|
3612
4069
|
const onInteractionHandler = () => setIsOpen(!isOpen);
|
|
3613
4070
|
const DropdownContent = isOpen ? ui_src/* LayoutSelector */.OF : null;
|
|
3614
|
-
const onSelectionHandler = props => {
|
|
3615
|
-
toolbarService.recordInteraction({
|
|
3616
|
-
interactionType: 'action',
|
|
3617
|
-
commands: [{
|
|
3618
|
-
commandName: 'setViewportGridLayout',
|
|
3619
|
-
commandOptions: {
|
|
3620
|
-
...props
|
|
3621
|
-
},
|
|
3622
|
-
context: 'DEFAULT'
|
|
3623
|
-
}]
|
|
3624
|
-
});
|
|
3625
|
-
};
|
|
3626
4071
|
return /*#__PURE__*/react.createElement(ui_src/* ToolbarButton */.hA, {
|
|
3627
4072
|
id: "Layout",
|
|
3628
4073
|
label: "Grid Layout",
|
|
@@ -3633,7 +4078,7 @@ function LayoutSelector(_ref) {
|
|
|
3633
4078
|
dropdownContent: DropdownContent !== null && /*#__PURE__*/react.createElement(DropdownContent, {
|
|
3634
4079
|
rows: rows,
|
|
3635
4080
|
columns: columns,
|
|
3636
|
-
onSelection:
|
|
4081
|
+
onSelection: onSelection
|
|
3637
4082
|
}),
|
|
3638
4083
|
isActive: isOpen,
|
|
3639
4084
|
type: "toggle"
|
|
@@ -3650,10 +4095,238 @@ LayoutSelector.defaultProps = {
|
|
|
3650
4095
|
columns: 3,
|
|
3651
4096
|
onLayoutChange: () => {}
|
|
3652
4097
|
};
|
|
3653
|
-
/* harmony default export */ const ToolbarLayoutSelector = (
|
|
3654
|
-
;// CONCATENATED MODULE: ../../../extensions/default/src/Toolbar/
|
|
4098
|
+
/* harmony default export */ const ToolbarLayoutSelector = (ToolbarLayoutSelectorWithServices);
|
|
4099
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/Toolbar/ToolbarSplitButtonWithServices.tsx
|
|
4100
|
+
function ToolbarSplitButtonWithServices_extends() { ToolbarSplitButtonWithServices_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 ToolbarSplitButtonWithServices_extends.apply(this, arguments); }
|
|
4101
|
+
|
|
4102
|
+
|
|
4103
|
+
|
|
4104
|
+
|
|
4105
|
+
function ToolbarSplitButtonWithServices(_ref) {
|
|
4106
|
+
let {
|
|
4107
|
+
isRadio,
|
|
4108
|
+
isAction,
|
|
4109
|
+
groupId,
|
|
4110
|
+
primary,
|
|
4111
|
+
secondary,
|
|
4112
|
+
items,
|
|
4113
|
+
renderer,
|
|
4114
|
+
onInteraction,
|
|
4115
|
+
servicesManager
|
|
4116
|
+
} = _ref;
|
|
4117
|
+
const {
|
|
4118
|
+
toolbarService
|
|
4119
|
+
} = servicesManager?.services;
|
|
4120
|
+
const handleItemClick = (item, index) => {
|
|
4121
|
+
const {
|
|
4122
|
+
id,
|
|
4123
|
+
type,
|
|
4124
|
+
commands
|
|
4125
|
+
} = item;
|
|
4126
|
+
onInteraction({
|
|
4127
|
+
groupId,
|
|
4128
|
+
itemId: id,
|
|
4129
|
+
interactionType: type,
|
|
4130
|
+
commands
|
|
4131
|
+
});
|
|
4132
|
+
setState(state => ({
|
|
4133
|
+
...state,
|
|
4134
|
+
primary: !isAction && isRadio ? {
|
|
4135
|
+
...item,
|
|
4136
|
+
index
|
|
4137
|
+
} : state.primary,
|
|
4138
|
+
isExpanded: false,
|
|
4139
|
+
items: getSplitButtonItems(items).filter(item => isRadio && !isAction ? item.index !== index : true)
|
|
4140
|
+
}));
|
|
4141
|
+
};
|
|
4142
|
+
|
|
4143
|
+
/* Bubbles up individual item clicks */
|
|
4144
|
+
const getSplitButtonItems = items => items.map((item, index) => ({
|
|
4145
|
+
...item,
|
|
4146
|
+
index,
|
|
4147
|
+
onClick: () => handleItemClick(item, index)
|
|
4148
|
+
}));
|
|
4149
|
+
const [buttonsState, setButtonState] = (0,react.useState)({
|
|
4150
|
+
primaryToolId: '',
|
|
4151
|
+
toggles: {},
|
|
4152
|
+
groups: {}
|
|
4153
|
+
});
|
|
4154
|
+
const [state, setState] = (0,react.useState)({
|
|
4155
|
+
primary,
|
|
4156
|
+
items: getSplitButtonItems(items).filter(item => isRadio && !isAction ? item.id !== primary.id : true)
|
|
4157
|
+
});
|
|
4158
|
+
const {
|
|
4159
|
+
primaryToolId,
|
|
4160
|
+
toggles
|
|
4161
|
+
} = buttonsState;
|
|
4162
|
+
const isPrimaryToggle = state.primary.type === 'toggle';
|
|
4163
|
+
const isPrimaryActive = state.primary.type === 'tool' && primaryToolId === state.primary.id || isPrimaryToggle && toggles[state.primary.id] === true;
|
|
4164
|
+
const PrimaryButtonComponent = toolbarService?.getButtonComponentForUIType(state.primary.uiType) ?? ui_src/* ToolbarButton */.hA;
|
|
4165
|
+
(0,react.useEffect)(() => {
|
|
4166
|
+
const {
|
|
4167
|
+
unsubscribe
|
|
4168
|
+
} = toolbarService.subscribe(toolbarService.EVENTS.TOOL_BAR_STATE_MODIFIED, state => {
|
|
4169
|
+
setButtonState({
|
|
4170
|
+
...state
|
|
4171
|
+
});
|
|
4172
|
+
});
|
|
4173
|
+
return () => {
|
|
4174
|
+
unsubscribe();
|
|
4175
|
+
};
|
|
4176
|
+
}, [toolbarService]);
|
|
4177
|
+
const updatedItems = state.items.map(item => {
|
|
4178
|
+
const isActive = item.type === 'tool' && primaryToolId === item.id;
|
|
4179
|
+
|
|
4180
|
+
// We could have added the
|
|
4181
|
+
// item.type === 'toggle' && toggles[item.id] === true
|
|
4182
|
+
// too but that makes the button active when the toggle is active under it
|
|
4183
|
+
// which feels weird
|
|
4184
|
+
return {
|
|
4185
|
+
...item,
|
|
4186
|
+
isActive
|
|
4187
|
+
};
|
|
4188
|
+
});
|
|
4189
|
+
const DefaultListItemRenderer = _ref2 => {
|
|
4190
|
+
let {
|
|
4191
|
+
type,
|
|
4192
|
+
icon,
|
|
4193
|
+
label,
|
|
4194
|
+
t,
|
|
4195
|
+
id
|
|
4196
|
+
} = _ref2;
|
|
4197
|
+
const isActive = type === 'toggle' && toggles[id] === true;
|
|
4198
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
4199
|
+
className: classnames_default()('hover:bg-primary-dark flex h-8 w-full flex-row items-center p-3', 'whitespace-pre text-base', isActive && 'bg-primary-dark', isActive ? 'text-[#348CFD]' : 'text-common-bright hover:bg-primary-dark hover:text-primary-light')
|
|
4200
|
+
}, icon && /*#__PURE__*/react.createElement("span", {
|
|
4201
|
+
className: "mr-4"
|
|
4202
|
+
}, /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
4203
|
+
name: icon,
|
|
4204
|
+
className: "h-5 w-5"
|
|
4205
|
+
})), /*#__PURE__*/react.createElement("span", {
|
|
4206
|
+
className: "mr-5"
|
|
4207
|
+
}, t(label)));
|
|
4208
|
+
};
|
|
4209
|
+
const listItemRenderer = renderer || DefaultListItemRenderer;
|
|
4210
|
+
return /*#__PURE__*/react.createElement(ui_src/* SplitButton */.aW, {
|
|
4211
|
+
isRadio: isRadio,
|
|
4212
|
+
isAction: isAction,
|
|
4213
|
+
primary: state.primary,
|
|
4214
|
+
secondary: secondary,
|
|
4215
|
+
items: updatedItems,
|
|
4216
|
+
groupId: groupId,
|
|
4217
|
+
renderer: listItemRenderer,
|
|
4218
|
+
isActive: isPrimaryActive || updatedItems.some(item => item.isActive),
|
|
4219
|
+
isToggle: isPrimaryToggle,
|
|
4220
|
+
onInteraction: onInteraction,
|
|
4221
|
+
Component: props => /*#__PURE__*/react.createElement(PrimaryButtonComponent, ToolbarSplitButtonWithServices_extends({}, props, {
|
|
4222
|
+
servicesManager: servicesManager
|
|
4223
|
+
}))
|
|
4224
|
+
});
|
|
4225
|
+
}
|
|
4226
|
+
ToolbarSplitButtonWithServices.propTypes = {
|
|
4227
|
+
isRadio: (prop_types_default()).bool,
|
|
4228
|
+
isAction: (prop_types_default()).bool,
|
|
4229
|
+
groupId: (prop_types_default()).string,
|
|
4230
|
+
primary: prop_types_default().shape({
|
|
4231
|
+
id: (prop_types_default()).string.isRequired,
|
|
4232
|
+
type: prop_types_default().oneOf(['tool', 'action', 'toggle']).isRequired,
|
|
4233
|
+
uiType: (prop_types_default()).string
|
|
4234
|
+
}),
|
|
4235
|
+
secondary: prop_types_default().shape({
|
|
4236
|
+
id: (prop_types_default()).string,
|
|
4237
|
+
icon: (prop_types_default()).string.isRequired,
|
|
4238
|
+
label: (prop_types_default()).string,
|
|
4239
|
+
tooltip: (prop_types_default()).string.isRequired,
|
|
4240
|
+
isActive: (prop_types_default()).bool
|
|
4241
|
+
}),
|
|
4242
|
+
items: prop_types_default().arrayOf(prop_types_default().shape({
|
|
4243
|
+
id: (prop_types_default()).string.isRequired,
|
|
4244
|
+
type: prop_types_default().oneOf(['tool', 'action', 'toggle']).isRequired,
|
|
4245
|
+
icon: (prop_types_default()).string,
|
|
4246
|
+
label: (prop_types_default()).string,
|
|
4247
|
+
tooltip: (prop_types_default()).string
|
|
4248
|
+
})),
|
|
4249
|
+
renderer: (prop_types_default()).func,
|
|
4250
|
+
onInteraction: (prop_types_default()).func.isRequired,
|
|
4251
|
+
servicesManager: prop_types_default().shape({
|
|
4252
|
+
services: prop_types_default().shape({
|
|
4253
|
+
toolbarService: (prop_types_default()).object
|
|
4254
|
+
})
|
|
4255
|
+
})
|
|
4256
|
+
};
|
|
4257
|
+
ToolbarSplitButtonWithServices.defaultProps = {
|
|
4258
|
+
isRadio: false,
|
|
4259
|
+
isAction: false
|
|
4260
|
+
};
|
|
4261
|
+
/* harmony default export */ const Toolbar_ToolbarSplitButtonWithServices = (ToolbarSplitButtonWithServices);
|
|
4262
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/Toolbar/ToolbarButtonWithServices.tsx
|
|
4263
|
+
function ToolbarButtonWithServices_extends() { ToolbarButtonWithServices_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 ToolbarButtonWithServices_extends.apply(this, arguments); }
|
|
3655
4264
|
|
|
3656
|
-
|
|
4265
|
+
|
|
4266
|
+
|
|
4267
|
+
function ToolbarButtonWithServices(_ref) {
|
|
4268
|
+
let {
|
|
4269
|
+
id,
|
|
4270
|
+
type,
|
|
4271
|
+
commands,
|
|
4272
|
+
onInteraction,
|
|
4273
|
+
servicesManager,
|
|
4274
|
+
...props
|
|
4275
|
+
} = _ref;
|
|
4276
|
+
const {
|
|
4277
|
+
toolbarService
|
|
4278
|
+
} = servicesManager?.services || {};
|
|
4279
|
+
const [buttonsState, setButtonState] = (0,react.useState)({
|
|
4280
|
+
primaryToolId: '',
|
|
4281
|
+
toggles: {},
|
|
4282
|
+
groups: {}
|
|
4283
|
+
});
|
|
4284
|
+
const {
|
|
4285
|
+
primaryToolId
|
|
4286
|
+
} = buttonsState;
|
|
4287
|
+
const isActive = type === 'tool' && id === primaryToolId || type === 'toggle' && buttonsState.toggles[id] === true;
|
|
4288
|
+
(0,react.useEffect)(() => {
|
|
4289
|
+
const {
|
|
4290
|
+
unsubscribe
|
|
4291
|
+
} = toolbarService.subscribe(toolbarService.EVENTS.TOOL_BAR_STATE_MODIFIED, state => {
|
|
4292
|
+
setButtonState({
|
|
4293
|
+
...state
|
|
4294
|
+
});
|
|
4295
|
+
});
|
|
4296
|
+
return () => {
|
|
4297
|
+
unsubscribe();
|
|
4298
|
+
};
|
|
4299
|
+
}, [toolbarService]);
|
|
4300
|
+
return /*#__PURE__*/react.createElement(ui_src/* ToolbarButton */.hA, ToolbarButtonWithServices_extends({
|
|
4301
|
+
commands: commands,
|
|
4302
|
+
id: id,
|
|
4303
|
+
type: type,
|
|
4304
|
+
isActive: isActive,
|
|
4305
|
+
onInteraction: onInteraction
|
|
4306
|
+
}, props));
|
|
4307
|
+
}
|
|
4308
|
+
ToolbarButtonWithServices.propTypes = {
|
|
4309
|
+
id: (prop_types_default()).string.isRequired,
|
|
4310
|
+
type: prop_types_default().oneOf(['tool', 'action', 'toggle']).isRequired,
|
|
4311
|
+
commands: prop_types_default().arrayOf(prop_types_default().shape({
|
|
4312
|
+
commandName: (prop_types_default()).string.isRequired,
|
|
4313
|
+
context: (prop_types_default()).string
|
|
4314
|
+
})),
|
|
4315
|
+
onInteraction: (prop_types_default()).func.isRequired,
|
|
4316
|
+
servicesManager: prop_types_default().shape({
|
|
4317
|
+
services: prop_types_default().shape({
|
|
4318
|
+
toolbarService: prop_types_default().shape({
|
|
4319
|
+
subscribe: (prop_types_default()).func.isRequired,
|
|
4320
|
+
state: prop_types_default().shape({
|
|
4321
|
+
primaryToolId: (prop_types_default()).string,
|
|
4322
|
+
toggles: prop_types_default().objectOf((prop_types_default()).bool),
|
|
4323
|
+
groups: prop_types_default().objectOf((prop_types_default()).object)
|
|
4324
|
+
}).isRequired
|
|
4325
|
+
}).isRequired
|
|
4326
|
+
}).isRequired
|
|
4327
|
+
}).isRequired
|
|
4328
|
+
};
|
|
4329
|
+
/* harmony default export */ const Toolbar_ToolbarButtonWithServices = (ToolbarButtonWithServices);
|
|
3657
4330
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getToolbarModule.tsx
|
|
3658
4331
|
|
|
3659
4332
|
|
|
@@ -3670,15 +4343,15 @@ function getToolbarModule(_ref) {
|
|
|
3670
4343
|
clickHandler: () => {}
|
|
3671
4344
|
}, {
|
|
3672
4345
|
name: 'ohif.action',
|
|
3673
|
-
defaultComponent:
|
|
4346
|
+
defaultComponent: Toolbar_ToolbarButtonWithServices,
|
|
3674
4347
|
clickHandler: () => {}
|
|
3675
4348
|
}, {
|
|
3676
4349
|
name: 'ohif.radioGroup',
|
|
3677
|
-
defaultComponent:
|
|
4350
|
+
defaultComponent: Toolbar_ToolbarButtonWithServices,
|
|
3678
4351
|
clickHandler: () => {}
|
|
3679
4352
|
}, {
|
|
3680
4353
|
name: 'ohif.splitButton',
|
|
3681
|
-
defaultComponent:
|
|
4354
|
+
defaultComponent: Toolbar_ToolbarSplitButtonWithServices,
|
|
3682
4355
|
clickHandler: () => {}
|
|
3683
4356
|
}, {
|
|
3684
4357
|
name: 'ohif.layoutSelector',
|
|
@@ -3686,7 +4359,7 @@ function getToolbarModule(_ref) {
|
|
|
3686
4359
|
clickHandler: (evt, clickedBtn, btnSectionName) => {}
|
|
3687
4360
|
}, {
|
|
3688
4361
|
name: 'ohif.toggle',
|
|
3689
|
-
defaultComponent:
|
|
4362
|
+
defaultComponent: Toolbar_ToolbarButtonWithServices,
|
|
3690
4363
|
clickHandler: () => {}
|
|
3691
4364
|
}];
|
|
3692
4365
|
}
|
|
@@ -3856,7 +4529,7 @@ function adaptItem(item, subProps) {
|
|
|
3856
4529
|
return newItem;
|
|
3857
4530
|
}
|
|
3858
4531
|
// EXTERNAL MODULE: ../../ui/src/components/ContextMenu/ContextMenu.tsx
|
|
3859
|
-
var ContextMenu = __webpack_require__(
|
|
4532
|
+
var ContextMenu = __webpack_require__(5638);
|
|
3860
4533
|
;// CONCATENATED MODULE: ../../../extensions/default/src/CustomizableContextMenu/ContextMenuController.tsx
|
|
3861
4534
|
|
|
3862
4535
|
|
|
@@ -3917,8 +4590,8 @@ class ContextMenuController {
|
|
|
3917
4590
|
defaultPosition: ContextMenuController._getDefaultPosition(defaultPointsPosition, event?.detail, viewportElement),
|
|
3918
4591
|
event,
|
|
3919
4592
|
content: ContextMenu/* default */.Z,
|
|
3920
|
-
// This naming is part of
|
|
3921
|
-
// Clicking outside
|
|
4593
|
+
// This naming is part of the uiDialogService convention
|
|
4594
|
+
// Clicking outside simply closes the dialog box.
|
|
3922
4595
|
onClickOutside: () => this.services.uiDialogService.dismiss({
|
|
3923
4596
|
id: 'context-menu'
|
|
3924
4597
|
}),
|
|
@@ -4065,10 +4738,10 @@ const defaultContextMenu = {
|
|
|
4065
4738
|
|
|
4066
4739
|
|
|
4067
4740
|
// EXTERNAL MODULE: ../../../node_modules/moment/moment.js
|
|
4068
|
-
var moment = __webpack_require__(
|
|
4741
|
+
var moment = __webpack_require__(71271);
|
|
4069
4742
|
var moment_default = /*#__PURE__*/__webpack_require__.n(moment);
|
|
4070
4743
|
// EXTERNAL MODULE: ../../../node_modules/react-window/dist/index.esm.js
|
|
4071
|
-
var index_esm = __webpack_require__(
|
|
4744
|
+
var index_esm = __webpack_require__(94614);
|
|
4072
4745
|
;// CONCATENATED MODULE: ../../../extensions/default/src/DicomTagBrowser/DicomTagTable.tsx
|
|
4073
4746
|
|
|
4074
4747
|
|
|
@@ -4093,34 +4766,34 @@ function ColumnHeaders(_ref) {
|
|
|
4093
4766
|
valueRef
|
|
4094
4767
|
} = _ref;
|
|
4095
4768
|
return /*#__PURE__*/react.createElement("div", {
|
|
4096
|
-
className: classnames_default()('
|
|
4769
|
+
className: classnames_default()('bg-secondary-dark ohif-scrollbar flex w-full flex-row overflow-y-scroll'),
|
|
4097
4770
|
style: rowVerticalPaddingStyle
|
|
4098
4771
|
}, /*#__PURE__*/react.createElement("div", {
|
|
4099
|
-
className: "
|
|
4772
|
+
className: "w-4/24 px-3"
|
|
4100
4773
|
}, /*#__PURE__*/react.createElement("label", {
|
|
4101
4774
|
ref: tagRef,
|
|
4102
|
-
className: "flex flex-
|
|
4775
|
+
className: "flex flex-1 select-none flex-col pl-1 text-lg text-white"
|
|
4103
4776
|
}, /*#__PURE__*/react.createElement("span", {
|
|
4104
4777
|
className: "flex flex-row items-center focus:outline-none"
|
|
4105
4778
|
}, "Tag"))), /*#__PURE__*/react.createElement("div", {
|
|
4106
|
-
className: "
|
|
4779
|
+
className: "w-2/24 px-3"
|
|
4107
4780
|
}, /*#__PURE__*/react.createElement("label", {
|
|
4108
4781
|
ref: vrRef,
|
|
4109
|
-
className: "flex flex-
|
|
4782
|
+
className: "flex flex-1 select-none flex-col pl-1 text-lg text-white"
|
|
4110
4783
|
}, /*#__PURE__*/react.createElement("span", {
|
|
4111
4784
|
className: "flex flex-row items-center focus:outline-none"
|
|
4112
4785
|
}, "VR"))), /*#__PURE__*/react.createElement("div", {
|
|
4113
|
-
className: "
|
|
4786
|
+
className: "w-6/24 px-3"
|
|
4114
4787
|
}, /*#__PURE__*/react.createElement("label", {
|
|
4115
4788
|
ref: keywordRef,
|
|
4116
|
-
className: "flex flex-
|
|
4789
|
+
className: "flex flex-1 select-none flex-col pl-1 text-lg text-white"
|
|
4117
4790
|
}, /*#__PURE__*/react.createElement("span", {
|
|
4118
4791
|
className: "flex flex-row items-center focus:outline-none"
|
|
4119
4792
|
}, "Keyword"))), /*#__PURE__*/react.createElement("div", {
|
|
4120
|
-
className: "
|
|
4793
|
+
className: "w-5/24 grow px-3"
|
|
4121
4794
|
}, /*#__PURE__*/react.createElement("label", {
|
|
4122
4795
|
ref: valueRef,
|
|
4123
|
-
className: "flex flex-
|
|
4796
|
+
className: "flex flex-1 select-none flex-col pl-1 text-lg text-white"
|
|
4124
4797
|
}, /*#__PURE__*/react.createElement("span", {
|
|
4125
4798
|
className: "flex flex-row items-center focus:outline-none"
|
|
4126
4799
|
}, "Value"))));
|
|
@@ -4193,16 +4866,16 @@ function DicomTagTable(_ref2) {
|
|
|
4193
4866
|
...style,
|
|
4194
4867
|
...rowStyle
|
|
4195
4868
|
},
|
|
4196
|
-
className: classnames_default()('hover:bg-secondary-main
|
|
4869
|
+
className: classnames_default()('hover:bg-secondary-main border-secondary-light flex w-full flex-row items-center break-all bg-black text-base transition duration-300', lineHeightClassName),
|
|
4197
4870
|
key: `DICOMTagRow-${index}`
|
|
4198
4871
|
}, /*#__PURE__*/react.createElement("div", {
|
|
4199
|
-
className: "
|
|
4872
|
+
className: "w-4/24 px-3"
|
|
4200
4873
|
}, row[0]), /*#__PURE__*/react.createElement("div", {
|
|
4201
|
-
className: "
|
|
4874
|
+
className: "w-2/24 px-3"
|
|
4202
4875
|
}, row[1]), /*#__PURE__*/react.createElement("div", {
|
|
4203
|
-
className: "
|
|
4876
|
+
className: "w-6/24 px-3"
|
|
4204
4877
|
}, row[2]), /*#__PURE__*/react.createElement("div", {
|
|
4205
|
-
className: "
|
|
4878
|
+
className: "w-5/24 grow px-3"
|
|
4206
4879
|
}, row[3]));
|
|
4207
4880
|
}, [rows]);
|
|
4208
4881
|
|
|
@@ -4240,7 +4913,7 @@ function DicomTagTable(_ref2) {
|
|
|
4240
4913
|
keywordRef: keywordRef,
|
|
4241
4914
|
valueRef: valueRef
|
|
4242
4915
|
}), /*#__PURE__*/react.createElement("div", {
|
|
4243
|
-
className: "m-auto
|
|
4916
|
+
className: "relative m-auto border-2 border-black bg-black",
|
|
4244
4917
|
style: {
|
|
4245
4918
|
height: '32rem'
|
|
4246
4919
|
}
|
|
@@ -4266,7 +4939,6 @@ function DicomTagTable(_ref2) {
|
|
|
4266
4939
|
|
|
4267
4940
|
|
|
4268
4941
|
|
|
4269
|
-
|
|
4270
4942
|
const {
|
|
4271
4943
|
ImageSet: DicomTagBrowser_ImageSet
|
|
4272
4944
|
} = src.classes;
|
|
@@ -4295,7 +4967,6 @@ const DicomTagBrowser = _ref => {
|
|
|
4295
4967
|
setSelectedDisplaySetInstanceUID(value.value);
|
|
4296
4968
|
setInstanceNumber(1);
|
|
4297
4969
|
};
|
|
4298
|
-
const searchInputRef = (0,react.useRef)(null);
|
|
4299
4970
|
const activeDisplaySet = displaySets.find(ds => ds.displaySetInstanceUID === selectedDisplaySetInstanceUID);
|
|
4300
4971
|
const isImageStack = _isImageStack(activeDisplaySet);
|
|
4301
4972
|
const showInstanceList = isImageStack && activeDisplaySet.images.length > 1;
|
|
@@ -4361,14 +5032,14 @@ const DicomTagBrowser = _ref => {
|
|
|
4361
5032
|
return /*#__PURE__*/react.createElement("div", {
|
|
4362
5033
|
className: "dicom-tag-browser-content"
|
|
4363
5034
|
}, /*#__PURE__*/react.createElement("div", {
|
|
4364
|
-
className: "flex flex-row
|
|
5035
|
+
className: "mb-6 flex flex-row items-center pl-1"
|
|
4365
5036
|
}, /*#__PURE__*/react.createElement("div", {
|
|
4366
|
-
className: "flex flex-row items-center
|
|
5037
|
+
className: "flex w-1/2 flex-row items-center"
|
|
4367
5038
|
}, /*#__PURE__*/react.createElement(ui_src/* Typography */.ZT, {
|
|
4368
5039
|
variant: "subtitle",
|
|
4369
5040
|
className: "mr-4"
|
|
4370
5041
|
}, "Series"), /*#__PURE__*/react.createElement("div", {
|
|
4371
|
-
className: "
|
|
5042
|
+
className: "mr-8 grow"
|
|
4372
5043
|
}, /*#__PURE__*/react.createElement(ui_src/* Select */.Ph, {
|
|
4373
5044
|
id: "display-set-selector",
|
|
4374
5045
|
isClearable: false,
|
|
@@ -4377,7 +5048,7 @@ const DicomTagBrowser = _ref => {
|
|
|
4377
5048
|
value: displaySetList.find(ds => ds.value === selectedDisplaySetInstanceUID),
|
|
4378
5049
|
className: "text-white"
|
|
4379
5050
|
}))), /*#__PURE__*/react.createElement("div", {
|
|
4380
|
-
className: "flex flex-row items-center
|
|
5051
|
+
className: "flex w-1/2 flex-row items-center"
|
|
4381
5052
|
}, showInstanceList && /*#__PURE__*/react.createElement(ui_src/* Typography */.ZT, {
|
|
4382
5053
|
variant: "subtitle",
|
|
4383
5054
|
className: "mr-4"
|
|
@@ -4396,32 +5067,14 @@ const DicomTagBrowser = _ref => {
|
|
|
4396
5067
|
labelPosition: "left",
|
|
4397
5068
|
trackColor: '#3a3f99'
|
|
4398
5069
|
})))), /*#__PURE__*/react.createElement("div", {
|
|
4399
|
-
className: "w-full
|
|
5070
|
+
className: "h-1 w-full bg-black"
|
|
4400
5071
|
}), /*#__PURE__*/react.createElement("div", {
|
|
4401
|
-
className: "
|
|
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",
|
|
5072
|
+
className: "my-3 flex w-1/2 flex-row"
|
|
5073
|
+
}, /*#__PURE__*/react.createElement(ui_src/* InputFilterText */.Xe, {
|
|
5074
|
+
className: "mr-8 block w-full",
|
|
4412
5075
|
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, {
|
|
5076
|
+
onDebounceChange: setFilterValue
|
|
5077
|
+
})), /*#__PURE__*/react.createElement(DicomTagBrowser_DicomTagTable, {
|
|
4425
5078
|
rows: filteredRows
|
|
4426
5079
|
}));
|
|
4427
5080
|
};
|
|
@@ -4594,61 +5247,62 @@ function _sortTagList(tagList) {
|
|
|
4594
5247
|
*/
|
|
4595
5248
|
const reuseCachedLayout = (state, hangingProtocolService, syncService) => {
|
|
4596
5249
|
const {
|
|
4597
|
-
|
|
4598
|
-
viewports,
|
|
4599
|
-
layout
|
|
5250
|
+
activeViewportId
|
|
4600
5251
|
} = state;
|
|
5252
|
+
const {
|
|
5253
|
+
protocol
|
|
5254
|
+
} = hangingProtocolService.getActiveProtocol();
|
|
4601
5255
|
const hpInfo = hangingProtocolService.getState();
|
|
4602
5256
|
const {
|
|
4603
5257
|
protocolId,
|
|
4604
5258
|
stageIndex,
|
|
4605
5259
|
activeStudyUID
|
|
4606
5260
|
} = hpInfo;
|
|
4607
|
-
const {
|
|
4608
|
-
protocol
|
|
4609
|
-
} = hangingProtocolService.getActiveProtocol();
|
|
4610
|
-
const stage = protocol.stages[stageIndex];
|
|
4611
|
-
const storeId = `${activeStudyUID}:${protocolId}:${stageIndex}`;
|
|
4612
5261
|
const syncState = syncService.getState();
|
|
4613
|
-
const cacheId = `${activeStudyUID}:${protocolId}`;
|
|
4614
5262
|
const viewportGridStore = {
|
|
4615
5263
|
...syncState.viewportGridStore
|
|
4616
5264
|
};
|
|
4617
|
-
const hangingProtocolStageIndexMap = {
|
|
4618
|
-
...syncState.hangingProtocolStageIndexMap
|
|
4619
|
-
};
|
|
4620
5265
|
const displaySetSelectorMap = {
|
|
4621
5266
|
...syncState.displaySetSelectorMap
|
|
4622
5267
|
};
|
|
5268
|
+
const stage = protocol.stages[stageIndex];
|
|
5269
|
+
const storeId = `${activeStudyUID}:${protocolId}:${stageIndex}`;
|
|
5270
|
+
const cacheId = `${activeStudyUID}:${protocolId}`;
|
|
5271
|
+
const hangingProtocolStageIndexMap = {
|
|
5272
|
+
...syncState.hangingProtocolStageIndexMap
|
|
5273
|
+
};
|
|
4623
5274
|
const {
|
|
4624
5275
|
rows,
|
|
4625
5276
|
columns
|
|
4626
5277
|
} = stage.viewportStructure.properties;
|
|
4627
|
-
const custom = stage.viewports.length !== state.viewports.
|
|
5278
|
+
const custom = stage.viewports.length !== state.viewports.size || state.layout.numRows !== rows || state.layout.numCols !== columns;
|
|
4628
5279
|
hangingProtocolStageIndexMap[cacheId] = hpInfo;
|
|
4629
5280
|
if (storeId && custom) {
|
|
4630
5281
|
viewportGridStore[storeId] = {
|
|
4631
5282
|
...state
|
|
4632
5283
|
};
|
|
4633
5284
|
}
|
|
4634
|
-
|
|
4635
|
-
const viewport = state.viewports[idx];
|
|
5285
|
+
state.viewports.forEach((viewport, viewportId) => {
|
|
4636
5286
|
const {
|
|
4637
5287
|
displaySetOptions,
|
|
4638
5288
|
displaySetInstanceUIDs
|
|
4639
5289
|
} = viewport;
|
|
4640
|
-
if (!displaySetOptions)
|
|
5290
|
+
if (!displaySetOptions) {
|
|
5291
|
+
return;
|
|
5292
|
+
}
|
|
4641
5293
|
for (let i = 0; i < displaySetOptions.length; i++) {
|
|
4642
5294
|
const displaySetUID = displaySetInstanceUIDs[i];
|
|
4643
|
-
if (!displaySetUID)
|
|
4644
|
-
|
|
5295
|
+
if (!displaySetUID) {
|
|
5296
|
+
continue;
|
|
5297
|
+
}
|
|
5298
|
+
if (viewportId === activeViewportId && i === 0) {
|
|
4645
5299
|
displaySetSelectorMap[`${activeStudyUID}:activeDisplaySet:0`] = displaySetUID;
|
|
4646
5300
|
}
|
|
4647
5301
|
if (displaySetOptions[i]?.id) {
|
|
4648
5302
|
displaySetSelectorMap[`${activeStudyUID}:${displaySetOptions[i].id}:${displaySetOptions[i].matchedDisplaySetsIndex || 0}`] = displaySetUID;
|
|
4649
5303
|
}
|
|
4650
5304
|
}
|
|
4651
|
-
}
|
|
5305
|
+
});
|
|
4652
5306
|
return {
|
|
4653
5307
|
hangingProtocolStageIndexMap,
|
|
4654
5308
|
viewportGridStore,
|
|
@@ -4660,22 +5314,24 @@ const reuseCachedLayout = (state, hangingProtocolService, syncService) => {
|
|
|
4660
5314
|
/**
|
|
4661
5315
|
* This find or create viewport is paired with the reduce results from
|
|
4662
5316
|
* below, and the action of this viewport is to look for previously filled
|
|
4663
|
-
* viewports, and to
|
|
5317
|
+
* viewports, and to reuse by position id. If there is no filled viewport,
|
|
4664
5318
|
* then one can be re-used from the display set if it isn't going to be displayed.
|
|
4665
5319
|
* @param hangingProtocolService - bound parameter supplied before using this
|
|
4666
5320
|
* @param viewportsByPosition - bound parameter supplied before using this
|
|
4667
|
-
* @param
|
|
5321
|
+
* @param position - the position in the grid to retrieve
|
|
4668
5322
|
* @param positionId - the current position on screen to retrieve
|
|
4669
5323
|
* @param options - the set of options used, so that subsequent calls can
|
|
4670
5324
|
* store state that is reset by the setLayout.
|
|
4671
5325
|
* This class uses the options to store the already viewed
|
|
4672
5326
|
* display sets, filling it initially with the pre-existing viewports.
|
|
4673
5327
|
*/
|
|
4674
|
-
const findViewportsByPosition_findOrCreateViewport = (hangingProtocolService, viewportsByPosition,
|
|
5328
|
+
const findViewportsByPosition_findOrCreateViewport = (hangingProtocolService, viewportsByPosition, position, positionId, options) => {
|
|
4675
5329
|
const byPositionViewport = viewportsByPosition?.[positionId];
|
|
4676
|
-
if (byPositionViewport)
|
|
4677
|
-
|
|
4678
|
-
|
|
5330
|
+
if (byPositionViewport) {
|
|
5331
|
+
return {
|
|
5332
|
+
...byPositionViewport
|
|
5333
|
+
};
|
|
5334
|
+
}
|
|
4679
5335
|
const {
|
|
4680
5336
|
protocolId,
|
|
4681
5337
|
stageIndex
|
|
@@ -4723,7 +5379,7 @@ const findViewportsByPosition = (state, _ref, syncService) => {
|
|
|
4723
5379
|
...syncState.viewportsByPosition
|
|
4724
5380
|
};
|
|
4725
5381
|
const initialInDisplay = [];
|
|
4726
|
-
|
|
5382
|
+
viewports.forEach(viewport => {
|
|
4727
5383
|
if (viewport.positionId) {
|
|
4728
5384
|
const storedViewport = {
|
|
4729
5385
|
...viewport,
|
|
@@ -4732,16 +5388,11 @@ const findViewportsByPosition = (state, _ref, syncService) => {
|
|
|
4732
5388
|
}
|
|
4733
5389
|
};
|
|
4734
5390
|
viewportsByPosition[viewport.positionId] = storedViewport;
|
|
4735
|
-
// The cache doesn't store the viewport options - it is only useful
|
|
4736
|
-
// for remembering the type of viewport and UIDs
|
|
4737
|
-
delete storedViewport.viewportId;
|
|
4738
|
-
delete storedViewport.viewportOptions.viewportId;
|
|
4739
5391
|
}
|
|
4740
|
-
}
|
|
5392
|
+
});
|
|
4741
5393
|
for (let row = 0; row < numRows; row++) {
|
|
4742
5394
|
for (let col = 0; col < numCols; col++) {
|
|
4743
|
-
const
|
|
4744
|
-
const positionId = viewports?.[pos]?.positionId || `${col}-${row}`;
|
|
5395
|
+
const positionId = `${col}-${row}`;
|
|
4745
5396
|
const viewport = viewportsByPosition[positionId];
|
|
4746
5397
|
if (viewport?.displaySetInstanceUIDs) {
|
|
4747
5398
|
initialInDisplay.push(...viewport.displaySetInstanceUIDs);
|
|
@@ -4756,8 +5407,8 @@ const findViewportsByPosition = (state, _ref, syncService) => {
|
|
|
4756
5407
|
};
|
|
4757
5408
|
};
|
|
4758
5409
|
/* harmony default export */ const src_findViewportsByPosition = (findViewportsByPosition);
|
|
4759
|
-
// EXTERNAL MODULE: ./index.js +
|
|
4760
|
-
var index = __webpack_require__(
|
|
5410
|
+
// EXTERNAL MODULE: ./index.js + 33 modules
|
|
5411
|
+
var index = __webpack_require__(59754);
|
|
4761
5412
|
;// CONCATENATED MODULE: ../../../extensions/default/src/commandsModule.ts
|
|
4762
5413
|
|
|
4763
5414
|
|
|
@@ -4859,7 +5510,9 @@ const commandsModule = _ref => {
|
|
|
4859
5510
|
stage
|
|
4860
5511
|
} = hangingProtocolService.getActiveProtocol();
|
|
4861
5512
|
const enableListener = button => {
|
|
4862
|
-
if (!button.id)
|
|
5513
|
+
if (!button.id) {
|
|
5514
|
+
return;
|
|
5515
|
+
}
|
|
4863
5516
|
const {
|
|
4864
5517
|
commands,
|
|
4865
5518
|
items
|
|
@@ -4868,14 +5521,16 @@ const commandsModule = _ref => {
|
|
|
4868
5521
|
items.forEach(enableListener);
|
|
4869
5522
|
}
|
|
4870
5523
|
const hpCommand = commands?.find?.(isHangingProtocolCommand);
|
|
4871
|
-
if (!hpCommand)
|
|
5524
|
+
if (!hpCommand) {
|
|
5525
|
+
return;
|
|
5526
|
+
}
|
|
4872
5527
|
const {
|
|
4873
5528
|
protocolId,
|
|
4874
5529
|
stageIndex,
|
|
4875
5530
|
stageId
|
|
4876
5531
|
} = hpCommand.commandOptions;
|
|
4877
5532
|
const isActive = (!protocolId || protocolId === protocol.id) && (stageIndex === undefined || stageIndex === toggleStageIndex) && (!stageId || stageId === stage.id);
|
|
4878
|
-
toolbarService.
|
|
5533
|
+
toolbarService.setToggled(button.id, isActive);
|
|
4879
5534
|
};
|
|
4880
5535
|
Object.values(toolbarService.getButtons()).forEach(enableListener);
|
|
4881
5536
|
},
|
|
@@ -4911,6 +5566,7 @@ const commandsModule = _ref => {
|
|
|
4911
5566
|
stageIndex,
|
|
4912
5567
|
reset = false
|
|
4913
5568
|
} = _ref3;
|
|
5569
|
+
const primaryToolBeforeHPChange = toolbarService.getActivePrimaryTool();
|
|
4914
5570
|
try {
|
|
4915
5571
|
// Stores in the state the display set selector id to displaySetUID mapping
|
|
4916
5572
|
// Pass in viewportId for the active viewport. This item will get set as
|
|
@@ -4927,7 +5583,7 @@ const commandsModule = _ref => {
|
|
|
4927
5583
|
displaySetSelectorMap
|
|
4928
5584
|
} = stateSyncReduce;
|
|
4929
5585
|
if (!protocolId) {
|
|
4930
|
-
//
|
|
5586
|
+
// Reuse the previous protocol id, and optionally stage
|
|
4931
5587
|
protocolId = hpInfo.protocolId;
|
|
4932
5588
|
if (stageId === undefined && stageIndex === undefined) {
|
|
4933
5589
|
stageIndex = hpInfo.stageIndex;
|
|
@@ -4970,22 +5626,44 @@ const commandsModule = _ref => {
|
|
|
4970
5626
|
delete displaySetSelectorMap[`${activeStudyUID || hpInfo.activeStudyUID}:activeDisplaySet:0`];
|
|
4971
5627
|
stateSyncService.store(stateSyncReduce);
|
|
4972
5628
|
// This is a default action applied
|
|
4973
|
-
|
|
5629
|
+
const {
|
|
5630
|
+
protocol
|
|
5631
|
+
} = hangingProtocolService.getActiveProtocol();
|
|
5632
|
+
actions.toggleHpTools();
|
|
5633
|
+
|
|
5634
|
+
// try to use the same tool in the new hanging protocol stage
|
|
5635
|
+
const primaryButton = toolbarService.getButton(primaryToolBeforeHPChange);
|
|
5636
|
+
if (primaryButton) {
|
|
5637
|
+
// is there any type of interaction on this button, if not it might be in the
|
|
5638
|
+
// items. This is a bit of a hack, but it works for now.
|
|
5639
|
+
|
|
5640
|
+
let interactionType = primaryButton.props?.interactionType;
|
|
5641
|
+
if (!interactionType && primaryButton.props?.items) {
|
|
5642
|
+
const firstItem = primaryButton.props.items[0];
|
|
5643
|
+
interactionType = firstItem.props?.interactionType || firstItem.props?.type;
|
|
5644
|
+
}
|
|
5645
|
+
if (interactionType) {
|
|
5646
|
+
toolbarService.recordInteraction({
|
|
5647
|
+
interactionType,
|
|
5648
|
+
...primaryButton.props
|
|
5649
|
+
});
|
|
5650
|
+
}
|
|
5651
|
+
}
|
|
5652
|
+
|
|
4974
5653
|
// Send the notification about updating the state
|
|
4975
5654
|
if (protocolId !== hpInfo.protocolId) {
|
|
4976
|
-
const {
|
|
4977
|
-
protocol
|
|
4978
|
-
} = hangingProtocolService.getActiveProtocol();
|
|
4979
5655
|
// The old protocol callbacks are used for turning off things
|
|
4980
5656
|
// like crosshairs when moving to the new HP
|
|
4981
5657
|
commandsManager.run(oldProtocol.callbacks?.onProtocolExit);
|
|
4982
5658
|
// The new protocol callback is used for things like
|
|
4983
5659
|
// activating modes etc.
|
|
4984
|
-
commandsManager.run(protocol.callbacks?.onProtocolEnter);
|
|
4985
5660
|
}
|
|
5661
|
+
|
|
5662
|
+
commandsManager.run(protocol.callbacks?.onProtocolEnter);
|
|
4986
5663
|
return true;
|
|
4987
5664
|
} catch (e) {
|
|
4988
|
-
|
|
5665
|
+
console.error(e);
|
|
5666
|
+
actions.toggleHpTools();
|
|
4989
5667
|
uiNotificationService.show({
|
|
4990
5668
|
title: 'Apply Hanging Protocol',
|
|
4991
5669
|
message: 'The hanging protocol could not be applied.',
|
|
@@ -5098,7 +5776,7 @@ const commandsModule = _ref => {
|
|
|
5098
5776
|
toggleOneUp() {
|
|
5099
5777
|
const viewportGridState = viewportGridService.getState();
|
|
5100
5778
|
const {
|
|
5101
|
-
|
|
5779
|
+
activeViewportId,
|
|
5102
5780
|
viewports,
|
|
5103
5781
|
layout
|
|
5104
5782
|
} = viewportGridState;
|
|
@@ -5106,7 +5784,7 @@ const commandsModule = _ref => {
|
|
|
5106
5784
|
displaySetInstanceUIDs,
|
|
5107
5785
|
displaySetOptions,
|
|
5108
5786
|
viewportOptions
|
|
5109
|
-
} = viewports
|
|
5787
|
+
} = viewports.get(activeViewportId);
|
|
5110
5788
|
if (layout.numCols === 1 && layout.numRows === 1) {
|
|
5111
5789
|
// The viewer is in one-up. Check if there is a state to restore/toggle back to.
|
|
5112
5790
|
const {
|
|
@@ -5117,24 +5795,33 @@ const commandsModule = _ref => {
|
|
|
5117
5795
|
}
|
|
5118
5796
|
// There is a state to toggle back to. The viewport that was
|
|
5119
5797
|
// originally toggled to one up was the former active viewport.
|
|
5120
|
-
const
|
|
5798
|
+
const viewportIdToUpdate = toggleOneUpViewportGridStore.activeViewportId;
|
|
5121
5799
|
|
|
5122
|
-
//
|
|
5123
|
-
//
|
|
5124
|
-
//
|
|
5125
|
-
//
|
|
5126
|
-
|
|
5800
|
+
// We are restoring the previous layout but taking into the account that
|
|
5801
|
+
// the current one up viewport might have a new displaySet dragged and dropped on it.
|
|
5802
|
+
// updatedViewportsViaHP below contains the viewports applicable to the HP that existed
|
|
5803
|
+
// prior to the toggle to one-up - including the updated viewports if a display
|
|
5804
|
+
// set swap were to have occurred.
|
|
5805
|
+
const updatedViewportsViaHP = displaySetInstanceUIDs.length > 1 ? [] : displaySetInstanceUIDs.map(displaySetInstanceUID => hangingProtocolService.getViewportsRequireUpdate(viewportIdToUpdate, displaySetInstanceUID)).flat();
|
|
5127
5806
|
|
|
5128
|
-
//
|
|
5807
|
+
// findOrCreateViewport returns either one of the updatedViewportsViaHP
|
|
5129
5808
|
// returned from the HP service OR if there is not one from the HP service then
|
|
5130
|
-
// simply returns what was in the previous state.
|
|
5131
|
-
const findOrCreateViewport =
|
|
5132
|
-
|
|
5133
|
-
|
|
5809
|
+
// simply returns what was in the previous state for a given position in the layout.
|
|
5810
|
+
const findOrCreateViewport = (position, positionId) => {
|
|
5811
|
+
// Find the viewport for the given position prior to the toggle to one-up.
|
|
5812
|
+
const preOneUpViewport = Array.from(toggleOneUpViewportGridStore.viewports.values()).find(viewport => viewport.positionId === positionId);
|
|
5813
|
+
|
|
5814
|
+
// Use the viewport id from before the toggle to one-up to find any updates to the viewport.
|
|
5815
|
+
const viewport = updatedViewportsViaHP.find(viewport => viewport.viewportId === preOneUpViewport.viewportId);
|
|
5816
|
+
return viewport ?
|
|
5817
|
+
// Use the applicable viewport from the HP updated viewports
|
|
5818
|
+
{
|
|
5134
5819
|
viewportOptions,
|
|
5135
5820
|
displaySetOptions,
|
|
5136
5821
|
...viewport
|
|
5137
|
-
} :
|
|
5822
|
+
} :
|
|
5823
|
+
// Use the previous viewport for the given position
|
|
5824
|
+
preOneUpViewport;
|
|
5138
5825
|
};
|
|
5139
5826
|
const layoutOptions = viewportGridService.getLayoutOptionsFromState(toggleOneUpViewportGridStore);
|
|
5140
5827
|
|
|
@@ -5142,7 +5829,7 @@ const commandsModule = _ref => {
|
|
|
5142
5829
|
viewportGridService.setLayout({
|
|
5143
5830
|
numRows: toggleOneUpViewportGridStore.layout.numRows,
|
|
5144
5831
|
numCols: toggleOneUpViewportGridStore.layout.numCols,
|
|
5145
|
-
|
|
5832
|
+
activeViewportId: viewportIdToUpdate,
|
|
5146
5833
|
layoutOptions,
|
|
5147
5834
|
findOrCreateViewport
|
|
5148
5835
|
});
|
|
@@ -5207,10 +5894,10 @@ const commandsModule = _ref => {
|
|
|
5207
5894
|
},
|
|
5208
5895
|
openDICOMTagViewer() {
|
|
5209
5896
|
const {
|
|
5210
|
-
|
|
5897
|
+
activeViewportId,
|
|
5211
5898
|
viewports
|
|
5212
5899
|
} = viewportGridService.getState();
|
|
5213
|
-
const activeViewportSpecificData = viewports
|
|
5900
|
+
const activeViewportSpecificData = viewports.get(activeViewportId);
|
|
5214
5901
|
const {
|
|
5215
5902
|
displaySetInstanceUIDs
|
|
5216
5903
|
} = activeViewportSpecificData;
|
|
@@ -5242,13 +5929,10 @@ const commandsModule = _ref => {
|
|
|
5242
5929
|
},
|
|
5243
5930
|
scrollActiveThumbnailIntoView: () => {
|
|
5244
5931
|
const {
|
|
5245
|
-
|
|
5932
|
+
activeViewportId,
|
|
5246
5933
|
viewports
|
|
5247
5934
|
} = viewportGridService.getState();
|
|
5248
|
-
|
|
5249
|
-
return;
|
|
5250
|
-
}
|
|
5251
|
-
const activeViewport = viewports[activeViewportIndex];
|
|
5935
|
+
const activeViewport = viewports.get(activeViewportId);
|
|
5252
5936
|
const activeDisplaySetInstanceUID = activeViewport.displaySetInstanceUIDs[0];
|
|
5253
5937
|
const thumbnailList = document.querySelector('#ohif-thumbnail-list');
|
|
5254
5938
|
if (!thumbnailList) {
|
|
@@ -5282,12 +5966,12 @@ const commandsModule = _ref => {
|
|
|
5282
5966
|
const currentDisplaySets = [...displaySetService.activeDisplaySets];
|
|
5283
5967
|
currentDisplaySets.sort(dsSortFn);
|
|
5284
5968
|
const {
|
|
5285
|
-
|
|
5969
|
+
activeViewportId,
|
|
5286
5970
|
viewports
|
|
5287
5971
|
} = viewportGridService.getState();
|
|
5288
5972
|
const {
|
|
5289
5973
|
displaySetInstanceUIDs
|
|
5290
|
-
} = viewports
|
|
5974
|
+
} = viewports.get(activeViewportId);
|
|
5291
5975
|
const activeDisplaySetIndex = currentDisplaySets.findIndex(displaySet => displaySetInstanceUIDs.includes(displaySet.displaySetInstanceUID));
|
|
5292
5976
|
let displaySetIndexToShow;
|
|
5293
5977
|
for (displaySetIndexToShow = activeDisplaySetIndex + direction; displaySetIndexToShow > -1 && displaySetIndexToShow < currentDisplaySets.length; displaySetIndexToShow += direction) {
|
|
@@ -5303,7 +5987,7 @@ const commandsModule = _ref => {
|
|
|
5303
5987
|
} = currentDisplaySets[displaySetIndexToShow];
|
|
5304
5988
|
let updatedViewports = [];
|
|
5305
5989
|
try {
|
|
5306
|
-
updatedViewports = hangingProtocolService.getViewportsRequireUpdate(
|
|
5990
|
+
updatedViewports = hangingProtocolService.getViewportsRequireUpdate(activeViewportId, displaySetInstanceUID);
|
|
5307
5991
|
} catch (error) {
|
|
5308
5992
|
console.warn(error);
|
|
5309
5993
|
uiNotificationService.show({
|
|
@@ -5397,7 +6081,6 @@ const commandsModule = _ref => {
|
|
|
5397
6081
|
* It is not included in the viewer mode by default.
|
|
5398
6082
|
*/
|
|
5399
6083
|
const hpMN = {
|
|
5400
|
-
hasUpdatedPriorsInformation: false,
|
|
5401
6084
|
id: '@ohif/mnGrid',
|
|
5402
6085
|
description: 'Has various hanging protocol grid layouts',
|
|
5403
6086
|
name: '2x2',
|
|
@@ -5418,7 +6101,8 @@ const hpMN = {
|
|
|
5418
6101
|
greaterThan: {
|
|
5419
6102
|
value: 0
|
|
5420
6103
|
}
|
|
5421
|
-
}
|
|
6104
|
+
},
|
|
6105
|
+
required: true
|
|
5422
6106
|
},
|
|
5423
6107
|
// This display set will select the specified items by preference
|
|
5424
6108
|
// It has no affect if nothing is specified in the URL.
|
|
@@ -5606,15 +6290,182 @@ const hpMN = {
|
|
|
5606
6290
|
numberOfPriorsReferenced: -1
|
|
5607
6291
|
};
|
|
5608
6292
|
/* harmony default export */ const hpMNGrid = (hpMN);
|
|
6293
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/hpCompare.ts
|
|
6294
|
+
const defaultDisplaySetSelector = {
|
|
6295
|
+
studyMatchingRules: [{
|
|
6296
|
+
// The priorInstance is a study counter that indicates what position this study is in
|
|
6297
|
+
// and the value comes from the options parameter.
|
|
6298
|
+
attribute: 'studyInstanceUIDsIndex',
|
|
6299
|
+
from: 'options',
|
|
6300
|
+
required: true,
|
|
6301
|
+
constraint: {
|
|
6302
|
+
equals: {
|
|
6303
|
+
value: 0
|
|
6304
|
+
}
|
|
6305
|
+
}
|
|
6306
|
+
}],
|
|
6307
|
+
seriesMatchingRules: [{
|
|
6308
|
+
attribute: 'numImageFrames',
|
|
6309
|
+
constraint: {
|
|
6310
|
+
greaterThan: {
|
|
6311
|
+
value: 0
|
|
6312
|
+
}
|
|
6313
|
+
}
|
|
6314
|
+
},
|
|
6315
|
+
// This display set will select the specified items by preference
|
|
6316
|
+
// It has no affect if nothing is specified in the URL.
|
|
6317
|
+
{
|
|
6318
|
+
attribute: 'isDisplaySetFromUrl',
|
|
6319
|
+
weight: 10,
|
|
6320
|
+
constraint: {
|
|
6321
|
+
equals: true
|
|
6322
|
+
}
|
|
6323
|
+
}]
|
|
6324
|
+
};
|
|
6325
|
+
const priorDisplaySetSelector = {
|
|
6326
|
+
studyMatchingRules: [{
|
|
6327
|
+
// The priorInstance is a study counter that indicates what position this study is in
|
|
6328
|
+
// and the value comes from the options parameter.
|
|
6329
|
+
attribute: 'studyInstanceUIDsIndex',
|
|
6330
|
+
from: 'options',
|
|
6331
|
+
required: true,
|
|
6332
|
+
constraint: {
|
|
6333
|
+
equals: {
|
|
6334
|
+
value: 1
|
|
6335
|
+
}
|
|
6336
|
+
}
|
|
6337
|
+
}],
|
|
6338
|
+
seriesMatchingRules: [{
|
|
6339
|
+
attribute: 'numImageFrames',
|
|
6340
|
+
constraint: {
|
|
6341
|
+
greaterThan: {
|
|
6342
|
+
value: 0
|
|
6343
|
+
}
|
|
6344
|
+
}
|
|
6345
|
+
},
|
|
6346
|
+
// This display set will select the specified items by preference
|
|
6347
|
+
// It has no affect if nothing is specified in the URL.
|
|
6348
|
+
{
|
|
6349
|
+
attribute: 'isDisplaySetFromUrl',
|
|
6350
|
+
weight: 10,
|
|
6351
|
+
constraint: {
|
|
6352
|
+
equals: true
|
|
6353
|
+
}
|
|
6354
|
+
}]
|
|
6355
|
+
};
|
|
6356
|
+
const currentDisplaySet = {
|
|
6357
|
+
id: 'defaultDisplaySetId'
|
|
6358
|
+
};
|
|
6359
|
+
const priorDisplaySet = {
|
|
6360
|
+
id: 'priorDisplaySetId'
|
|
6361
|
+
};
|
|
6362
|
+
const currentViewport0 = {
|
|
6363
|
+
viewportOptions: {
|
|
6364
|
+
toolGroupId: 'default',
|
|
6365
|
+
allowUnmatchedView: true
|
|
6366
|
+
},
|
|
6367
|
+
displaySets: [currentDisplaySet]
|
|
6368
|
+
};
|
|
6369
|
+
const currentViewport1 = {
|
|
6370
|
+
...currentViewport0,
|
|
6371
|
+
displaySets: [{
|
|
6372
|
+
...currentDisplaySet,
|
|
6373
|
+
matchedDisplaySetsIndex: 1
|
|
6374
|
+
}]
|
|
6375
|
+
};
|
|
6376
|
+
const priorViewport0 = {
|
|
6377
|
+
...currentViewport0,
|
|
6378
|
+
displaySets: [priorDisplaySet]
|
|
6379
|
+
};
|
|
6380
|
+
const priorViewport1 = {
|
|
6381
|
+
...priorViewport0,
|
|
6382
|
+
displaySets: [{
|
|
6383
|
+
...priorDisplaySet,
|
|
6384
|
+
matchedDisplaySetsIndex: 1
|
|
6385
|
+
}]
|
|
6386
|
+
};
|
|
6387
|
+
|
|
6388
|
+
/**
|
|
6389
|
+
* This hanging protocol can be activated on the primary mode by directly
|
|
6390
|
+
* referencing it in a URL or by directly including it within a mode, e.g.:
|
|
6391
|
+
* `&hangingProtocolId=@ohif/mnGrid` added to the viewer URL
|
|
6392
|
+
* It is not included in the viewer mode by default.
|
|
6393
|
+
*/
|
|
6394
|
+
const hpMNCompare = {
|
|
6395
|
+
id: '@ohif/hpCompare',
|
|
6396
|
+
description: 'Compare two studies in various layouts',
|
|
6397
|
+
name: 'Compare Two Studies',
|
|
6398
|
+
numberOfPriorsReferenced: 1,
|
|
6399
|
+
protocolMatchingRules: [{
|
|
6400
|
+
id: 'Two Studies',
|
|
6401
|
+
weight: 1000,
|
|
6402
|
+
attribute: 'StudyInstanceUID',
|
|
6403
|
+
// The 'from' attribute says where to get the 'attribute' value from. In this case
|
|
6404
|
+
// prior means the second study in the study list.
|
|
6405
|
+
from: 'prior',
|
|
6406
|
+
required: true,
|
|
6407
|
+
constraint: {
|
|
6408
|
+
notNull: true
|
|
6409
|
+
}
|
|
6410
|
+
}],
|
|
6411
|
+
toolGroupIds: ['default'],
|
|
6412
|
+
displaySetSelectors: {
|
|
6413
|
+
defaultDisplaySetId: defaultDisplaySetSelector,
|
|
6414
|
+
priorDisplaySetId: priorDisplaySetSelector
|
|
6415
|
+
},
|
|
6416
|
+
defaultViewport: {
|
|
6417
|
+
viewportOptions: {
|
|
6418
|
+
viewportType: 'stack',
|
|
6419
|
+
toolGroupId: 'default',
|
|
6420
|
+
allowUnmatchedView: true
|
|
6421
|
+
},
|
|
6422
|
+
displaySets: [{
|
|
6423
|
+
id: 'defaultDisplaySetId',
|
|
6424
|
+
matchedDisplaySetsIndex: -1
|
|
6425
|
+
}]
|
|
6426
|
+
},
|
|
6427
|
+
stages: [{
|
|
6428
|
+
name: '2x2',
|
|
6429
|
+
stageActivation: {
|
|
6430
|
+
enabled: {
|
|
6431
|
+
minViewportsMatched: 4
|
|
6432
|
+
}
|
|
6433
|
+
},
|
|
6434
|
+
viewportStructure: {
|
|
6435
|
+
layoutType: 'grid',
|
|
6436
|
+
properties: {
|
|
6437
|
+
rows: 2,
|
|
6438
|
+
columns: 2
|
|
6439
|
+
}
|
|
6440
|
+
},
|
|
6441
|
+
viewports: [currentViewport0, priorViewport0, currentViewport1, priorViewport1]
|
|
6442
|
+
}, {
|
|
6443
|
+
name: '2x1',
|
|
6444
|
+
stageActivation: {
|
|
6445
|
+
enabled: {
|
|
6446
|
+
minViewportsMatched: 2
|
|
6447
|
+
}
|
|
6448
|
+
},
|
|
6449
|
+
viewportStructure: {
|
|
6450
|
+
layoutType: 'grid',
|
|
6451
|
+
properties: {
|
|
6452
|
+
rows: 1,
|
|
6453
|
+
columns: 2
|
|
6454
|
+
}
|
|
6455
|
+
},
|
|
6456
|
+
viewports: [currentViewport0, priorViewport0]
|
|
6457
|
+
}]
|
|
6458
|
+
};
|
|
6459
|
+
/* harmony default export */ const hpCompare = (hpMNCompare);
|
|
5609
6460
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getHangingProtocolModule.js
|
|
5610
6461
|
|
|
6462
|
+
|
|
5611
6463
|
const defaultProtocol = {
|
|
5612
6464
|
id: 'default',
|
|
5613
6465
|
locked: true,
|
|
5614
6466
|
// Don't store this hanging protocol as it applies to the currently active
|
|
5615
6467
|
// display set by default
|
|
5616
6468
|
// cacheId: null,
|
|
5617
|
-
hasUpdatedPriorsInformation: false,
|
|
5618
6469
|
name: 'Default',
|
|
5619
6470
|
createdDate: '2021-02-23T19:22:08.894Z',
|
|
5620
6471
|
modifiedDate: '2023-04-01',
|
|
@@ -5679,6 +6530,7 @@ const defaultProtocol = {
|
|
|
5679
6530
|
viewports: [{
|
|
5680
6531
|
viewportOptions: {
|
|
5681
6532
|
viewportType: 'stack',
|
|
6533
|
+
viewportId: 'default',
|
|
5682
6534
|
toolGroupId: 'default',
|
|
5683
6535
|
// This will specify the initial image options index if it matches in the URL
|
|
5684
6536
|
// and will otherwise not specify anything.
|
|
@@ -5708,6 +6560,11 @@ function getHangingProtocolModule() {
|
|
|
5708
6560
|
{
|
|
5709
6561
|
name: hpMNGrid.id,
|
|
5710
6562
|
protocol: hpMNGrid
|
|
6563
|
+
},
|
|
6564
|
+
// Create a MxN comparison hanging protocol available by default
|
|
6565
|
+
{
|
|
6566
|
+
name: hpCompare.id,
|
|
6567
|
+
protocol: hpCompare
|
|
5711
6568
|
}];
|
|
5712
6569
|
}
|
|
5713
6570
|
/* harmony default export */ const src_getHangingProtocolModule = (getHangingProtocolModule);
|
|
@@ -5730,21 +6587,21 @@ function DataSourceSelector() {
|
|
|
5730
6587
|
height: '100%'
|
|
5731
6588
|
}
|
|
5732
6589
|
}, /*#__PURE__*/react.createElement("div", {
|
|
5733
|
-
className: "h-screen w-screen
|
|
6590
|
+
className: "flex h-screen w-screen items-center justify-center "
|
|
5734
6591
|
}, /*#__PURE__*/react.createElement("div", {
|
|
5735
|
-
className: "
|
|
6592
|
+
className: "bg-secondary-dark mx-auto space-y-2 rounded-lg py-8 px-8 drop-shadow-md"
|
|
5736
6593
|
}, /*#__PURE__*/react.createElement("img", {
|
|
5737
|
-
className: "
|
|
6594
|
+
className: "mx-auto block h-14",
|
|
5738
6595
|
src: "./ohif-logo.svg",
|
|
5739
6596
|
alt: "OHIF"
|
|
5740
6597
|
}), /*#__PURE__*/react.createElement("div", {
|
|
5741
|
-
className: "
|
|
6598
|
+
className: "space-y-2 pt-4 text-center"
|
|
5742
6599
|
}, dsConfigs.filter(it => it.sourceName !== 'dicomjson' && it.sourceName !== 'dicomlocal').map(ds => /*#__PURE__*/react.createElement("div", {
|
|
5743
6600
|
key: ds.sourceName
|
|
5744
6601
|
}, /*#__PURE__*/react.createElement("h1", {
|
|
5745
6602
|
className: "text-white"
|
|
5746
|
-
}, ds.friendlyName), /*#__PURE__*/react.createElement(ui_src/* Button */.zx, {
|
|
5747
|
-
type: ui_src/* ButtonEnums.type */.LZ.
|
|
6603
|
+
}, ds.configuration?.friendlyName || ds.friendlyName), /*#__PURE__*/react.createElement(ui_src/* Button */.zx, {
|
|
6604
|
+
type: ui_src/* ButtonEnums.type */.LZ.dt.primary,
|
|
5748
6605
|
className: classnames_default()('ml-2'),
|
|
5749
6606
|
onClick: () => {
|
|
5750
6607
|
navigate({
|
|
@@ -5755,10 +6612,442 @@ function DataSourceSelector() {
|
|
|
5755
6612
|
}, ds.sourceName), /*#__PURE__*/react.createElement("br", null)))))));
|
|
5756
6613
|
}
|
|
5757
6614
|
/* harmony default export */ const Panels_DataSourceSelector = (DataSourceSelector);
|
|
6615
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/Components/ItemListComponent.tsx
|
|
6616
|
+
|
|
6617
|
+
|
|
6618
|
+
|
|
6619
|
+
|
|
6620
|
+
function ItemListComponent(_ref) {
|
|
6621
|
+
let {
|
|
6622
|
+
itemLabel,
|
|
6623
|
+
itemList,
|
|
6624
|
+
onItemClicked
|
|
6625
|
+
} = _ref;
|
|
6626
|
+
const {
|
|
6627
|
+
t
|
|
6628
|
+
} = (0,es/* useTranslation */.$G)('DataSourceConfiguration');
|
|
6629
|
+
const [filterValue, setFilterValue] = (0,react.useState)('');
|
|
6630
|
+
(0,react.useEffect)(() => {
|
|
6631
|
+
setFilterValue('');
|
|
6632
|
+
}, [itemList]);
|
|
6633
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6634
|
+
className: "flex min-h-[1px] grow flex-col gap-4"
|
|
6635
|
+
}, /*#__PURE__*/react.createElement("div", {
|
|
6636
|
+
className: "flex items-center justify-between"
|
|
6637
|
+
}, /*#__PURE__*/react.createElement("div", {
|
|
6638
|
+
className: "text-primary-light text-[20px]"
|
|
6639
|
+
}, t(`Select ${itemLabel}`)), /*#__PURE__*/react.createElement(ui_src/* InputFilterText */.Xe, {
|
|
6640
|
+
className: "max-w-[40%] grow",
|
|
6641
|
+
value: filterValue,
|
|
6642
|
+
onDebounceChange: setFilterValue,
|
|
6643
|
+
placeholder: t(`Search ${itemLabel} list`)
|
|
6644
|
+
})), /*#__PURE__*/react.createElement("div", {
|
|
6645
|
+
className: "relative flex min-h-[1px] grow flex-col bg-black text-[14px]"
|
|
6646
|
+
}, itemList == null ? /*#__PURE__*/react.createElement(ui_src/* LoadingIndicatorProgress */.LE, {
|
|
6647
|
+
className: 'h-full w-full'
|
|
6648
|
+
}) : itemList.length === 0 ? /*#__PURE__*/react.createElement("div", {
|
|
6649
|
+
className: "text-primary-light flex h-full flex-col items-center justify-center px-6 py-4"
|
|
6650
|
+
}, /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
6651
|
+
name: "magnifier",
|
|
6652
|
+
className: "mb-4"
|
|
6653
|
+
}), /*#__PURE__*/react.createElement("span", null, t(`No ${itemLabel} available`))) : /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
|
|
6654
|
+
className: "bg-secondary-dark px-3 py-1.5 text-white"
|
|
6655
|
+
}, t(itemLabel)), /*#__PURE__*/react.createElement("div", {
|
|
6656
|
+
className: "ohif-scrollbar overflow-auto"
|
|
6657
|
+
}, itemList.filter(item => !filterValue || item.name.toLowerCase().includes(filterValue.toLowerCase())).map(item => {
|
|
6658
|
+
const border = 'rounded border-transparent border-b-secondary-light border-[1px] hover:border-primary-light';
|
|
6659
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6660
|
+
className: classnames_default()('hover:text-primary-light hover:bg-primary-dark group mx-2 flex items-center justify-between px-6 py-2', border),
|
|
6661
|
+
key: item.id
|
|
6662
|
+
}, /*#__PURE__*/react.createElement("div", null, item.name), /*#__PURE__*/react.createElement(ui_src/* Button */.zx, {
|
|
6663
|
+
onClick: () => onItemClicked(item),
|
|
6664
|
+
className: "invisible group-hover:visible",
|
|
6665
|
+
endIcon: /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
6666
|
+
name: "arrow-left"
|
|
6667
|
+
})
|
|
6668
|
+
}, t('Select')));
|
|
6669
|
+
})))));
|
|
6670
|
+
}
|
|
6671
|
+
/* harmony default export */ const Components_ItemListComponent = (ItemListComponent);
|
|
6672
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/Components/DataSourceConfigurationModalComponent.tsx
|
|
6673
|
+
|
|
6674
|
+
|
|
6675
|
+
|
|
6676
|
+
|
|
6677
|
+
|
|
6678
|
+
const NO_WRAP_ELLIPSIS_CLASS_NAMES = 'text-ellipsis whitespace-nowrap overflow-hidden';
|
|
6679
|
+
function DataSourceConfigurationModalComponent(_ref) {
|
|
6680
|
+
let {
|
|
6681
|
+
configurationAPI,
|
|
6682
|
+
configuredItems,
|
|
6683
|
+
onHide
|
|
6684
|
+
} = _ref;
|
|
6685
|
+
const {
|
|
6686
|
+
t
|
|
6687
|
+
} = (0,es/* useTranslation */.$G)('DataSourceConfiguration');
|
|
6688
|
+
const [itemList, setItemList] = (0,react.useState)();
|
|
6689
|
+
const [selectedItems, setSelectedItems] = (0,react.useState)(configuredItems);
|
|
6690
|
+
const [errorMessage, setErrorMessage] = (0,react.useState)();
|
|
6691
|
+
const [itemLabels] = (0,react.useState)(configurationAPI.getItemLabels());
|
|
6692
|
+
|
|
6693
|
+
// Determines whether to show the full/existing configuration for the data source.
|
|
6694
|
+
// A full or complete configuration is one where the data source (path) has the
|
|
6695
|
+
// maximum/required number of path items. Anything less is considered not complete and
|
|
6696
|
+
// the configuration starts from scratch (i.e. as if no items are configured at all).
|
|
6697
|
+
// TODO: consider configuration starting from a partial (i.e. non-empty) configuration
|
|
6698
|
+
const [showFullConfig, setShowFullConfig] = (0,react.useState)(itemLabels.length === configuredItems.length);
|
|
6699
|
+
|
|
6700
|
+
/**
|
|
6701
|
+
* The index of the selected item that is considered current and for which
|
|
6702
|
+
* its sub-items should be displayed in the items list component. When the
|
|
6703
|
+
* full/existing configuration for a data source is to be shown, the current
|
|
6704
|
+
* selected item is the second to last in the `selectedItems` list.
|
|
6705
|
+
*/
|
|
6706
|
+
const currentSelectedItemIndex = showFullConfig ? selectedItems.length - 2 : selectedItems.length - 1;
|
|
6707
|
+
(0,react.useEffect)(() => {
|
|
6708
|
+
let shouldUpdate = true;
|
|
6709
|
+
setErrorMessage(null);
|
|
6710
|
+
|
|
6711
|
+
// Clear out the former/old list while we fetch the next sub item list.
|
|
6712
|
+
setItemList(null);
|
|
6713
|
+
if (selectedItems.length === 0) {
|
|
6714
|
+
configurationAPI.initialize().then(items => {
|
|
6715
|
+
if (shouldUpdate) {
|
|
6716
|
+
setItemList(items);
|
|
6717
|
+
}
|
|
6718
|
+
}).catch(error => setErrorMessage(error.message));
|
|
6719
|
+
} else if (!showFullConfig && selectedItems.length === itemLabels.length) {
|
|
6720
|
+
// The last item to configure the data source (path) has been selected.
|
|
6721
|
+
configurationAPI.setCurrentItem(selectedItems[selectedItems.length - 1]);
|
|
6722
|
+
// We can hide the modal dialog now.
|
|
6723
|
+
onHide();
|
|
6724
|
+
} else {
|
|
6725
|
+
configurationAPI.setCurrentItem(selectedItems[currentSelectedItemIndex]).then(items => {
|
|
6726
|
+
if (shouldUpdate) {
|
|
6727
|
+
setItemList(items);
|
|
6728
|
+
}
|
|
6729
|
+
}).catch(error => setErrorMessage(error.message));
|
|
6730
|
+
}
|
|
6731
|
+
return () => {
|
|
6732
|
+
shouldUpdate = false;
|
|
6733
|
+
};
|
|
6734
|
+
}, [selectedItems, configurationAPI, onHide, itemLabels, showFullConfig, currentSelectedItemIndex]);
|
|
6735
|
+
const getSelectedItemCursorClasses = itemIndex => itemIndex !== itemLabels.length - 1 && itemIndex < selectedItems.length ? 'cursor-pointer' : 'cursor-auto';
|
|
6736
|
+
const getSelectedItemBackgroundClasses = itemIndex => itemIndex < selectedItems.length ? classnames_default()('bg-black/[.4]', itemIndex !== itemLabels.length - 1 ? 'hover:bg-transparent active:bg-secondary-dark' : '') : 'bg-transparent';
|
|
6737
|
+
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';
|
|
6738
|
+
const getSelectedItemTextClasses = itemIndex => itemIndex <= selectedItems.length ? 'text-primary-light' : 'text-primary-active';
|
|
6739
|
+
const getErrorComponent = () => {
|
|
6740
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6741
|
+
className: "flex min-h-[1px] grow flex-col gap-4"
|
|
6742
|
+
}, /*#__PURE__*/react.createElement("div", {
|
|
6743
|
+
className: "text-primary-light text-[20px]"
|
|
6744
|
+
}, t(`Error fetching ${itemLabels[selectedItems.length]} list`)), /*#__PURE__*/react.createElement("div", {
|
|
6745
|
+
className: "grow bg-black p-4 text-[14px]"
|
|
6746
|
+
}, errorMessage));
|
|
6747
|
+
};
|
|
6748
|
+
const getSelectedItemsComponent = () => {
|
|
6749
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6750
|
+
className: "flex gap-4"
|
|
6751
|
+
}, itemLabels.map((itemLabel, itemLabelIndex) => {
|
|
6752
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6753
|
+
key: itemLabel,
|
|
6754
|
+
className: classnames_default()('flex min-w-[1px] shrink basis-[200px] flex-col gap-1 rounded-md p-3.5', getSelectedItemCursorClasses(itemLabelIndex), getSelectedItemBackgroundClasses(itemLabelIndex), getSelectedItemBorderClasses(itemLabelIndex), getSelectedItemTextClasses(itemLabelIndex)),
|
|
6755
|
+
onClick: showFullConfig && itemLabelIndex < currentSelectedItemIndex || itemLabelIndex <= currentSelectedItemIndex ? () => {
|
|
6756
|
+
setShowFullConfig(false);
|
|
6757
|
+
setSelectedItems(theList => theList.slice(0, itemLabelIndex));
|
|
6758
|
+
} : undefined
|
|
6759
|
+
}, /*#__PURE__*/react.createElement("div", {
|
|
6760
|
+
className: "text- flex items-center gap-2"
|
|
6761
|
+
}, itemLabelIndex < selectedItems.length ? /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
6762
|
+
name: "status-tracked"
|
|
6763
|
+
}) : /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
6764
|
+
name: "status-untracked"
|
|
6765
|
+
}), /*#__PURE__*/react.createElement("div", {
|
|
6766
|
+
className: classnames_default()(NO_WRAP_ELLIPSIS_CLASS_NAMES)
|
|
6767
|
+
}, t(itemLabel))), itemLabelIndex < selectedItems.length ? /*#__PURE__*/react.createElement("div", {
|
|
6768
|
+
className: classnames_default()('text-[14px] text-white', NO_WRAP_ELLIPSIS_CLASS_NAMES)
|
|
6769
|
+
}, selectedItems[itemLabelIndex].name) : /*#__PURE__*/react.createElement("br", null));
|
|
6770
|
+
}));
|
|
6771
|
+
};
|
|
6772
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6773
|
+
className: "flex h-[calc(100vh-300px)] select-none flex-col gap-4 pt-0.5"
|
|
6774
|
+
}, getSelectedItemsComponent(), /*#__PURE__*/react.createElement("div", {
|
|
6775
|
+
className: "h-0.5 w-full shrink-0 bg-black"
|
|
6776
|
+
}), errorMessage ? getErrorComponent() : /*#__PURE__*/react.createElement(Components_ItemListComponent, {
|
|
6777
|
+
itemLabel: itemLabels[currentSelectedItemIndex + 1],
|
|
6778
|
+
itemList: itemList,
|
|
6779
|
+
onItemClicked: item => {
|
|
6780
|
+
setShowFullConfig(false);
|
|
6781
|
+
setSelectedItems(theList => [...theList.slice(0, currentSelectedItemIndex + 1), item]);
|
|
6782
|
+
}
|
|
6783
|
+
}));
|
|
6784
|
+
}
|
|
6785
|
+
/* harmony default export */ const Components_DataSourceConfigurationModalComponent = (DataSourceConfigurationModalComponent);
|
|
6786
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/Components/DataSourceConfigurationComponent.tsx
|
|
6787
|
+
|
|
6788
|
+
|
|
6789
|
+
|
|
6790
|
+
|
|
6791
|
+
function DataSourceConfigurationComponent(_ref) {
|
|
6792
|
+
let {
|
|
6793
|
+
servicesManager,
|
|
6794
|
+
extensionManager
|
|
6795
|
+
} = _ref;
|
|
6796
|
+
const {
|
|
6797
|
+
t
|
|
6798
|
+
} = (0,es/* useTranslation */.$G)('DataSourceConfiguration');
|
|
6799
|
+
const {
|
|
6800
|
+
show,
|
|
6801
|
+
hide
|
|
6802
|
+
} = (0,ui_src/* useModal */.dd)();
|
|
6803
|
+
const {
|
|
6804
|
+
customizationService
|
|
6805
|
+
} = servicesManager.services;
|
|
6806
|
+
const [configurationAPI, setConfigurationAPI] = (0,react.useState)();
|
|
6807
|
+
const [configuredItems, setConfiguredItems] = (0,react.useState)();
|
|
6808
|
+
(0,react.useEffect)(() => {
|
|
6809
|
+
let shouldUpdate = true;
|
|
6810
|
+
const dataSourceChangedCallback = async () => {
|
|
6811
|
+
const activeDataSourceDef = extensionManager.getActiveDataSourceDefinition();
|
|
6812
|
+
if (!activeDataSourceDef.configuration.configurationAPI) {
|
|
6813
|
+
return;
|
|
6814
|
+
}
|
|
6815
|
+
const {
|
|
6816
|
+
factory: configurationAPIFactory
|
|
6817
|
+
} = customizationService.get(activeDataSourceDef.configuration.configurationAPI) ?? {};
|
|
6818
|
+
if (!configurationAPIFactory) {
|
|
6819
|
+
return;
|
|
6820
|
+
}
|
|
6821
|
+
const configAPI = configurationAPIFactory(activeDataSourceDef.sourceName);
|
|
6822
|
+
setConfigurationAPI(configAPI);
|
|
6823
|
+
|
|
6824
|
+
// New configuration API means that the existing configured items must be cleared.
|
|
6825
|
+
setConfiguredItems(null);
|
|
6826
|
+
configAPI.getConfiguredItems().then(list => {
|
|
6827
|
+
if (shouldUpdate) {
|
|
6828
|
+
setConfiguredItems(list);
|
|
6829
|
+
}
|
|
6830
|
+
});
|
|
6831
|
+
};
|
|
6832
|
+
const sub = extensionManager.subscribe(extensionManager.EVENTS.ACTIVE_DATA_SOURCE_CHANGED, dataSourceChangedCallback);
|
|
6833
|
+
dataSourceChangedCallback();
|
|
6834
|
+
return () => {
|
|
6835
|
+
shouldUpdate = false;
|
|
6836
|
+
sub.unsubscribe();
|
|
6837
|
+
};
|
|
6838
|
+
}, []);
|
|
6839
|
+
const showConfigurationModal = (0,react.useCallback)(() => {
|
|
6840
|
+
show({
|
|
6841
|
+
content: Components_DataSourceConfigurationModalComponent,
|
|
6842
|
+
title: t('Configure Data Source'),
|
|
6843
|
+
contentProps: {
|
|
6844
|
+
configurationAPI,
|
|
6845
|
+
configuredItems,
|
|
6846
|
+
onHide: hide
|
|
6847
|
+
}
|
|
6848
|
+
});
|
|
6849
|
+
}, [configurationAPI, configuredItems]);
|
|
6850
|
+
(0,react.useEffect)(() => {
|
|
6851
|
+
if (!configurationAPI || !configuredItems) {
|
|
6852
|
+
return;
|
|
6853
|
+
}
|
|
6854
|
+
if (configuredItems.length !== configurationAPI.getItemLabels().length) {
|
|
6855
|
+
// Not the correct number of configured items, so show the modal to configure the data source.
|
|
6856
|
+
showConfigurationModal();
|
|
6857
|
+
}
|
|
6858
|
+
}, [configurationAPI, configuredItems, showConfigurationModal]);
|
|
6859
|
+
return configuredItems ? /*#__PURE__*/react.createElement("div", {
|
|
6860
|
+
className: "text-aqua-pale flex items-center overflow-hidden"
|
|
6861
|
+
}, /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
6862
|
+
name: "settings",
|
|
6863
|
+
className: "mr-2.5 h-3.5 w-3.5 shrink-0 cursor-pointer",
|
|
6864
|
+
onClick: showConfigurationModal
|
|
6865
|
+
}), configuredItems.map((item, itemIndex) => {
|
|
6866
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6867
|
+
key: itemIndex,
|
|
6868
|
+
className: "flex overflow-hidden"
|
|
6869
|
+
}, /*#__PURE__*/react.createElement("div", {
|
|
6870
|
+
key: itemIndex,
|
|
6871
|
+
className: "overflow-hidden text-ellipsis whitespace-nowrap"
|
|
6872
|
+
}, item.name), itemIndex !== configuredItems.length - 1 && /*#__PURE__*/react.createElement("div", {
|
|
6873
|
+
className: "px-2.5"
|
|
6874
|
+
}, "|"));
|
|
6875
|
+
})) : /*#__PURE__*/react.createElement(react.Fragment, null);
|
|
6876
|
+
}
|
|
6877
|
+
/* harmony default export */ const Components_DataSourceConfigurationComponent = (DataSourceConfigurationComponent);
|
|
6878
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/DataSourceConfigurationAPI/GoogleCloudDataSourceConfigurationAPI.ts
|
|
6879
|
+
/**
|
|
6880
|
+
* This file contains the implementations of BaseDataSourceConfigurationAPIItem
|
|
6881
|
+
* and BaseDataSourceConfigurationAPI for the Google cloud healthcare API. To
|
|
6882
|
+
* better understand this implementation and/or to implement custom implementations,
|
|
6883
|
+
* see the platform\core\src\types\DataSourceConfigurationAPI.ts and its JS doc
|
|
6884
|
+
* comments as a guide.
|
|
6885
|
+
*/
|
|
6886
|
+
/**
|
|
6887
|
+
* The various Google Cloud Healthcare path item types.
|
|
6888
|
+
*/
|
|
6889
|
+
var ItemType = /*#__PURE__*/function (ItemType) {
|
|
6890
|
+
ItemType[ItemType["projects"] = 0] = "projects";
|
|
6891
|
+
ItemType[ItemType["locations"] = 1] = "locations";
|
|
6892
|
+
ItemType[ItemType["datasets"] = 2] = "datasets";
|
|
6893
|
+
ItemType[ItemType["dicomStores"] = 3] = "dicomStores";
|
|
6894
|
+
return ItemType;
|
|
6895
|
+
}(ItemType || {});
|
|
6896
|
+
const initialUrl = 'https://cloudresourcemanager.googleapis.com/v1';
|
|
6897
|
+
const baseHealthcareUrl = 'https://healthcare.googleapis.com/v1';
|
|
6898
|
+
class GoogleCloudDataSourceConfigurationAPIItem {
|
|
6899
|
+
constructor() {
|
|
6900
|
+
this.id = void 0;
|
|
6901
|
+
this.name = void 0;
|
|
6902
|
+
this.url = void 0;
|
|
6903
|
+
this.itemType = void 0;
|
|
6904
|
+
}
|
|
6905
|
+
}
|
|
6906
|
+
class GoogleCloudDataSourceConfigurationAPI {
|
|
6907
|
+
constructor(dataSourceName, servicesManager, extensionManager) {
|
|
6908
|
+
this._extensionManager = void 0;
|
|
6909
|
+
this._fetchOptions = void 0;
|
|
6910
|
+
this._dataSourceName = void 0;
|
|
6911
|
+
this.getItemLabels = () => ['Project', 'Location', 'Data set', 'DICOM store'];
|
|
6912
|
+
this._dataSourceName = dataSourceName;
|
|
6913
|
+
this._extensionManager = extensionManager;
|
|
6914
|
+
const userAuthenticationService = servicesManager.services.userAuthenticationService;
|
|
6915
|
+
this._fetchOptions = {
|
|
6916
|
+
method: 'GET',
|
|
6917
|
+
headers: userAuthenticationService.getAuthorizationHeader()
|
|
6918
|
+
};
|
|
6919
|
+
}
|
|
6920
|
+
async initialize() {
|
|
6921
|
+
const url = `${initialUrl}/projects`;
|
|
6922
|
+
const projects = await GoogleCloudDataSourceConfigurationAPI._doFetch(url, ItemType.projects, this._fetchOptions);
|
|
6923
|
+
if (!projects?.length) {
|
|
6924
|
+
return [];
|
|
6925
|
+
}
|
|
6926
|
+
const projectItems = projects.map(project => {
|
|
6927
|
+
return {
|
|
6928
|
+
id: project.projectId,
|
|
6929
|
+
name: project.name,
|
|
6930
|
+
itemType: ItemType.projects,
|
|
6931
|
+
url: `${baseHealthcareUrl}/projects/${project.projectId}`
|
|
6932
|
+
};
|
|
6933
|
+
});
|
|
6934
|
+
return projectItems;
|
|
6935
|
+
}
|
|
6936
|
+
async setCurrentItem(anItem) {
|
|
6937
|
+
const googleCloudItem = anItem;
|
|
6938
|
+
if (googleCloudItem.itemType === ItemType.dicomStores) {
|
|
6939
|
+
// Last configurable item, so update the data source configuration.
|
|
6940
|
+
const url = `${googleCloudItem.url}/dicomWeb`;
|
|
6941
|
+
const dataSourceDefCopy = JSON.parse(JSON.stringify(this._extensionManager.getDataSourceDefinition(this._dataSourceName)));
|
|
6942
|
+
dataSourceDefCopy.configuration = {
|
|
6943
|
+
...dataSourceDefCopy.configuration,
|
|
6944
|
+
wadoUriRoot: url,
|
|
6945
|
+
qidoRoot: url,
|
|
6946
|
+
wadoRoot: url
|
|
6947
|
+
};
|
|
6948
|
+
this._extensionManager.updateDataSourceConfiguration(dataSourceDefCopy.sourceName, dataSourceDefCopy.configuration);
|
|
6949
|
+
return [];
|
|
6950
|
+
}
|
|
6951
|
+
const subItemType = googleCloudItem.itemType + 1;
|
|
6952
|
+
const subItemField = `${ItemType[subItemType]}`;
|
|
6953
|
+
const url = `${googleCloudItem.url}/${subItemField}`;
|
|
6954
|
+
const fetchedSubItems = await GoogleCloudDataSourceConfigurationAPI._doFetch(url, subItemType, this._fetchOptions);
|
|
6955
|
+
if (!fetchedSubItems?.length) {
|
|
6956
|
+
return [];
|
|
6957
|
+
}
|
|
6958
|
+
const subItems = fetchedSubItems.map(subItem => {
|
|
6959
|
+
const nameSplit = subItem.name.split('/');
|
|
6960
|
+
return {
|
|
6961
|
+
id: subItem.name,
|
|
6962
|
+
name: nameSplit[nameSplit.length - 1],
|
|
6963
|
+
itemType: subItemType,
|
|
6964
|
+
url: `${baseHealthcareUrl}/${subItem.name}`
|
|
6965
|
+
};
|
|
6966
|
+
});
|
|
6967
|
+
return subItems;
|
|
6968
|
+
}
|
|
6969
|
+
async getConfiguredItems() {
|
|
6970
|
+
const dataSourceDefinition = this._extensionManager.getDataSourceDefinition(this._dataSourceName);
|
|
6971
|
+
const url = dataSourceDefinition.configuration.wadoUriRoot;
|
|
6972
|
+
const projectsIndex = url.indexOf('projects');
|
|
6973
|
+
// Split the configured URL into (essentially) pairs (i.e. item type followed by item)
|
|
6974
|
+
// Explicitly: ['projects','aProject','locations','aLocation','datasets','aDataSet','dicomStores','aDicomStore']
|
|
6975
|
+
// Note that a partial configuration will have a subset of the above.
|
|
6976
|
+
const urlSplit = url.substring(projectsIndex).split('/');
|
|
6977
|
+
const configuredItems = [];
|
|
6978
|
+
for (let itemType = 0;
|
|
6979
|
+
// the number of configured items is either the max (4) or the number extracted from the url split
|
|
6980
|
+
itemType < 4 && (itemType + 1) * 2 < urlSplit.length; itemType += 1) {
|
|
6981
|
+
if (itemType === ItemType.projects) {
|
|
6982
|
+
const projectId = urlSplit[1];
|
|
6983
|
+
const projectUrl = `${initialUrl}/projects/${projectId}`;
|
|
6984
|
+
const data = await GoogleCloudDataSourceConfigurationAPI._doFetch(projectUrl, ItemType.projects, this._fetchOptions);
|
|
6985
|
+
const project = data[0];
|
|
6986
|
+
configuredItems.push({
|
|
6987
|
+
id: project.projectId,
|
|
6988
|
+
name: project.name,
|
|
6989
|
+
itemType: itemType,
|
|
6990
|
+
url: `${baseHealthcareUrl}/projects/${project.projectId}`
|
|
6991
|
+
});
|
|
6992
|
+
} else {
|
|
6993
|
+
const relativePath = urlSplit.slice(0, itemType * 2 + 2).join('/');
|
|
6994
|
+
configuredItems.push({
|
|
6995
|
+
id: relativePath,
|
|
6996
|
+
name: urlSplit[itemType * 2 + 1],
|
|
6997
|
+
itemType: itemType,
|
|
6998
|
+
url: `${baseHealthcareUrl}/${relativePath}`
|
|
6999
|
+
});
|
|
7000
|
+
}
|
|
7001
|
+
}
|
|
7002
|
+
return configuredItems;
|
|
7003
|
+
}
|
|
7004
|
+
|
|
7005
|
+
/**
|
|
7006
|
+
* Fetches an array of items the specified item type.
|
|
7007
|
+
* @param urlStr the fetch url
|
|
7008
|
+
* @param fetchItemType the type to fetch
|
|
7009
|
+
* @param fetchOptions the header options for the fetch (e.g. authorization header)
|
|
7010
|
+
* @param fetchSearchParams any search query params; currently only used for paging results
|
|
7011
|
+
* @returns an array of items of the specified type
|
|
7012
|
+
*/
|
|
7013
|
+
static async _doFetch(urlStr, fetchItemType) {
|
|
7014
|
+
let fetchOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
7015
|
+
let fetchSearchParams = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
7016
|
+
try {
|
|
7017
|
+
const url = new URL(urlStr);
|
|
7018
|
+
url.search = new URLSearchParams(fetchSearchParams).toString();
|
|
7019
|
+
const response = await fetch(url, fetchOptions);
|
|
7020
|
+
const data = await response.json();
|
|
7021
|
+
if (response.status >= 200 && response.status < 300 && data != null) {
|
|
7022
|
+
if (data.nextPageToken != null) {
|
|
7023
|
+
fetchSearchParams.pageToken = data.nextPageToken;
|
|
7024
|
+
const subPageData = await this._doFetch(urlStr, fetchItemType, fetchOptions, fetchSearchParams);
|
|
7025
|
+
data[ItemType[fetchItemType]] = data[ItemType[fetchItemType]].concat(subPageData);
|
|
7026
|
+
}
|
|
7027
|
+
if (data[ItemType[fetchItemType]]) {
|
|
7028
|
+
return data[ItemType[fetchItemType]];
|
|
7029
|
+
} else if (data.name) {
|
|
7030
|
+
return [data];
|
|
7031
|
+
} else {
|
|
7032
|
+
return [];
|
|
7033
|
+
}
|
|
7034
|
+
} else {
|
|
7035
|
+
const message = data?.error?.message || `Error returned from Google Cloud Healthcare: ${response.status} - ${response.statusText}`;
|
|
7036
|
+
throw new Error(message);
|
|
7037
|
+
}
|
|
7038
|
+
} catch (err) {
|
|
7039
|
+
const message = err?.message || 'Error occurred during fetch request.';
|
|
7040
|
+
throw new Error(message);
|
|
7041
|
+
}
|
|
7042
|
+
}
|
|
7043
|
+
}
|
|
7044
|
+
|
|
5758
7045
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getCustomizationModule.tsx
|
|
5759
7046
|
|
|
5760
7047
|
|
|
5761
7048
|
|
|
7049
|
+
|
|
7050
|
+
|
|
5762
7051
|
/**
|
|
5763
7052
|
*
|
|
5764
7053
|
* Note: this is an example of how the customization module can be used
|
|
@@ -5768,7 +7057,11 @@ function DataSourceSelector() {
|
|
|
5768
7057
|
* custom page for the user to view their profile, or to add a custom
|
|
5769
7058
|
* page for login etc.
|
|
5770
7059
|
*/
|
|
5771
|
-
function getCustomizationModule() {
|
|
7060
|
+
function getCustomizationModule(_ref) {
|
|
7061
|
+
let {
|
|
7062
|
+
servicesManager,
|
|
7063
|
+
extensionManager
|
|
7064
|
+
} = _ref;
|
|
5772
7065
|
return [{
|
|
5773
7066
|
name: 'helloPage',
|
|
5774
7067
|
value: {
|
|
@@ -5835,12 +7128,16 @@ function getCustomizationModule() {
|
|
|
5835
7128
|
{
|
|
5836
7129
|
id: 'ohif.overlayItem',
|
|
5837
7130
|
content: function (props) {
|
|
5838
|
-
if (this.condition && !this.condition(props))
|
|
7131
|
+
if (this.condition && !this.condition(props)) {
|
|
7132
|
+
return null;
|
|
7133
|
+
}
|
|
5839
7134
|
const {
|
|
5840
7135
|
instance
|
|
5841
7136
|
} = props;
|
|
5842
7137
|
const value = instance && this.attribute ? instance[this.attribute] : this.contentF && typeof this.contentF === 'function' ? this.contentF(props) : null;
|
|
5843
|
-
if (!value)
|
|
7138
|
+
if (!value) {
|
|
7139
|
+
return null;
|
|
7140
|
+
}
|
|
5844
7141
|
return /*#__PURE__*/react.createElement("span", {
|
|
5845
7142
|
className: "overlay-item flex flex-row",
|
|
5846
7143
|
style: {
|
|
@@ -5878,11 +7175,22 @@ function getCustomizationModule() {
|
|
|
5878
7175
|
}
|
|
5879
7176
|
return clonedObject;
|
|
5880
7177
|
}
|
|
7178
|
+
}, {
|
|
7179
|
+
// the generic GUI component to configure a data source using an instance of a BaseDataSourceConfigurationAPI
|
|
7180
|
+
id: 'ohif.dataSourceConfigurationComponent',
|
|
7181
|
+
component: Components_DataSourceConfigurationComponent.bind(null, {
|
|
7182
|
+
servicesManager,
|
|
7183
|
+
extensionManager
|
|
7184
|
+
})
|
|
7185
|
+
}, {
|
|
7186
|
+
// The factory for creating an instance of a BaseDataSourceConfigurationAPI for Google Cloud Healthcare
|
|
7187
|
+
id: 'ohif.dataSourceConfigurationAPI.google',
|
|
7188
|
+
factory: dataSourceName => new GoogleCloudDataSourceConfigurationAPI(dataSourceName, servicesManager, extensionManager)
|
|
5881
7189
|
}]
|
|
5882
7190
|
}];
|
|
5883
7191
|
}
|
|
5884
7192
|
// EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/calculate-suv/dist/calculate-suv.esm.js
|
|
5885
|
-
var calculate_suv_esm = __webpack_require__(
|
|
7193
|
+
var calculate_suv_esm = __webpack_require__(15747);
|
|
5886
7194
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getPTImageIdInstanceMetadata.ts
|
|
5887
7195
|
|
|
5888
7196
|
const getPTImageIdInstanceMetadata_metadataProvider = src["default"].classes.MetadataProvider;
|
|
@@ -5891,9 +7199,12 @@ function getPTImageIdInstanceMetadata(imageId) {
|
|
|
5891
7199
|
if (!dicomMetaData) {
|
|
5892
7200
|
throw new Error('dicom metadata are required');
|
|
5893
7201
|
}
|
|
5894
|
-
if (dicomMetaData.SeriesDate === undefined || dicomMetaData.SeriesTime === undefined || dicomMetaData.
|
|
7202
|
+
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
7203
|
throw new Error('required metadata are missing');
|
|
5896
7204
|
}
|
|
7205
|
+
if (dicomMetaData.PatientWeight === undefined) {
|
|
7206
|
+
console.warn('PatientWeight missing from PT instance metadata');
|
|
7207
|
+
}
|
|
5897
7208
|
const instanceMetadata = {
|
|
5898
7209
|
CorrectedImage: dicomMetaData.CorrectedImage,
|
|
5899
7210
|
Units: dicomMetaData.Units,
|
|
@@ -6064,6 +7375,8 @@ const handlePETImageMetadata = _ref2 => {
|
|
|
6064
7375
|
|
|
6065
7376
|
|
|
6066
7377
|
|
|
7378
|
+
|
|
7379
|
+
|
|
6067
7380
|
const defaultExtension = {
|
|
6068
7381
|
/**
|
|
6069
7382
|
* Only required property. Should be a unique value across all extensions.
|