@ohif/app 3.7.0-beta.9 → 3.7.0-beta.90
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.0edb40e9d9467dd3a189.js → 12.bundle.c51f9611deb347508909.js} +6 -6
- package/dist/{295.bundle.957b1159fec14b9199a1.js → 125.bundle.253395f320b72180da63.js} +6 -6
- package/dist/{351.bundle.0742237651aef9694a65.js → 181.bundle.73fc96c6b3ab1fabedc8.js} +226 -204
- package/dist/{351.css → 181.css} +1 -1
- package/dist/{744.bundle.c459c690581bc8a522d8.js → 19.bundle.a858382f8b2b4ba8d3cb.js} +240 -375
- package/dist/{606.bundle.5d876f5f3dd8287f0a28.js → 202.bundle.96bbb4547a346fe3921f.js} +1420 -750
- package/dist/{926.bundle.dbc9d0e591cb9217fda2.js → 220.bundle.f7e1c96c94245e70f2be.js} +990 -400
- package/dist/221.bundle.e2afcda7523b858d7edb.js +1723 -0
- package/dist/221.css +2 -0
- package/dist/{664.bundle.09abae984223969d1bde.js → 23.bundle.e008ad788170f2ed5569.js} +5 -6
- package/dist/{976.bundle.3f8bfb620791f4508420.js → 236.bundle.80a95257cee3c60edce1.js} +88 -104
- package/dist/{55.bundle.550a823e75eb608e8d5e.js → 250.bundle.4bebed43526c7e06344f.js} +52 -36
- package/dist/{973.bundle.5aa91607481865ead93f.js → 281.bundle.1d024348a9e68cabcb75.js} +18 -14
- package/dist/{82.bundle.978be6f7595202cd342b.js → 342.bundle.4949499cddc0e73aed86.js} +1765 -476
- package/dist/{404.bundle.83acdec604ed84f4b772.js → 359.bundle.293ba004301607ab27ff.js} +46 -131
- package/dist/{192.bundle.655fc9c5aeff41110aa9.js → 370.bundle.28d7737cee0832695236.js} +113 -99
- package/dist/{790.bundle.08e37fd3b64af8dd8e78.js → 410.bundle.492283c5b53922d55610.js} +11 -9
- package/dist/{151.bundle.31ea35044218837bf73f.js → 417.bundle.af0a207c29b109f84159.js} +49 -17
- package/dist/{569.bundle.c8e771a8d28e237b32be.js → 451.bundle.1c714bfb8b66d3a5adfb.js} +86 -106
- package/dist/{581.bundle.dc6197189f7c88c27d4c.js → 471.bundle.4aaec34d87b0c93687c1.js} +78 -99
- package/dist/{199.bundle.251f86c6e2eee85c49a5.js → 506.bundle.0e2f4377f64c0c78e5f9.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.b5c524ec95748332cb1d.js +532 -0
- package/dist/{984.bundle.0c8b7d8388a662ad5ebc.js → 663.bundle.5bed0c9a4ac30d4be7e9.js} +68 -38
- package/dist/{205.bundle.b5a473c200dcf2bbcdb4.js → 686.bundle.dccef1f36e4bc79bcc48.js} +6 -6
- package/dist/{50.bundle.bec52570fe00c2ccced8.js → 687.bundle.aefdf23ca61906e42117.js} +218 -9
- package/dist/{331.bundle.bd0c13931a21d53086c9.js → 743.bundle.4bfe6e562ffb2c22708f.js} +26281 -21326
- package/dist/{728.bundle.d13856835357400fef82.js → 774.bundle.7528cba56a1407357144.js} +95 -64
- package/dist/{381.bundle.0905e683605fcbc0895f.js → 775.bundle.2285e7e0e67878948c0d.js} +16 -16
- package/dist/{283.bundle.b43e001c27e02b0199aa.js → 782.bundle.98fa888b2e3f8ad7d37e.js} +117 -67
- package/dist/{642.bundle.1ab1e9ea67caeaedb189.js → 814.bundle.5ab8b6dbbade2e65975f.js} +6 -6
- package/dist/{799.bundle.758558e64147e5aad612.js → 822.bundle.00de6455c18be0307b41.js} +81 -34
- package/dist/831.bundle.83658f62fcc769043605.js +16700 -0
- package/dist/{707.bundle.9622c314b0ea3488d69a.js → 877.bundle.896122a750e45a7719ae.js} +1022 -708
- package/dist/{953.bundle.3b0189ebc11cf0946f18.js → 886.bundle.7324d84913daffb6a4c4.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.8c09a01840ab8aa32734.js} +7093 -987
- package/dist/{208.bundle.05451122c341d80d3c22.js → 99.bundle.eff869422ff7114f5403.js} +85 -104
- package/dist/_redirects +1 -1
- package/dist/app-config.js +35 -17
- package/dist/{app.bundle.d2ebd2fcc8b88864ebeb.js → app.bundle.ccda811fb90f522f9ec2.js} +71937 -66734
- package/dist/app.bundle.css +13 -12
- 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 +1 -1
- package/dist/{index.worker.1c69152d710fa7b84bce.worker.js → index.worker.e62ecca63f1a2e124230.worker.js} +2 -2
- package/dist/index.worker.e62ecca63f1a2e124230.worker.js.map +1 -0
- package/dist/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 +20 -22
- package/dist/616.bundle.d0581701281977bea39b.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 → 877.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 + 64 modules
|
|
35
|
+
var src = __webpack_require__(67869);
|
|
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,11 +820,17 @@ 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)
|
|
831
|
+
if (!valueElem) {
|
|
832
|
+
return false;
|
|
833
|
+
}
|
|
810
834
|
if (valueElem.vr == 'DA') {
|
|
811
835
|
return this.compareDateRange(testValue, valueElem.Value[0]);
|
|
812
836
|
}
|
|
@@ -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 + 99 modules
|
|
2066
|
+
var i18n_src = __webpack_require__(34708);
|
|
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.90";
|
|
2170
|
+
const commitHash = "eb22328fc05d06fc4411805e7a30f826659d796a";
|
|
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');
|
|
@@ -2404,9 +2511,9 @@ function PanelStudyBrowser(_ref) {
|
|
|
2404
2511
|
const isMounted = (0,react.useRef)(true);
|
|
2405
2512
|
const onDoubleClickThumbnailHandler = displaySetInstanceUID => {
|
|
2406
2513
|
let updatedViewports = [];
|
|
2407
|
-
const
|
|
2514
|
+
const viewportId = activeViewportId;
|
|
2408
2515
|
try {
|
|
2409
|
-
updatedViewports = hangingProtocolService.getViewportsRequireUpdate(
|
|
2516
|
+
updatedViewports = hangingProtocolService.getViewportsRequireUpdate(viewportId, displaySetInstanceUID);
|
|
2410
2517
|
} catch (error) {
|
|
2411
2518
|
console.warn(error);
|
|
2412
2519
|
uiNotificationService.show({
|
|
@@ -2427,6 +2534,10 @@ function PanelStudyBrowser(_ref) {
|
|
|
2427
2534
|
const qidoForStudyUID = await dataSource.query.studies.search({
|
|
2428
2535
|
studyInstanceUid: StudyInstanceUID
|
|
2429
2536
|
});
|
|
2537
|
+
if (!qidoForStudyUID?.length) {
|
|
2538
|
+
navigate('/notfoundstudy', '_self');
|
|
2539
|
+
throw new Error('Invalid study URL');
|
|
2540
|
+
}
|
|
2430
2541
|
let qidoStudiesForPatient = qidoForStudyUID;
|
|
2431
2542
|
|
|
2432
2543
|
// try to fetch the prior studies based on the patientID if the
|
|
@@ -2457,8 +2568,7 @@ function PanelStudyBrowser(_ref) {
|
|
|
2457
2568
|
});
|
|
2458
2569
|
}
|
|
2459
2570
|
StudyInstanceUIDs.forEach(sid => fetchStudiesForPatient(sid));
|
|
2460
|
-
|
|
2461
|
-
}, [StudyInstanceUIDs, getStudiesForPatientByMRN]);
|
|
2571
|
+
}, [StudyInstanceUIDs, dataSource, getStudiesForPatientByMRN, navigate]);
|
|
2462
2572
|
|
|
2463
2573
|
// // ~~ Initial Thumbnails
|
|
2464
2574
|
(0,react.useEffect)(() => {
|
|
@@ -2470,24 +2580,25 @@ function PanelStudyBrowser(_ref) {
|
|
|
2470
2580
|
const imageId = imageIds[Math.floor(imageIds.length / 2)];
|
|
2471
2581
|
|
|
2472
2582
|
// 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
|
-
}
|
|
2583
|
+
if (!imageId || displaySet?.unsupported) {
|
|
2584
|
+
return;
|
|
2484
2585
|
}
|
|
2586
|
+
// When the image arrives, render it and store the result in the thumbnailImgSrcMap
|
|
2587
|
+
newImageSrcEntry[dSet.displaySetInstanceUID] = await getImageSrc(imageId);
|
|
2588
|
+
if (!isMounted.current) {
|
|
2589
|
+
return;
|
|
2590
|
+
}
|
|
2591
|
+
setThumbnailImageSrcMap(prevState => {
|
|
2592
|
+
return {
|
|
2593
|
+
...prevState,
|
|
2594
|
+
...newImageSrcEntry
|
|
2595
|
+
};
|
|
2596
|
+
});
|
|
2485
2597
|
});
|
|
2486
2598
|
return () => {
|
|
2487
2599
|
isMounted.current = false;
|
|
2488
2600
|
};
|
|
2489
|
-
|
|
2490
|
-
}, []);
|
|
2601
|
+
}, [StudyInstanceUIDs, dataSource, displaySetService, getImageSrc]);
|
|
2491
2602
|
|
|
2492
2603
|
// ~~ displaySets
|
|
2493
2604
|
(0,react.useEffect)(() => {
|
|
@@ -2496,50 +2607,59 @@ function PanelStudyBrowser(_ref) {
|
|
|
2496
2607
|
const mappedDisplaySets = _mapDisplaySets(currentDisplaySets, thumbnailImageSrcMap);
|
|
2497
2608
|
sortStudyInstances(mappedDisplaySets);
|
|
2498
2609
|
setDisplaySets(mappedDisplaySets);
|
|
2499
|
-
|
|
2500
|
-
}, [thumbnailImageSrcMap]);
|
|
2610
|
+
}, [StudyInstanceUIDs, thumbnailImageSrcMap, displaySetService]);
|
|
2501
2611
|
|
|
2502
2612
|
// ~~ subscriptions --> displaySets
|
|
2503
2613
|
(0,react.useEffect)(() => {
|
|
2504
2614
|
// DISPLAY_SETS_ADDED returns an array of DisplaySets that were added
|
|
2505
2615
|
const SubscriptionDisplaySetsAdded = displaySetService.subscribe(displaySetService.EVENTS.DISPLAY_SETS_ADDED, data => {
|
|
2506
2616
|
const {
|
|
2507
|
-
displaySetsAdded
|
|
2617
|
+
displaySetsAdded,
|
|
2618
|
+
options
|
|
2508
2619
|
} = data;
|
|
2509
2620
|
displaySetsAdded.forEach(async dSet => {
|
|
2510
2621
|
const newImageSrcEntry = {};
|
|
2511
2622
|
const displaySet = displaySetService.getDisplaySetByUID(dSet.displaySetInstanceUID);
|
|
2623
|
+
if (displaySet?.unsupported) {
|
|
2624
|
+
return;
|
|
2625
|
+
}
|
|
2512
2626
|
const imageIds = dataSource.getImageIdsForDisplaySet(displaySet);
|
|
2513
2627
|
const imageId = imageIds[Math.floor(imageIds.length / 2)];
|
|
2514
2628
|
|
|
2515
2629
|
// 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
|
-
}
|
|
2630
|
+
if (!imageId) {
|
|
2631
|
+
return;
|
|
2527
2632
|
}
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2633
|
+
// When the image arrives, render it and store the result in the thumbnailImgSrcMap
|
|
2634
|
+
newImageSrcEntry[dSet.displaySetInstanceUID] = await getImageSrc(imageId, dSet.initialViewport);
|
|
2635
|
+
setThumbnailImageSrcMap(prevState => {
|
|
2636
|
+
return {
|
|
2637
|
+
...prevState,
|
|
2638
|
+
...newImageSrcEntry
|
|
2639
|
+
};
|
|
2640
|
+
});
|
|
2641
|
+
});
|
|
2642
|
+
});
|
|
2643
|
+
return () => {
|
|
2644
|
+
SubscriptionDisplaySetsAdded.unsubscribe();
|
|
2645
|
+
};
|
|
2646
|
+
}, [getImageSrc, dataSource, displaySetService]);
|
|
2647
|
+
(0,react.useEffect)(() => {
|
|
2531
2648
|
// TODO: Will this always hold _all_ the displaySets we care about?
|
|
2532
2649
|
// DISPLAY_SETS_CHANGED returns `DisplaySerService.activeDisplaySets`
|
|
2533
2650
|
const SubscriptionDisplaySetsChanged = displaySetService.subscribe(displaySetService.EVENTS.DISPLAY_SETS_CHANGED, changedDisplaySets => {
|
|
2534
2651
|
const mappedDisplaySets = _mapDisplaySets(changedDisplaySets, thumbnailImageSrcMap);
|
|
2535
2652
|
setDisplaySets(mappedDisplaySets);
|
|
2536
2653
|
});
|
|
2654
|
+
const SubscriptionDisplaySetMetaDataInvalidated = displaySetService.subscribe(displaySetService.EVENTS.DISPLAY_SET_SERIES_METADATA_INVALIDATED, () => {
|
|
2655
|
+
const mappedDisplaySets = _mapDisplaySets(displaySetService.getActiveDisplaySets(), thumbnailImageSrcMap);
|
|
2656
|
+
setDisplaySets(mappedDisplaySets);
|
|
2657
|
+
});
|
|
2537
2658
|
return () => {
|
|
2538
|
-
SubscriptionDisplaySetsAdded.unsubscribe();
|
|
2539
2659
|
SubscriptionDisplaySetsChanged.unsubscribe();
|
|
2660
|
+
SubscriptionDisplaySetMetaDataInvalidated.unsubscribe();
|
|
2540
2661
|
};
|
|
2541
|
-
|
|
2542
|
-
}, []);
|
|
2662
|
+
}, [StudyInstanceUIDs, thumbnailImageSrcMap, displaySetService]);
|
|
2543
2663
|
const tabs = _createStudyBrowserTabs(StudyInstanceUIDs, studyDisplayList, displaySets);
|
|
2544
2664
|
|
|
2545
2665
|
// TODO: Should not fire this on "close"
|
|
@@ -2554,7 +2674,7 @@ function PanelStudyBrowser(_ref) {
|
|
|
2554
2674
|
requestDisplaySetCreationForStudy(displaySetService, StudyInstanceUID, madeInClient);
|
|
2555
2675
|
}
|
|
2556
2676
|
}
|
|
2557
|
-
const activeDisplaySetInstanceUIDs = viewports
|
|
2677
|
+
const activeDisplaySetInstanceUIDs = viewports.get(activeViewportId)?.displaySetInstanceUIDs;
|
|
2558
2678
|
return /*#__PURE__*/react.createElement(ui_src/* StudyBrowser */.eX, {
|
|
2559
2679
|
tabs: tabs,
|
|
2560
2680
|
servicesManager: servicesManager,
|
|
@@ -2605,7 +2725,7 @@ function _mapDisplaySets(displaySets, thumbnailImageSrcMap) {
|
|
|
2605
2725
|
const thumbnailNoImageDisplaySets = [];
|
|
2606
2726
|
displaySets.filter(ds => !ds.excludeFromThumbnailBrowser).forEach(ds => {
|
|
2607
2727
|
const imageSrc = thumbnailImageSrcMap[ds.displaySetInstanceUID];
|
|
2608
|
-
const componentType = _getComponentType(ds
|
|
2728
|
+
const componentType = _getComponentType(ds);
|
|
2609
2729
|
const array = componentType === 'thumbnail' ? thumbnailDisplaySets : thumbnailNoImageDisplaySets;
|
|
2610
2730
|
array.push({
|
|
2611
2731
|
displaySetInstanceUID: ds.displaySetInstanceUID,
|
|
@@ -2617,21 +2737,23 @@ function _mapDisplaySets(displaySets, thumbnailImageSrcMap) {
|
|
|
2617
2737
|
numInstances: ds.numImageFrames,
|
|
2618
2738
|
countIcon: ds.countIcon,
|
|
2619
2739
|
StudyInstanceUID: ds.StudyInstanceUID,
|
|
2740
|
+
messages: ds.messages,
|
|
2620
2741
|
componentType,
|
|
2621
2742
|
imageSrc,
|
|
2622
2743
|
dragData: {
|
|
2623
2744
|
type: 'displayset',
|
|
2624
2745
|
displaySetInstanceUID: ds.displaySetInstanceUID
|
|
2625
2746
|
// .. Any other data to pass
|
|
2626
|
-
}
|
|
2747
|
+
},
|
|
2748
|
+
|
|
2749
|
+
isHydratedForDerivedDisplaySet: ds.isHydrated
|
|
2627
2750
|
});
|
|
2628
2751
|
});
|
|
2629
|
-
|
|
2630
2752
|
return [...thumbnailDisplaySets, ...thumbnailNoImageDisplaySets];
|
|
2631
2753
|
}
|
|
2632
2754
|
const thumbnailNoImageModalities = ['SR', 'SEG', 'SM', 'RTSTRUCT', 'RTPLAN', 'RTDOSE'];
|
|
2633
|
-
function _getComponentType(
|
|
2634
|
-
if (thumbnailNoImageModalities.includes(Modality)) {
|
|
2755
|
+
function _getComponentType(ds) {
|
|
2756
|
+
if (thumbnailNoImageModalities.includes(ds.Modality) || ds?.unsupported) {
|
|
2635
2757
|
// TODO probably others.
|
|
2636
2758
|
return 'thumbnailNoImage';
|
|
2637
2759
|
}
|
|
@@ -2798,7 +2920,7 @@ function ActionButtons(_ref) {
|
|
|
2798
2920
|
const {
|
|
2799
2921
|
t
|
|
2800
2922
|
} = (0,es/* useTranslation */.$G)('MeasurementTable');
|
|
2801
|
-
return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement(ui_src/*
|
|
2923
|
+
return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement(ui_src/* LegacyButtonGroup */.HO, {
|
|
2802
2924
|
color: "black",
|
|
2803
2925
|
size: "inherit"
|
|
2804
2926
|
}, /*#__PURE__*/react.createElement(ui_src/* LegacyButton */.mN, {
|
|
@@ -2819,7 +2941,7 @@ ActionButtons.defaultProps = {
|
|
|
2819
2941
|
};
|
|
2820
2942
|
/* harmony default export */ const Panels_ActionButtons = (ActionButtons);
|
|
2821
2943
|
// EXTERNAL MODULE: ../../../node_modules/lodash.debounce/index.js
|
|
2822
|
-
var lodash_debounce = __webpack_require__(
|
|
2944
|
+
var lodash_debounce = __webpack_require__(8324);
|
|
2823
2945
|
var lodash_debounce_default = /*#__PURE__*/__webpack_require__.n(lodash_debounce);
|
|
2824
2946
|
;// CONCATENATED MODULE: ../../../extensions/default/src/Panels/createReportDialogPrompt.tsx
|
|
2825
2947
|
/* eslint-disable react/display-name */
|
|
@@ -2906,11 +3028,11 @@ function createReportDialogPrompt(uiDialogService, _ref) {
|
|
|
2906
3028
|
actions: [{
|
|
2907
3029
|
id: 'cancel',
|
|
2908
3030
|
text: 'Cancel',
|
|
2909
|
-
type: ui_src/* ButtonEnums.type */.LZ.
|
|
3031
|
+
type: ui_src/* ButtonEnums.type */.LZ.dt.secondary
|
|
2910
3032
|
}, {
|
|
2911
3033
|
id: 'save',
|
|
2912
3034
|
text: 'Save',
|
|
2913
|
-
type: ui_src/* ButtonEnums.type */.LZ.
|
|
3035
|
+
type: ui_src/* ButtonEnums.type */.LZ.dt.primary
|
|
2914
3036
|
}],
|
|
2915
3037
|
// TODO: Should be on button press...
|
|
2916
3038
|
onSubmit: _handleFormSubmit,
|
|
@@ -2939,7 +3061,7 @@ function createReportDialogPrompt(uiDialogService, _ref) {
|
|
|
2939
3061
|
};
|
|
2940
3062
|
return /*#__PURE__*/react.createElement(react.Fragment, null, dataSourcesOpts.length > 1 && /*#__PURE__*/react.createElement(ui_src/* Select */.Ph, {
|
|
2941
3063
|
closeMenuOnSelect: true,
|
|
2942
|
-
className: "mr-2 bg-black
|
|
3064
|
+
className: "border-primary-main mr-2 bg-black",
|
|
2943
3065
|
options: dataSourcesOpts,
|
|
2944
3066
|
placeholder: dataSourcesOpts.find(option => option.value === value.dataSourceName).placeHolder,
|
|
2945
3067
|
value: value.dataSourceName,
|
|
@@ -2954,7 +3076,7 @@ function createReportDialogPrompt(uiDialogService, _ref) {
|
|
|
2954
3076
|
autoFocus: true,
|
|
2955
3077
|
label: "Enter the report name",
|
|
2956
3078
|
labelClassName: "text-white text-[14px] leading-[1.2]",
|
|
2957
|
-
className: "
|
|
3079
|
+
className: "border-primary-main bg-black",
|
|
2958
3080
|
type: "text",
|
|
2959
3081
|
value: value.label,
|
|
2960
3082
|
onChange: onChangeHandler,
|
|
@@ -2973,12 +3095,13 @@ function createReportDialogPrompt(uiDialogService, _ref) {
|
|
|
2973
3095
|
/**
|
|
2974
3096
|
*
|
|
2975
3097
|
* @param {*} servicesManager
|
|
2976
|
-
* @param {*} dataSource
|
|
2977
|
-
* @param {*} measurements
|
|
2978
|
-
* @param {*} options
|
|
2979
|
-
* @returns {string[]} displaySetInstanceUIDs
|
|
2980
3098
|
*/
|
|
2981
|
-
async function createReportAsync(
|
|
3099
|
+
async function createReportAsync(_ref) {
|
|
3100
|
+
let {
|
|
3101
|
+
servicesManager,
|
|
3102
|
+
getReport,
|
|
3103
|
+
reportType = 'measurement'
|
|
3104
|
+
} = _ref;
|
|
2982
3105
|
const {
|
|
2983
3106
|
displaySetService,
|
|
2984
3107
|
uiNotificationService,
|
|
@@ -2988,32 +3111,27 @@ async function createReportAsync(servicesManager, commandsManager, dataSource, m
|
|
|
2988
3111
|
showOverlay: true,
|
|
2989
3112
|
isDraggable: false,
|
|
2990
3113
|
centralize: true,
|
|
2991
|
-
// TODO: Create a loading indicator component + zeplin design?
|
|
2992
3114
|
content: Loading
|
|
2993
3115
|
});
|
|
2994
3116
|
try {
|
|
2995
|
-
const naturalizedReport = await
|
|
2996
|
-
measurementData: measurements,
|
|
2997
|
-
dataSource,
|
|
2998
|
-
additionalFindingTypes: ['ArrowAnnotate'],
|
|
2999
|
-
options
|
|
3000
|
-
}, 'CORNERSTONE_STRUCTURED_REPORT');
|
|
3117
|
+
const naturalizedReport = await getReport();
|
|
3001
3118
|
|
|
3002
3119
|
// The "Mode" route listens for DicomMetadataStore changes
|
|
3003
3120
|
// When a new instance is added, it listens and
|
|
3004
3121
|
// automatically calls makeDisplaySets
|
|
3005
3122
|
src.DicomMetadataStore.addInstances([naturalizedReport], true);
|
|
3006
|
-
const
|
|
3123
|
+
const displaySet = displaySetService.getMostRecentDisplaySet();
|
|
3124
|
+
const displaySetInstanceUID = displaySet.displaySetInstanceUID;
|
|
3007
3125
|
uiNotificationService.show({
|
|
3008
3126
|
title: 'Create Report',
|
|
3009
|
-
message:
|
|
3127
|
+
message: `${reportType} saved successfully`,
|
|
3010
3128
|
type: 'success'
|
|
3011
3129
|
});
|
|
3012
3130
|
return [displaySetInstanceUID];
|
|
3013
3131
|
} catch (error) {
|
|
3014
3132
|
uiNotificationService.show({
|
|
3015
3133
|
title: 'Create Report',
|
|
3016
|
-
message: error.message ||
|
|
3134
|
+
message: error.message || `Failed to store ${reportType}`,
|
|
3017
3135
|
type: 'error'
|
|
3018
3136
|
});
|
|
3019
3137
|
} finally {
|
|
@@ -3105,7 +3223,7 @@ function PanelMeasurementTable(_ref) {
|
|
|
3105
3223
|
} = _ref;
|
|
3106
3224
|
const [viewportGrid, viewportGridService] = (0,ui_src/* useViewportGrid */.O_)();
|
|
3107
3225
|
const {
|
|
3108
|
-
|
|
3226
|
+
activeViewportId,
|
|
3109
3227
|
viewports
|
|
3110
3228
|
} = viewportGrid;
|
|
3111
3229
|
const {
|
|
@@ -3148,7 +3266,7 @@ function PanelMeasurementTable(_ref) {
|
|
|
3148
3266
|
}
|
|
3149
3267
|
async function createReport() {
|
|
3150
3268
|
// filter measurements that are added to the active study
|
|
3151
|
-
const activeViewport = viewports
|
|
3269
|
+
const activeViewport = viewports.get(activeViewportId);
|
|
3152
3270
|
const measurements = measurementService.getMeasurements();
|
|
3153
3271
|
const displaySet = displaySetService.getDisplaySetByUID(activeViewport.displaySetInstanceUIDs[0]);
|
|
3154
3272
|
const trackedMeasurements = measurements.filter(m => displaySet.StudyInstanceUID === m.referenceStudyUID);
|
|
@@ -3172,10 +3290,21 @@ function PanelMeasurementTable(_ref) {
|
|
|
3172
3290
|
promptResult.value === undefined || promptResult.value === '' ? 'Research Derived Series' // default
|
|
3173
3291
|
: promptResult.value; // provided value
|
|
3174
3292
|
|
|
3175
|
-
//
|
|
3293
|
+
// Reuse an existing series having the same series description to avoid
|
|
3176
3294
|
// creating too many series instances.
|
|
3177
3295
|
const options = findSRWithSameSeriesDescription(SeriesDescription, displaySetService);
|
|
3178
|
-
|
|
3296
|
+
const getReport = async () => {
|
|
3297
|
+
return commandsManager.runCommand('storeMeasurements', {
|
|
3298
|
+
measurementData: trackedMeasurements,
|
|
3299
|
+
dataSource,
|
|
3300
|
+
additionalFindingTypes: ['ArrowAnnotate'],
|
|
3301
|
+
options
|
|
3302
|
+
}, 'CORNERSTONE_STRUCTURED_REPORT');
|
|
3303
|
+
};
|
|
3304
|
+
return Actions_createReportAsync({
|
|
3305
|
+
servicesManager,
|
|
3306
|
+
getReport
|
|
3307
|
+
});
|
|
3179
3308
|
}
|
|
3180
3309
|
}
|
|
3181
3310
|
const jumpToImage = _ref2 => {
|
|
@@ -3183,7 +3312,7 @@ function PanelMeasurementTable(_ref) {
|
|
|
3183
3312
|
uid,
|
|
3184
3313
|
isActive
|
|
3185
3314
|
} = _ref2;
|
|
3186
|
-
measurementService.jumpToMeasurement(viewportGrid.
|
|
3315
|
+
measurementService.jumpToMeasurement(viewportGrid.activeViewportId, uid);
|
|
3187
3316
|
onMeasurementItemClickHandler({
|
|
3188
3317
|
uid,
|
|
3189
3318
|
isActive
|
|
@@ -3255,7 +3384,7 @@ function PanelMeasurementTable(_ref) {
|
|
|
3255
3384
|
labelClassName: "text-white text-[14px] leading-[1.2]",
|
|
3256
3385
|
autoFocus: true,
|
|
3257
3386
|
id: "annotation",
|
|
3258
|
-
className: "
|
|
3387
|
+
className: "border-primary-main bg-black",
|
|
3259
3388
|
type: "text",
|
|
3260
3389
|
value: value.label,
|
|
3261
3390
|
onChange: onChangeHandler,
|
|
@@ -3265,11 +3394,11 @@ function PanelMeasurementTable(_ref) {
|
|
|
3265
3394
|
actions: [{
|
|
3266
3395
|
id: 'cancel',
|
|
3267
3396
|
text: 'Cancel',
|
|
3268
|
-
type: ui_src/* ButtonEnums.type */.LZ.
|
|
3397
|
+
type: ui_src/* ButtonEnums.type */.LZ.dt.secondary
|
|
3269
3398
|
}, {
|
|
3270
3399
|
id: 'save',
|
|
3271
3400
|
text: 'Save',
|
|
3272
|
-
type: ui_src/* ButtonEnums.type */.LZ.
|
|
3401
|
+
type: ui_src/* ButtonEnums.type */.LZ.dt.primary
|
|
3273
3402
|
}],
|
|
3274
3403
|
onSubmit: onSubmitHandler
|
|
3275
3404
|
}
|
|
@@ -3289,7 +3418,7 @@ function PanelMeasurementTable(_ref) {
|
|
|
3289
3418
|
}
|
|
3290
3419
|
};
|
|
3291
3420
|
return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
|
|
3292
|
-
className: "
|
|
3421
|
+
className: "ohif-scrollbar overflow-y-auto overflow-x-hidden",
|
|
3293
3422
|
"data-cy": 'measurements-panel'
|
|
3294
3423
|
}, /*#__PURE__*/react.createElement(ui_src/* MeasurementTable */.wt, {
|
|
3295
3424
|
title: "Measurements",
|
|
@@ -3316,7 +3445,7 @@ function _getMappedMeasurements(measurementService) {
|
|
|
3316
3445
|
|
|
3317
3446
|
/**
|
|
3318
3447
|
* Map the measurements to the display text.
|
|
3319
|
-
* Adds finding and site
|
|
3448
|
+
* Adds finding and site information to the displayText and/or label,
|
|
3320
3449
|
* and provides as 'displayText' and 'label', while providing the original
|
|
3321
3450
|
* values as baseDisplayText and baseLabel
|
|
3322
3451
|
*/
|
|
@@ -3336,7 +3465,9 @@ function _mapMeasurementToDisplay(measurement, index, types) {
|
|
|
3336
3465
|
if (findingSites) {
|
|
3337
3466
|
const siteText = [];
|
|
3338
3467
|
findingSites.forEach(site => {
|
|
3339
|
-
if (site?.text !== label)
|
|
3468
|
+
if (site?.text !== label) {
|
|
3469
|
+
siteText.push(site.text);
|
|
3470
|
+
}
|
|
3340
3471
|
});
|
|
3341
3472
|
displayText = [...siteText, ...displayText];
|
|
3342
3473
|
}
|
|
@@ -3360,6 +3491,7 @@ function _mapMeasurementToDisplay(measurement, index, types) {
|
|
|
3360
3491
|
|
|
3361
3492
|
|
|
3362
3493
|
|
|
3494
|
+
|
|
3363
3495
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getPanelModule.tsx
|
|
3364
3496
|
|
|
3365
3497
|
|
|
@@ -3384,7 +3516,7 @@ function getPanelModule(_ref) {
|
|
|
3384
3516
|
};
|
|
3385
3517
|
return [{
|
|
3386
3518
|
name: 'seriesList',
|
|
3387
|
-
iconName: '
|
|
3519
|
+
iconName: 'tab-studies',
|
|
3388
3520
|
iconLabel: 'Studies',
|
|
3389
3521
|
label: 'Studies',
|
|
3390
3522
|
component: Panels_WrappedPanelStudyBrowser.bind(null, {
|
|
@@ -3403,25 +3535,335 @@ function getPanelModule(_ref) {
|
|
|
3403
3535
|
}
|
|
3404
3536
|
/* harmony default export */ const src_getPanelModule = (getPanelModule);
|
|
3405
3537
|
// EXTERNAL MODULE: ../../core/src/utils/isImage.js
|
|
3406
|
-
var isImage = __webpack_require__(
|
|
3538
|
+
var isImage = __webpack_require__(11835);
|
|
3407
3539
|
// EXTERNAL MODULE: ../../core/src/utils/sopClassDictionary.js
|
|
3408
|
-
var sopClassDictionary = __webpack_require__(
|
|
3540
|
+
var sopClassDictionary = __webpack_require__(24369);
|
|
3409
3541
|
// EXTERNAL MODULE: ../../core/src/classes/ImageSet.ts
|
|
3410
|
-
var ImageSet = __webpack_require__(
|
|
3542
|
+
var ImageSet = __webpack_require__(13950);
|
|
3411
3543
|
// EXTERNAL MODULE: ../../core/src/utils/isDisplaySetReconstructable.js
|
|
3412
|
-
var isDisplaySetReconstructable = __webpack_require__(
|
|
3544
|
+
var isDisplaySetReconstructable = __webpack_require__(89359);
|
|
3413
3545
|
;// CONCATENATED MODULE: ../../../extensions/default/package.json
|
|
3414
3546
|
const package_namespaceObject = JSON.parse('{"u2":"@ohif/extension-default"}');
|
|
3415
3547
|
;// CONCATENATED MODULE: ../../../extensions/default/src/id.js
|
|
3416
3548
|
|
|
3417
3549
|
const id = package_namespaceObject.u2;
|
|
3418
3550
|
|
|
3551
|
+
// EXTERNAL MODULE: ../../core/src/utils/sortInstancesByPosition.ts
|
|
3552
|
+
var sortInstancesByPosition = __webpack_require__(87425);
|
|
3553
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/validations/checkMultiframe.ts
|
|
3554
|
+
|
|
3555
|
+
|
|
3556
|
+
|
|
3557
|
+
/**
|
|
3558
|
+
* Check various multi frame issues. It calls OHIF core functions
|
|
3559
|
+
* @param {*} multiFrameInstance
|
|
3560
|
+
* @param {*} warnings
|
|
3561
|
+
*/
|
|
3562
|
+
function checkMultiFrame(multiFrameInstance, messages) {
|
|
3563
|
+
if (!(0,isDisplaySetReconstructable/* hasPixelMeasurements */.hu)(multiFrameInstance)) {
|
|
3564
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.MULTIFRAME_NO_PIXEL_MEASUREMENTS);
|
|
3565
|
+
}
|
|
3566
|
+
if (!(0,isDisplaySetReconstructable/* hasOrientation */.sb)(multiFrameInstance)) {
|
|
3567
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.MULTIFRAME_NO_ORIENTATION);
|
|
3568
|
+
}
|
|
3569
|
+
if (!(0,isDisplaySetReconstructable/* hasPosition */.kN)(multiFrameInstance)) {
|
|
3570
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.MULTIFRAME_NO_POSITION_INFORMATION);
|
|
3571
|
+
}
|
|
3572
|
+
}
|
|
3573
|
+
// EXTERNAL MODULE: ../../core/src/utils/toNumber.js
|
|
3574
|
+
var toNumber = __webpack_require__(94972);
|
|
3575
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/validations/areAllImageDimensionsEqual.ts
|
|
3576
|
+
|
|
3577
|
+
|
|
3578
|
+
/**
|
|
3579
|
+
* Check if the frames in a series has different dimensions
|
|
3580
|
+
* @param {*} instances
|
|
3581
|
+
* @returns
|
|
3582
|
+
*/
|
|
3583
|
+
function areAllImageDimensionsEqual(instances) {
|
|
3584
|
+
if (!instances?.length) {
|
|
3585
|
+
return false;
|
|
3586
|
+
}
|
|
3587
|
+
const firstImage = instances[0];
|
|
3588
|
+
const firstImageRows = (0,toNumber/* default */.Z)(firstImage.Rows);
|
|
3589
|
+
const firstImageColumns = (0,toNumber/* default */.Z)(firstImage.Columns);
|
|
3590
|
+
for (let i = 1; i < instances.length; i++) {
|
|
3591
|
+
const instance = instances[i];
|
|
3592
|
+
const {
|
|
3593
|
+
Rows,
|
|
3594
|
+
Columns
|
|
3595
|
+
} = instance;
|
|
3596
|
+
if (Rows !== firstImageRows || Columns !== firstImageColumns) {
|
|
3597
|
+
return false;
|
|
3598
|
+
}
|
|
3599
|
+
}
|
|
3600
|
+
return true;
|
|
3601
|
+
}
|
|
3602
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/validations/areAllImageComponentsEqual.ts
|
|
3603
|
+
|
|
3604
|
+
|
|
3605
|
+
/**
|
|
3606
|
+
* Check if all voxels in series images has same number of components (samplesPerPixel)
|
|
3607
|
+
* @param {*} instances
|
|
3608
|
+
* @returns
|
|
3609
|
+
*/
|
|
3610
|
+
function areAllImageComponentsEqual(instances) {
|
|
3611
|
+
if (!instances?.length) {
|
|
3612
|
+
return false;
|
|
3613
|
+
}
|
|
3614
|
+
const firstImage = instances[0];
|
|
3615
|
+
const firstImageSamplesPerPixel = (0,toNumber/* default */.Z)(firstImage.SamplesPerPixel);
|
|
3616
|
+
for (let i = 1; i < instances.length; i++) {
|
|
3617
|
+
const instance = instances[i];
|
|
3618
|
+
const {
|
|
3619
|
+
SamplesPerPixel
|
|
3620
|
+
} = instance;
|
|
3621
|
+
if (SamplesPerPixel !== firstImageSamplesPerPixel) {
|
|
3622
|
+
return false;
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3625
|
+
return true;
|
|
3626
|
+
}
|
|
3627
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/validations/areAllImageOrientationsEqual.ts
|
|
3628
|
+
|
|
3629
|
+
|
|
3630
|
+
|
|
3631
|
+
/**
|
|
3632
|
+
* Check is the series has frames with different orientations
|
|
3633
|
+
* @param {*} instances
|
|
3634
|
+
* @returns
|
|
3635
|
+
*/
|
|
3636
|
+
function areAllImageOrientationsEqual(instances) {
|
|
3637
|
+
if (!instances?.length) {
|
|
3638
|
+
return false;
|
|
3639
|
+
}
|
|
3640
|
+
const firstImage = instances[0];
|
|
3641
|
+
const firstImageOrientationPatient = (0,toNumber/* default */.Z)(firstImage.ImageOrientationPatient);
|
|
3642
|
+
for (let i = 1; i < instances.length; i++) {
|
|
3643
|
+
const instance = instances[i];
|
|
3644
|
+
const imageOrientationPatient = (0,toNumber/* default */.Z)(instance.ImageOrientationPatient);
|
|
3645
|
+
if (!(0,isDisplaySetReconstructable/* _isSameOrientation */.NB)(imageOrientationPatient, firstImageOrientationPatient)) {
|
|
3646
|
+
return false;
|
|
3647
|
+
}
|
|
3648
|
+
}
|
|
3649
|
+
return true;
|
|
3650
|
+
}
|
|
3651
|
+
// EXTERNAL MODULE: ../../../node_modules/gl-matrix/esm/index.js + 10 modules
|
|
3652
|
+
var esm = __webpack_require__(45451);
|
|
3653
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/calculateScanAxisNormal.ts
|
|
3654
|
+
|
|
3655
|
+
|
|
3656
|
+
/**
|
|
3657
|
+
* Calculates the scanAxisNormal based on a image orientation vector extract from a frame
|
|
3658
|
+
* @param {*} imageOrientation
|
|
3659
|
+
* @returns
|
|
3660
|
+
*/
|
|
3661
|
+
function calculateScanAxisNormal(imageOrientation) {
|
|
3662
|
+
const rowCosineVec = esm/* vec3.fromValues */.R3.fromValues(imageOrientation[0], imageOrientation[1], imageOrientation[2]);
|
|
3663
|
+
const colCosineVec = esm/* vec3.fromValues */.R3.fromValues(imageOrientation[3], imageOrientation[4], imageOrientation[5]);
|
|
3664
|
+
return esm/* vec3.cross */.R3.cross(esm/* vec3.create */.R3.create(), rowCosineVec, colCosineVec);
|
|
3665
|
+
}
|
|
3666
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/validations/areAllImagePositionsEqual.ts
|
|
3667
|
+
|
|
3668
|
+
|
|
3669
|
+
|
|
3670
|
+
|
|
3671
|
+
|
|
3672
|
+
/**
|
|
3673
|
+
* Checks if there is a position shift between consecutive frames
|
|
3674
|
+
* @param {*} previousPosition
|
|
3675
|
+
* @param {*} actualPosition
|
|
3676
|
+
* @param {*} scanAxisNormal
|
|
3677
|
+
* @param {*} averageSpacingBetweenFrames
|
|
3678
|
+
* @returns
|
|
3679
|
+
*/
|
|
3680
|
+
function _checkSeriesPositionShift(previousPosition, actualPosition, scanAxisNormal, averageSpacingBetweenFrames) {
|
|
3681
|
+
// predicted position should be the previous position added by the multiplication
|
|
3682
|
+
// of the scanAxisNormal and the average spacing between frames
|
|
3683
|
+
const predictedPosition = esm/* vec3.scaleAndAdd */.R3.scaleAndAdd(esm/* vec3.create */.R3.create(), previousPosition, scanAxisNormal, averageSpacingBetweenFrames);
|
|
3684
|
+
return esm/* vec3.distance */.R3.distance(actualPosition, predictedPosition) > averageSpacingBetweenFrames;
|
|
3685
|
+
}
|
|
3686
|
+
|
|
3687
|
+
/**
|
|
3688
|
+
* Checks if a series has position shifts between consecutive frames
|
|
3689
|
+
* @param {*} instances
|
|
3690
|
+
* @returns
|
|
3691
|
+
*/
|
|
3692
|
+
function areAllImagePositionsEqual(instances) {
|
|
3693
|
+
if (!instances?.length) {
|
|
3694
|
+
return false;
|
|
3695
|
+
}
|
|
3696
|
+
const firstImageOrientationPatient = (0,toNumber/* default */.Z)(instances[0].ImageOrientationPatient);
|
|
3697
|
+
if (!firstImageOrientationPatient) {
|
|
3698
|
+
return false;
|
|
3699
|
+
}
|
|
3700
|
+
const scanAxisNormal = calculateScanAxisNormal(firstImageOrientationPatient);
|
|
3701
|
+
const firstImagePositionPatient = (0,toNumber/* default */.Z)(instances[0].ImagePositionPatient);
|
|
3702
|
+
const lastIpp = (0,toNumber/* default */.Z)(instances[instances.length - 1].ImagePositionPatient);
|
|
3703
|
+
const averageSpacingBetweenFrames = (0,isDisplaySetReconstructable/* _getPerpendicularDistance */.Xn)(firstImagePositionPatient, lastIpp) / (instances.length - 1);
|
|
3704
|
+
let previousImagePositionPatient = firstImagePositionPatient;
|
|
3705
|
+
for (let i = 1; i < instances.length; i++) {
|
|
3706
|
+
const instance = instances[i];
|
|
3707
|
+
const imagePositionPatient = (0,toNumber/* default */.Z)(instance.ImagePositionPatient);
|
|
3708
|
+
if (_checkSeriesPositionShift(previousImagePositionPatient, imagePositionPatient, scanAxisNormal, averageSpacingBetweenFrames)) {
|
|
3709
|
+
return false;
|
|
3710
|
+
}
|
|
3711
|
+
previousImagePositionPatient = imagePositionPatient;
|
|
3712
|
+
}
|
|
3713
|
+
return true;
|
|
3714
|
+
}
|
|
3715
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/validations/areAllImageSpacingEqual.ts
|
|
3716
|
+
|
|
3717
|
+
|
|
3718
|
+
|
|
3719
|
+
/**
|
|
3720
|
+
* Checks if series has spacing issues
|
|
3721
|
+
* @param {*} instances
|
|
3722
|
+
* @param {*} warnings
|
|
3723
|
+
*/
|
|
3724
|
+
function areAllImageSpacingEqual(instances, messages) {
|
|
3725
|
+
if (!instances?.length) {
|
|
3726
|
+
return;
|
|
3727
|
+
}
|
|
3728
|
+
const firstImagePositionPatient = (0,toNumber/* default */.Z)(instances[0].ImagePositionPatient);
|
|
3729
|
+
if (!firstImagePositionPatient) {
|
|
3730
|
+
return;
|
|
3731
|
+
}
|
|
3732
|
+
const lastIpp = (0,toNumber/* default */.Z)(instances[instances.length - 1].ImagePositionPatient);
|
|
3733
|
+
const averageSpacingBetweenFrames = (0,isDisplaySetReconstructable/* _getPerpendicularDistance */.Xn)(firstImagePositionPatient, lastIpp) / (instances.length - 1);
|
|
3734
|
+
let previousImagePositionPatient = firstImagePositionPatient;
|
|
3735
|
+
const issuesFound = [];
|
|
3736
|
+
for (let i = 1; i < instances.length; i++) {
|
|
3737
|
+
const instance = instances[i];
|
|
3738
|
+
const imagePositionPatient = (0,toNumber/* default */.Z)(instance.ImagePositionPatient);
|
|
3739
|
+
const spacingBetweenFrames = (0,isDisplaySetReconstructable/* _getPerpendicularDistance */.Xn)(imagePositionPatient, previousImagePositionPatient);
|
|
3740
|
+
const spacingIssue = (0,isDisplaySetReconstructable/* _getSpacingIssue */.bg)(spacingBetweenFrames, averageSpacingBetweenFrames);
|
|
3741
|
+
if (spacingIssue) {
|
|
3742
|
+
const issue = spacingIssue.issue;
|
|
3743
|
+
|
|
3744
|
+
// avoid multiple warning of the same thing
|
|
3745
|
+
if (!issuesFound.includes(issue)) {
|
|
3746
|
+
issuesFound.push(issue);
|
|
3747
|
+
if (issue === isDisplaySetReconstructable/* reconstructionIssues */.e1.MISSING_FRAMES) {
|
|
3748
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.MISSING_FRAMES);
|
|
3749
|
+
} else if (issue === isDisplaySetReconstructable/* reconstructionIssues */.e1.IRREGULAR_SPACING) {
|
|
3750
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.IRREGULAR_SPACING);
|
|
3751
|
+
}
|
|
3752
|
+
}
|
|
3753
|
+
// we just want to find issues not how many
|
|
3754
|
+
if (issuesFound.length > 1) {
|
|
3755
|
+
break;
|
|
3756
|
+
}
|
|
3757
|
+
}
|
|
3758
|
+
previousImagePositionPatient = imagePositionPatient;
|
|
3759
|
+
}
|
|
3760
|
+
}
|
|
3761
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/utils/validations/checkSingleFrames.ts
|
|
3762
|
+
|
|
3763
|
+
|
|
3764
|
+
|
|
3765
|
+
|
|
3766
|
+
|
|
3767
|
+
|
|
3768
|
+
|
|
3769
|
+
/**
|
|
3770
|
+
* Runs various checks in a single frame series
|
|
3771
|
+
* @param {*} instances
|
|
3772
|
+
* @param {*} warnings
|
|
3773
|
+
*/
|
|
3774
|
+
function checkSingleFrames(instances, messages) {
|
|
3775
|
+
if (instances.length > 2) {
|
|
3776
|
+
if (!areAllImageDimensionsEqual(instances)) {
|
|
3777
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.INCONSISTENT_DIMENSIONS);
|
|
3778
|
+
}
|
|
3779
|
+
if (!areAllImageComponentsEqual(instances)) {
|
|
3780
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.INCONSISTENT_COMPONENTS);
|
|
3781
|
+
}
|
|
3782
|
+
if (!areAllImageOrientationsEqual(instances)) {
|
|
3783
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.INCONSISTENT_ORIENTATIONS);
|
|
3784
|
+
}
|
|
3785
|
+
if (!areAllImagePositionsEqual(instances)) {
|
|
3786
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.INCONSISTENT_POSITION_INFORMATION);
|
|
3787
|
+
}
|
|
3788
|
+
areAllImageSpacingEqual(instances, messages);
|
|
3789
|
+
}
|
|
3790
|
+
}
|
|
3791
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/getDisplaySetMessages.ts
|
|
3792
|
+
|
|
3793
|
+
|
|
3794
|
+
|
|
3795
|
+
|
|
3796
|
+
|
|
3797
|
+
/**
|
|
3798
|
+
* Checks if a series is reconstructable to a 3D volume.
|
|
3799
|
+
*
|
|
3800
|
+
* @param {Object[]} instances An array of `OHIFInstanceMetadata` objects.
|
|
3801
|
+
*/
|
|
3802
|
+
function getDisplaySetMessages(instances, isReconstructable) {
|
|
3803
|
+
const messages = new src/* DisplaySetMessageList */.iK();
|
|
3804
|
+
if (!instances.length) {
|
|
3805
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.NO_VALID_INSTANCES);
|
|
3806
|
+
}
|
|
3807
|
+
const firstInstance = instances[0];
|
|
3808
|
+
// Due to current requirements, LOCALIZER series doesn't have any messages
|
|
3809
|
+
if (firstInstance?.ImageType?.includes('LOCALIZER')) {
|
|
3810
|
+
return messages;
|
|
3811
|
+
}
|
|
3812
|
+
const Modality = firstInstance.Modality;
|
|
3813
|
+
if (!isDisplaySetReconstructable/* constructableModalities */.M6.includes(Modality)) {
|
|
3814
|
+
return messages;
|
|
3815
|
+
}
|
|
3816
|
+
const isMultiframe = firstInstance.NumberOfFrames > 1;
|
|
3817
|
+
// Can't reconstruct if all instances don't have the ImagePositionPatient.
|
|
3818
|
+
if (!isMultiframe && !instances.every(instance => instance.ImagePositionPatient)) {
|
|
3819
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.NO_POSITION_INFORMATION);
|
|
3820
|
+
}
|
|
3821
|
+
const sortedInstances = (0,sortInstancesByPosition/* default */.Z)(instances);
|
|
3822
|
+
isMultiframe ? checkMultiFrame(sortedInstances[0], messages) : checkSingleFrames(sortedInstances, messages);
|
|
3823
|
+
if (!isReconstructable) {
|
|
3824
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.NOT_RECONSTRUCTABLE);
|
|
3825
|
+
}
|
|
3826
|
+
return messages;
|
|
3827
|
+
}
|
|
3828
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/getDisplaySetsFromUnsupportedSeries.js
|
|
3829
|
+
|
|
3830
|
+
|
|
3831
|
+
/**
|
|
3832
|
+
* Default handler for a instance list with an unsupported sopClassUID
|
|
3833
|
+
*/
|
|
3834
|
+
function getDisplaySetsFromUnsupportedSeries(instances) {
|
|
3835
|
+
const imageSet = new ImageSet/* default */.Z(instances);
|
|
3836
|
+
const messages = new src/* DisplaySetMessageList */.iK();
|
|
3837
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.UNSUPPORTED_DISPLAYSET);
|
|
3838
|
+
const instance = instances[0];
|
|
3839
|
+
imageSet.setAttributes({
|
|
3840
|
+
displaySetInstanceUID: imageSet.uid,
|
|
3841
|
+
// create a local alias for the imageSet UID
|
|
3842
|
+
SeriesDate: instance.SeriesDate,
|
|
3843
|
+
SeriesTime: instance.SeriesTime,
|
|
3844
|
+
SeriesInstanceUID: instance.SeriesInstanceUID,
|
|
3845
|
+
StudyInstanceUID: instance.StudyInstanceUID,
|
|
3846
|
+
SeriesNumber: instance.SeriesNumber || 0,
|
|
3847
|
+
FrameRate: instance.FrameTime,
|
|
3848
|
+
SOPClassUID: instance.SOPClassUID,
|
|
3849
|
+
SeriesDescription: instance.SeriesDescription || '',
|
|
3850
|
+
Modality: instance.Modality,
|
|
3851
|
+
numImageFrames: instances.length,
|
|
3852
|
+
unsupported: true,
|
|
3853
|
+
SOPClassHandlerId: 'unsupported',
|
|
3854
|
+
isReconstructable: false,
|
|
3855
|
+
messages
|
|
3856
|
+
});
|
|
3857
|
+
return [imageSet];
|
|
3858
|
+
}
|
|
3419
3859
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getSopClassHandlerModule.js
|
|
3420
3860
|
|
|
3421
3861
|
|
|
3422
3862
|
|
|
3423
3863
|
|
|
3424
3864
|
|
|
3865
|
+
|
|
3866
|
+
|
|
3425
3867
|
const sopClassHandlerName = 'stack';
|
|
3426
3868
|
const isMultiFrame = instance => {
|
|
3427
3869
|
return instance.NumberOfFrames > 1;
|
|
@@ -3432,9 +3874,9 @@ const makeDisplaySet = instances => {
|
|
|
3432
3874
|
const {
|
|
3433
3875
|
value: isReconstructable,
|
|
3434
3876
|
averageSpacingBetweenFrames
|
|
3435
|
-
} = (0,isDisplaySetReconstructable/* default */.
|
|
3436
|
-
|
|
3877
|
+
} = (0,isDisplaySetReconstructable/* default */.ZP)(instances);
|
|
3437
3878
|
// set appropriate attributes to image set...
|
|
3879
|
+
const messages = getDisplaySetMessages(instances, isReconstructable);
|
|
3438
3880
|
imageSet.setAttributes({
|
|
3439
3881
|
displaySetInstanceUID: imageSet.uid,
|
|
3440
3882
|
// create a local alias for the imageSet UID
|
|
@@ -3452,6 +3894,7 @@ const makeDisplaySet = instances => {
|
|
|
3452
3894
|
numImageFrames: instances.length,
|
|
3453
3895
|
SOPClassHandlerId: `${id}.sopClassHandlerModule.${sopClassHandlerName}`,
|
|
3454
3896
|
isReconstructable,
|
|
3897
|
+
messages,
|
|
3455
3898
|
averageSpacingBetweenFrames: averageSpacingBetweenFrames || null
|
|
3456
3899
|
});
|
|
3457
3900
|
|
|
@@ -3558,6 +4001,10 @@ function getSopClassHandlerModule() {
|
|
|
3558
4001
|
name: sopClassHandlerName,
|
|
3559
4002
|
sopClassUids,
|
|
3560
4003
|
getDisplaySetsFromSeries
|
|
4004
|
+
}, {
|
|
4005
|
+
name: 'not-supported-display-sets-handler',
|
|
4006
|
+
sopClassUids: [],
|
|
4007
|
+
getDisplaySetsFromSeries: getDisplaySetsFromUnsupportedSeries
|
|
3561
4008
|
}];
|
|
3562
4009
|
}
|
|
3563
4010
|
/* harmony default export */ const src_getSopClassHandlerModule = (getSopClassHandlerModule);
|
|
@@ -3565,44 +4012,53 @@ function getSopClassHandlerModule() {
|
|
|
3565
4012
|
|
|
3566
4013
|
function ToolbarDivider() {
|
|
3567
4014
|
return /*#__PURE__*/react.createElement("span", {
|
|
3568
|
-
className: "
|
|
4015
|
+
className: "border-common-dark mx-2 h-8 w-4 self-center border-l"
|
|
3569
4016
|
});
|
|
3570
4017
|
}
|
|
3571
4018
|
;// CONCATENATED MODULE: ../../../extensions/default/src/Toolbar/ToolbarLayoutSelector.tsx
|
|
4019
|
+
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
4020
|
|
|
3573
4021
|
|
|
3574
4022
|
|
|
3575
4023
|
|
|
3576
|
-
function
|
|
4024
|
+
function ToolbarLayoutSelectorWithServices(_ref) {
|
|
3577
4025
|
let {
|
|
3578
|
-
rows,
|
|
3579
|
-
columns,
|
|
3580
|
-
className,
|
|
3581
4026
|
servicesManager,
|
|
3582
|
-
...
|
|
4027
|
+
...props
|
|
3583
4028
|
} = _ref;
|
|
3584
|
-
const [isOpen, setIsOpen] = (0,react.useState)(false);
|
|
3585
4029
|
const {
|
|
3586
|
-
hangingProtocolService,
|
|
3587
4030
|
toolbarService
|
|
3588
4031
|
} = servicesManager.services;
|
|
4032
|
+
const onSelection = (0,react.useCallback)(props => {
|
|
4033
|
+
toolbarService.recordInteraction({
|
|
4034
|
+
interactionType: 'action',
|
|
4035
|
+
commands: [{
|
|
4036
|
+
commandName: 'setViewportGridLayout',
|
|
4037
|
+
commandOptions: {
|
|
4038
|
+
...props
|
|
4039
|
+
},
|
|
4040
|
+
context: 'DEFAULT'
|
|
4041
|
+
}]
|
|
4042
|
+
});
|
|
4043
|
+
}, [toolbarService]);
|
|
4044
|
+
return /*#__PURE__*/react.createElement(LayoutSelector, ToolbarLayoutSelector_extends({}, props, {
|
|
4045
|
+
onSelection: onSelection
|
|
4046
|
+
}));
|
|
4047
|
+
}
|
|
4048
|
+
function LayoutSelector(_ref2) {
|
|
4049
|
+
let {
|
|
4050
|
+
rows,
|
|
4051
|
+
columns,
|
|
4052
|
+
className,
|
|
4053
|
+
onSelection,
|
|
4054
|
+
...rest
|
|
4055
|
+
} = _ref2;
|
|
4056
|
+
const [isOpen, setIsOpen] = (0,react.useState)(false);
|
|
3589
4057
|
const closeOnOutsideClick = () => {
|
|
3590
4058
|
if (isOpen) {
|
|
3591
4059
|
setIsOpen(false);
|
|
3592
4060
|
}
|
|
3593
4061
|
};
|
|
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
4062
|
(0,react.useEffect)(() => {
|
|
3607
4063
|
window.addEventListener('click', closeOnOutsideClick);
|
|
3608
4064
|
return () => {
|
|
@@ -3611,18 +4067,6 @@ function LayoutSelector(_ref) {
|
|
|
3611
4067
|
}, [isOpen]);
|
|
3612
4068
|
const onInteractionHandler = () => setIsOpen(!isOpen);
|
|
3613
4069
|
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
4070
|
return /*#__PURE__*/react.createElement(ui_src/* ToolbarButton */.hA, {
|
|
3627
4071
|
id: "Layout",
|
|
3628
4072
|
label: "Grid Layout",
|
|
@@ -3633,7 +4077,7 @@ function LayoutSelector(_ref) {
|
|
|
3633
4077
|
dropdownContent: DropdownContent !== null && /*#__PURE__*/react.createElement(DropdownContent, {
|
|
3634
4078
|
rows: rows,
|
|
3635
4079
|
columns: columns,
|
|
3636
|
-
onSelection:
|
|
4080
|
+
onSelection: onSelection
|
|
3637
4081
|
}),
|
|
3638
4082
|
isActive: isOpen,
|
|
3639
4083
|
type: "toggle"
|
|
@@ -3650,10 +4094,238 @@ LayoutSelector.defaultProps = {
|
|
|
3650
4094
|
columns: 3,
|
|
3651
4095
|
onLayoutChange: () => {}
|
|
3652
4096
|
};
|
|
3653
|
-
/* harmony default export */ const ToolbarLayoutSelector = (
|
|
3654
|
-
;// CONCATENATED MODULE: ../../../extensions/default/src/Toolbar/
|
|
4097
|
+
/* harmony default export */ const ToolbarLayoutSelector = (ToolbarLayoutSelectorWithServices);
|
|
4098
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/Toolbar/ToolbarSplitButtonWithServices.tsx
|
|
4099
|
+
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); }
|
|
4100
|
+
|
|
3655
4101
|
|
|
3656
|
-
|
|
4102
|
+
|
|
4103
|
+
|
|
4104
|
+
function ToolbarSplitButtonWithServices(_ref) {
|
|
4105
|
+
let {
|
|
4106
|
+
isRadio,
|
|
4107
|
+
isAction,
|
|
4108
|
+
groupId,
|
|
4109
|
+
primary,
|
|
4110
|
+
secondary,
|
|
4111
|
+
items,
|
|
4112
|
+
renderer,
|
|
4113
|
+
onInteraction,
|
|
4114
|
+
servicesManager
|
|
4115
|
+
} = _ref;
|
|
4116
|
+
const {
|
|
4117
|
+
toolbarService
|
|
4118
|
+
} = servicesManager?.services;
|
|
4119
|
+
const handleItemClick = (item, index) => {
|
|
4120
|
+
const {
|
|
4121
|
+
id,
|
|
4122
|
+
type,
|
|
4123
|
+
commands
|
|
4124
|
+
} = item;
|
|
4125
|
+
onInteraction({
|
|
4126
|
+
groupId,
|
|
4127
|
+
itemId: id,
|
|
4128
|
+
interactionType: type,
|
|
4129
|
+
commands
|
|
4130
|
+
});
|
|
4131
|
+
setState(state => ({
|
|
4132
|
+
...state,
|
|
4133
|
+
primary: !isAction && isRadio ? {
|
|
4134
|
+
...item,
|
|
4135
|
+
index
|
|
4136
|
+
} : state.primary,
|
|
4137
|
+
isExpanded: false,
|
|
4138
|
+
items: getSplitButtonItems(items).filter(item => isRadio && !isAction ? item.index !== index : true)
|
|
4139
|
+
}));
|
|
4140
|
+
};
|
|
4141
|
+
|
|
4142
|
+
/* Bubbles up individual item clicks */
|
|
4143
|
+
const getSplitButtonItems = items => items.map((item, index) => ({
|
|
4144
|
+
...item,
|
|
4145
|
+
index,
|
|
4146
|
+
onClick: () => handleItemClick(item, index)
|
|
4147
|
+
}));
|
|
4148
|
+
const [buttonsState, setButtonState] = (0,react.useState)({
|
|
4149
|
+
primaryToolId: '',
|
|
4150
|
+
toggles: {},
|
|
4151
|
+
groups: {}
|
|
4152
|
+
});
|
|
4153
|
+
const [state, setState] = (0,react.useState)({
|
|
4154
|
+
primary,
|
|
4155
|
+
items: getSplitButtonItems(items).filter(item => isRadio && !isAction ? item.id !== primary.id : true)
|
|
4156
|
+
});
|
|
4157
|
+
const {
|
|
4158
|
+
primaryToolId,
|
|
4159
|
+
toggles
|
|
4160
|
+
} = buttonsState;
|
|
4161
|
+
const isPrimaryToggle = state.primary.type === 'toggle';
|
|
4162
|
+
const isPrimaryActive = state.primary.type === 'tool' && primaryToolId === state.primary.id || isPrimaryToggle && toggles[state.primary.id] === true;
|
|
4163
|
+
const PrimaryButtonComponent = toolbarService?.getButtonComponentForUIType(state.primary.uiType) ?? ui_src/* ToolbarButton */.hA;
|
|
4164
|
+
(0,react.useEffect)(() => {
|
|
4165
|
+
const {
|
|
4166
|
+
unsubscribe
|
|
4167
|
+
} = toolbarService.subscribe(toolbarService.EVENTS.TOOL_BAR_STATE_MODIFIED, state => {
|
|
4168
|
+
setButtonState({
|
|
4169
|
+
...state
|
|
4170
|
+
});
|
|
4171
|
+
});
|
|
4172
|
+
return () => {
|
|
4173
|
+
unsubscribe();
|
|
4174
|
+
};
|
|
4175
|
+
}, [toolbarService]);
|
|
4176
|
+
const updatedItems = state.items.map(item => {
|
|
4177
|
+
const isActive = item.type === 'tool' && primaryToolId === item.id;
|
|
4178
|
+
|
|
4179
|
+
// We could have added the
|
|
4180
|
+
// item.type === 'toggle' && toggles[item.id] === true
|
|
4181
|
+
// too but that makes the button active when the toggle is active under it
|
|
4182
|
+
// which feels weird
|
|
4183
|
+
return {
|
|
4184
|
+
...item,
|
|
4185
|
+
isActive
|
|
4186
|
+
};
|
|
4187
|
+
});
|
|
4188
|
+
const DefaultListItemRenderer = _ref2 => {
|
|
4189
|
+
let {
|
|
4190
|
+
type,
|
|
4191
|
+
icon,
|
|
4192
|
+
label,
|
|
4193
|
+
t,
|
|
4194
|
+
id
|
|
4195
|
+
} = _ref2;
|
|
4196
|
+
const isActive = type === 'toggle' && toggles[id] === true;
|
|
4197
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
4198
|
+
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')
|
|
4199
|
+
}, icon && /*#__PURE__*/react.createElement("span", {
|
|
4200
|
+
className: "mr-4"
|
|
4201
|
+
}, /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
4202
|
+
name: icon,
|
|
4203
|
+
className: "h-5 w-5"
|
|
4204
|
+
})), /*#__PURE__*/react.createElement("span", {
|
|
4205
|
+
className: "mr-5"
|
|
4206
|
+
}, t(label)));
|
|
4207
|
+
};
|
|
4208
|
+
const listItemRenderer = renderer || DefaultListItemRenderer;
|
|
4209
|
+
return /*#__PURE__*/react.createElement(ui_src/* SplitButton */.aW, {
|
|
4210
|
+
isRadio: isRadio,
|
|
4211
|
+
isAction: isAction,
|
|
4212
|
+
primary: state.primary,
|
|
4213
|
+
secondary: secondary,
|
|
4214
|
+
items: updatedItems,
|
|
4215
|
+
groupId: groupId,
|
|
4216
|
+
renderer: listItemRenderer,
|
|
4217
|
+
isActive: isPrimaryActive || updatedItems.some(item => item.isActive),
|
|
4218
|
+
isToggle: isPrimaryToggle,
|
|
4219
|
+
onInteraction: onInteraction,
|
|
4220
|
+
Component: props => /*#__PURE__*/react.createElement(PrimaryButtonComponent, ToolbarSplitButtonWithServices_extends({}, props, {
|
|
4221
|
+
servicesManager: servicesManager
|
|
4222
|
+
}))
|
|
4223
|
+
});
|
|
4224
|
+
}
|
|
4225
|
+
ToolbarSplitButtonWithServices.propTypes = {
|
|
4226
|
+
isRadio: (prop_types_default()).bool,
|
|
4227
|
+
isAction: (prop_types_default()).bool,
|
|
4228
|
+
groupId: (prop_types_default()).string,
|
|
4229
|
+
primary: prop_types_default().shape({
|
|
4230
|
+
id: (prop_types_default()).string.isRequired,
|
|
4231
|
+
type: prop_types_default().oneOf(['tool', 'action', 'toggle']).isRequired,
|
|
4232
|
+
uiType: (prop_types_default()).string
|
|
4233
|
+
}),
|
|
4234
|
+
secondary: prop_types_default().shape({
|
|
4235
|
+
id: (prop_types_default()).string,
|
|
4236
|
+
icon: (prop_types_default()).string.isRequired,
|
|
4237
|
+
label: (prop_types_default()).string,
|
|
4238
|
+
tooltip: (prop_types_default()).string.isRequired,
|
|
4239
|
+
isActive: (prop_types_default()).bool
|
|
4240
|
+
}),
|
|
4241
|
+
items: prop_types_default().arrayOf(prop_types_default().shape({
|
|
4242
|
+
id: (prop_types_default()).string.isRequired,
|
|
4243
|
+
type: prop_types_default().oneOf(['tool', 'action', 'toggle']).isRequired,
|
|
4244
|
+
icon: (prop_types_default()).string,
|
|
4245
|
+
label: (prop_types_default()).string,
|
|
4246
|
+
tooltip: (prop_types_default()).string
|
|
4247
|
+
})),
|
|
4248
|
+
renderer: (prop_types_default()).func,
|
|
4249
|
+
onInteraction: (prop_types_default()).func.isRequired,
|
|
4250
|
+
servicesManager: prop_types_default().shape({
|
|
4251
|
+
services: prop_types_default().shape({
|
|
4252
|
+
toolbarService: (prop_types_default()).object
|
|
4253
|
+
})
|
|
4254
|
+
})
|
|
4255
|
+
};
|
|
4256
|
+
ToolbarSplitButtonWithServices.defaultProps = {
|
|
4257
|
+
isRadio: false,
|
|
4258
|
+
isAction: false
|
|
4259
|
+
};
|
|
4260
|
+
/* harmony default export */ const Toolbar_ToolbarSplitButtonWithServices = (ToolbarSplitButtonWithServices);
|
|
4261
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/Toolbar/ToolbarButtonWithServices.tsx
|
|
4262
|
+
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); }
|
|
4263
|
+
|
|
4264
|
+
|
|
4265
|
+
|
|
4266
|
+
function ToolbarButtonWithServices(_ref) {
|
|
4267
|
+
let {
|
|
4268
|
+
id,
|
|
4269
|
+
type,
|
|
4270
|
+
commands,
|
|
4271
|
+
onInteraction,
|
|
4272
|
+
servicesManager,
|
|
4273
|
+
...props
|
|
4274
|
+
} = _ref;
|
|
4275
|
+
const {
|
|
4276
|
+
toolbarService
|
|
4277
|
+
} = servicesManager?.services || {};
|
|
4278
|
+
const [buttonsState, setButtonState] = (0,react.useState)({
|
|
4279
|
+
primaryToolId: '',
|
|
4280
|
+
toggles: {},
|
|
4281
|
+
groups: {}
|
|
4282
|
+
});
|
|
4283
|
+
const {
|
|
4284
|
+
primaryToolId
|
|
4285
|
+
} = buttonsState;
|
|
4286
|
+
const isActive = type === 'tool' && id === primaryToolId || type === 'toggle' && buttonsState.toggles[id] === true;
|
|
4287
|
+
(0,react.useEffect)(() => {
|
|
4288
|
+
const {
|
|
4289
|
+
unsubscribe
|
|
4290
|
+
} = toolbarService.subscribe(toolbarService.EVENTS.TOOL_BAR_STATE_MODIFIED, state => {
|
|
4291
|
+
setButtonState({
|
|
4292
|
+
...state
|
|
4293
|
+
});
|
|
4294
|
+
});
|
|
4295
|
+
return () => {
|
|
4296
|
+
unsubscribe();
|
|
4297
|
+
};
|
|
4298
|
+
}, [toolbarService]);
|
|
4299
|
+
return /*#__PURE__*/react.createElement(ui_src/* ToolbarButton */.hA, ToolbarButtonWithServices_extends({
|
|
4300
|
+
commands: commands,
|
|
4301
|
+
id: id,
|
|
4302
|
+
type: type,
|
|
4303
|
+
isActive: isActive,
|
|
4304
|
+
onInteraction: onInteraction
|
|
4305
|
+
}, props));
|
|
4306
|
+
}
|
|
4307
|
+
ToolbarButtonWithServices.propTypes = {
|
|
4308
|
+
id: (prop_types_default()).string.isRequired,
|
|
4309
|
+
type: prop_types_default().oneOf(['tool', 'action', 'toggle']).isRequired,
|
|
4310
|
+
commands: prop_types_default().arrayOf(prop_types_default().shape({
|
|
4311
|
+
commandName: (prop_types_default()).string.isRequired,
|
|
4312
|
+
context: (prop_types_default()).string
|
|
4313
|
+
})),
|
|
4314
|
+
onInteraction: (prop_types_default()).func.isRequired,
|
|
4315
|
+
servicesManager: prop_types_default().shape({
|
|
4316
|
+
services: prop_types_default().shape({
|
|
4317
|
+
toolbarService: prop_types_default().shape({
|
|
4318
|
+
subscribe: (prop_types_default()).func.isRequired,
|
|
4319
|
+
state: prop_types_default().shape({
|
|
4320
|
+
primaryToolId: (prop_types_default()).string,
|
|
4321
|
+
toggles: prop_types_default().objectOf((prop_types_default()).bool),
|
|
4322
|
+
groups: prop_types_default().objectOf((prop_types_default()).object)
|
|
4323
|
+
}).isRequired
|
|
4324
|
+
}).isRequired
|
|
4325
|
+
}).isRequired
|
|
4326
|
+
}).isRequired
|
|
4327
|
+
};
|
|
4328
|
+
/* harmony default export */ const Toolbar_ToolbarButtonWithServices = (ToolbarButtonWithServices);
|
|
3657
4329
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getToolbarModule.tsx
|
|
3658
4330
|
|
|
3659
4331
|
|
|
@@ -3670,15 +4342,15 @@ function getToolbarModule(_ref) {
|
|
|
3670
4342
|
clickHandler: () => {}
|
|
3671
4343
|
}, {
|
|
3672
4344
|
name: 'ohif.action',
|
|
3673
|
-
defaultComponent:
|
|
4345
|
+
defaultComponent: Toolbar_ToolbarButtonWithServices,
|
|
3674
4346
|
clickHandler: () => {}
|
|
3675
4347
|
}, {
|
|
3676
4348
|
name: 'ohif.radioGroup',
|
|
3677
|
-
defaultComponent:
|
|
4349
|
+
defaultComponent: Toolbar_ToolbarButtonWithServices,
|
|
3678
4350
|
clickHandler: () => {}
|
|
3679
4351
|
}, {
|
|
3680
4352
|
name: 'ohif.splitButton',
|
|
3681
|
-
defaultComponent:
|
|
4353
|
+
defaultComponent: Toolbar_ToolbarSplitButtonWithServices,
|
|
3682
4354
|
clickHandler: () => {}
|
|
3683
4355
|
}, {
|
|
3684
4356
|
name: 'ohif.layoutSelector',
|
|
@@ -3686,7 +4358,7 @@ function getToolbarModule(_ref) {
|
|
|
3686
4358
|
clickHandler: (evt, clickedBtn, btnSectionName) => {}
|
|
3687
4359
|
}, {
|
|
3688
4360
|
name: 'ohif.toggle',
|
|
3689
|
-
defaultComponent:
|
|
4361
|
+
defaultComponent: Toolbar_ToolbarButtonWithServices,
|
|
3690
4362
|
clickHandler: () => {}
|
|
3691
4363
|
}];
|
|
3692
4364
|
}
|
|
@@ -3856,7 +4528,7 @@ function adaptItem(item, subProps) {
|
|
|
3856
4528
|
return newItem;
|
|
3857
4529
|
}
|
|
3858
4530
|
// EXTERNAL MODULE: ../../ui/src/components/ContextMenu/ContextMenu.tsx
|
|
3859
|
-
var ContextMenu = __webpack_require__(
|
|
4531
|
+
var ContextMenu = __webpack_require__(5638);
|
|
3860
4532
|
;// CONCATENATED MODULE: ../../../extensions/default/src/CustomizableContextMenu/ContextMenuController.tsx
|
|
3861
4533
|
|
|
3862
4534
|
|
|
@@ -3917,8 +4589,8 @@ class ContextMenuController {
|
|
|
3917
4589
|
defaultPosition: ContextMenuController._getDefaultPosition(defaultPointsPosition, event?.detail, viewportElement),
|
|
3918
4590
|
event,
|
|
3919
4591
|
content: ContextMenu/* default */.Z,
|
|
3920
|
-
// This naming is part of
|
|
3921
|
-
// Clicking outside
|
|
4592
|
+
// This naming is part of the uiDialogService convention
|
|
4593
|
+
// Clicking outside simply closes the dialog box.
|
|
3922
4594
|
onClickOutside: () => this.services.uiDialogService.dismiss({
|
|
3923
4595
|
id: 'context-menu'
|
|
3924
4596
|
}),
|
|
@@ -4065,10 +4737,10 @@ const defaultContextMenu = {
|
|
|
4065
4737
|
|
|
4066
4738
|
|
|
4067
4739
|
// EXTERNAL MODULE: ../../../node_modules/moment/moment.js
|
|
4068
|
-
var moment = __webpack_require__(
|
|
4740
|
+
var moment = __webpack_require__(71271);
|
|
4069
4741
|
var moment_default = /*#__PURE__*/__webpack_require__.n(moment);
|
|
4070
4742
|
// EXTERNAL MODULE: ../../../node_modules/react-window/dist/index.esm.js
|
|
4071
|
-
var index_esm = __webpack_require__(
|
|
4743
|
+
var index_esm = __webpack_require__(94614);
|
|
4072
4744
|
;// CONCATENATED MODULE: ../../../extensions/default/src/DicomTagBrowser/DicomTagTable.tsx
|
|
4073
4745
|
|
|
4074
4746
|
|
|
@@ -4093,34 +4765,34 @@ function ColumnHeaders(_ref) {
|
|
|
4093
4765
|
valueRef
|
|
4094
4766
|
} = _ref;
|
|
4095
4767
|
return /*#__PURE__*/react.createElement("div", {
|
|
4096
|
-
className: classnames_default()('
|
|
4768
|
+
className: classnames_default()('bg-secondary-dark ohif-scrollbar flex w-full flex-row overflow-y-scroll'),
|
|
4097
4769
|
style: rowVerticalPaddingStyle
|
|
4098
4770
|
}, /*#__PURE__*/react.createElement("div", {
|
|
4099
|
-
className: "
|
|
4771
|
+
className: "w-4/24 px-3"
|
|
4100
4772
|
}, /*#__PURE__*/react.createElement("label", {
|
|
4101
4773
|
ref: tagRef,
|
|
4102
|
-
className: "flex flex-
|
|
4774
|
+
className: "flex flex-1 select-none flex-col pl-1 text-lg text-white"
|
|
4103
4775
|
}, /*#__PURE__*/react.createElement("span", {
|
|
4104
4776
|
className: "flex flex-row items-center focus:outline-none"
|
|
4105
4777
|
}, "Tag"))), /*#__PURE__*/react.createElement("div", {
|
|
4106
|
-
className: "
|
|
4778
|
+
className: "w-2/24 px-3"
|
|
4107
4779
|
}, /*#__PURE__*/react.createElement("label", {
|
|
4108
4780
|
ref: vrRef,
|
|
4109
|
-
className: "flex flex-
|
|
4781
|
+
className: "flex flex-1 select-none flex-col pl-1 text-lg text-white"
|
|
4110
4782
|
}, /*#__PURE__*/react.createElement("span", {
|
|
4111
4783
|
className: "flex flex-row items-center focus:outline-none"
|
|
4112
4784
|
}, "VR"))), /*#__PURE__*/react.createElement("div", {
|
|
4113
|
-
className: "
|
|
4785
|
+
className: "w-6/24 px-3"
|
|
4114
4786
|
}, /*#__PURE__*/react.createElement("label", {
|
|
4115
4787
|
ref: keywordRef,
|
|
4116
|
-
className: "flex flex-
|
|
4788
|
+
className: "flex flex-1 select-none flex-col pl-1 text-lg text-white"
|
|
4117
4789
|
}, /*#__PURE__*/react.createElement("span", {
|
|
4118
4790
|
className: "flex flex-row items-center focus:outline-none"
|
|
4119
4791
|
}, "Keyword"))), /*#__PURE__*/react.createElement("div", {
|
|
4120
|
-
className: "
|
|
4792
|
+
className: "w-5/24 grow px-3"
|
|
4121
4793
|
}, /*#__PURE__*/react.createElement("label", {
|
|
4122
4794
|
ref: valueRef,
|
|
4123
|
-
className: "flex flex-
|
|
4795
|
+
className: "flex flex-1 select-none flex-col pl-1 text-lg text-white"
|
|
4124
4796
|
}, /*#__PURE__*/react.createElement("span", {
|
|
4125
4797
|
className: "flex flex-row items-center focus:outline-none"
|
|
4126
4798
|
}, "Value"))));
|
|
@@ -4193,16 +4865,16 @@ function DicomTagTable(_ref2) {
|
|
|
4193
4865
|
...style,
|
|
4194
4866
|
...rowStyle
|
|
4195
4867
|
},
|
|
4196
|
-
className: classnames_default()('hover:bg-secondary-main
|
|
4868
|
+
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
4869
|
key: `DICOMTagRow-${index}`
|
|
4198
4870
|
}, /*#__PURE__*/react.createElement("div", {
|
|
4199
|
-
className: "
|
|
4871
|
+
className: "w-4/24 px-3"
|
|
4200
4872
|
}, row[0]), /*#__PURE__*/react.createElement("div", {
|
|
4201
|
-
className: "
|
|
4873
|
+
className: "w-2/24 px-3"
|
|
4202
4874
|
}, row[1]), /*#__PURE__*/react.createElement("div", {
|
|
4203
|
-
className: "
|
|
4875
|
+
className: "w-6/24 px-3"
|
|
4204
4876
|
}, row[2]), /*#__PURE__*/react.createElement("div", {
|
|
4205
|
-
className: "
|
|
4877
|
+
className: "w-5/24 grow px-3"
|
|
4206
4878
|
}, row[3]));
|
|
4207
4879
|
}, [rows]);
|
|
4208
4880
|
|
|
@@ -4240,7 +4912,7 @@ function DicomTagTable(_ref2) {
|
|
|
4240
4912
|
keywordRef: keywordRef,
|
|
4241
4913
|
valueRef: valueRef
|
|
4242
4914
|
}), /*#__PURE__*/react.createElement("div", {
|
|
4243
|
-
className: "m-auto
|
|
4915
|
+
className: "relative m-auto border-2 border-black bg-black",
|
|
4244
4916
|
style: {
|
|
4245
4917
|
height: '32rem'
|
|
4246
4918
|
}
|
|
@@ -4266,7 +4938,6 @@ function DicomTagTable(_ref2) {
|
|
|
4266
4938
|
|
|
4267
4939
|
|
|
4268
4940
|
|
|
4269
|
-
|
|
4270
4941
|
const {
|
|
4271
4942
|
ImageSet: DicomTagBrowser_ImageSet
|
|
4272
4943
|
} = src.classes;
|
|
@@ -4295,7 +4966,6 @@ const DicomTagBrowser = _ref => {
|
|
|
4295
4966
|
setSelectedDisplaySetInstanceUID(value.value);
|
|
4296
4967
|
setInstanceNumber(1);
|
|
4297
4968
|
};
|
|
4298
|
-
const searchInputRef = (0,react.useRef)(null);
|
|
4299
4969
|
const activeDisplaySet = displaySets.find(ds => ds.displaySetInstanceUID === selectedDisplaySetInstanceUID);
|
|
4300
4970
|
const isImageStack = _isImageStack(activeDisplaySet);
|
|
4301
4971
|
const showInstanceList = isImageStack && activeDisplaySet.images.length > 1;
|
|
@@ -4361,14 +5031,14 @@ const DicomTagBrowser = _ref => {
|
|
|
4361
5031
|
return /*#__PURE__*/react.createElement("div", {
|
|
4362
5032
|
className: "dicom-tag-browser-content"
|
|
4363
5033
|
}, /*#__PURE__*/react.createElement("div", {
|
|
4364
|
-
className: "flex flex-row
|
|
5034
|
+
className: "mb-6 flex flex-row items-center pl-1"
|
|
4365
5035
|
}, /*#__PURE__*/react.createElement("div", {
|
|
4366
|
-
className: "flex flex-row items-center
|
|
5036
|
+
className: "flex w-1/2 flex-row items-center"
|
|
4367
5037
|
}, /*#__PURE__*/react.createElement(ui_src/* Typography */.ZT, {
|
|
4368
5038
|
variant: "subtitle",
|
|
4369
5039
|
className: "mr-4"
|
|
4370
5040
|
}, "Series"), /*#__PURE__*/react.createElement("div", {
|
|
4371
|
-
className: "
|
|
5041
|
+
className: "mr-8 grow"
|
|
4372
5042
|
}, /*#__PURE__*/react.createElement(ui_src/* Select */.Ph, {
|
|
4373
5043
|
id: "display-set-selector",
|
|
4374
5044
|
isClearable: false,
|
|
@@ -4377,7 +5047,7 @@ const DicomTagBrowser = _ref => {
|
|
|
4377
5047
|
value: displaySetList.find(ds => ds.value === selectedDisplaySetInstanceUID),
|
|
4378
5048
|
className: "text-white"
|
|
4379
5049
|
}))), /*#__PURE__*/react.createElement("div", {
|
|
4380
|
-
className: "flex flex-row items-center
|
|
5050
|
+
className: "flex w-1/2 flex-row items-center"
|
|
4381
5051
|
}, showInstanceList && /*#__PURE__*/react.createElement(ui_src/* Typography */.ZT, {
|
|
4382
5052
|
variant: "subtitle",
|
|
4383
5053
|
className: "mr-4"
|
|
@@ -4396,32 +5066,14 @@ const DicomTagBrowser = _ref => {
|
|
|
4396
5066
|
labelPosition: "left",
|
|
4397
5067
|
trackColor: '#3a3f99'
|
|
4398
5068
|
})))), /*#__PURE__*/react.createElement("div", {
|
|
4399
|
-
className: "w-full
|
|
5069
|
+
className: "h-1 w-full bg-black"
|
|
4400
5070
|
}), /*#__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",
|
|
5071
|
+
className: "my-3 flex w-1/2 flex-row"
|
|
5072
|
+
}, /*#__PURE__*/react.createElement(ui_src/* InputFilterText */.Xe, {
|
|
5073
|
+
className: "mr-8 block w-full",
|
|
4412
5074
|
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, {
|
|
5075
|
+
onDebounceChange: setFilterValue
|
|
5076
|
+
})), /*#__PURE__*/react.createElement(DicomTagBrowser_DicomTagTable, {
|
|
4425
5077
|
rows: filteredRows
|
|
4426
5078
|
}));
|
|
4427
5079
|
};
|
|
@@ -4594,61 +5246,62 @@ function _sortTagList(tagList) {
|
|
|
4594
5246
|
*/
|
|
4595
5247
|
const reuseCachedLayout = (state, hangingProtocolService, syncService) => {
|
|
4596
5248
|
const {
|
|
4597
|
-
|
|
4598
|
-
viewports,
|
|
4599
|
-
layout
|
|
5249
|
+
activeViewportId
|
|
4600
5250
|
} = state;
|
|
5251
|
+
const {
|
|
5252
|
+
protocol
|
|
5253
|
+
} = hangingProtocolService.getActiveProtocol();
|
|
4601
5254
|
const hpInfo = hangingProtocolService.getState();
|
|
4602
5255
|
const {
|
|
4603
5256
|
protocolId,
|
|
4604
5257
|
stageIndex,
|
|
4605
5258
|
activeStudyUID
|
|
4606
5259
|
} = hpInfo;
|
|
4607
|
-
const {
|
|
4608
|
-
protocol
|
|
4609
|
-
} = hangingProtocolService.getActiveProtocol();
|
|
4610
|
-
const stage = protocol.stages[stageIndex];
|
|
4611
|
-
const storeId = `${activeStudyUID}:${protocolId}:${stageIndex}`;
|
|
4612
5260
|
const syncState = syncService.getState();
|
|
4613
|
-
const cacheId = `${activeStudyUID}:${protocolId}`;
|
|
4614
5261
|
const viewportGridStore = {
|
|
4615
5262
|
...syncState.viewportGridStore
|
|
4616
5263
|
};
|
|
5264
|
+
const displaySetSelectorMap = {
|
|
5265
|
+
...syncState.displaySetSelectorMap
|
|
5266
|
+
};
|
|
5267
|
+
const stage = protocol.stages[stageIndex];
|
|
5268
|
+
const storeId = `${activeStudyUID}:${protocolId}:${stageIndex}`;
|
|
5269
|
+
const cacheId = `${activeStudyUID}:${protocolId}`;
|
|
4617
5270
|
const hangingProtocolStageIndexMap = {
|
|
4618
5271
|
...syncState.hangingProtocolStageIndexMap
|
|
4619
5272
|
};
|
|
4620
|
-
const displaySetSelectorMap = {
|
|
4621
|
-
...syncState.displaySetSelectorMap
|
|
4622
|
-
};
|
|
4623
5273
|
const {
|
|
4624
5274
|
rows,
|
|
4625
5275
|
columns
|
|
4626
5276
|
} = stage.viewportStructure.properties;
|
|
4627
|
-
const custom = stage.viewports.length !== state.viewports.
|
|
5277
|
+
const custom = stage.viewports.length !== state.viewports.size || state.layout.numRows !== rows || state.layout.numCols !== columns;
|
|
4628
5278
|
hangingProtocolStageIndexMap[cacheId] = hpInfo;
|
|
4629
5279
|
if (storeId && custom) {
|
|
4630
5280
|
viewportGridStore[storeId] = {
|
|
4631
5281
|
...state
|
|
4632
5282
|
};
|
|
4633
5283
|
}
|
|
4634
|
-
|
|
4635
|
-
const viewport = state.viewports[idx];
|
|
5284
|
+
state.viewports.forEach((viewport, viewportId) => {
|
|
4636
5285
|
const {
|
|
4637
5286
|
displaySetOptions,
|
|
4638
5287
|
displaySetInstanceUIDs
|
|
4639
5288
|
} = viewport;
|
|
4640
|
-
if (!displaySetOptions)
|
|
5289
|
+
if (!displaySetOptions) {
|
|
5290
|
+
return;
|
|
5291
|
+
}
|
|
4641
5292
|
for (let i = 0; i < displaySetOptions.length; i++) {
|
|
4642
5293
|
const displaySetUID = displaySetInstanceUIDs[i];
|
|
4643
|
-
if (!displaySetUID)
|
|
4644
|
-
|
|
5294
|
+
if (!displaySetUID) {
|
|
5295
|
+
continue;
|
|
5296
|
+
}
|
|
5297
|
+
if (viewportId === activeViewportId && i === 0) {
|
|
4645
5298
|
displaySetSelectorMap[`${activeStudyUID}:activeDisplaySet:0`] = displaySetUID;
|
|
4646
5299
|
}
|
|
4647
5300
|
if (displaySetOptions[i]?.id) {
|
|
4648
5301
|
displaySetSelectorMap[`${activeStudyUID}:${displaySetOptions[i].id}:${displaySetOptions[i].matchedDisplaySetsIndex || 0}`] = displaySetUID;
|
|
4649
5302
|
}
|
|
4650
5303
|
}
|
|
4651
|
-
}
|
|
5304
|
+
});
|
|
4652
5305
|
return {
|
|
4653
5306
|
hangingProtocolStageIndexMap,
|
|
4654
5307
|
viewportGridStore,
|
|
@@ -4660,22 +5313,24 @@ const reuseCachedLayout = (state, hangingProtocolService, syncService) => {
|
|
|
4660
5313
|
/**
|
|
4661
5314
|
* This find or create viewport is paired with the reduce results from
|
|
4662
5315
|
* below, and the action of this viewport is to look for previously filled
|
|
4663
|
-
* viewports, and to
|
|
5316
|
+
* viewports, and to reuse by position id. If there is no filled viewport,
|
|
4664
5317
|
* then one can be re-used from the display set if it isn't going to be displayed.
|
|
4665
5318
|
* @param hangingProtocolService - bound parameter supplied before using this
|
|
4666
5319
|
* @param viewportsByPosition - bound parameter supplied before using this
|
|
4667
|
-
* @param
|
|
5320
|
+
* @param position - the position in the grid to retrieve
|
|
4668
5321
|
* @param positionId - the current position on screen to retrieve
|
|
4669
5322
|
* @param options - the set of options used, so that subsequent calls can
|
|
4670
5323
|
* store state that is reset by the setLayout.
|
|
4671
5324
|
* This class uses the options to store the already viewed
|
|
4672
5325
|
* display sets, filling it initially with the pre-existing viewports.
|
|
4673
5326
|
*/
|
|
4674
|
-
const findViewportsByPosition_findOrCreateViewport = (hangingProtocolService, viewportsByPosition,
|
|
5327
|
+
const findViewportsByPosition_findOrCreateViewport = (hangingProtocolService, viewportsByPosition, position, positionId, options) => {
|
|
4675
5328
|
const byPositionViewport = viewportsByPosition?.[positionId];
|
|
4676
|
-
if (byPositionViewport)
|
|
4677
|
-
|
|
4678
|
-
|
|
5329
|
+
if (byPositionViewport) {
|
|
5330
|
+
return {
|
|
5331
|
+
...byPositionViewport
|
|
5332
|
+
};
|
|
5333
|
+
}
|
|
4679
5334
|
const {
|
|
4680
5335
|
protocolId,
|
|
4681
5336
|
stageIndex
|
|
@@ -4723,7 +5378,7 @@ const findViewportsByPosition = (state, _ref, syncService) => {
|
|
|
4723
5378
|
...syncState.viewportsByPosition
|
|
4724
5379
|
};
|
|
4725
5380
|
const initialInDisplay = [];
|
|
4726
|
-
|
|
5381
|
+
viewports.forEach(viewport => {
|
|
4727
5382
|
if (viewport.positionId) {
|
|
4728
5383
|
const storedViewport = {
|
|
4729
5384
|
...viewport,
|
|
@@ -4732,16 +5387,11 @@ const findViewportsByPosition = (state, _ref, syncService) => {
|
|
|
4732
5387
|
}
|
|
4733
5388
|
};
|
|
4734
5389
|
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
5390
|
}
|
|
4740
|
-
}
|
|
5391
|
+
});
|
|
4741
5392
|
for (let row = 0; row < numRows; row++) {
|
|
4742
5393
|
for (let col = 0; col < numCols; col++) {
|
|
4743
|
-
const
|
|
4744
|
-
const positionId = viewports?.[pos]?.positionId || `${col}-${row}`;
|
|
5394
|
+
const positionId = `${col}-${row}`;
|
|
4745
5395
|
const viewport = viewportsByPosition[positionId];
|
|
4746
5396
|
if (viewport?.displaySetInstanceUIDs) {
|
|
4747
5397
|
initialInDisplay.push(...viewport.displaySetInstanceUIDs);
|
|
@@ -4756,8 +5406,8 @@ const findViewportsByPosition = (state, _ref, syncService) => {
|
|
|
4756
5406
|
};
|
|
4757
5407
|
};
|
|
4758
5408
|
/* harmony default export */ const src_findViewportsByPosition = (findViewportsByPosition);
|
|
4759
|
-
// EXTERNAL MODULE: ./index.js +
|
|
4760
|
-
var index = __webpack_require__(
|
|
5409
|
+
// EXTERNAL MODULE: ./index.js + 33 modules
|
|
5410
|
+
var index = __webpack_require__(59754);
|
|
4761
5411
|
;// CONCATENATED MODULE: ../../../extensions/default/src/commandsModule.ts
|
|
4762
5412
|
|
|
4763
5413
|
|
|
@@ -4859,7 +5509,9 @@ const commandsModule = _ref => {
|
|
|
4859
5509
|
stage
|
|
4860
5510
|
} = hangingProtocolService.getActiveProtocol();
|
|
4861
5511
|
const enableListener = button => {
|
|
4862
|
-
if (!button.id)
|
|
5512
|
+
if (!button.id) {
|
|
5513
|
+
return;
|
|
5514
|
+
}
|
|
4863
5515
|
const {
|
|
4864
5516
|
commands,
|
|
4865
5517
|
items
|
|
@@ -4868,14 +5520,16 @@ const commandsModule = _ref => {
|
|
|
4868
5520
|
items.forEach(enableListener);
|
|
4869
5521
|
}
|
|
4870
5522
|
const hpCommand = commands?.find?.(isHangingProtocolCommand);
|
|
4871
|
-
if (!hpCommand)
|
|
5523
|
+
if (!hpCommand) {
|
|
5524
|
+
return;
|
|
5525
|
+
}
|
|
4872
5526
|
const {
|
|
4873
5527
|
protocolId,
|
|
4874
5528
|
stageIndex,
|
|
4875
5529
|
stageId
|
|
4876
5530
|
} = hpCommand.commandOptions;
|
|
4877
5531
|
const isActive = (!protocolId || protocolId === protocol.id) && (stageIndex === undefined || stageIndex === toggleStageIndex) && (!stageId || stageId === stage.id);
|
|
4878
|
-
toolbarService.
|
|
5532
|
+
toolbarService.setToggled(button.id, isActive);
|
|
4879
5533
|
};
|
|
4880
5534
|
Object.values(toolbarService.getButtons()).forEach(enableListener);
|
|
4881
5535
|
},
|
|
@@ -4927,7 +5581,7 @@ const commandsModule = _ref => {
|
|
|
4927
5581
|
displaySetSelectorMap
|
|
4928
5582
|
} = stateSyncReduce;
|
|
4929
5583
|
if (!protocolId) {
|
|
4930
|
-
//
|
|
5584
|
+
// Reuse the previous protocol id, and optionally stage
|
|
4931
5585
|
protocolId = hpInfo.protocolId;
|
|
4932
5586
|
if (stageId === undefined && stageIndex === undefined) {
|
|
4933
5587
|
stageIndex = hpInfo.stageIndex;
|
|
@@ -4970,19 +5624,20 @@ const commandsModule = _ref => {
|
|
|
4970
5624
|
delete displaySetSelectorMap[`${activeStudyUID || hpInfo.activeStudyUID}:activeDisplaySet:0`];
|
|
4971
5625
|
stateSyncService.store(stateSyncReduce);
|
|
4972
5626
|
// This is a default action applied
|
|
4973
|
-
|
|
5627
|
+
const {
|
|
5628
|
+
protocol
|
|
5629
|
+
} = hangingProtocolService.getActiveProtocol();
|
|
5630
|
+
actions.toggleHpTools(protocol);
|
|
4974
5631
|
// Send the notification about updating the state
|
|
4975
5632
|
if (protocolId !== hpInfo.protocolId) {
|
|
4976
|
-
const {
|
|
4977
|
-
protocol
|
|
4978
|
-
} = hangingProtocolService.getActiveProtocol();
|
|
4979
5633
|
// The old protocol callbacks are used for turning off things
|
|
4980
5634
|
// like crosshairs when moving to the new HP
|
|
4981
5635
|
commandsManager.run(oldProtocol.callbacks?.onProtocolExit);
|
|
4982
5636
|
// The new protocol callback is used for things like
|
|
4983
5637
|
// activating modes etc.
|
|
4984
|
-
commandsManager.run(protocol.callbacks?.onProtocolEnter);
|
|
4985
5638
|
}
|
|
5639
|
+
|
|
5640
|
+
commandsManager.run(protocol.callbacks?.onProtocolEnter);
|
|
4986
5641
|
return true;
|
|
4987
5642
|
} catch (e) {
|
|
4988
5643
|
actions.toggleHpTools(hangingProtocolService.getActiveProtocol());
|
|
@@ -5098,7 +5753,7 @@ const commandsModule = _ref => {
|
|
|
5098
5753
|
toggleOneUp() {
|
|
5099
5754
|
const viewportGridState = viewportGridService.getState();
|
|
5100
5755
|
const {
|
|
5101
|
-
|
|
5756
|
+
activeViewportId,
|
|
5102
5757
|
viewports,
|
|
5103
5758
|
layout
|
|
5104
5759
|
} = viewportGridState;
|
|
@@ -5106,7 +5761,7 @@ const commandsModule = _ref => {
|
|
|
5106
5761
|
displaySetInstanceUIDs,
|
|
5107
5762
|
displaySetOptions,
|
|
5108
5763
|
viewportOptions
|
|
5109
|
-
} = viewports
|
|
5764
|
+
} = viewports.get(activeViewportId);
|
|
5110
5765
|
if (layout.numCols === 1 && layout.numRows === 1) {
|
|
5111
5766
|
// The viewer is in one-up. Check if there is a state to restore/toggle back to.
|
|
5112
5767
|
const {
|
|
@@ -5117,24 +5772,33 @@ const commandsModule = _ref => {
|
|
|
5117
5772
|
}
|
|
5118
5773
|
// There is a state to toggle back to. The viewport that was
|
|
5119
5774
|
// originally toggled to one up was the former active viewport.
|
|
5120
|
-
const
|
|
5775
|
+
const viewportIdToUpdate = toggleOneUpViewportGridStore.activeViewportId;
|
|
5121
5776
|
|
|
5122
|
-
//
|
|
5123
|
-
//
|
|
5124
|
-
//
|
|
5125
|
-
//
|
|
5126
|
-
|
|
5777
|
+
// We are restoring the previous layout but taking into the account that
|
|
5778
|
+
// the current one up viewport might have a new displaySet dragged and dropped on it.
|
|
5779
|
+
// updatedViewportsViaHP below contains the viewports applicable to the HP that existed
|
|
5780
|
+
// prior to the toggle to one-up - including the updated viewports if a display
|
|
5781
|
+
// set swap were to have occurred.
|
|
5782
|
+
const updatedViewportsViaHP = displaySetInstanceUIDs.length > 1 ? [] : displaySetInstanceUIDs.map(displaySetInstanceUID => hangingProtocolService.getViewportsRequireUpdate(viewportIdToUpdate, displaySetInstanceUID)).flat();
|
|
5127
5783
|
|
|
5128
|
-
//
|
|
5784
|
+
// findOrCreateViewport returns either one of the updatedViewportsViaHP
|
|
5129
5785
|
// 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
|
-
|
|
5786
|
+
// simply returns what was in the previous state for a given position in the layout.
|
|
5787
|
+
const findOrCreateViewport = (position, positionId) => {
|
|
5788
|
+
// Find the viewport for the given position prior to the toggle to one-up.
|
|
5789
|
+
const preOneUpViewport = Array.from(toggleOneUpViewportGridStore.viewports.values()).find(viewport => viewport.positionId === positionId);
|
|
5790
|
+
|
|
5791
|
+
// Use the viewport id from before the toggle to one-up to find any updates to the viewport.
|
|
5792
|
+
const viewport = updatedViewportsViaHP.find(viewport => viewport.viewportId === preOneUpViewport.viewportId);
|
|
5793
|
+
return viewport ?
|
|
5794
|
+
// Use the applicable viewport from the HP updated viewports
|
|
5795
|
+
{
|
|
5134
5796
|
viewportOptions,
|
|
5135
5797
|
displaySetOptions,
|
|
5136
5798
|
...viewport
|
|
5137
|
-
} :
|
|
5799
|
+
} :
|
|
5800
|
+
// Use the previous viewport for the given position
|
|
5801
|
+
preOneUpViewport;
|
|
5138
5802
|
};
|
|
5139
5803
|
const layoutOptions = viewportGridService.getLayoutOptionsFromState(toggleOneUpViewportGridStore);
|
|
5140
5804
|
|
|
@@ -5142,7 +5806,7 @@ const commandsModule = _ref => {
|
|
|
5142
5806
|
viewportGridService.setLayout({
|
|
5143
5807
|
numRows: toggleOneUpViewportGridStore.layout.numRows,
|
|
5144
5808
|
numCols: toggleOneUpViewportGridStore.layout.numCols,
|
|
5145
|
-
|
|
5809
|
+
activeViewportId: viewportIdToUpdate,
|
|
5146
5810
|
layoutOptions,
|
|
5147
5811
|
findOrCreateViewport
|
|
5148
5812
|
});
|
|
@@ -5207,10 +5871,10 @@ const commandsModule = _ref => {
|
|
|
5207
5871
|
},
|
|
5208
5872
|
openDICOMTagViewer() {
|
|
5209
5873
|
const {
|
|
5210
|
-
|
|
5874
|
+
activeViewportId,
|
|
5211
5875
|
viewports
|
|
5212
5876
|
} = viewportGridService.getState();
|
|
5213
|
-
const activeViewportSpecificData = viewports
|
|
5877
|
+
const activeViewportSpecificData = viewports.get(activeViewportId);
|
|
5214
5878
|
const {
|
|
5215
5879
|
displaySetInstanceUIDs
|
|
5216
5880
|
} = activeViewportSpecificData;
|
|
@@ -5242,13 +5906,10 @@ const commandsModule = _ref => {
|
|
|
5242
5906
|
},
|
|
5243
5907
|
scrollActiveThumbnailIntoView: () => {
|
|
5244
5908
|
const {
|
|
5245
|
-
|
|
5909
|
+
activeViewportId,
|
|
5246
5910
|
viewports
|
|
5247
5911
|
} = viewportGridService.getState();
|
|
5248
|
-
|
|
5249
|
-
return;
|
|
5250
|
-
}
|
|
5251
|
-
const activeViewport = viewports[activeViewportIndex];
|
|
5912
|
+
const activeViewport = viewports.get(activeViewportId);
|
|
5252
5913
|
const activeDisplaySetInstanceUID = activeViewport.displaySetInstanceUIDs[0];
|
|
5253
5914
|
const thumbnailList = document.querySelector('#ohif-thumbnail-list');
|
|
5254
5915
|
if (!thumbnailList) {
|
|
@@ -5282,12 +5943,12 @@ const commandsModule = _ref => {
|
|
|
5282
5943
|
const currentDisplaySets = [...displaySetService.activeDisplaySets];
|
|
5283
5944
|
currentDisplaySets.sort(dsSortFn);
|
|
5284
5945
|
const {
|
|
5285
|
-
|
|
5946
|
+
activeViewportId,
|
|
5286
5947
|
viewports
|
|
5287
5948
|
} = viewportGridService.getState();
|
|
5288
5949
|
const {
|
|
5289
5950
|
displaySetInstanceUIDs
|
|
5290
|
-
} = viewports
|
|
5951
|
+
} = viewports.get(activeViewportId);
|
|
5291
5952
|
const activeDisplaySetIndex = currentDisplaySets.findIndex(displaySet => displaySetInstanceUIDs.includes(displaySet.displaySetInstanceUID));
|
|
5292
5953
|
let displaySetIndexToShow;
|
|
5293
5954
|
for (displaySetIndexToShow = activeDisplaySetIndex + direction; displaySetIndexToShow > -1 && displaySetIndexToShow < currentDisplaySets.length; displaySetIndexToShow += direction) {
|
|
@@ -5303,7 +5964,7 @@ const commandsModule = _ref => {
|
|
|
5303
5964
|
} = currentDisplaySets[displaySetIndexToShow];
|
|
5304
5965
|
let updatedViewports = [];
|
|
5305
5966
|
try {
|
|
5306
|
-
updatedViewports = hangingProtocolService.getViewportsRequireUpdate(
|
|
5967
|
+
updatedViewports = hangingProtocolService.getViewportsRequireUpdate(activeViewportId, displaySetInstanceUID);
|
|
5307
5968
|
} catch (error) {
|
|
5308
5969
|
console.warn(error);
|
|
5309
5970
|
uiNotificationService.show({
|
|
@@ -5397,7 +6058,6 @@ const commandsModule = _ref => {
|
|
|
5397
6058
|
* It is not included in the viewer mode by default.
|
|
5398
6059
|
*/
|
|
5399
6060
|
const hpMN = {
|
|
5400
|
-
hasUpdatedPriorsInformation: false,
|
|
5401
6061
|
id: '@ohif/mnGrid',
|
|
5402
6062
|
description: 'Has various hanging protocol grid layouts',
|
|
5403
6063
|
name: '2x2',
|
|
@@ -5606,15 +6266,182 @@ const hpMN = {
|
|
|
5606
6266
|
numberOfPriorsReferenced: -1
|
|
5607
6267
|
};
|
|
5608
6268
|
/* harmony default export */ const hpMNGrid = (hpMN);
|
|
6269
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/hpCompare.ts
|
|
6270
|
+
const defaultDisplaySetSelector = {
|
|
6271
|
+
studyMatchingRules: [{
|
|
6272
|
+
// The priorInstance is a study counter that indicates what position this study is in
|
|
6273
|
+
// and the value comes from the options parameter.
|
|
6274
|
+
attribute: 'studyInstanceUIDsIndex',
|
|
6275
|
+
from: 'options',
|
|
6276
|
+
required: true,
|
|
6277
|
+
constraint: {
|
|
6278
|
+
equals: {
|
|
6279
|
+
value: 0
|
|
6280
|
+
}
|
|
6281
|
+
}
|
|
6282
|
+
}],
|
|
6283
|
+
seriesMatchingRules: [{
|
|
6284
|
+
attribute: 'numImageFrames',
|
|
6285
|
+
constraint: {
|
|
6286
|
+
greaterThan: {
|
|
6287
|
+
value: 0
|
|
6288
|
+
}
|
|
6289
|
+
}
|
|
6290
|
+
},
|
|
6291
|
+
// This display set will select the specified items by preference
|
|
6292
|
+
// It has no affect if nothing is specified in the URL.
|
|
6293
|
+
{
|
|
6294
|
+
attribute: 'isDisplaySetFromUrl',
|
|
6295
|
+
weight: 10,
|
|
6296
|
+
constraint: {
|
|
6297
|
+
equals: true
|
|
6298
|
+
}
|
|
6299
|
+
}]
|
|
6300
|
+
};
|
|
6301
|
+
const priorDisplaySetSelector = {
|
|
6302
|
+
studyMatchingRules: [{
|
|
6303
|
+
// The priorInstance is a study counter that indicates what position this study is in
|
|
6304
|
+
// and the value comes from the options parameter.
|
|
6305
|
+
attribute: 'studyInstanceUIDsIndex',
|
|
6306
|
+
from: 'options',
|
|
6307
|
+
required: true,
|
|
6308
|
+
constraint: {
|
|
6309
|
+
equals: {
|
|
6310
|
+
value: 1
|
|
6311
|
+
}
|
|
6312
|
+
}
|
|
6313
|
+
}],
|
|
6314
|
+
seriesMatchingRules: [{
|
|
6315
|
+
attribute: 'numImageFrames',
|
|
6316
|
+
constraint: {
|
|
6317
|
+
greaterThan: {
|
|
6318
|
+
value: 0
|
|
6319
|
+
}
|
|
6320
|
+
}
|
|
6321
|
+
},
|
|
6322
|
+
// This display set will select the specified items by preference
|
|
6323
|
+
// It has no affect if nothing is specified in the URL.
|
|
6324
|
+
{
|
|
6325
|
+
attribute: 'isDisplaySetFromUrl',
|
|
6326
|
+
weight: 10,
|
|
6327
|
+
constraint: {
|
|
6328
|
+
equals: true
|
|
6329
|
+
}
|
|
6330
|
+
}]
|
|
6331
|
+
};
|
|
6332
|
+
const currentDisplaySet = {
|
|
6333
|
+
id: 'defaultDisplaySetId'
|
|
6334
|
+
};
|
|
6335
|
+
const priorDisplaySet = {
|
|
6336
|
+
id: 'priorDisplaySetId'
|
|
6337
|
+
};
|
|
6338
|
+
const currentViewport0 = {
|
|
6339
|
+
viewportOptions: {
|
|
6340
|
+
toolGroupId: 'default',
|
|
6341
|
+
allowUnmatchedView: true
|
|
6342
|
+
},
|
|
6343
|
+
displaySets: [currentDisplaySet]
|
|
6344
|
+
};
|
|
6345
|
+
const currentViewport1 = {
|
|
6346
|
+
...currentViewport0,
|
|
6347
|
+
displaySets: [{
|
|
6348
|
+
...currentDisplaySet,
|
|
6349
|
+
matchedDisplaySetsIndex: 1
|
|
6350
|
+
}]
|
|
6351
|
+
};
|
|
6352
|
+
const priorViewport0 = {
|
|
6353
|
+
...currentViewport0,
|
|
6354
|
+
displaySets: [priorDisplaySet]
|
|
6355
|
+
};
|
|
6356
|
+
const priorViewport1 = {
|
|
6357
|
+
...priorViewport0,
|
|
6358
|
+
displaySets: [{
|
|
6359
|
+
...priorDisplaySet,
|
|
6360
|
+
matchedDisplaySetsIndex: 1
|
|
6361
|
+
}]
|
|
6362
|
+
};
|
|
6363
|
+
|
|
6364
|
+
/**
|
|
6365
|
+
* This hanging protocol can be activated on the primary mode by directly
|
|
6366
|
+
* referencing it in a URL or by directly including it within a mode, e.g.:
|
|
6367
|
+
* `&hangingProtocolId=@ohif/mnGrid` added to the viewer URL
|
|
6368
|
+
* It is not included in the viewer mode by default.
|
|
6369
|
+
*/
|
|
6370
|
+
const hpMNCompare = {
|
|
6371
|
+
id: '@ohif/hpCompare',
|
|
6372
|
+
description: 'Compare two studies in various layouts',
|
|
6373
|
+
name: 'Compare Two Studies',
|
|
6374
|
+
numberOfPriorsReferenced: 1,
|
|
6375
|
+
protocolMatchingRules: [{
|
|
6376
|
+
id: 'Two Studies',
|
|
6377
|
+
weight: 1000,
|
|
6378
|
+
attribute: 'StudyInstanceUID',
|
|
6379
|
+
// The 'from' attribute says where to get the 'attribute' value from. In this case
|
|
6380
|
+
// prior means the second study in the study list.
|
|
6381
|
+
from: 'prior',
|
|
6382
|
+
required: true,
|
|
6383
|
+
constraint: {
|
|
6384
|
+
notNull: true
|
|
6385
|
+
}
|
|
6386
|
+
}],
|
|
6387
|
+
toolGroupIds: ['default'],
|
|
6388
|
+
displaySetSelectors: {
|
|
6389
|
+
defaultDisplaySetId: defaultDisplaySetSelector,
|
|
6390
|
+
priorDisplaySetId: priorDisplaySetSelector
|
|
6391
|
+
},
|
|
6392
|
+
defaultViewport: {
|
|
6393
|
+
viewportOptions: {
|
|
6394
|
+
viewportType: 'stack',
|
|
6395
|
+
toolGroupId: 'default',
|
|
6396
|
+
allowUnmatchedView: true
|
|
6397
|
+
},
|
|
6398
|
+
displaySets: [{
|
|
6399
|
+
id: 'defaultDisplaySetId',
|
|
6400
|
+
matchedDisplaySetsIndex: -1
|
|
6401
|
+
}]
|
|
6402
|
+
},
|
|
6403
|
+
stages: [{
|
|
6404
|
+
name: '2x2',
|
|
6405
|
+
stageActivation: {
|
|
6406
|
+
enabled: {
|
|
6407
|
+
minViewportsMatched: 4
|
|
6408
|
+
}
|
|
6409
|
+
},
|
|
6410
|
+
viewportStructure: {
|
|
6411
|
+
layoutType: 'grid',
|
|
6412
|
+
properties: {
|
|
6413
|
+
rows: 2,
|
|
6414
|
+
columns: 2
|
|
6415
|
+
}
|
|
6416
|
+
},
|
|
6417
|
+
viewports: [currentViewport0, priorViewport0, currentViewport1, priorViewport1]
|
|
6418
|
+
}, {
|
|
6419
|
+
name: '2x1',
|
|
6420
|
+
stageActivation: {
|
|
6421
|
+
enabled: {
|
|
6422
|
+
minViewportsMatched: 2
|
|
6423
|
+
}
|
|
6424
|
+
},
|
|
6425
|
+
viewportStructure: {
|
|
6426
|
+
layoutType: 'grid',
|
|
6427
|
+
properties: {
|
|
6428
|
+
rows: 1,
|
|
6429
|
+
columns: 2
|
|
6430
|
+
}
|
|
6431
|
+
},
|
|
6432
|
+
viewports: [currentViewport0, priorViewport0]
|
|
6433
|
+
}]
|
|
6434
|
+
};
|
|
6435
|
+
/* harmony default export */ const hpCompare = (hpMNCompare);
|
|
5609
6436
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getHangingProtocolModule.js
|
|
5610
6437
|
|
|
6438
|
+
|
|
5611
6439
|
const defaultProtocol = {
|
|
5612
6440
|
id: 'default',
|
|
5613
6441
|
locked: true,
|
|
5614
6442
|
// Don't store this hanging protocol as it applies to the currently active
|
|
5615
6443
|
// display set by default
|
|
5616
6444
|
// cacheId: null,
|
|
5617
|
-
hasUpdatedPriorsInformation: false,
|
|
5618
6445
|
name: 'Default',
|
|
5619
6446
|
createdDate: '2021-02-23T19:22:08.894Z',
|
|
5620
6447
|
modifiedDate: '2023-04-01',
|
|
@@ -5679,6 +6506,7 @@ const defaultProtocol = {
|
|
|
5679
6506
|
viewports: [{
|
|
5680
6507
|
viewportOptions: {
|
|
5681
6508
|
viewportType: 'stack',
|
|
6509
|
+
viewportId: 'default',
|
|
5682
6510
|
toolGroupId: 'default',
|
|
5683
6511
|
// This will specify the initial image options index if it matches in the URL
|
|
5684
6512
|
// and will otherwise not specify anything.
|
|
@@ -5708,6 +6536,11 @@ function getHangingProtocolModule() {
|
|
|
5708
6536
|
{
|
|
5709
6537
|
name: hpMNGrid.id,
|
|
5710
6538
|
protocol: hpMNGrid
|
|
6539
|
+
},
|
|
6540
|
+
// Create a MxN comparison hanging protocol available by default
|
|
6541
|
+
{
|
|
6542
|
+
name: hpCompare.id,
|
|
6543
|
+
protocol: hpCompare
|
|
5711
6544
|
}];
|
|
5712
6545
|
}
|
|
5713
6546
|
/* harmony default export */ const src_getHangingProtocolModule = (getHangingProtocolModule);
|
|
@@ -5730,21 +6563,21 @@ function DataSourceSelector() {
|
|
|
5730
6563
|
height: '100%'
|
|
5731
6564
|
}
|
|
5732
6565
|
}, /*#__PURE__*/react.createElement("div", {
|
|
5733
|
-
className: "h-screen w-screen
|
|
6566
|
+
className: "flex h-screen w-screen items-center justify-center "
|
|
5734
6567
|
}, /*#__PURE__*/react.createElement("div", {
|
|
5735
|
-
className: "
|
|
6568
|
+
className: "bg-secondary-dark mx-auto space-y-2 rounded-lg py-8 px-8 drop-shadow-md"
|
|
5736
6569
|
}, /*#__PURE__*/react.createElement("img", {
|
|
5737
|
-
className: "
|
|
6570
|
+
className: "mx-auto block h-14",
|
|
5738
6571
|
src: "./ohif-logo.svg",
|
|
5739
6572
|
alt: "OHIF"
|
|
5740
6573
|
}), /*#__PURE__*/react.createElement("div", {
|
|
5741
|
-
className: "
|
|
6574
|
+
className: "space-y-2 pt-4 text-center"
|
|
5742
6575
|
}, dsConfigs.filter(it => it.sourceName !== 'dicomjson' && it.sourceName !== 'dicomlocal').map(ds => /*#__PURE__*/react.createElement("div", {
|
|
5743
6576
|
key: ds.sourceName
|
|
5744
6577
|
}, /*#__PURE__*/react.createElement("h1", {
|
|
5745
6578
|
className: "text-white"
|
|
5746
|
-
}, ds.friendlyName), /*#__PURE__*/react.createElement(ui_src/* Button */.zx, {
|
|
5747
|
-
type: ui_src/* ButtonEnums.type */.LZ.
|
|
6579
|
+
}, ds.configuration?.friendlyName || ds.friendlyName), /*#__PURE__*/react.createElement(ui_src/* Button */.zx, {
|
|
6580
|
+
type: ui_src/* ButtonEnums.type */.LZ.dt.primary,
|
|
5748
6581
|
className: classnames_default()('ml-2'),
|
|
5749
6582
|
onClick: () => {
|
|
5750
6583
|
navigate({
|
|
@@ -5755,10 +6588,442 @@ function DataSourceSelector() {
|
|
|
5755
6588
|
}, ds.sourceName), /*#__PURE__*/react.createElement("br", null)))))));
|
|
5756
6589
|
}
|
|
5757
6590
|
/* harmony default export */ const Panels_DataSourceSelector = (DataSourceSelector);
|
|
6591
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/Components/ItemListComponent.tsx
|
|
6592
|
+
|
|
6593
|
+
|
|
6594
|
+
|
|
6595
|
+
|
|
6596
|
+
function ItemListComponent(_ref) {
|
|
6597
|
+
let {
|
|
6598
|
+
itemLabel,
|
|
6599
|
+
itemList,
|
|
6600
|
+
onItemClicked
|
|
6601
|
+
} = _ref;
|
|
6602
|
+
const {
|
|
6603
|
+
t
|
|
6604
|
+
} = (0,es/* useTranslation */.$G)('DataSourceConfiguration');
|
|
6605
|
+
const [filterValue, setFilterValue] = (0,react.useState)('');
|
|
6606
|
+
(0,react.useEffect)(() => {
|
|
6607
|
+
setFilterValue('');
|
|
6608
|
+
}, [itemList]);
|
|
6609
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6610
|
+
className: "flex min-h-[1px] grow flex-col gap-4"
|
|
6611
|
+
}, /*#__PURE__*/react.createElement("div", {
|
|
6612
|
+
className: "flex items-center justify-between"
|
|
6613
|
+
}, /*#__PURE__*/react.createElement("div", {
|
|
6614
|
+
className: "text-primary-light text-[20px]"
|
|
6615
|
+
}, t(`Select ${itemLabel}`)), /*#__PURE__*/react.createElement(ui_src/* InputFilterText */.Xe, {
|
|
6616
|
+
className: "max-w-[40%] grow",
|
|
6617
|
+
value: filterValue,
|
|
6618
|
+
onDebounceChange: setFilterValue,
|
|
6619
|
+
placeholder: t(`Search ${itemLabel} list`)
|
|
6620
|
+
})), /*#__PURE__*/react.createElement("div", {
|
|
6621
|
+
className: "relative flex min-h-[1px] grow flex-col bg-black text-[14px]"
|
|
6622
|
+
}, itemList == null ? /*#__PURE__*/react.createElement(ui_src/* LoadingIndicatorProgress */.LE, {
|
|
6623
|
+
className: 'h-full w-full'
|
|
6624
|
+
}) : itemList.length === 0 ? /*#__PURE__*/react.createElement("div", {
|
|
6625
|
+
className: "text-primary-light flex h-full flex-col items-center justify-center px-6 py-4"
|
|
6626
|
+
}, /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
6627
|
+
name: "magnifier",
|
|
6628
|
+
className: "mb-4"
|
|
6629
|
+
}), /*#__PURE__*/react.createElement("span", null, t(`No ${itemLabel} available`))) : /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
|
|
6630
|
+
className: "bg-secondary-dark px-3 py-1.5 text-white"
|
|
6631
|
+
}, t(itemLabel)), /*#__PURE__*/react.createElement("div", {
|
|
6632
|
+
className: "ohif-scrollbar overflow-auto"
|
|
6633
|
+
}, itemList.filter(item => !filterValue || item.name.toLowerCase().includes(filterValue.toLowerCase())).map(item => {
|
|
6634
|
+
const border = 'rounded border-transparent border-b-secondary-light border-[1px] hover:border-primary-light';
|
|
6635
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6636
|
+
className: classnames_default()('hover:text-primary-light hover:bg-primary-dark group mx-2 flex items-center justify-between px-6 py-2', border),
|
|
6637
|
+
key: item.id
|
|
6638
|
+
}, /*#__PURE__*/react.createElement("div", null, item.name), /*#__PURE__*/react.createElement(ui_src/* Button */.zx, {
|
|
6639
|
+
onClick: () => onItemClicked(item),
|
|
6640
|
+
className: "invisible group-hover:visible",
|
|
6641
|
+
endIcon: /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
6642
|
+
name: "arrow-left"
|
|
6643
|
+
})
|
|
6644
|
+
}, t('Select')));
|
|
6645
|
+
})))));
|
|
6646
|
+
}
|
|
6647
|
+
/* harmony default export */ const Components_ItemListComponent = (ItemListComponent);
|
|
6648
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/Components/DataSourceConfigurationModalComponent.tsx
|
|
6649
|
+
|
|
6650
|
+
|
|
6651
|
+
|
|
6652
|
+
|
|
6653
|
+
|
|
6654
|
+
const NO_WRAP_ELLIPSIS_CLASS_NAMES = 'text-ellipsis whitespace-nowrap overflow-hidden';
|
|
6655
|
+
function DataSourceConfigurationModalComponent(_ref) {
|
|
6656
|
+
let {
|
|
6657
|
+
configurationAPI,
|
|
6658
|
+
configuredItems,
|
|
6659
|
+
onHide
|
|
6660
|
+
} = _ref;
|
|
6661
|
+
const {
|
|
6662
|
+
t
|
|
6663
|
+
} = (0,es/* useTranslation */.$G)('DataSourceConfiguration');
|
|
6664
|
+
const [itemList, setItemList] = (0,react.useState)();
|
|
6665
|
+
const [selectedItems, setSelectedItems] = (0,react.useState)(configuredItems);
|
|
6666
|
+
const [errorMessage, setErrorMessage] = (0,react.useState)();
|
|
6667
|
+
const [itemLabels] = (0,react.useState)(configurationAPI.getItemLabels());
|
|
6668
|
+
|
|
6669
|
+
// Determines whether to show the full/existing configuration for the data source.
|
|
6670
|
+
// A full or complete configuration is one where the data source (path) has the
|
|
6671
|
+
// maximum/required number of path items. Anything less is considered not complete and
|
|
6672
|
+
// the configuration starts from scratch (i.e. as if no items are configured at all).
|
|
6673
|
+
// TODO: consider configuration starting from a partial (i.e. non-empty) configuration
|
|
6674
|
+
const [showFullConfig, setShowFullConfig] = (0,react.useState)(itemLabels.length === configuredItems.length);
|
|
6675
|
+
|
|
6676
|
+
/**
|
|
6677
|
+
* The index of the selected item that is considered current and for which
|
|
6678
|
+
* its sub-items should be displayed in the items list component. When the
|
|
6679
|
+
* full/existing configuration for a data source is to be shown, the current
|
|
6680
|
+
* selected item is the second to last in the `selectedItems` list.
|
|
6681
|
+
*/
|
|
6682
|
+
const currentSelectedItemIndex = showFullConfig ? selectedItems.length - 2 : selectedItems.length - 1;
|
|
6683
|
+
(0,react.useEffect)(() => {
|
|
6684
|
+
let shouldUpdate = true;
|
|
6685
|
+
setErrorMessage(null);
|
|
6686
|
+
|
|
6687
|
+
// Clear out the former/old list while we fetch the next sub item list.
|
|
6688
|
+
setItemList(null);
|
|
6689
|
+
if (selectedItems.length === 0) {
|
|
6690
|
+
configurationAPI.initialize().then(items => {
|
|
6691
|
+
if (shouldUpdate) {
|
|
6692
|
+
setItemList(items);
|
|
6693
|
+
}
|
|
6694
|
+
}).catch(error => setErrorMessage(error.message));
|
|
6695
|
+
} else if (!showFullConfig && selectedItems.length === itemLabels.length) {
|
|
6696
|
+
// The last item to configure the data source (path) has been selected.
|
|
6697
|
+
configurationAPI.setCurrentItem(selectedItems[selectedItems.length - 1]);
|
|
6698
|
+
// We can hide the modal dialog now.
|
|
6699
|
+
onHide();
|
|
6700
|
+
} else {
|
|
6701
|
+
configurationAPI.setCurrentItem(selectedItems[currentSelectedItemIndex]).then(items => {
|
|
6702
|
+
if (shouldUpdate) {
|
|
6703
|
+
setItemList(items);
|
|
6704
|
+
}
|
|
6705
|
+
}).catch(error => setErrorMessage(error.message));
|
|
6706
|
+
}
|
|
6707
|
+
return () => {
|
|
6708
|
+
shouldUpdate = false;
|
|
6709
|
+
};
|
|
6710
|
+
}, [selectedItems, configurationAPI, onHide, itemLabels, showFullConfig, currentSelectedItemIndex]);
|
|
6711
|
+
const getSelectedItemCursorClasses = itemIndex => itemIndex !== itemLabels.length - 1 && itemIndex < selectedItems.length ? 'cursor-pointer' : 'cursor-auto';
|
|
6712
|
+
const getSelectedItemBackgroundClasses = itemIndex => itemIndex < selectedItems.length ? classnames_default()('bg-black/[.4]', itemIndex !== itemLabels.length - 1 ? 'hover:bg-transparent active:bg-secondary-dark' : '') : 'bg-transparent';
|
|
6713
|
+
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';
|
|
6714
|
+
const getSelectedItemTextClasses = itemIndex => itemIndex <= selectedItems.length ? 'text-primary-light' : 'text-primary-active';
|
|
6715
|
+
const getErrorComponent = () => {
|
|
6716
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6717
|
+
className: "flex min-h-[1px] grow flex-col gap-4"
|
|
6718
|
+
}, /*#__PURE__*/react.createElement("div", {
|
|
6719
|
+
className: "text-primary-light text-[20px]"
|
|
6720
|
+
}, t(`Error fetching ${itemLabels[selectedItems.length]} list`)), /*#__PURE__*/react.createElement("div", {
|
|
6721
|
+
className: "grow bg-black p-4 text-[14px]"
|
|
6722
|
+
}, errorMessage));
|
|
6723
|
+
};
|
|
6724
|
+
const getSelectedItemsComponent = () => {
|
|
6725
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6726
|
+
className: "flex gap-4"
|
|
6727
|
+
}, itemLabels.map((itemLabel, itemLabelIndex) => {
|
|
6728
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6729
|
+
key: itemLabel,
|
|
6730
|
+
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)),
|
|
6731
|
+
onClick: showFullConfig && itemLabelIndex < currentSelectedItemIndex || itemLabelIndex <= currentSelectedItemIndex ? () => {
|
|
6732
|
+
setShowFullConfig(false);
|
|
6733
|
+
setSelectedItems(theList => theList.slice(0, itemLabelIndex));
|
|
6734
|
+
} : undefined
|
|
6735
|
+
}, /*#__PURE__*/react.createElement("div", {
|
|
6736
|
+
className: "text- flex items-center gap-2"
|
|
6737
|
+
}, itemLabelIndex < selectedItems.length ? /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
6738
|
+
name: "status-tracked"
|
|
6739
|
+
}) : /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
6740
|
+
name: "status-untracked"
|
|
6741
|
+
}), /*#__PURE__*/react.createElement("div", {
|
|
6742
|
+
className: classnames_default()(NO_WRAP_ELLIPSIS_CLASS_NAMES)
|
|
6743
|
+
}, t(itemLabel))), itemLabelIndex < selectedItems.length ? /*#__PURE__*/react.createElement("div", {
|
|
6744
|
+
className: classnames_default()('text-[14px] text-white', NO_WRAP_ELLIPSIS_CLASS_NAMES)
|
|
6745
|
+
}, selectedItems[itemLabelIndex].name) : /*#__PURE__*/react.createElement("br", null));
|
|
6746
|
+
}));
|
|
6747
|
+
};
|
|
6748
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6749
|
+
className: "flex h-[calc(100vh-300px)] select-none flex-col gap-4 pt-0.5"
|
|
6750
|
+
}, getSelectedItemsComponent(), /*#__PURE__*/react.createElement("div", {
|
|
6751
|
+
className: "h-0.5 w-full shrink-0 bg-black"
|
|
6752
|
+
}), errorMessage ? getErrorComponent() : /*#__PURE__*/react.createElement(Components_ItemListComponent, {
|
|
6753
|
+
itemLabel: itemLabels[currentSelectedItemIndex + 1],
|
|
6754
|
+
itemList: itemList,
|
|
6755
|
+
onItemClicked: item => {
|
|
6756
|
+
setShowFullConfig(false);
|
|
6757
|
+
setSelectedItems(theList => [...theList.slice(0, currentSelectedItemIndex + 1), item]);
|
|
6758
|
+
}
|
|
6759
|
+
}));
|
|
6760
|
+
}
|
|
6761
|
+
/* harmony default export */ const Components_DataSourceConfigurationModalComponent = (DataSourceConfigurationModalComponent);
|
|
6762
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/Components/DataSourceConfigurationComponent.tsx
|
|
6763
|
+
|
|
6764
|
+
|
|
6765
|
+
|
|
6766
|
+
|
|
6767
|
+
function DataSourceConfigurationComponent(_ref) {
|
|
6768
|
+
let {
|
|
6769
|
+
servicesManager,
|
|
6770
|
+
extensionManager
|
|
6771
|
+
} = _ref;
|
|
6772
|
+
const {
|
|
6773
|
+
t
|
|
6774
|
+
} = (0,es/* useTranslation */.$G)('DataSourceConfiguration');
|
|
6775
|
+
const {
|
|
6776
|
+
show,
|
|
6777
|
+
hide
|
|
6778
|
+
} = (0,ui_src/* useModal */.dd)();
|
|
6779
|
+
const {
|
|
6780
|
+
customizationService
|
|
6781
|
+
} = servicesManager.services;
|
|
6782
|
+
const [configurationAPI, setConfigurationAPI] = (0,react.useState)();
|
|
6783
|
+
const [configuredItems, setConfiguredItems] = (0,react.useState)();
|
|
6784
|
+
(0,react.useEffect)(() => {
|
|
6785
|
+
let shouldUpdate = true;
|
|
6786
|
+
const dataSourceChangedCallback = async () => {
|
|
6787
|
+
const activeDataSourceDef = extensionManager.getActiveDataSourceDefinition();
|
|
6788
|
+
if (!activeDataSourceDef.configuration.configurationAPI) {
|
|
6789
|
+
return;
|
|
6790
|
+
}
|
|
6791
|
+
const {
|
|
6792
|
+
factory: configurationAPIFactory
|
|
6793
|
+
} = customizationService.get(activeDataSourceDef.configuration.configurationAPI) ?? {};
|
|
6794
|
+
if (!configurationAPIFactory) {
|
|
6795
|
+
return;
|
|
6796
|
+
}
|
|
6797
|
+
const configAPI = configurationAPIFactory(activeDataSourceDef.sourceName);
|
|
6798
|
+
setConfigurationAPI(configAPI);
|
|
6799
|
+
|
|
6800
|
+
// New configuration API means that the existing configured items must be cleared.
|
|
6801
|
+
setConfiguredItems(null);
|
|
6802
|
+
configAPI.getConfiguredItems().then(list => {
|
|
6803
|
+
if (shouldUpdate) {
|
|
6804
|
+
setConfiguredItems(list);
|
|
6805
|
+
}
|
|
6806
|
+
});
|
|
6807
|
+
};
|
|
6808
|
+
const sub = extensionManager.subscribe(extensionManager.EVENTS.ACTIVE_DATA_SOURCE_CHANGED, dataSourceChangedCallback);
|
|
6809
|
+
dataSourceChangedCallback();
|
|
6810
|
+
return () => {
|
|
6811
|
+
shouldUpdate = false;
|
|
6812
|
+
sub.unsubscribe();
|
|
6813
|
+
};
|
|
6814
|
+
}, []);
|
|
6815
|
+
const showConfigurationModal = (0,react.useCallback)(() => {
|
|
6816
|
+
show({
|
|
6817
|
+
content: Components_DataSourceConfigurationModalComponent,
|
|
6818
|
+
title: t('Configure Data Source'),
|
|
6819
|
+
contentProps: {
|
|
6820
|
+
configurationAPI,
|
|
6821
|
+
configuredItems,
|
|
6822
|
+
onHide: hide
|
|
6823
|
+
}
|
|
6824
|
+
});
|
|
6825
|
+
}, [configurationAPI, configuredItems]);
|
|
6826
|
+
(0,react.useEffect)(() => {
|
|
6827
|
+
if (!configurationAPI || !configuredItems) {
|
|
6828
|
+
return;
|
|
6829
|
+
}
|
|
6830
|
+
if (configuredItems.length !== configurationAPI.getItemLabels().length) {
|
|
6831
|
+
// Not the correct number of configured items, so show the modal to configure the data source.
|
|
6832
|
+
showConfigurationModal();
|
|
6833
|
+
}
|
|
6834
|
+
}, [configurationAPI, configuredItems, showConfigurationModal]);
|
|
6835
|
+
return configuredItems ? /*#__PURE__*/react.createElement("div", {
|
|
6836
|
+
className: "text-aqua-pale flex items-center overflow-hidden"
|
|
6837
|
+
}, /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
6838
|
+
name: "settings",
|
|
6839
|
+
className: "mr-2.5 h-3.5 w-3.5 shrink-0 cursor-pointer",
|
|
6840
|
+
onClick: showConfigurationModal
|
|
6841
|
+
}), configuredItems.map((item, itemIndex) => {
|
|
6842
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6843
|
+
key: itemIndex,
|
|
6844
|
+
className: "flex overflow-hidden"
|
|
6845
|
+
}, /*#__PURE__*/react.createElement("div", {
|
|
6846
|
+
key: itemIndex,
|
|
6847
|
+
className: "overflow-hidden text-ellipsis whitespace-nowrap"
|
|
6848
|
+
}, item.name), itemIndex !== configuredItems.length - 1 && /*#__PURE__*/react.createElement("div", {
|
|
6849
|
+
className: "px-2.5"
|
|
6850
|
+
}, "|"));
|
|
6851
|
+
})) : /*#__PURE__*/react.createElement(react.Fragment, null);
|
|
6852
|
+
}
|
|
6853
|
+
/* harmony default export */ const Components_DataSourceConfigurationComponent = (DataSourceConfigurationComponent);
|
|
6854
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/DataSourceConfigurationAPI/GoogleCloudDataSourceConfigurationAPI.ts
|
|
6855
|
+
/**
|
|
6856
|
+
* This file contains the implementations of BaseDataSourceConfigurationAPIItem
|
|
6857
|
+
* and BaseDataSourceConfigurationAPI for the Google cloud healthcare API. To
|
|
6858
|
+
* better understand this implementation and/or to implement custom implementations,
|
|
6859
|
+
* see the platform\core\src\types\DataSourceConfigurationAPI.ts and its JS doc
|
|
6860
|
+
* comments as a guide.
|
|
6861
|
+
*/
|
|
6862
|
+
/**
|
|
6863
|
+
* The various Google Cloud Healthcare path item types.
|
|
6864
|
+
*/
|
|
6865
|
+
var ItemType = /*#__PURE__*/function (ItemType) {
|
|
6866
|
+
ItemType[ItemType["projects"] = 0] = "projects";
|
|
6867
|
+
ItemType[ItemType["locations"] = 1] = "locations";
|
|
6868
|
+
ItemType[ItemType["datasets"] = 2] = "datasets";
|
|
6869
|
+
ItemType[ItemType["dicomStores"] = 3] = "dicomStores";
|
|
6870
|
+
return ItemType;
|
|
6871
|
+
}(ItemType || {});
|
|
6872
|
+
const initialUrl = 'https://cloudresourcemanager.googleapis.com/v1';
|
|
6873
|
+
const baseHealthcareUrl = 'https://healthcare.googleapis.com/v1';
|
|
6874
|
+
class GoogleCloudDataSourceConfigurationAPIItem {
|
|
6875
|
+
constructor() {
|
|
6876
|
+
this.id = void 0;
|
|
6877
|
+
this.name = void 0;
|
|
6878
|
+
this.url = void 0;
|
|
6879
|
+
this.itemType = void 0;
|
|
6880
|
+
}
|
|
6881
|
+
}
|
|
6882
|
+
class GoogleCloudDataSourceConfigurationAPI {
|
|
6883
|
+
constructor(dataSourceName, servicesManager, extensionManager) {
|
|
6884
|
+
this._extensionManager = void 0;
|
|
6885
|
+
this._fetchOptions = void 0;
|
|
6886
|
+
this._dataSourceName = void 0;
|
|
6887
|
+
this.getItemLabels = () => ['Project', 'Location', 'Data set', 'DICOM store'];
|
|
6888
|
+
this._dataSourceName = dataSourceName;
|
|
6889
|
+
this._extensionManager = extensionManager;
|
|
6890
|
+
const userAuthenticationService = servicesManager.services.userAuthenticationService;
|
|
6891
|
+
this._fetchOptions = {
|
|
6892
|
+
method: 'GET',
|
|
6893
|
+
headers: userAuthenticationService.getAuthorizationHeader()
|
|
6894
|
+
};
|
|
6895
|
+
}
|
|
6896
|
+
async initialize() {
|
|
6897
|
+
const url = `${initialUrl}/projects`;
|
|
6898
|
+
const projects = await GoogleCloudDataSourceConfigurationAPI._doFetch(url, ItemType.projects, this._fetchOptions);
|
|
6899
|
+
if (!projects?.length) {
|
|
6900
|
+
return [];
|
|
6901
|
+
}
|
|
6902
|
+
const projectItems = projects.map(project => {
|
|
6903
|
+
return {
|
|
6904
|
+
id: project.projectId,
|
|
6905
|
+
name: project.name,
|
|
6906
|
+
itemType: ItemType.projects,
|
|
6907
|
+
url: `${baseHealthcareUrl}/projects/${project.projectId}`
|
|
6908
|
+
};
|
|
6909
|
+
});
|
|
6910
|
+
return projectItems;
|
|
6911
|
+
}
|
|
6912
|
+
async setCurrentItem(anItem) {
|
|
6913
|
+
const googleCloudItem = anItem;
|
|
6914
|
+
if (googleCloudItem.itemType === ItemType.dicomStores) {
|
|
6915
|
+
// Last configurable item, so update the data source configuration.
|
|
6916
|
+
const url = `${googleCloudItem.url}/dicomWeb`;
|
|
6917
|
+
const dataSourceDefCopy = JSON.parse(JSON.stringify(this._extensionManager.getDataSourceDefinition(this._dataSourceName)));
|
|
6918
|
+
dataSourceDefCopy.configuration = {
|
|
6919
|
+
...dataSourceDefCopy.configuration,
|
|
6920
|
+
wadoUriRoot: url,
|
|
6921
|
+
qidoRoot: url,
|
|
6922
|
+
wadoRoot: url
|
|
6923
|
+
};
|
|
6924
|
+
this._extensionManager.updateDataSourceConfiguration(dataSourceDefCopy.sourceName, dataSourceDefCopy.configuration);
|
|
6925
|
+
return [];
|
|
6926
|
+
}
|
|
6927
|
+
const subItemType = googleCloudItem.itemType + 1;
|
|
6928
|
+
const subItemField = `${ItemType[subItemType]}`;
|
|
6929
|
+
const url = `${googleCloudItem.url}/${subItemField}`;
|
|
6930
|
+
const fetchedSubItems = await GoogleCloudDataSourceConfigurationAPI._doFetch(url, subItemType, this._fetchOptions);
|
|
6931
|
+
if (!fetchedSubItems?.length) {
|
|
6932
|
+
return [];
|
|
6933
|
+
}
|
|
6934
|
+
const subItems = fetchedSubItems.map(subItem => {
|
|
6935
|
+
const nameSplit = subItem.name.split('/');
|
|
6936
|
+
return {
|
|
6937
|
+
id: subItem.name,
|
|
6938
|
+
name: nameSplit[nameSplit.length - 1],
|
|
6939
|
+
itemType: subItemType,
|
|
6940
|
+
url: `${baseHealthcareUrl}/${subItem.name}`
|
|
6941
|
+
};
|
|
6942
|
+
});
|
|
6943
|
+
return subItems;
|
|
6944
|
+
}
|
|
6945
|
+
async getConfiguredItems() {
|
|
6946
|
+
const dataSourceDefinition = this._extensionManager.getDataSourceDefinition(this._dataSourceName);
|
|
6947
|
+
const url = dataSourceDefinition.configuration.wadoUriRoot;
|
|
6948
|
+
const projectsIndex = url.indexOf('projects');
|
|
6949
|
+
// Split the configured URL into (essentially) pairs (i.e. item type followed by item)
|
|
6950
|
+
// Explicitly: ['projects','aProject','locations','aLocation','datasets','aDataSet','dicomStores','aDicomStore']
|
|
6951
|
+
// Note that a partial configuration will have a subset of the above.
|
|
6952
|
+
const urlSplit = url.substring(projectsIndex).split('/');
|
|
6953
|
+
const configuredItems = [];
|
|
6954
|
+
for (let itemType = 0;
|
|
6955
|
+
// the number of configured items is either the max (4) or the number extracted from the url split
|
|
6956
|
+
itemType < 4 && (itemType + 1) * 2 < urlSplit.length; itemType += 1) {
|
|
6957
|
+
if (itemType === ItemType.projects) {
|
|
6958
|
+
const projectId = urlSplit[1];
|
|
6959
|
+
const projectUrl = `${initialUrl}/projects/${projectId}`;
|
|
6960
|
+
const data = await GoogleCloudDataSourceConfigurationAPI._doFetch(projectUrl, ItemType.projects, this._fetchOptions);
|
|
6961
|
+
const project = data[0];
|
|
6962
|
+
configuredItems.push({
|
|
6963
|
+
id: project.projectId,
|
|
6964
|
+
name: project.name,
|
|
6965
|
+
itemType: itemType,
|
|
6966
|
+
url: `${baseHealthcareUrl}/projects/${project.projectId}`
|
|
6967
|
+
});
|
|
6968
|
+
} else {
|
|
6969
|
+
const relativePath = urlSplit.slice(0, itemType * 2 + 2).join('/');
|
|
6970
|
+
configuredItems.push({
|
|
6971
|
+
id: relativePath,
|
|
6972
|
+
name: urlSplit[itemType * 2 + 1],
|
|
6973
|
+
itemType: itemType,
|
|
6974
|
+
url: `${baseHealthcareUrl}/${relativePath}`
|
|
6975
|
+
});
|
|
6976
|
+
}
|
|
6977
|
+
}
|
|
6978
|
+
return configuredItems;
|
|
6979
|
+
}
|
|
6980
|
+
|
|
6981
|
+
/**
|
|
6982
|
+
* Fetches an array of items the specified item type.
|
|
6983
|
+
* @param urlStr the fetch url
|
|
6984
|
+
* @param fetchItemType the type to fetch
|
|
6985
|
+
* @param fetchOptions the header options for the fetch (e.g. authorization header)
|
|
6986
|
+
* @param fetchSearchParams any search query params; currently only used for paging results
|
|
6987
|
+
* @returns an array of items of the specified type
|
|
6988
|
+
*/
|
|
6989
|
+
static async _doFetch(urlStr, fetchItemType) {
|
|
6990
|
+
let fetchOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
6991
|
+
let fetchSearchParams = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
6992
|
+
try {
|
|
6993
|
+
const url = new URL(urlStr);
|
|
6994
|
+
url.search = new URLSearchParams(fetchSearchParams).toString();
|
|
6995
|
+
const response = await fetch(url, fetchOptions);
|
|
6996
|
+
const data = await response.json();
|
|
6997
|
+
if (response.status >= 200 && response.status < 300 && data != null) {
|
|
6998
|
+
if (data.nextPageToken != null) {
|
|
6999
|
+
fetchSearchParams.pageToken = data.nextPageToken;
|
|
7000
|
+
const subPageData = await this._doFetch(urlStr, fetchItemType, fetchOptions, fetchSearchParams);
|
|
7001
|
+
data[ItemType[fetchItemType]] = data[ItemType[fetchItemType]].concat(subPageData);
|
|
7002
|
+
}
|
|
7003
|
+
if (data[ItemType[fetchItemType]]) {
|
|
7004
|
+
return data[ItemType[fetchItemType]];
|
|
7005
|
+
} else if (data.name) {
|
|
7006
|
+
return [data];
|
|
7007
|
+
} else {
|
|
7008
|
+
return [];
|
|
7009
|
+
}
|
|
7010
|
+
} else {
|
|
7011
|
+
const message = data?.error?.message || `Error returned from Google Cloud Healthcare: ${response.status} - ${response.statusText}`;
|
|
7012
|
+
throw new Error(message);
|
|
7013
|
+
}
|
|
7014
|
+
} catch (err) {
|
|
7015
|
+
const message = err?.message || 'Error occurred during fetch request.';
|
|
7016
|
+
throw new Error(message);
|
|
7017
|
+
}
|
|
7018
|
+
}
|
|
7019
|
+
}
|
|
7020
|
+
|
|
5758
7021
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getCustomizationModule.tsx
|
|
5759
7022
|
|
|
5760
7023
|
|
|
5761
7024
|
|
|
7025
|
+
|
|
7026
|
+
|
|
5762
7027
|
/**
|
|
5763
7028
|
*
|
|
5764
7029
|
* Note: this is an example of how the customization module can be used
|
|
@@ -5768,7 +7033,11 @@ function DataSourceSelector() {
|
|
|
5768
7033
|
* custom page for the user to view their profile, or to add a custom
|
|
5769
7034
|
* page for login etc.
|
|
5770
7035
|
*/
|
|
5771
|
-
function getCustomizationModule() {
|
|
7036
|
+
function getCustomizationModule(_ref) {
|
|
7037
|
+
let {
|
|
7038
|
+
servicesManager,
|
|
7039
|
+
extensionManager
|
|
7040
|
+
} = _ref;
|
|
5772
7041
|
return [{
|
|
5773
7042
|
name: 'helloPage',
|
|
5774
7043
|
value: {
|
|
@@ -5835,12 +7104,16 @@ function getCustomizationModule() {
|
|
|
5835
7104
|
{
|
|
5836
7105
|
id: 'ohif.overlayItem',
|
|
5837
7106
|
content: function (props) {
|
|
5838
|
-
if (this.condition && !this.condition(props))
|
|
7107
|
+
if (this.condition && !this.condition(props)) {
|
|
7108
|
+
return null;
|
|
7109
|
+
}
|
|
5839
7110
|
const {
|
|
5840
7111
|
instance
|
|
5841
7112
|
} = props;
|
|
5842
7113
|
const value = instance && this.attribute ? instance[this.attribute] : this.contentF && typeof this.contentF === 'function' ? this.contentF(props) : null;
|
|
5843
|
-
if (!value)
|
|
7114
|
+
if (!value) {
|
|
7115
|
+
return null;
|
|
7116
|
+
}
|
|
5844
7117
|
return /*#__PURE__*/react.createElement("span", {
|
|
5845
7118
|
className: "overlay-item flex flex-row",
|
|
5846
7119
|
style: {
|
|
@@ -5878,11 +7151,22 @@ function getCustomizationModule() {
|
|
|
5878
7151
|
}
|
|
5879
7152
|
return clonedObject;
|
|
5880
7153
|
}
|
|
7154
|
+
}, {
|
|
7155
|
+
// the generic GUI component to configure a data source using an instance of a BaseDataSourceConfigurationAPI
|
|
7156
|
+
id: 'ohif.dataSourceConfigurationComponent',
|
|
7157
|
+
component: Components_DataSourceConfigurationComponent.bind(null, {
|
|
7158
|
+
servicesManager,
|
|
7159
|
+
extensionManager
|
|
7160
|
+
})
|
|
7161
|
+
}, {
|
|
7162
|
+
// The factory for creating an instance of a BaseDataSourceConfigurationAPI for Google Cloud Healthcare
|
|
7163
|
+
id: 'ohif.dataSourceConfigurationAPI.google',
|
|
7164
|
+
factory: dataSourceName => new GoogleCloudDataSourceConfigurationAPI(dataSourceName, servicesManager, extensionManager)
|
|
5881
7165
|
}]
|
|
5882
7166
|
}];
|
|
5883
7167
|
}
|
|
5884
7168
|
// EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/calculate-suv/dist/calculate-suv.esm.js
|
|
5885
|
-
var calculate_suv_esm = __webpack_require__(
|
|
7169
|
+
var calculate_suv_esm = __webpack_require__(15747);
|
|
5886
7170
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getPTImageIdInstanceMetadata.ts
|
|
5887
7171
|
|
|
5888
7172
|
const getPTImageIdInstanceMetadata_metadataProvider = src["default"].classes.MetadataProvider;
|
|
@@ -5891,9 +7175,12 @@ function getPTImageIdInstanceMetadata(imageId) {
|
|
|
5891
7175
|
if (!dicomMetaData) {
|
|
5892
7176
|
throw new Error('dicom metadata are required');
|
|
5893
7177
|
}
|
|
5894
|
-
if (dicomMetaData.SeriesDate === undefined || dicomMetaData.SeriesTime === undefined || dicomMetaData.
|
|
7178
|
+
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
7179
|
throw new Error('required metadata are missing');
|
|
5896
7180
|
}
|
|
7181
|
+
if (dicomMetaData.PatientWeight === undefined) {
|
|
7182
|
+
console.warn('PatientWeight missing from PT instance metadata');
|
|
7183
|
+
}
|
|
5897
7184
|
const instanceMetadata = {
|
|
5898
7185
|
CorrectedImage: dicomMetaData.CorrectedImage,
|
|
5899
7186
|
Units: dicomMetaData.Units,
|
|
@@ -6064,6 +7351,8 @@ const handlePETImageMetadata = _ref2 => {
|
|
|
6064
7351
|
|
|
6065
7352
|
|
|
6066
7353
|
|
|
7354
|
+
|
|
7355
|
+
|
|
6067
7356
|
const defaultExtension = {
|
|
6068
7357
|
/**
|
|
6069
7358
|
* Only required property. Should be a unique value across all extensions.
|