@ohif/app 3.7.0-beta.1 → 3.7.0-beta.100
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.06cb87cf1c42b9f20bd2.js → 12.bundle.34050abb042540a90a3a.js} +6 -6
- package/dist/{295.bundle.957b1159fec14b9199a1.js → 125.bundle.253395f320b72180da63.js} +6 -6
- package/dist/{351.bundle.2d4bc19d8b493879dbbe.js → 181.bundle.169383e9b1a0358b44e8.js} +227 -205
- package/dist/{351.css → 181.css} +1 -1
- package/dist/{744.bundle.392a124e4ee20ad6a657.js → 19.bundle.eef637102334f1832ba9.js} +246 -385
- 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.0b9f7401294213262852.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.2305e2f8244de8ccbaee.js → 236.bundle.7768b3e29b1fd618b9ec.js} +89 -105
- package/dist/{55.bundle.5f5e5ef9087b0beee35c.js → 250.bundle.8084960e3318cda37317.js} +52 -36
- package/dist/{973.bundle.a51bb5b329263c9e75e2.js → 281.bundle.39cb630582cf8114fd5e.js} +18 -14
- package/dist/{82.bundle.da0c036b2e572719dbc5.js → 342.bundle.6edc7ac022b4218ec99f.js} +1776 -482
- package/dist/{404.bundle.902c664e3e581335a5d2.js → 359.bundle.a8f6cf2f90fe05fc346d.js} +46 -131
- package/dist/{192.bundle.4fee0d418ae32bb7ab30.js → 370.bundle.4e1276530ba7757347f5.js} +113 -99
- package/dist/{790.bundle.aa7a8bebec3483d90f3f.js → 410.bundle.5a330214c0c31cbf2551.js} +11 -9
- package/dist/{151.bundle.31ea35044218837bf73f.js → 417.bundle.af0a207c29b109f84159.js} +49 -17
- package/dist/{569.bundle.0ed8d8178ffd43fe1c34.js → 451.bundle.9fd36f52ff69594f0669.js} +98 -107
- package/dist/{581.bundle.360d26f97b37da8faec3.js → 471.bundle.b3d77b83b1593c09a504.js} +78 -98
- package/dist/{199.bundle.290ef76d4ab8358e29bb.js → 506.bundle.ac385e382f79bbf4f306.js} +11 -14
- 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.f75fd669ddfe4ecf9c1b.js +532 -0
- package/dist/{984.bundle.4e002ef9b3468bddb68b.js → 663.bundle.3863ac49f85320c8ca96.js} +68 -38
- package/dist/{205.bundle.b5a473c200dcf2bbcdb4.js → 686.bundle.dccef1f36e4bc79bcc48.js} +6 -6
- package/dist/{50.bundle.03f455d441f2138ce49e.js → 687.bundle.ebd1260565c31ab9ad08.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.7cf0fabc69d49a8a2c5d.js → 782.bundle.8c17030f76b75035564c.js} +123 -80
- package/dist/{642.bundle.89f15ef57fbad2a1019b.js → 814.bundle.cc0ed4fc75cb16e34f02.js} +6 -6
- package/dist/{707.bundle.832f50366089fd23e93b.js → 82.bundle.7a89cd8b81eb7e1e5c66.js} +1187 -808
- package/dist/{799.bundle.ca18bdf4abe4d9abea26.js → 822.bundle.0545d6dbb49515aa04ee.js} +81 -34
- package/dist/831.bundle.83658f62fcc769043605.js +16700 -0
- package/dist/{953.bundle.9e3a7225f07336bfcb41.js → 886.bundle.4b3a7f2079d085fdbcb3.js} +34 -29
- package/dist/945.min.worker.js +1 -1
- package/dist/945.min.worker.js.map +1 -1
- package/dist/{270.bundle.4564621556b0f963a004.js → 957.bundle.71558794566041f37a92.js} +7110 -997
- package/dist/{208.bundle.29fe1842c33000edc75d.js → 99.bundle.c6876aaaa3ff2f1b08a1.js} +86 -105
- package/dist/_redirects +1 -1
- package/dist/app-config.js +35 -17
- package/dist/app.bundle.css +13 -12
- package/dist/{app.bundle.3ad961046deb5f47678a.js → app.bundle.dc0e89948c4f4568fe20.js} +73720 -68191
- package/dist/assets/yandex-browser-manifest.json +1 -1
- package/dist/cornerstoneDICOMImageLoader.min.js +1 -1
- package/dist/cornerstoneDICOMImageLoader.min.js.map +1 -1
- package/dist/{dicom-microscopy-viewer.bundle.aa60bdf008c32c39cfd7.js → dicom-microscopy-viewer.bundle.2c146384eb9466d02ff8.js} +5 -4
- package/dist/es6-shim.min.js +3569 -2
- package/dist/google.js +8 -7
- package/dist/index.html +2 -1
- package/dist/{index.worker.1c69152d710fa7b84bce.worker.js → index.worker.e62ecca63f1a2e124230.worker.js} +2 -2
- package/dist/index.worker.e62ecca63f1a2e124230.worker.js.map +1 -0
- package/dist/init-service-worker.js +3 -5
- package/dist/oidc-client.min.js +10857 -39
- package/dist/polyfill.min.js +184 -1
- package/dist/silent-refresh.html +18 -9
- package/dist/sw.js +1 -1
- package/package.json +20 -22
- package/dist/616.bundle.b76c70aeeed8b142593c.js +0 -685
- package/dist/780.bundle.fd0f13dc92e9caa0581e.js +0 -4769
- package/dist/index.worker.1c69152d710fa7b84bce.worker.js.map +0 -1
- /package/dist/{806.css → 19.css} +0 -0
- /package/dist/{55.css → 250.css} +0 -0
- /package/dist/{707.css → 82.css} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
(
|
|
2
|
+
(self["webpackChunk"] = self["webpackChunk"] || []).push([[342],{
|
|
3
3
|
|
|
4
|
-
/***/
|
|
4
|
+
/***/ 56342:
|
|
5
5
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
6
6
|
|
|
7
7
|
// ESM COMPAT FLAG
|
|
@@ -11,6 +11,8 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
11
11
|
__webpack_require__.d(__webpack_exports__, {
|
|
12
12
|
ContextMenuController: () => (/* reexport */ ContextMenuController),
|
|
13
13
|
CustomizableContextMenuTypes: () => (/* reexport */ types_namespaceObject),
|
|
14
|
+
createReportAsync: () => (/* reexport */ Actions_createReportAsync),
|
|
15
|
+
createReportDialogPrompt: () => (/* reexport */ createReportDialogPrompt),
|
|
14
16
|
"default": () => (/* binding */ default_src),
|
|
15
17
|
dicomWebUtils: () => (/* reexport */ utils_namespaceObject),
|
|
16
18
|
getStudiesForPatientByMRN: () => (/* reexport */ Panels_getStudiesForPatientByMRN)
|
|
@@ -28,11 +30,11 @@ __webpack_require__.d(utils_namespaceObject, {
|
|
|
28
30
|
});
|
|
29
31
|
|
|
30
32
|
// EXTERNAL MODULE: ../../../node_modules/dicomweb-client/build/dicomweb-client.es.js
|
|
31
|
-
var dicomweb_client_es = __webpack_require__(
|
|
32
|
-
// EXTERNAL MODULE: ../../core/src/index.ts +
|
|
33
|
-
var src = __webpack_require__(
|
|
33
|
+
var dicomweb_client_es = __webpack_require__(97604);
|
|
34
|
+
// EXTERNAL MODULE: ../../core/src/index.ts + 65 modules
|
|
35
|
+
var src = __webpack_require__(71771);
|
|
34
36
|
// EXTERNAL MODULE: ../../core/src/utils/sortStudy.ts
|
|
35
|
-
var sortStudy = __webpack_require__(
|
|
37
|
+
var sortStudy = __webpack_require__(62971);
|
|
36
38
|
;// CONCATENATED MODULE: ../../../extensions/default/src/DicomWebDataSource/qido.js
|
|
37
39
|
/**
|
|
38
40
|
* QIDO - Query based on ID for DICOM Objects
|
|
@@ -378,7 +380,7 @@ function getImageId(_ref) {
|
|
|
378
380
|
}
|
|
379
381
|
}
|
|
380
382
|
// EXTERNAL MODULE: ../../../node_modules/dcmjs/build/dcmjs.es.js
|
|
381
|
-
var dcmjs_es = __webpack_require__(
|
|
383
|
+
var dcmjs_es = __webpack_require__(67540);
|
|
382
384
|
;// CONCATENATED MODULE: ../../../extensions/default/src/DicomWebDataSource/wado/retrieveMetadataLoader.js
|
|
383
385
|
/**
|
|
384
386
|
* Class to define inheritance of load retrieve strategy.
|
|
@@ -638,7 +640,7 @@ const StudyMetaDataPromises = new Map();
|
|
|
638
640
|
*
|
|
639
641
|
* @param {Object} server Object with server configuration parameters
|
|
640
642
|
* @param {string} StudyInstanceUID The UID of the Study to be retrieved
|
|
641
|
-
* @param {boolean} enabledStudyLazyLoad Whether the study metadata should be loaded
|
|
643
|
+
* @param {boolean} enabledStudyLazyLoad Whether the study metadata should be loaded asynchronously.
|
|
642
644
|
* @param {function} storeInstancesCallback A callback used to store the retrieved instance metadata.
|
|
643
645
|
* @param {Object} [filters] - Object containing filters to be applied on retrieve metadata process
|
|
644
646
|
* @param {string} [filter.seriesInstanceUID] - series instance uid to filter results against
|
|
@@ -708,12 +710,16 @@ class StaticWadoClient extends dicomweb_client_es.api.DICOMwebClient {
|
|
|
708
710
|
* @returns
|
|
709
711
|
*/
|
|
710
712
|
async searchForStudies(options) {
|
|
711
|
-
if (!this.staticWado)
|
|
713
|
+
if (!this.staticWado) {
|
|
714
|
+
return super.searchForStudies(options);
|
|
715
|
+
}
|
|
712
716
|
const searchResult = await super.searchForStudies(options);
|
|
713
717
|
const {
|
|
714
718
|
queryParams
|
|
715
719
|
} = options;
|
|
716
|
-
if (!queryParams)
|
|
720
|
+
if (!queryParams) {
|
|
721
|
+
return searchResult;
|
|
722
|
+
}
|
|
717
723
|
const lowerParams = this.toLowerParams(queryParams);
|
|
718
724
|
const filtered = searchResult.filter(study => {
|
|
719
725
|
for (const key of Object.keys(StaticWadoClient.studyFilterKeys)) {
|
|
@@ -726,12 +732,16 @@ class StaticWadoClient extends dicomweb_client_es.api.DICOMwebClient {
|
|
|
726
732
|
return filtered;
|
|
727
733
|
}
|
|
728
734
|
async searchForSeries(options) {
|
|
729
|
-
if (!this.staticWado)
|
|
735
|
+
if (!this.staticWado) {
|
|
736
|
+
return super.searchForSeries(options);
|
|
737
|
+
}
|
|
730
738
|
const searchResult = await super.searchForSeries(options);
|
|
731
739
|
const {
|
|
732
740
|
queryParams
|
|
733
741
|
} = options;
|
|
734
|
-
if (!queryParams)
|
|
742
|
+
if (!queryParams) {
|
|
743
|
+
return searchResult;
|
|
744
|
+
}
|
|
735
745
|
const lowerParams = this.toLowerParams(queryParams);
|
|
736
746
|
const filtered = searchResult.filter(series => {
|
|
737
747
|
for (const key of Object.keys(StaticWadoClient.seriesFilterKeys)) {
|
|
@@ -767,8 +777,12 @@ class StaticWadoClient extends dicomweb_client_es.api.DICOMwebClient {
|
|
|
767
777
|
actual = actual.Alphabetic;
|
|
768
778
|
}
|
|
769
779
|
if (typeof actual == 'string') {
|
|
770
|
-
if (actual.length === 0)
|
|
771
|
-
|
|
780
|
+
if (actual.length === 0) {
|
|
781
|
+
return true;
|
|
782
|
+
}
|
|
783
|
+
if (desired.length === 0 || desired === '*') {
|
|
784
|
+
return true;
|
|
785
|
+
}
|
|
772
786
|
if (desired[0] === '*' && desired[desired.length - 1] === '*') {
|
|
773
787
|
// console.log(`Comparing ${actual} to ${desired.substring(1, desired.length - 1)}`)
|
|
774
788
|
return actual.indexOf(desired.substring(1, desired.length - 1)) != -1;
|
|
@@ -783,9 +797,13 @@ class StaticWadoClient extends dicomweb_client_es.api.DICOMwebClient {
|
|
|
783
797
|
|
|
784
798
|
/** Compares a pair of dates to see if the value is within the range */
|
|
785
799
|
compareDateRange(range, value) {
|
|
786
|
-
if (!value)
|
|
800
|
+
if (!value) {
|
|
801
|
+
return true;
|
|
802
|
+
}
|
|
787
803
|
const dash = range.indexOf('-');
|
|
788
|
-
if (dash === -1)
|
|
804
|
+
if (dash === -1) {
|
|
805
|
+
return this.compareValues(range, value);
|
|
806
|
+
}
|
|
789
807
|
const start = range.substring(0, dash);
|
|
790
808
|
const end = range.substring(dash + 1);
|
|
791
809
|
return (!start || value >= start) && (!end || value <= end);
|
|
@@ -802,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 + 134 modules
|
|
2066
|
+
var i18n_src = __webpack_require__(50376);
|
|
1997
2067
|
// EXTERNAL MODULE: ../../../node_modules/classnames/index.js
|
|
1998
|
-
var classnames = __webpack_require__(
|
|
2068
|
+
var classnames = __webpack_require__(44921);
|
|
1999
2069
|
var classnames_default = /*#__PURE__*/__webpack_require__.n(classnames);
|
|
2000
2070
|
;// CONCATENATED MODULE: ../../../extensions/default/src/Toolbar/Toolbar.tsx
|
|
2001
2071
|
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
@@ -2009,48 +2079,21 @@ function Toolbar(_ref) {
|
|
|
2009
2079
|
toolbarService
|
|
2010
2080
|
} = servicesManager.services;
|
|
2011
2081
|
const [toolbarButtons, setToolbarButtons] = (0,react.useState)([]);
|
|
2012
|
-
const [buttonState, setButtonState] = (0,react.useState)({
|
|
2013
|
-
primaryToolId: '',
|
|
2014
|
-
toggles: {},
|
|
2015
|
-
groups: {}
|
|
2016
|
-
});
|
|
2017
|
-
|
|
2018
|
-
// Could track buttons and state separately...?
|
|
2019
2082
|
(0,react.useEffect)(() => {
|
|
2020
2083
|
const {
|
|
2021
|
-
unsubscribe
|
|
2084
|
+
unsubscribe
|
|
2022
2085
|
} = toolbarService.subscribe(toolbarService.EVENTS.TOOL_BAR_MODIFIED, () => setToolbarButtons(toolbarService.getButtonSection('primary')));
|
|
2023
|
-
const {
|
|
2024
|
-
unsubscribe: unsub2
|
|
2025
|
-
} = toolbarService.subscribe(toolbarService.EVENTS.TOOL_BAR_STATE_MODIFIED, () => setButtonState({
|
|
2026
|
-
...toolbarService.state
|
|
2027
|
-
}));
|
|
2028
2086
|
return () => {
|
|
2029
|
-
|
|
2030
|
-
unsub2();
|
|
2087
|
+
unsubscribe();
|
|
2031
2088
|
};
|
|
2032
2089
|
}, [toolbarService]);
|
|
2033
|
-
|
|
2090
|
+
const onInteraction = (0,react.useCallback)(args => toolbarService.recordInteraction(args), [toolbarService]);
|
|
2091
|
+
return /*#__PURE__*/react.createElement(react.Fragment, null, toolbarButtons.map(toolDef => {
|
|
2034
2092
|
const {
|
|
2035
2093
|
id,
|
|
2036
2094
|
Component,
|
|
2037
2095
|
componentProps
|
|
2038
2096
|
} = toolDef;
|
|
2039
|
-
// TODO: ...
|
|
2040
|
-
|
|
2041
|
-
// isActive if:
|
|
2042
|
-
// - id is primary?
|
|
2043
|
-
// - id is in list of "toggled on"?
|
|
2044
|
-
let isActive;
|
|
2045
|
-
if (componentProps.type === 'toggle') {
|
|
2046
|
-
isActive = buttonState.toggles[id];
|
|
2047
|
-
}
|
|
2048
|
-
// Also need... to filter list for splitButton, and set primary based on most recently clicked
|
|
2049
|
-
// Also need to kill the radioGroup button's magic logic
|
|
2050
|
-
// Everything should be reactive off these props, so commands can inform ToolbarService
|
|
2051
|
-
|
|
2052
|
-
// These can... Trigger toolbar events based on updates?
|
|
2053
|
-
// Then sync using useEffect, or simply modify the state here?
|
|
2054
2097
|
return (
|
|
2055
2098
|
/*#__PURE__*/
|
|
2056
2099
|
// The margin for separating the tools on the toolbar should go here and NOT in each individual component (button) item.
|
|
@@ -2061,16 +2104,13 @@ function Toolbar(_ref) {
|
|
|
2061
2104
|
}, /*#__PURE__*/react.createElement(Component, _extends({
|
|
2062
2105
|
id: id
|
|
2063
2106
|
}, componentProps, {
|
|
2064
|
-
|
|
2065
|
-
isActive: isActive,
|
|
2066
|
-
onInteraction: args => toolbarService.recordInteraction(args),
|
|
2107
|
+
onInteraction: onInteraction,
|
|
2067
2108
|
servicesManager: servicesManager
|
|
2068
2109
|
})))
|
|
2069
2110
|
);
|
|
2070
2111
|
}));
|
|
2071
2112
|
}
|
|
2072
|
-
;// CONCATENATED MODULE: ../../../extensions/default/src/ViewerLayout/
|
|
2073
|
-
|
|
2113
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/ViewerLayout/ViewerHeader.tsx
|
|
2074
2114
|
|
|
2075
2115
|
|
|
2076
2116
|
|
|
@@ -2085,20 +2125,11 @@ const {
|
|
|
2085
2125
|
defaultLanguage,
|
|
2086
2126
|
currentLanguage
|
|
2087
2127
|
} = i18n_src["default"];
|
|
2088
|
-
function
|
|
2128
|
+
function ViewerHeader(_ref) {
|
|
2089
2129
|
let {
|
|
2090
|
-
// From Extension Module Params
|
|
2091
|
-
extensionManager,
|
|
2092
|
-
servicesManager,
|
|
2093
2130
|
hotkeysManager,
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
viewports,
|
|
2097
|
-
ViewportGridComp,
|
|
2098
|
-
leftPanels = [],
|
|
2099
|
-
rightPanels = [],
|
|
2100
|
-
leftPanelDefaultClosed = false,
|
|
2101
|
-
rightPanelDefaultClosed = false
|
|
2131
|
+
extensionManager,
|
|
2132
|
+
servicesManager
|
|
2102
2133
|
} = _ref;
|
|
2103
2134
|
const [appConfig] = (0,state/* useAppConfig */.M)();
|
|
2104
2135
|
const navigate = (0,dist/* useNavigate */.s0)();
|
|
@@ -2108,16 +2139,12 @@ function ViewerLayout(_ref) {
|
|
|
2108
2139
|
pathname
|
|
2109
2140
|
} = location;
|
|
2110
2141
|
const dataSourceIdx = pathname.indexOf('/', 1);
|
|
2111
|
-
// const search =
|
|
2112
|
-
// dataSourceIdx === -1
|
|
2113
|
-
// ? undefined
|
|
2114
|
-
// : `datasources=${pathname.substring(dataSourceIdx + 1)}`;
|
|
2115
|
-
|
|
2116
|
-
// Todo: Handle parameters in a better way.
|
|
2117
2142
|
const query = new URLSearchParams(window.location.search);
|
|
2118
2143
|
const configUrl = query.get('configUrl');
|
|
2144
|
+
const dataSourceName = pathname.substring(dataSourceIdx + 1);
|
|
2145
|
+
const existingDataSource = extensionManager.getDataSources(dataSourceName);
|
|
2119
2146
|
const searchQuery = new URLSearchParams();
|
|
2120
|
-
if (dataSourceIdx !== -1) {
|
|
2147
|
+
if (dataSourceIdx !== -1 && existingDataSource) {
|
|
2121
2148
|
searchQuery.append('datasources', pathname.substring(dataSourceIdx + 1));
|
|
2122
2149
|
}
|
|
2123
2150
|
if (configUrl) {
|
|
@@ -2135,16 +2162,12 @@ function ViewerLayout(_ref) {
|
|
|
2135
2162
|
show,
|
|
2136
2163
|
hide
|
|
2137
2164
|
} = (0,ui_src/* useModal */.dd)();
|
|
2138
|
-
const [showLoadingIndicator, setShowLoadingIndicator] = (0,react.useState)(appConfig.showLoadingIndicator);
|
|
2139
|
-
const {
|
|
2140
|
-
hangingProtocolService
|
|
2141
|
-
} = servicesManager.services;
|
|
2142
2165
|
const {
|
|
2143
2166
|
hotkeyDefinitions,
|
|
2144
2167
|
hotkeyDefaults
|
|
2145
2168
|
} = hotkeysManager;
|
|
2146
|
-
const versionNumber = "3.7.0-beta.
|
|
2147
|
-
const commitHash = "
|
|
2169
|
+
const versionNumber = "3.7.0-beta.100";
|
|
2170
|
+
const commitHash = "1fd98d922094d10fe0c6e9df726314ec9fce49e8";
|
|
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,13 +2920,13 @@ 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
|
-
}, /*#__PURE__*/react.createElement(ui_src/*
|
|
2926
|
+
}, /*#__PURE__*/react.createElement(ui_src/* LegacyButton */.mN, {
|
|
2805
2927
|
className: "px-2 py-2 text-base",
|
|
2806
2928
|
onClick: onExportClick
|
|
2807
|
-
}, t('Export CSV')), /*#__PURE__*/react.createElement(ui_src/*
|
|
2929
|
+
}, t('Export CSV')), /*#__PURE__*/react.createElement(ui_src/* LegacyButton */.mN, {
|
|
2808
2930
|
className: "px-2 py-2 text-base",
|
|
2809
2931
|
onClick: onCreateReportClick
|
|
2810
2932
|
}, t('Create Report'))));
|
|
@@ -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:
|
|
3031
|
+
type: ui_src/* ButtonEnums.type */.LZ.dt.secondary
|
|
2910
3032
|
}, {
|
|
2911
3033
|
id: 'save',
|
|
2912
3034
|
text: 'Save',
|
|
2913
|
-
type:
|
|
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,23 +3384,21 @@ 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,
|
|
3262
3391
|
onKeyPress: onKeyPressHandler
|
|
3263
3392
|
});
|
|
3264
3393
|
},
|
|
3265
|
-
actions: [
|
|
3266
|
-
// temp: swap button types until colors are updated
|
|
3267
|
-
{
|
|
3394
|
+
actions: [{
|
|
3268
3395
|
id: 'cancel',
|
|
3269
3396
|
text: 'Cancel',
|
|
3270
|
-
type:
|
|
3397
|
+
type: ui_src/* ButtonEnums.type */.LZ.dt.secondary
|
|
3271
3398
|
}, {
|
|
3272
3399
|
id: 'save',
|
|
3273
3400
|
text: 'Save',
|
|
3274
|
-
type:
|
|
3401
|
+
type: ui_src/* ButtonEnums.type */.LZ.dt.primary
|
|
3275
3402
|
}],
|
|
3276
3403
|
onSubmit: onSubmitHandler
|
|
3277
3404
|
}
|
|
@@ -3291,7 +3418,7 @@ function PanelMeasurementTable(_ref) {
|
|
|
3291
3418
|
}
|
|
3292
3419
|
};
|
|
3293
3420
|
return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
|
|
3294
|
-
className: "
|
|
3421
|
+
className: "ohif-scrollbar overflow-y-auto overflow-x-hidden",
|
|
3295
3422
|
"data-cy": 'measurements-panel'
|
|
3296
3423
|
}, /*#__PURE__*/react.createElement(ui_src/* MeasurementTable */.wt, {
|
|
3297
3424
|
title: "Measurements",
|
|
@@ -3318,7 +3445,7 @@ function _getMappedMeasurements(measurementService) {
|
|
|
3318
3445
|
|
|
3319
3446
|
/**
|
|
3320
3447
|
* Map the measurements to the display text.
|
|
3321
|
-
* Adds finding and site
|
|
3448
|
+
* Adds finding and site information to the displayText and/or label,
|
|
3322
3449
|
* and provides as 'displayText' and 'label', while providing the original
|
|
3323
3450
|
* values as baseDisplayText and baseLabel
|
|
3324
3451
|
*/
|
|
@@ -3338,7 +3465,9 @@ function _mapMeasurementToDisplay(measurement, index, types) {
|
|
|
3338
3465
|
if (findingSites) {
|
|
3339
3466
|
const siteText = [];
|
|
3340
3467
|
findingSites.forEach(site => {
|
|
3341
|
-
if (site?.text !== label)
|
|
3468
|
+
if (site?.text !== label) {
|
|
3469
|
+
siteText.push(site.text);
|
|
3470
|
+
}
|
|
3342
3471
|
});
|
|
3343
3472
|
displayText = [...siteText, ...displayText];
|
|
3344
3473
|
}
|
|
@@ -3362,6 +3491,7 @@ function _mapMeasurementToDisplay(measurement, index, types) {
|
|
|
3362
3491
|
|
|
3363
3492
|
|
|
3364
3493
|
|
|
3494
|
+
|
|
3365
3495
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getPanelModule.tsx
|
|
3366
3496
|
|
|
3367
3497
|
|
|
@@ -3386,7 +3516,7 @@ function getPanelModule(_ref) {
|
|
|
3386
3516
|
};
|
|
3387
3517
|
return [{
|
|
3388
3518
|
name: 'seriesList',
|
|
3389
|
-
iconName: '
|
|
3519
|
+
iconName: 'tab-studies',
|
|
3390
3520
|
iconLabel: 'Studies',
|
|
3391
3521
|
label: 'Studies',
|
|
3392
3522
|
component: Panels_WrappedPanelStudyBrowser.bind(null, {
|
|
@@ -3405,25 +3535,340 @@ function getPanelModule(_ref) {
|
|
|
3405
3535
|
}
|
|
3406
3536
|
/* harmony default export */ const src_getPanelModule = (getPanelModule);
|
|
3407
3537
|
// EXTERNAL MODULE: ../../core/src/utils/isImage.js
|
|
3408
|
-
var isImage = __webpack_require__(
|
|
3538
|
+
var isImage = __webpack_require__(11835);
|
|
3409
3539
|
// EXTERNAL MODULE: ../../core/src/utils/sopClassDictionary.js
|
|
3410
|
-
var sopClassDictionary = __webpack_require__(
|
|
3540
|
+
var sopClassDictionary = __webpack_require__(24369);
|
|
3411
3541
|
// EXTERNAL MODULE: ../../core/src/classes/ImageSet.ts
|
|
3412
|
-
var ImageSet = __webpack_require__(
|
|
3542
|
+
var ImageSet = __webpack_require__(13950);
|
|
3413
3543
|
// EXTERNAL MODULE: ../../core/src/utils/isDisplaySetReconstructable.js
|
|
3414
|
-
var isDisplaySetReconstructable = __webpack_require__(
|
|
3544
|
+
var isDisplaySetReconstructable = __webpack_require__(89359);
|
|
3415
3545
|
;// CONCATENATED MODULE: ../../../extensions/default/package.json
|
|
3416
3546
|
const package_namespaceObject = JSON.parse('{"u2":"@ohif/extension-default"}');
|
|
3417
3547
|
;// CONCATENATED MODULE: ../../../extensions/default/src/id.js
|
|
3418
3548
|
|
|
3419
3549
|
const id = package_namespaceObject.u2;
|
|
3420
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
|
+
const firstInstance = instances[0];
|
|
3805
|
+
if (!instances.length || firstInstance) {
|
|
3806
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.NO_VALID_INSTANCES);
|
|
3807
|
+
return;
|
|
3808
|
+
}
|
|
3809
|
+
const {
|
|
3810
|
+
Modality,
|
|
3811
|
+
ImageType,
|
|
3812
|
+
NumberOfFrames
|
|
3813
|
+
} = firstInstance;
|
|
3814
|
+
// Due to current requirements, LOCALIZER series doesn't have any messages
|
|
3815
|
+
if (ImageType?.includes('LOCALIZER')) {
|
|
3816
|
+
return messages;
|
|
3817
|
+
}
|
|
3818
|
+
if (!isDisplaySetReconstructable/* constructableModalities */.M6.includes(Modality)) {
|
|
3819
|
+
return messages;
|
|
3820
|
+
}
|
|
3821
|
+
const isMultiframe = NumberOfFrames > 1;
|
|
3822
|
+
// Can't reconstruct if all instances don't have the ImagePositionPatient.
|
|
3823
|
+
if (!isMultiframe && !instances.every(instance => instance.ImagePositionPatient)) {
|
|
3824
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.NO_POSITION_INFORMATION);
|
|
3825
|
+
}
|
|
3826
|
+
const sortedInstances = (0,sortInstancesByPosition/* default */.Z)(instances);
|
|
3827
|
+
isMultiframe ? checkMultiFrame(sortedInstances[0], messages) : checkSingleFrames(sortedInstances, messages);
|
|
3828
|
+
if (!isReconstructable) {
|
|
3829
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.NOT_RECONSTRUCTABLE);
|
|
3830
|
+
}
|
|
3831
|
+
return messages;
|
|
3832
|
+
}
|
|
3833
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/getDisplaySetsFromUnsupportedSeries.js
|
|
3834
|
+
|
|
3835
|
+
|
|
3836
|
+
/**
|
|
3837
|
+
* Default handler for a instance list with an unsupported sopClassUID
|
|
3838
|
+
*/
|
|
3839
|
+
function getDisplaySetsFromUnsupportedSeries(instances) {
|
|
3840
|
+
const imageSet = new ImageSet/* default */.Z(instances);
|
|
3841
|
+
const messages = new src/* DisplaySetMessageList */.iK();
|
|
3842
|
+
messages.addMessage(src/* DisplaySetMessage */.Lt.CODES.UNSUPPORTED_DISPLAYSET);
|
|
3843
|
+
const instance = instances[0];
|
|
3844
|
+
imageSet.setAttributes({
|
|
3845
|
+
displaySetInstanceUID: imageSet.uid,
|
|
3846
|
+
// create a local alias for the imageSet UID
|
|
3847
|
+
SeriesDate: instance.SeriesDate,
|
|
3848
|
+
SeriesTime: instance.SeriesTime,
|
|
3849
|
+
SeriesInstanceUID: instance.SeriesInstanceUID,
|
|
3850
|
+
StudyInstanceUID: instance.StudyInstanceUID,
|
|
3851
|
+
SeriesNumber: instance.SeriesNumber || 0,
|
|
3852
|
+
FrameRate: instance.FrameTime,
|
|
3853
|
+
SOPClassUID: instance.SOPClassUID,
|
|
3854
|
+
SeriesDescription: instance.SeriesDescription || '',
|
|
3855
|
+
Modality: instance.Modality,
|
|
3856
|
+
numImageFrames: instances.length,
|
|
3857
|
+
unsupported: true,
|
|
3858
|
+
SOPClassHandlerId: 'unsupported',
|
|
3859
|
+
isReconstructable: false,
|
|
3860
|
+
messages
|
|
3861
|
+
});
|
|
3862
|
+
return [imageSet];
|
|
3863
|
+
}
|
|
3421
3864
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getSopClassHandlerModule.js
|
|
3422
3865
|
|
|
3423
3866
|
|
|
3424
3867
|
|
|
3425
3868
|
|
|
3426
3869
|
|
|
3870
|
+
|
|
3871
|
+
|
|
3427
3872
|
const sopClassHandlerName = 'stack';
|
|
3428
3873
|
const isMultiFrame = instance => {
|
|
3429
3874
|
return instance.NumberOfFrames > 1;
|
|
@@ -3434,9 +3879,9 @@ const makeDisplaySet = instances => {
|
|
|
3434
3879
|
const {
|
|
3435
3880
|
value: isReconstructable,
|
|
3436
3881
|
averageSpacingBetweenFrames
|
|
3437
|
-
} = (0,isDisplaySetReconstructable/* default */.
|
|
3438
|
-
|
|
3882
|
+
} = (0,isDisplaySetReconstructable/* default */.ZP)(instances);
|
|
3439
3883
|
// set appropriate attributes to image set...
|
|
3884
|
+
const messages = getDisplaySetMessages(instances, isReconstructable);
|
|
3440
3885
|
imageSet.setAttributes({
|
|
3441
3886
|
displaySetInstanceUID: imageSet.uid,
|
|
3442
3887
|
// create a local alias for the imageSet UID
|
|
@@ -3454,6 +3899,7 @@ const makeDisplaySet = instances => {
|
|
|
3454
3899
|
numImageFrames: instances.length,
|
|
3455
3900
|
SOPClassHandlerId: `${id}.sopClassHandlerModule.${sopClassHandlerName}`,
|
|
3456
3901
|
isReconstructable,
|
|
3902
|
+
messages,
|
|
3457
3903
|
averageSpacingBetweenFrames: averageSpacingBetweenFrames || null
|
|
3458
3904
|
});
|
|
3459
3905
|
|
|
@@ -3560,6 +4006,10 @@ function getSopClassHandlerModule() {
|
|
|
3560
4006
|
name: sopClassHandlerName,
|
|
3561
4007
|
sopClassUids,
|
|
3562
4008
|
getDisplaySetsFromSeries
|
|
4009
|
+
}, {
|
|
4010
|
+
name: 'not-supported-display-sets-handler',
|
|
4011
|
+
sopClassUids: [],
|
|
4012
|
+
getDisplaySetsFromSeries: getDisplaySetsFromUnsupportedSeries
|
|
3563
4013
|
}];
|
|
3564
4014
|
}
|
|
3565
4015
|
/* harmony default export */ const src_getSopClassHandlerModule = (getSopClassHandlerModule);
|
|
@@ -3567,44 +4017,53 @@ function getSopClassHandlerModule() {
|
|
|
3567
4017
|
|
|
3568
4018
|
function ToolbarDivider() {
|
|
3569
4019
|
return /*#__PURE__*/react.createElement("span", {
|
|
3570
|
-
className: "
|
|
4020
|
+
className: "border-common-dark mx-2 h-8 w-4 self-center border-l"
|
|
3571
4021
|
});
|
|
3572
4022
|
}
|
|
3573
4023
|
;// CONCATENATED MODULE: ../../../extensions/default/src/Toolbar/ToolbarLayoutSelector.tsx
|
|
4024
|
+
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); }
|
|
3574
4025
|
|
|
3575
4026
|
|
|
3576
4027
|
|
|
3577
4028
|
|
|
3578
|
-
function
|
|
4029
|
+
function ToolbarLayoutSelectorWithServices(_ref) {
|
|
3579
4030
|
let {
|
|
3580
|
-
rows,
|
|
3581
|
-
columns,
|
|
3582
|
-
className,
|
|
3583
4031
|
servicesManager,
|
|
3584
|
-
...
|
|
4032
|
+
...props
|
|
3585
4033
|
} = _ref;
|
|
3586
|
-
const [isOpen, setIsOpen] = (0,react.useState)(false);
|
|
3587
4034
|
const {
|
|
3588
|
-
hangingProtocolService,
|
|
3589
4035
|
toolbarService
|
|
3590
4036
|
} = servicesManager.services;
|
|
4037
|
+
const onSelection = (0,react.useCallback)(props => {
|
|
4038
|
+
toolbarService.recordInteraction({
|
|
4039
|
+
interactionType: 'action',
|
|
4040
|
+
commands: [{
|
|
4041
|
+
commandName: 'setViewportGridLayout',
|
|
4042
|
+
commandOptions: {
|
|
4043
|
+
...props
|
|
4044
|
+
},
|
|
4045
|
+
context: 'DEFAULT'
|
|
4046
|
+
}]
|
|
4047
|
+
});
|
|
4048
|
+
}, [toolbarService]);
|
|
4049
|
+
return /*#__PURE__*/react.createElement(LayoutSelector, ToolbarLayoutSelector_extends({}, props, {
|
|
4050
|
+
onSelection: onSelection
|
|
4051
|
+
}));
|
|
4052
|
+
}
|
|
4053
|
+
function LayoutSelector(_ref2) {
|
|
4054
|
+
let {
|
|
4055
|
+
rows,
|
|
4056
|
+
columns,
|
|
4057
|
+
className,
|
|
4058
|
+
onSelection,
|
|
4059
|
+
...rest
|
|
4060
|
+
} = _ref2;
|
|
4061
|
+
const [isOpen, setIsOpen] = (0,react.useState)(false);
|
|
3591
4062
|
const closeOnOutsideClick = () => {
|
|
3592
4063
|
if (isOpen) {
|
|
3593
4064
|
setIsOpen(false);
|
|
3594
4065
|
}
|
|
3595
4066
|
};
|
|
3596
|
-
(0,react.useEffect)(() => {
|
|
3597
|
-
const {
|
|
3598
|
-
unsubscribe
|
|
3599
|
-
} = hangingProtocolService.subscribe(hangingProtocolService.EVENTS.PROTOCOL_CHANGED, evt => {
|
|
3600
|
-
const {
|
|
3601
|
-
protocol
|
|
3602
|
-
} = evt;
|
|
3603
|
-
});
|
|
3604
|
-
return () => {
|
|
3605
|
-
unsubscribe();
|
|
3606
|
-
};
|
|
3607
|
-
}, [hangingProtocolService]);
|
|
3608
4067
|
(0,react.useEffect)(() => {
|
|
3609
4068
|
window.addEventListener('click', closeOnOutsideClick);
|
|
3610
4069
|
return () => {
|
|
@@ -3613,18 +4072,6 @@ function LayoutSelector(_ref) {
|
|
|
3613
4072
|
}, [isOpen]);
|
|
3614
4073
|
const onInteractionHandler = () => setIsOpen(!isOpen);
|
|
3615
4074
|
const DropdownContent = isOpen ? ui_src/* LayoutSelector */.OF : null;
|
|
3616
|
-
const onSelectionHandler = props => {
|
|
3617
|
-
toolbarService.recordInteraction({
|
|
3618
|
-
interactionType: 'action',
|
|
3619
|
-
commands: [{
|
|
3620
|
-
commandName: 'setViewportGridLayout',
|
|
3621
|
-
commandOptions: {
|
|
3622
|
-
...props
|
|
3623
|
-
},
|
|
3624
|
-
context: 'DEFAULT'
|
|
3625
|
-
}]
|
|
3626
|
-
});
|
|
3627
|
-
};
|
|
3628
4075
|
return /*#__PURE__*/react.createElement(ui_src/* ToolbarButton */.hA, {
|
|
3629
4076
|
id: "Layout",
|
|
3630
4077
|
label: "Grid Layout",
|
|
@@ -3635,7 +4082,7 @@ function LayoutSelector(_ref) {
|
|
|
3635
4082
|
dropdownContent: DropdownContent !== null && /*#__PURE__*/react.createElement(DropdownContent, {
|
|
3636
4083
|
rows: rows,
|
|
3637
4084
|
columns: columns,
|
|
3638
|
-
onSelection:
|
|
4085
|
+
onSelection: onSelection
|
|
3639
4086
|
}),
|
|
3640
4087
|
isActive: isOpen,
|
|
3641
4088
|
type: "toggle"
|
|
@@ -3652,10 +4099,238 @@ LayoutSelector.defaultProps = {
|
|
|
3652
4099
|
columns: 3,
|
|
3653
4100
|
onLayoutChange: () => {}
|
|
3654
4101
|
};
|
|
3655
|
-
/* harmony default export */ const ToolbarLayoutSelector = (
|
|
3656
|
-
;// CONCATENATED MODULE: ../../../extensions/default/src/Toolbar/
|
|
4102
|
+
/* harmony default export */ const ToolbarLayoutSelector = (ToolbarLayoutSelectorWithServices);
|
|
4103
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/Toolbar/ToolbarSplitButtonWithServices.tsx
|
|
4104
|
+
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); }
|
|
4105
|
+
|
|
4106
|
+
|
|
4107
|
+
|
|
4108
|
+
|
|
4109
|
+
function ToolbarSplitButtonWithServices(_ref) {
|
|
4110
|
+
let {
|
|
4111
|
+
isRadio,
|
|
4112
|
+
isAction,
|
|
4113
|
+
groupId,
|
|
4114
|
+
primary,
|
|
4115
|
+
secondary,
|
|
4116
|
+
items,
|
|
4117
|
+
renderer,
|
|
4118
|
+
onInteraction,
|
|
4119
|
+
servicesManager
|
|
4120
|
+
} = _ref;
|
|
4121
|
+
const {
|
|
4122
|
+
toolbarService
|
|
4123
|
+
} = servicesManager?.services;
|
|
4124
|
+
const handleItemClick = (item, index) => {
|
|
4125
|
+
const {
|
|
4126
|
+
id,
|
|
4127
|
+
type,
|
|
4128
|
+
commands
|
|
4129
|
+
} = item;
|
|
4130
|
+
onInteraction({
|
|
4131
|
+
groupId,
|
|
4132
|
+
itemId: id,
|
|
4133
|
+
interactionType: type,
|
|
4134
|
+
commands
|
|
4135
|
+
});
|
|
4136
|
+
setState(state => ({
|
|
4137
|
+
...state,
|
|
4138
|
+
primary: !isAction && isRadio ? {
|
|
4139
|
+
...item,
|
|
4140
|
+
index
|
|
4141
|
+
} : state.primary,
|
|
4142
|
+
isExpanded: false,
|
|
4143
|
+
items: getSplitButtonItems(items).filter(item => isRadio && !isAction ? item.index !== index : true)
|
|
4144
|
+
}));
|
|
4145
|
+
};
|
|
4146
|
+
|
|
4147
|
+
/* Bubbles up individual item clicks */
|
|
4148
|
+
const getSplitButtonItems = items => items.map((item, index) => ({
|
|
4149
|
+
...item,
|
|
4150
|
+
index,
|
|
4151
|
+
onClick: () => handleItemClick(item, index)
|
|
4152
|
+
}));
|
|
4153
|
+
const [buttonsState, setButtonState] = (0,react.useState)({
|
|
4154
|
+
primaryToolId: '',
|
|
4155
|
+
toggles: {},
|
|
4156
|
+
groups: {}
|
|
4157
|
+
});
|
|
4158
|
+
const [state, setState] = (0,react.useState)({
|
|
4159
|
+
primary,
|
|
4160
|
+
items: getSplitButtonItems(items).filter(item => isRadio && !isAction ? item.id !== primary.id : true)
|
|
4161
|
+
});
|
|
4162
|
+
const {
|
|
4163
|
+
primaryToolId,
|
|
4164
|
+
toggles
|
|
4165
|
+
} = buttonsState;
|
|
4166
|
+
const isPrimaryToggle = state.primary.type === 'toggle';
|
|
4167
|
+
const isPrimaryActive = state.primary.type === 'tool' && primaryToolId === state.primary.id || isPrimaryToggle && toggles[state.primary.id] === true;
|
|
4168
|
+
const PrimaryButtonComponent = toolbarService?.getButtonComponentForUIType(state.primary.uiType) ?? ui_src/* ToolbarButton */.hA;
|
|
4169
|
+
(0,react.useEffect)(() => {
|
|
4170
|
+
const {
|
|
4171
|
+
unsubscribe
|
|
4172
|
+
} = toolbarService.subscribe(toolbarService.EVENTS.TOOL_BAR_STATE_MODIFIED, state => {
|
|
4173
|
+
setButtonState({
|
|
4174
|
+
...state
|
|
4175
|
+
});
|
|
4176
|
+
});
|
|
4177
|
+
return () => {
|
|
4178
|
+
unsubscribe();
|
|
4179
|
+
};
|
|
4180
|
+
}, [toolbarService]);
|
|
4181
|
+
const updatedItems = state.items.map(item => {
|
|
4182
|
+
const isActive = item.type === 'tool' && primaryToolId === item.id;
|
|
4183
|
+
|
|
4184
|
+
// We could have added the
|
|
4185
|
+
// item.type === 'toggle' && toggles[item.id] === true
|
|
4186
|
+
// too but that makes the button active when the toggle is active under it
|
|
4187
|
+
// which feels weird
|
|
4188
|
+
return {
|
|
4189
|
+
...item,
|
|
4190
|
+
isActive
|
|
4191
|
+
};
|
|
4192
|
+
});
|
|
4193
|
+
const DefaultListItemRenderer = _ref2 => {
|
|
4194
|
+
let {
|
|
4195
|
+
type,
|
|
4196
|
+
icon,
|
|
4197
|
+
label,
|
|
4198
|
+
t,
|
|
4199
|
+
id
|
|
4200
|
+
} = _ref2;
|
|
4201
|
+
const isActive = type === 'toggle' && toggles[id] === true;
|
|
4202
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
4203
|
+
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')
|
|
4204
|
+
}, icon && /*#__PURE__*/react.createElement("span", {
|
|
4205
|
+
className: "mr-4"
|
|
4206
|
+
}, /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
4207
|
+
name: icon,
|
|
4208
|
+
className: "h-5 w-5"
|
|
4209
|
+
})), /*#__PURE__*/react.createElement("span", {
|
|
4210
|
+
className: "mr-5"
|
|
4211
|
+
}, t(label)));
|
|
4212
|
+
};
|
|
4213
|
+
const listItemRenderer = renderer || DefaultListItemRenderer;
|
|
4214
|
+
return /*#__PURE__*/react.createElement(ui_src/* SplitButton */.aW, {
|
|
4215
|
+
isRadio: isRadio,
|
|
4216
|
+
isAction: isAction,
|
|
4217
|
+
primary: state.primary,
|
|
4218
|
+
secondary: secondary,
|
|
4219
|
+
items: updatedItems,
|
|
4220
|
+
groupId: groupId,
|
|
4221
|
+
renderer: listItemRenderer,
|
|
4222
|
+
isActive: isPrimaryActive || updatedItems.some(item => item.isActive),
|
|
4223
|
+
isToggle: isPrimaryToggle,
|
|
4224
|
+
onInteraction: onInteraction,
|
|
4225
|
+
Component: props => /*#__PURE__*/react.createElement(PrimaryButtonComponent, ToolbarSplitButtonWithServices_extends({}, props, {
|
|
4226
|
+
servicesManager: servicesManager
|
|
4227
|
+
}))
|
|
4228
|
+
});
|
|
4229
|
+
}
|
|
4230
|
+
ToolbarSplitButtonWithServices.propTypes = {
|
|
4231
|
+
isRadio: (prop_types_default()).bool,
|
|
4232
|
+
isAction: (prop_types_default()).bool,
|
|
4233
|
+
groupId: (prop_types_default()).string,
|
|
4234
|
+
primary: prop_types_default().shape({
|
|
4235
|
+
id: (prop_types_default()).string.isRequired,
|
|
4236
|
+
type: prop_types_default().oneOf(['tool', 'action', 'toggle']).isRequired,
|
|
4237
|
+
uiType: (prop_types_default()).string
|
|
4238
|
+
}),
|
|
4239
|
+
secondary: prop_types_default().shape({
|
|
4240
|
+
id: (prop_types_default()).string,
|
|
4241
|
+
icon: (prop_types_default()).string.isRequired,
|
|
4242
|
+
label: (prop_types_default()).string,
|
|
4243
|
+
tooltip: (prop_types_default()).string.isRequired,
|
|
4244
|
+
isActive: (prop_types_default()).bool
|
|
4245
|
+
}),
|
|
4246
|
+
items: prop_types_default().arrayOf(prop_types_default().shape({
|
|
4247
|
+
id: (prop_types_default()).string.isRequired,
|
|
4248
|
+
type: prop_types_default().oneOf(['tool', 'action', 'toggle']).isRequired,
|
|
4249
|
+
icon: (prop_types_default()).string,
|
|
4250
|
+
label: (prop_types_default()).string,
|
|
4251
|
+
tooltip: (prop_types_default()).string
|
|
4252
|
+
})),
|
|
4253
|
+
renderer: (prop_types_default()).func,
|
|
4254
|
+
onInteraction: (prop_types_default()).func.isRequired,
|
|
4255
|
+
servicesManager: prop_types_default().shape({
|
|
4256
|
+
services: prop_types_default().shape({
|
|
4257
|
+
toolbarService: (prop_types_default()).object
|
|
4258
|
+
})
|
|
4259
|
+
})
|
|
4260
|
+
};
|
|
4261
|
+
ToolbarSplitButtonWithServices.defaultProps = {
|
|
4262
|
+
isRadio: false,
|
|
4263
|
+
isAction: false
|
|
4264
|
+
};
|
|
4265
|
+
/* harmony default export */ const Toolbar_ToolbarSplitButtonWithServices = (ToolbarSplitButtonWithServices);
|
|
4266
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/Toolbar/ToolbarButtonWithServices.tsx
|
|
4267
|
+
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); }
|
|
4268
|
+
|
|
3657
4269
|
|
|
3658
|
-
|
|
4270
|
+
|
|
4271
|
+
function ToolbarButtonWithServices(_ref) {
|
|
4272
|
+
let {
|
|
4273
|
+
id,
|
|
4274
|
+
type,
|
|
4275
|
+
commands,
|
|
4276
|
+
onInteraction,
|
|
4277
|
+
servicesManager,
|
|
4278
|
+
...props
|
|
4279
|
+
} = _ref;
|
|
4280
|
+
const {
|
|
4281
|
+
toolbarService
|
|
4282
|
+
} = servicesManager?.services || {};
|
|
4283
|
+
const [buttonsState, setButtonState] = (0,react.useState)({
|
|
4284
|
+
primaryToolId: '',
|
|
4285
|
+
toggles: {},
|
|
4286
|
+
groups: {}
|
|
4287
|
+
});
|
|
4288
|
+
const {
|
|
4289
|
+
primaryToolId
|
|
4290
|
+
} = buttonsState;
|
|
4291
|
+
const isActive = type === 'tool' && id === primaryToolId || type === 'toggle' && buttonsState.toggles[id] === true;
|
|
4292
|
+
(0,react.useEffect)(() => {
|
|
4293
|
+
const {
|
|
4294
|
+
unsubscribe
|
|
4295
|
+
} = toolbarService.subscribe(toolbarService.EVENTS.TOOL_BAR_STATE_MODIFIED, state => {
|
|
4296
|
+
setButtonState({
|
|
4297
|
+
...state
|
|
4298
|
+
});
|
|
4299
|
+
});
|
|
4300
|
+
return () => {
|
|
4301
|
+
unsubscribe();
|
|
4302
|
+
};
|
|
4303
|
+
}, [toolbarService]);
|
|
4304
|
+
return /*#__PURE__*/react.createElement(ui_src/* ToolbarButton */.hA, ToolbarButtonWithServices_extends({
|
|
4305
|
+
commands: commands,
|
|
4306
|
+
id: id,
|
|
4307
|
+
type: type,
|
|
4308
|
+
isActive: isActive,
|
|
4309
|
+
onInteraction: onInteraction
|
|
4310
|
+
}, props));
|
|
4311
|
+
}
|
|
4312
|
+
ToolbarButtonWithServices.propTypes = {
|
|
4313
|
+
id: (prop_types_default()).string.isRequired,
|
|
4314
|
+
type: prop_types_default().oneOf(['tool', 'action', 'toggle']).isRequired,
|
|
4315
|
+
commands: prop_types_default().arrayOf(prop_types_default().shape({
|
|
4316
|
+
commandName: (prop_types_default()).string.isRequired,
|
|
4317
|
+
context: (prop_types_default()).string
|
|
4318
|
+
})),
|
|
4319
|
+
onInteraction: (prop_types_default()).func.isRequired,
|
|
4320
|
+
servicesManager: prop_types_default().shape({
|
|
4321
|
+
services: prop_types_default().shape({
|
|
4322
|
+
toolbarService: prop_types_default().shape({
|
|
4323
|
+
subscribe: (prop_types_default()).func.isRequired,
|
|
4324
|
+
state: prop_types_default().shape({
|
|
4325
|
+
primaryToolId: (prop_types_default()).string,
|
|
4326
|
+
toggles: prop_types_default().objectOf((prop_types_default()).bool),
|
|
4327
|
+
groups: prop_types_default().objectOf((prop_types_default()).object)
|
|
4328
|
+
}).isRequired
|
|
4329
|
+
}).isRequired
|
|
4330
|
+
}).isRequired
|
|
4331
|
+
}).isRequired
|
|
4332
|
+
};
|
|
4333
|
+
/* harmony default export */ const Toolbar_ToolbarButtonWithServices = (ToolbarButtonWithServices);
|
|
3659
4334
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getToolbarModule.tsx
|
|
3660
4335
|
|
|
3661
4336
|
|
|
@@ -3672,15 +4347,15 @@ function getToolbarModule(_ref) {
|
|
|
3672
4347
|
clickHandler: () => {}
|
|
3673
4348
|
}, {
|
|
3674
4349
|
name: 'ohif.action',
|
|
3675
|
-
defaultComponent:
|
|
4350
|
+
defaultComponent: Toolbar_ToolbarButtonWithServices,
|
|
3676
4351
|
clickHandler: () => {}
|
|
3677
4352
|
}, {
|
|
3678
4353
|
name: 'ohif.radioGroup',
|
|
3679
|
-
defaultComponent:
|
|
4354
|
+
defaultComponent: Toolbar_ToolbarButtonWithServices,
|
|
3680
4355
|
clickHandler: () => {}
|
|
3681
4356
|
}, {
|
|
3682
4357
|
name: 'ohif.splitButton',
|
|
3683
|
-
defaultComponent:
|
|
4358
|
+
defaultComponent: Toolbar_ToolbarSplitButtonWithServices,
|
|
3684
4359
|
clickHandler: () => {}
|
|
3685
4360
|
}, {
|
|
3686
4361
|
name: 'ohif.layoutSelector',
|
|
@@ -3688,7 +4363,7 @@ function getToolbarModule(_ref) {
|
|
|
3688
4363
|
clickHandler: (evt, clickedBtn, btnSectionName) => {}
|
|
3689
4364
|
}, {
|
|
3690
4365
|
name: 'ohif.toggle',
|
|
3691
|
-
defaultComponent:
|
|
4366
|
+
defaultComponent: Toolbar_ToolbarButtonWithServices,
|
|
3692
4367
|
clickHandler: () => {}
|
|
3693
4368
|
}];
|
|
3694
4369
|
}
|
|
@@ -3858,7 +4533,7 @@ function adaptItem(item, subProps) {
|
|
|
3858
4533
|
return newItem;
|
|
3859
4534
|
}
|
|
3860
4535
|
// EXTERNAL MODULE: ../../ui/src/components/ContextMenu/ContextMenu.tsx
|
|
3861
|
-
var ContextMenu = __webpack_require__(
|
|
4536
|
+
var ContextMenu = __webpack_require__(5638);
|
|
3862
4537
|
;// CONCATENATED MODULE: ../../../extensions/default/src/CustomizableContextMenu/ContextMenuController.tsx
|
|
3863
4538
|
|
|
3864
4539
|
|
|
@@ -3919,8 +4594,8 @@ class ContextMenuController {
|
|
|
3919
4594
|
defaultPosition: ContextMenuController._getDefaultPosition(defaultPointsPosition, event?.detail, viewportElement),
|
|
3920
4595
|
event,
|
|
3921
4596
|
content: ContextMenu/* default */.Z,
|
|
3922
|
-
// This naming is part of
|
|
3923
|
-
// Clicking outside
|
|
4597
|
+
// This naming is part of the uiDialogService convention
|
|
4598
|
+
// Clicking outside simply closes the dialog box.
|
|
3924
4599
|
onClickOutside: () => this.services.uiDialogService.dismiss({
|
|
3925
4600
|
id: 'context-menu'
|
|
3926
4601
|
}),
|
|
@@ -4067,10 +4742,10 @@ const defaultContextMenu = {
|
|
|
4067
4742
|
|
|
4068
4743
|
|
|
4069
4744
|
// EXTERNAL MODULE: ../../../node_modules/moment/moment.js
|
|
4070
|
-
var moment = __webpack_require__(
|
|
4745
|
+
var moment = __webpack_require__(71271);
|
|
4071
4746
|
var moment_default = /*#__PURE__*/__webpack_require__.n(moment);
|
|
4072
4747
|
// EXTERNAL MODULE: ../../../node_modules/react-window/dist/index.esm.js
|
|
4073
|
-
var index_esm = __webpack_require__(
|
|
4748
|
+
var index_esm = __webpack_require__(94614);
|
|
4074
4749
|
;// CONCATENATED MODULE: ../../../extensions/default/src/DicomTagBrowser/DicomTagTable.tsx
|
|
4075
4750
|
|
|
4076
4751
|
|
|
@@ -4095,34 +4770,34 @@ function ColumnHeaders(_ref) {
|
|
|
4095
4770
|
valueRef
|
|
4096
4771
|
} = _ref;
|
|
4097
4772
|
return /*#__PURE__*/react.createElement("div", {
|
|
4098
|
-
className: classnames_default()('
|
|
4773
|
+
className: classnames_default()('bg-secondary-dark ohif-scrollbar flex w-full flex-row overflow-y-scroll'),
|
|
4099
4774
|
style: rowVerticalPaddingStyle
|
|
4100
4775
|
}, /*#__PURE__*/react.createElement("div", {
|
|
4101
|
-
className: "
|
|
4776
|
+
className: "w-4/24 px-3"
|
|
4102
4777
|
}, /*#__PURE__*/react.createElement("label", {
|
|
4103
4778
|
ref: tagRef,
|
|
4104
|
-
className: "flex flex-
|
|
4779
|
+
className: "flex flex-1 select-none flex-col pl-1 text-lg text-white"
|
|
4105
4780
|
}, /*#__PURE__*/react.createElement("span", {
|
|
4106
4781
|
className: "flex flex-row items-center focus:outline-none"
|
|
4107
4782
|
}, "Tag"))), /*#__PURE__*/react.createElement("div", {
|
|
4108
|
-
className: "
|
|
4783
|
+
className: "w-2/24 px-3"
|
|
4109
4784
|
}, /*#__PURE__*/react.createElement("label", {
|
|
4110
4785
|
ref: vrRef,
|
|
4111
|
-
className: "flex flex-
|
|
4786
|
+
className: "flex flex-1 select-none flex-col pl-1 text-lg text-white"
|
|
4112
4787
|
}, /*#__PURE__*/react.createElement("span", {
|
|
4113
4788
|
className: "flex flex-row items-center focus:outline-none"
|
|
4114
4789
|
}, "VR"))), /*#__PURE__*/react.createElement("div", {
|
|
4115
|
-
className: "
|
|
4790
|
+
className: "w-6/24 px-3"
|
|
4116
4791
|
}, /*#__PURE__*/react.createElement("label", {
|
|
4117
4792
|
ref: keywordRef,
|
|
4118
|
-
className: "flex flex-
|
|
4793
|
+
className: "flex flex-1 select-none flex-col pl-1 text-lg text-white"
|
|
4119
4794
|
}, /*#__PURE__*/react.createElement("span", {
|
|
4120
4795
|
className: "flex flex-row items-center focus:outline-none"
|
|
4121
4796
|
}, "Keyword"))), /*#__PURE__*/react.createElement("div", {
|
|
4122
|
-
className: "
|
|
4797
|
+
className: "w-5/24 grow px-3"
|
|
4123
4798
|
}, /*#__PURE__*/react.createElement("label", {
|
|
4124
4799
|
ref: valueRef,
|
|
4125
|
-
className: "flex flex-
|
|
4800
|
+
className: "flex flex-1 select-none flex-col pl-1 text-lg text-white"
|
|
4126
4801
|
}, /*#__PURE__*/react.createElement("span", {
|
|
4127
4802
|
className: "flex flex-row items-center focus:outline-none"
|
|
4128
4803
|
}, "Value"))));
|
|
@@ -4195,16 +4870,16 @@ function DicomTagTable(_ref2) {
|
|
|
4195
4870
|
...style,
|
|
4196
4871
|
...rowStyle
|
|
4197
4872
|
},
|
|
4198
|
-
className: classnames_default()('hover:bg-secondary-main
|
|
4873
|
+
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),
|
|
4199
4874
|
key: `DICOMTagRow-${index}`
|
|
4200
4875
|
}, /*#__PURE__*/react.createElement("div", {
|
|
4201
|
-
className: "
|
|
4876
|
+
className: "w-4/24 px-3"
|
|
4202
4877
|
}, row[0]), /*#__PURE__*/react.createElement("div", {
|
|
4203
|
-
className: "
|
|
4878
|
+
className: "w-2/24 px-3"
|
|
4204
4879
|
}, row[1]), /*#__PURE__*/react.createElement("div", {
|
|
4205
|
-
className: "
|
|
4880
|
+
className: "w-6/24 px-3"
|
|
4206
4881
|
}, row[2]), /*#__PURE__*/react.createElement("div", {
|
|
4207
|
-
className: "
|
|
4882
|
+
className: "w-5/24 grow px-3"
|
|
4208
4883
|
}, row[3]));
|
|
4209
4884
|
}, [rows]);
|
|
4210
4885
|
|
|
@@ -4242,7 +4917,7 @@ function DicomTagTable(_ref2) {
|
|
|
4242
4917
|
keywordRef: keywordRef,
|
|
4243
4918
|
valueRef: valueRef
|
|
4244
4919
|
}), /*#__PURE__*/react.createElement("div", {
|
|
4245
|
-
className: "m-auto
|
|
4920
|
+
className: "relative m-auto border-2 border-black bg-black",
|
|
4246
4921
|
style: {
|
|
4247
4922
|
height: '32rem'
|
|
4248
4923
|
}
|
|
@@ -4268,7 +4943,6 @@ function DicomTagTable(_ref2) {
|
|
|
4268
4943
|
|
|
4269
4944
|
|
|
4270
4945
|
|
|
4271
|
-
|
|
4272
4946
|
const {
|
|
4273
4947
|
ImageSet: DicomTagBrowser_ImageSet
|
|
4274
4948
|
} = src.classes;
|
|
@@ -4297,7 +4971,6 @@ const DicomTagBrowser = _ref => {
|
|
|
4297
4971
|
setSelectedDisplaySetInstanceUID(value.value);
|
|
4298
4972
|
setInstanceNumber(1);
|
|
4299
4973
|
};
|
|
4300
|
-
const searchInputRef = (0,react.useRef)(null);
|
|
4301
4974
|
const activeDisplaySet = displaySets.find(ds => ds.displaySetInstanceUID === selectedDisplaySetInstanceUID);
|
|
4302
4975
|
const isImageStack = _isImageStack(activeDisplaySet);
|
|
4303
4976
|
const showInstanceList = isImageStack && activeDisplaySet.images.length > 1;
|
|
@@ -4363,14 +5036,14 @@ const DicomTagBrowser = _ref => {
|
|
|
4363
5036
|
return /*#__PURE__*/react.createElement("div", {
|
|
4364
5037
|
className: "dicom-tag-browser-content"
|
|
4365
5038
|
}, /*#__PURE__*/react.createElement("div", {
|
|
4366
|
-
className: "flex flex-row
|
|
5039
|
+
className: "mb-6 flex flex-row items-center pl-1"
|
|
4367
5040
|
}, /*#__PURE__*/react.createElement("div", {
|
|
4368
|
-
className: "flex flex-row items-center
|
|
5041
|
+
className: "flex w-1/2 flex-row items-center"
|
|
4369
5042
|
}, /*#__PURE__*/react.createElement(ui_src/* Typography */.ZT, {
|
|
4370
5043
|
variant: "subtitle",
|
|
4371
5044
|
className: "mr-4"
|
|
4372
5045
|
}, "Series"), /*#__PURE__*/react.createElement("div", {
|
|
4373
|
-
className: "
|
|
5046
|
+
className: "mr-8 grow"
|
|
4374
5047
|
}, /*#__PURE__*/react.createElement(ui_src/* Select */.Ph, {
|
|
4375
5048
|
id: "display-set-selector",
|
|
4376
5049
|
isClearable: false,
|
|
@@ -4379,7 +5052,7 @@ const DicomTagBrowser = _ref => {
|
|
|
4379
5052
|
value: displaySetList.find(ds => ds.value === selectedDisplaySetInstanceUID),
|
|
4380
5053
|
className: "text-white"
|
|
4381
5054
|
}))), /*#__PURE__*/react.createElement("div", {
|
|
4382
|
-
className: "flex flex-row items-center
|
|
5055
|
+
className: "flex w-1/2 flex-row items-center"
|
|
4383
5056
|
}, showInstanceList && /*#__PURE__*/react.createElement(ui_src/* Typography */.ZT, {
|
|
4384
5057
|
variant: "subtitle",
|
|
4385
5058
|
className: "mr-4"
|
|
@@ -4398,32 +5071,14 @@ const DicomTagBrowser = _ref => {
|
|
|
4398
5071
|
labelPosition: "left",
|
|
4399
5072
|
trackColor: '#3a3f99'
|
|
4400
5073
|
})))), /*#__PURE__*/react.createElement("div", {
|
|
4401
|
-
className: "w-full
|
|
5074
|
+
className: "h-1 w-full bg-black"
|
|
4402
5075
|
}), /*#__PURE__*/react.createElement("div", {
|
|
4403
|
-
className: "
|
|
4404
|
-
}, /*#__PURE__*/react.createElement(
|
|
4405
|
-
className: "
|
|
4406
|
-
}, /*#__PURE__*/react.createElement("span", {
|
|
4407
|
-
className: "absolute inset-y-0 left-0 flex items-center pl-2"
|
|
4408
|
-
}, /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
4409
|
-
name: "icon-search"
|
|
4410
|
-
})), /*#__PURE__*/react.createElement("input", {
|
|
4411
|
-
ref: searchInputRef,
|
|
4412
|
-
type: "text",
|
|
4413
|
-
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",
|
|
5076
|
+
className: "my-3 flex w-1/2 flex-row"
|
|
5077
|
+
}, /*#__PURE__*/react.createElement(ui_src/* InputFilterText */.Xe, {
|
|
5078
|
+
className: "mr-8 block w-full",
|
|
4414
5079
|
placeholder: "Search metadata...",
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
}), /*#__PURE__*/react.createElement("span", {
|
|
4418
|
-
className: "absolute inset-y-0 right-0 flex items-center pr-2"
|
|
4419
|
-
}, /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
4420
|
-
name: "icon-clear-field",
|
|
4421
|
-
className: classnames_default()('cursor-pointer', filterValue ? '' : 'hidden'),
|
|
4422
|
-
onClick: () => {
|
|
4423
|
-
searchInputRef.current.value = '';
|
|
4424
|
-
debouncedSetFilterValue('');
|
|
4425
|
-
}
|
|
4426
|
-
})))), /*#__PURE__*/react.createElement(DicomTagBrowser_DicomTagTable, {
|
|
5080
|
+
onDebounceChange: setFilterValue
|
|
5081
|
+
})), /*#__PURE__*/react.createElement(DicomTagBrowser_DicomTagTable, {
|
|
4427
5082
|
rows: filteredRows
|
|
4428
5083
|
}));
|
|
4429
5084
|
};
|
|
@@ -4596,61 +5251,62 @@ function _sortTagList(tagList) {
|
|
|
4596
5251
|
*/
|
|
4597
5252
|
const reuseCachedLayout = (state, hangingProtocolService, syncService) => {
|
|
4598
5253
|
const {
|
|
4599
|
-
|
|
4600
|
-
viewports,
|
|
4601
|
-
layout
|
|
5254
|
+
activeViewportId
|
|
4602
5255
|
} = state;
|
|
5256
|
+
const {
|
|
5257
|
+
protocol
|
|
5258
|
+
} = hangingProtocolService.getActiveProtocol();
|
|
4603
5259
|
const hpInfo = hangingProtocolService.getState();
|
|
4604
5260
|
const {
|
|
4605
5261
|
protocolId,
|
|
4606
5262
|
stageIndex,
|
|
4607
5263
|
activeStudyUID
|
|
4608
5264
|
} = hpInfo;
|
|
4609
|
-
const {
|
|
4610
|
-
protocol
|
|
4611
|
-
} = hangingProtocolService.getActiveProtocol();
|
|
4612
|
-
const stage = protocol.stages[stageIndex];
|
|
4613
|
-
const storeId = `${activeStudyUID}:${protocolId}:${stageIndex}`;
|
|
4614
5265
|
const syncState = syncService.getState();
|
|
4615
|
-
const cacheId = `${activeStudyUID}:${protocolId}`;
|
|
4616
5266
|
const viewportGridStore = {
|
|
4617
5267
|
...syncState.viewportGridStore
|
|
4618
5268
|
};
|
|
4619
|
-
const hangingProtocolStageIndexMap = {
|
|
4620
|
-
...syncState.hangingProtocolStageIndexMap
|
|
4621
|
-
};
|
|
4622
5269
|
const displaySetSelectorMap = {
|
|
4623
5270
|
...syncState.displaySetSelectorMap
|
|
4624
5271
|
};
|
|
5272
|
+
const stage = protocol.stages[stageIndex];
|
|
5273
|
+
const storeId = `${activeStudyUID}:${protocolId}:${stageIndex}`;
|
|
5274
|
+
const cacheId = `${activeStudyUID}:${protocolId}`;
|
|
5275
|
+
const hangingProtocolStageIndexMap = {
|
|
5276
|
+
...syncState.hangingProtocolStageIndexMap
|
|
5277
|
+
};
|
|
4625
5278
|
const {
|
|
4626
5279
|
rows,
|
|
4627
5280
|
columns
|
|
4628
5281
|
} = stage.viewportStructure.properties;
|
|
4629
|
-
const custom = stage.viewports.length !== state.viewports.
|
|
5282
|
+
const custom = stage.viewports.length !== state.viewports.size || state.layout.numRows !== rows || state.layout.numCols !== columns;
|
|
4630
5283
|
hangingProtocolStageIndexMap[cacheId] = hpInfo;
|
|
4631
5284
|
if (storeId && custom) {
|
|
4632
5285
|
viewportGridStore[storeId] = {
|
|
4633
5286
|
...state
|
|
4634
5287
|
};
|
|
4635
5288
|
}
|
|
4636
|
-
|
|
4637
|
-
const viewport = state.viewports[idx];
|
|
5289
|
+
state.viewports.forEach((viewport, viewportId) => {
|
|
4638
5290
|
const {
|
|
4639
5291
|
displaySetOptions,
|
|
4640
5292
|
displaySetInstanceUIDs
|
|
4641
5293
|
} = viewport;
|
|
4642
|
-
if (!displaySetOptions)
|
|
5294
|
+
if (!displaySetOptions) {
|
|
5295
|
+
return;
|
|
5296
|
+
}
|
|
4643
5297
|
for (let i = 0; i < displaySetOptions.length; i++) {
|
|
4644
5298
|
const displaySetUID = displaySetInstanceUIDs[i];
|
|
4645
|
-
if (!displaySetUID)
|
|
4646
|
-
|
|
5299
|
+
if (!displaySetUID) {
|
|
5300
|
+
continue;
|
|
5301
|
+
}
|
|
5302
|
+
if (viewportId === activeViewportId && i === 0) {
|
|
4647
5303
|
displaySetSelectorMap[`${activeStudyUID}:activeDisplaySet:0`] = displaySetUID;
|
|
4648
5304
|
}
|
|
4649
5305
|
if (displaySetOptions[i]?.id) {
|
|
4650
5306
|
displaySetSelectorMap[`${activeStudyUID}:${displaySetOptions[i].id}:${displaySetOptions[i].matchedDisplaySetsIndex || 0}`] = displaySetUID;
|
|
4651
5307
|
}
|
|
4652
5308
|
}
|
|
4653
|
-
}
|
|
5309
|
+
});
|
|
4654
5310
|
return {
|
|
4655
5311
|
hangingProtocolStageIndexMap,
|
|
4656
5312
|
viewportGridStore,
|
|
@@ -4662,22 +5318,24 @@ const reuseCachedLayout = (state, hangingProtocolService, syncService) => {
|
|
|
4662
5318
|
/**
|
|
4663
5319
|
* This find or create viewport is paired with the reduce results from
|
|
4664
5320
|
* below, and the action of this viewport is to look for previously filled
|
|
4665
|
-
* viewports, and to
|
|
5321
|
+
* viewports, and to reuse by position id. If there is no filled viewport,
|
|
4666
5322
|
* then one can be re-used from the display set if it isn't going to be displayed.
|
|
4667
5323
|
* @param hangingProtocolService - bound parameter supplied before using this
|
|
4668
5324
|
* @param viewportsByPosition - bound parameter supplied before using this
|
|
4669
|
-
* @param
|
|
5325
|
+
* @param position - the position in the grid to retrieve
|
|
4670
5326
|
* @param positionId - the current position on screen to retrieve
|
|
4671
5327
|
* @param options - the set of options used, so that subsequent calls can
|
|
4672
5328
|
* store state that is reset by the setLayout.
|
|
4673
5329
|
* This class uses the options to store the already viewed
|
|
4674
5330
|
* display sets, filling it initially with the pre-existing viewports.
|
|
4675
5331
|
*/
|
|
4676
|
-
const findViewportsByPosition_findOrCreateViewport = (hangingProtocolService, viewportsByPosition,
|
|
5332
|
+
const findViewportsByPosition_findOrCreateViewport = (hangingProtocolService, viewportsByPosition, position, positionId, options) => {
|
|
4677
5333
|
const byPositionViewport = viewportsByPosition?.[positionId];
|
|
4678
|
-
if (byPositionViewport)
|
|
4679
|
-
|
|
4680
|
-
|
|
5334
|
+
if (byPositionViewport) {
|
|
5335
|
+
return {
|
|
5336
|
+
...byPositionViewport
|
|
5337
|
+
};
|
|
5338
|
+
}
|
|
4681
5339
|
const {
|
|
4682
5340
|
protocolId,
|
|
4683
5341
|
stageIndex
|
|
@@ -4725,7 +5383,7 @@ const findViewportsByPosition = (state, _ref, syncService) => {
|
|
|
4725
5383
|
...syncState.viewportsByPosition
|
|
4726
5384
|
};
|
|
4727
5385
|
const initialInDisplay = [];
|
|
4728
|
-
|
|
5386
|
+
viewports.forEach(viewport => {
|
|
4729
5387
|
if (viewport.positionId) {
|
|
4730
5388
|
const storedViewport = {
|
|
4731
5389
|
...viewport,
|
|
@@ -4734,16 +5392,11 @@ const findViewportsByPosition = (state, _ref, syncService) => {
|
|
|
4734
5392
|
}
|
|
4735
5393
|
};
|
|
4736
5394
|
viewportsByPosition[viewport.positionId] = storedViewport;
|
|
4737
|
-
// The cache doesn't store the viewport options - it is only useful
|
|
4738
|
-
// for remembering the type of viewport and UIDs
|
|
4739
|
-
delete storedViewport.viewportId;
|
|
4740
|
-
delete storedViewport.viewportOptions.viewportId;
|
|
4741
5395
|
}
|
|
4742
|
-
}
|
|
5396
|
+
});
|
|
4743
5397
|
for (let row = 0; row < numRows; row++) {
|
|
4744
5398
|
for (let col = 0; col < numCols; col++) {
|
|
4745
|
-
const
|
|
4746
|
-
const positionId = viewports?.[pos]?.positionId || `${col}-${row}`;
|
|
5399
|
+
const positionId = `${col}-${row}`;
|
|
4747
5400
|
const viewport = viewportsByPosition[positionId];
|
|
4748
5401
|
if (viewport?.displaySetInstanceUIDs) {
|
|
4749
5402
|
initialInDisplay.push(...viewport.displaySetInstanceUIDs);
|
|
@@ -4758,8 +5411,8 @@ const findViewportsByPosition = (state, _ref, syncService) => {
|
|
|
4758
5411
|
};
|
|
4759
5412
|
};
|
|
4760
5413
|
/* harmony default export */ const src_findViewportsByPosition = (findViewportsByPosition);
|
|
4761
|
-
// EXTERNAL MODULE: ./index.js +
|
|
4762
|
-
var index = __webpack_require__(
|
|
5414
|
+
// EXTERNAL MODULE: ./index.js + 33 modules
|
|
5415
|
+
var index = __webpack_require__(59754);
|
|
4763
5416
|
;// CONCATENATED MODULE: ../../../extensions/default/src/commandsModule.ts
|
|
4764
5417
|
|
|
4765
5418
|
|
|
@@ -4861,7 +5514,9 @@ const commandsModule = _ref => {
|
|
|
4861
5514
|
stage
|
|
4862
5515
|
} = hangingProtocolService.getActiveProtocol();
|
|
4863
5516
|
const enableListener = button => {
|
|
4864
|
-
if (!button.id)
|
|
5517
|
+
if (!button.id) {
|
|
5518
|
+
return;
|
|
5519
|
+
}
|
|
4865
5520
|
const {
|
|
4866
5521
|
commands,
|
|
4867
5522
|
items
|
|
@@ -4870,14 +5525,16 @@ const commandsModule = _ref => {
|
|
|
4870
5525
|
items.forEach(enableListener);
|
|
4871
5526
|
}
|
|
4872
5527
|
const hpCommand = commands?.find?.(isHangingProtocolCommand);
|
|
4873
|
-
if (!hpCommand)
|
|
5528
|
+
if (!hpCommand) {
|
|
5529
|
+
return;
|
|
5530
|
+
}
|
|
4874
5531
|
const {
|
|
4875
5532
|
protocolId,
|
|
4876
5533
|
stageIndex,
|
|
4877
5534
|
stageId
|
|
4878
5535
|
} = hpCommand.commandOptions;
|
|
4879
5536
|
const isActive = (!protocolId || protocolId === protocol.id) && (stageIndex === undefined || stageIndex === toggleStageIndex) && (!stageId || stageId === stage.id);
|
|
4880
|
-
toolbarService.
|
|
5537
|
+
toolbarService.setToggled(button.id, isActive);
|
|
4881
5538
|
};
|
|
4882
5539
|
Object.values(toolbarService.getButtons()).forEach(enableListener);
|
|
4883
5540
|
},
|
|
@@ -4929,7 +5586,7 @@ const commandsModule = _ref => {
|
|
|
4929
5586
|
displaySetSelectorMap
|
|
4930
5587
|
} = stateSyncReduce;
|
|
4931
5588
|
if (!protocolId) {
|
|
4932
|
-
//
|
|
5589
|
+
// Reuse the previous protocol id, and optionally stage
|
|
4933
5590
|
protocolId = hpInfo.protocolId;
|
|
4934
5591
|
if (stageId === undefined && stageIndex === undefined) {
|
|
4935
5592
|
stageIndex = hpInfo.stageIndex;
|
|
@@ -4972,19 +5629,20 @@ const commandsModule = _ref => {
|
|
|
4972
5629
|
delete displaySetSelectorMap[`${activeStudyUID || hpInfo.activeStudyUID}:activeDisplaySet:0`];
|
|
4973
5630
|
stateSyncService.store(stateSyncReduce);
|
|
4974
5631
|
// This is a default action applied
|
|
4975
|
-
|
|
5632
|
+
const {
|
|
5633
|
+
protocol
|
|
5634
|
+
} = hangingProtocolService.getActiveProtocol();
|
|
5635
|
+
actions.toggleHpTools(protocol);
|
|
4976
5636
|
// Send the notification about updating the state
|
|
4977
5637
|
if (protocolId !== hpInfo.protocolId) {
|
|
4978
|
-
const {
|
|
4979
|
-
protocol
|
|
4980
|
-
} = hangingProtocolService.getActiveProtocol();
|
|
4981
5638
|
// The old protocol callbacks are used for turning off things
|
|
4982
5639
|
// like crosshairs when moving to the new HP
|
|
4983
5640
|
commandsManager.run(oldProtocol.callbacks?.onProtocolExit);
|
|
4984
5641
|
// The new protocol callback is used for things like
|
|
4985
5642
|
// activating modes etc.
|
|
4986
|
-
commandsManager.run(protocol.callbacks?.onProtocolEnter);
|
|
4987
5643
|
}
|
|
5644
|
+
|
|
5645
|
+
commandsManager.run(protocol.callbacks?.onProtocolEnter);
|
|
4988
5646
|
return true;
|
|
4989
5647
|
} catch (e) {
|
|
4990
5648
|
actions.toggleHpTools(hangingProtocolService.getActiveProtocol());
|
|
@@ -5100,7 +5758,7 @@ const commandsModule = _ref => {
|
|
|
5100
5758
|
toggleOneUp() {
|
|
5101
5759
|
const viewportGridState = viewportGridService.getState();
|
|
5102
5760
|
const {
|
|
5103
|
-
|
|
5761
|
+
activeViewportId,
|
|
5104
5762
|
viewports,
|
|
5105
5763
|
layout
|
|
5106
5764
|
} = viewportGridState;
|
|
@@ -5108,7 +5766,7 @@ const commandsModule = _ref => {
|
|
|
5108
5766
|
displaySetInstanceUIDs,
|
|
5109
5767
|
displaySetOptions,
|
|
5110
5768
|
viewportOptions
|
|
5111
|
-
} = viewports
|
|
5769
|
+
} = viewports.get(activeViewportId);
|
|
5112
5770
|
if (layout.numCols === 1 && layout.numRows === 1) {
|
|
5113
5771
|
// The viewer is in one-up. Check if there is a state to restore/toggle back to.
|
|
5114
5772
|
const {
|
|
@@ -5119,24 +5777,33 @@ const commandsModule = _ref => {
|
|
|
5119
5777
|
}
|
|
5120
5778
|
// There is a state to toggle back to. The viewport that was
|
|
5121
5779
|
// originally toggled to one up was the former active viewport.
|
|
5122
|
-
const
|
|
5780
|
+
const viewportIdToUpdate = toggleOneUpViewportGridStore.activeViewportId;
|
|
5123
5781
|
|
|
5124
|
-
//
|
|
5125
|
-
//
|
|
5126
|
-
//
|
|
5127
|
-
//
|
|
5128
|
-
|
|
5782
|
+
// We are restoring the previous layout but taking into the account that
|
|
5783
|
+
// the current one up viewport might have a new displaySet dragged and dropped on it.
|
|
5784
|
+
// updatedViewportsViaHP below contains the viewports applicable to the HP that existed
|
|
5785
|
+
// prior to the toggle to one-up - including the updated viewports if a display
|
|
5786
|
+
// set swap were to have occurred.
|
|
5787
|
+
const updatedViewportsViaHP = displaySetInstanceUIDs.length > 1 ? [] : displaySetInstanceUIDs.map(displaySetInstanceUID => hangingProtocolService.getViewportsRequireUpdate(viewportIdToUpdate, displaySetInstanceUID)).flat();
|
|
5129
5788
|
|
|
5130
|
-
//
|
|
5789
|
+
// findOrCreateViewport returns either one of the updatedViewportsViaHP
|
|
5131
5790
|
// returned from the HP service OR if there is not one from the HP service then
|
|
5132
|
-
// simply returns what was in the previous state.
|
|
5133
|
-
const findOrCreateViewport =
|
|
5134
|
-
|
|
5135
|
-
|
|
5791
|
+
// simply returns what was in the previous state for a given position in the layout.
|
|
5792
|
+
const findOrCreateViewport = (position, positionId) => {
|
|
5793
|
+
// Find the viewport for the given position prior to the toggle to one-up.
|
|
5794
|
+
const preOneUpViewport = Array.from(toggleOneUpViewportGridStore.viewports.values()).find(viewport => viewport.positionId === positionId);
|
|
5795
|
+
|
|
5796
|
+
// Use the viewport id from before the toggle to one-up to find any updates to the viewport.
|
|
5797
|
+
const viewport = updatedViewportsViaHP.find(viewport => viewport.viewportId === preOneUpViewport.viewportId);
|
|
5798
|
+
return viewport ?
|
|
5799
|
+
// Use the applicable viewport from the HP updated viewports
|
|
5800
|
+
{
|
|
5136
5801
|
viewportOptions,
|
|
5137
5802
|
displaySetOptions,
|
|
5138
5803
|
...viewport
|
|
5139
|
-
} :
|
|
5804
|
+
} :
|
|
5805
|
+
// Use the previous viewport for the given position
|
|
5806
|
+
preOneUpViewport;
|
|
5140
5807
|
};
|
|
5141
5808
|
const layoutOptions = viewportGridService.getLayoutOptionsFromState(toggleOneUpViewportGridStore);
|
|
5142
5809
|
|
|
@@ -5144,7 +5811,7 @@ const commandsModule = _ref => {
|
|
|
5144
5811
|
viewportGridService.setLayout({
|
|
5145
5812
|
numRows: toggleOneUpViewportGridStore.layout.numRows,
|
|
5146
5813
|
numCols: toggleOneUpViewportGridStore.layout.numCols,
|
|
5147
|
-
|
|
5814
|
+
activeViewportId: viewportIdToUpdate,
|
|
5148
5815
|
layoutOptions,
|
|
5149
5816
|
findOrCreateViewport
|
|
5150
5817
|
});
|
|
@@ -5209,10 +5876,10 @@ const commandsModule = _ref => {
|
|
|
5209
5876
|
},
|
|
5210
5877
|
openDICOMTagViewer() {
|
|
5211
5878
|
const {
|
|
5212
|
-
|
|
5879
|
+
activeViewportId,
|
|
5213
5880
|
viewports
|
|
5214
5881
|
} = viewportGridService.getState();
|
|
5215
|
-
const activeViewportSpecificData = viewports
|
|
5882
|
+
const activeViewportSpecificData = viewports.get(activeViewportId);
|
|
5216
5883
|
const {
|
|
5217
5884
|
displaySetInstanceUIDs
|
|
5218
5885
|
} = activeViewportSpecificData;
|
|
@@ -5244,13 +5911,10 @@ const commandsModule = _ref => {
|
|
|
5244
5911
|
},
|
|
5245
5912
|
scrollActiveThumbnailIntoView: () => {
|
|
5246
5913
|
const {
|
|
5247
|
-
|
|
5914
|
+
activeViewportId,
|
|
5248
5915
|
viewports
|
|
5249
5916
|
} = viewportGridService.getState();
|
|
5250
|
-
|
|
5251
|
-
return;
|
|
5252
|
-
}
|
|
5253
|
-
const activeViewport = viewports[activeViewportIndex];
|
|
5917
|
+
const activeViewport = viewports.get(activeViewportId);
|
|
5254
5918
|
const activeDisplaySetInstanceUID = activeViewport.displaySetInstanceUIDs[0];
|
|
5255
5919
|
const thumbnailList = document.querySelector('#ohif-thumbnail-list');
|
|
5256
5920
|
if (!thumbnailList) {
|
|
@@ -5284,12 +5948,12 @@ const commandsModule = _ref => {
|
|
|
5284
5948
|
const currentDisplaySets = [...displaySetService.activeDisplaySets];
|
|
5285
5949
|
currentDisplaySets.sort(dsSortFn);
|
|
5286
5950
|
const {
|
|
5287
|
-
|
|
5951
|
+
activeViewportId,
|
|
5288
5952
|
viewports
|
|
5289
5953
|
} = viewportGridService.getState();
|
|
5290
5954
|
const {
|
|
5291
5955
|
displaySetInstanceUIDs
|
|
5292
|
-
} = viewports
|
|
5956
|
+
} = viewports.get(activeViewportId);
|
|
5293
5957
|
const activeDisplaySetIndex = currentDisplaySets.findIndex(displaySet => displaySetInstanceUIDs.includes(displaySet.displaySetInstanceUID));
|
|
5294
5958
|
let displaySetIndexToShow;
|
|
5295
5959
|
for (displaySetIndexToShow = activeDisplaySetIndex + direction; displaySetIndexToShow > -1 && displaySetIndexToShow < currentDisplaySets.length; displaySetIndexToShow += direction) {
|
|
@@ -5305,7 +5969,7 @@ const commandsModule = _ref => {
|
|
|
5305
5969
|
} = currentDisplaySets[displaySetIndexToShow];
|
|
5306
5970
|
let updatedViewports = [];
|
|
5307
5971
|
try {
|
|
5308
|
-
updatedViewports = hangingProtocolService.getViewportsRequireUpdate(
|
|
5972
|
+
updatedViewports = hangingProtocolService.getViewportsRequireUpdate(activeViewportId, displaySetInstanceUID);
|
|
5309
5973
|
} catch (error) {
|
|
5310
5974
|
console.warn(error);
|
|
5311
5975
|
uiNotificationService.show({
|
|
@@ -5399,7 +6063,6 @@ const commandsModule = _ref => {
|
|
|
5399
6063
|
* It is not included in the viewer mode by default.
|
|
5400
6064
|
*/
|
|
5401
6065
|
const hpMN = {
|
|
5402
|
-
hasUpdatedPriorsInformation: false,
|
|
5403
6066
|
id: '@ohif/mnGrid',
|
|
5404
6067
|
description: 'Has various hanging protocol grid layouts',
|
|
5405
6068
|
name: '2x2',
|
|
@@ -5420,7 +6083,8 @@ const hpMN = {
|
|
|
5420
6083
|
greaterThan: {
|
|
5421
6084
|
value: 0
|
|
5422
6085
|
}
|
|
5423
|
-
}
|
|
6086
|
+
},
|
|
6087
|
+
required: true
|
|
5424
6088
|
},
|
|
5425
6089
|
// This display set will select the specified items by preference
|
|
5426
6090
|
// It has no affect if nothing is specified in the URL.
|
|
@@ -5608,15 +6272,182 @@ const hpMN = {
|
|
|
5608
6272
|
numberOfPriorsReferenced: -1
|
|
5609
6273
|
};
|
|
5610
6274
|
/* harmony default export */ const hpMNGrid = (hpMN);
|
|
6275
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/hpCompare.ts
|
|
6276
|
+
const defaultDisplaySetSelector = {
|
|
6277
|
+
studyMatchingRules: [{
|
|
6278
|
+
// The priorInstance is a study counter that indicates what position this study is in
|
|
6279
|
+
// and the value comes from the options parameter.
|
|
6280
|
+
attribute: 'studyInstanceUIDsIndex',
|
|
6281
|
+
from: 'options',
|
|
6282
|
+
required: true,
|
|
6283
|
+
constraint: {
|
|
6284
|
+
equals: {
|
|
6285
|
+
value: 0
|
|
6286
|
+
}
|
|
6287
|
+
}
|
|
6288
|
+
}],
|
|
6289
|
+
seriesMatchingRules: [{
|
|
6290
|
+
attribute: 'numImageFrames',
|
|
6291
|
+
constraint: {
|
|
6292
|
+
greaterThan: {
|
|
6293
|
+
value: 0
|
|
6294
|
+
}
|
|
6295
|
+
}
|
|
6296
|
+
},
|
|
6297
|
+
// This display set will select the specified items by preference
|
|
6298
|
+
// It has no affect if nothing is specified in the URL.
|
|
6299
|
+
{
|
|
6300
|
+
attribute: 'isDisplaySetFromUrl',
|
|
6301
|
+
weight: 10,
|
|
6302
|
+
constraint: {
|
|
6303
|
+
equals: true
|
|
6304
|
+
}
|
|
6305
|
+
}]
|
|
6306
|
+
};
|
|
6307
|
+
const priorDisplaySetSelector = {
|
|
6308
|
+
studyMatchingRules: [{
|
|
6309
|
+
// The priorInstance is a study counter that indicates what position this study is in
|
|
6310
|
+
// and the value comes from the options parameter.
|
|
6311
|
+
attribute: 'studyInstanceUIDsIndex',
|
|
6312
|
+
from: 'options',
|
|
6313
|
+
required: true,
|
|
6314
|
+
constraint: {
|
|
6315
|
+
equals: {
|
|
6316
|
+
value: 1
|
|
6317
|
+
}
|
|
6318
|
+
}
|
|
6319
|
+
}],
|
|
6320
|
+
seriesMatchingRules: [{
|
|
6321
|
+
attribute: 'numImageFrames',
|
|
6322
|
+
constraint: {
|
|
6323
|
+
greaterThan: {
|
|
6324
|
+
value: 0
|
|
6325
|
+
}
|
|
6326
|
+
}
|
|
6327
|
+
},
|
|
6328
|
+
// This display set will select the specified items by preference
|
|
6329
|
+
// It has no affect if nothing is specified in the URL.
|
|
6330
|
+
{
|
|
6331
|
+
attribute: 'isDisplaySetFromUrl',
|
|
6332
|
+
weight: 10,
|
|
6333
|
+
constraint: {
|
|
6334
|
+
equals: true
|
|
6335
|
+
}
|
|
6336
|
+
}]
|
|
6337
|
+
};
|
|
6338
|
+
const currentDisplaySet = {
|
|
6339
|
+
id: 'defaultDisplaySetId'
|
|
6340
|
+
};
|
|
6341
|
+
const priorDisplaySet = {
|
|
6342
|
+
id: 'priorDisplaySetId'
|
|
6343
|
+
};
|
|
6344
|
+
const currentViewport0 = {
|
|
6345
|
+
viewportOptions: {
|
|
6346
|
+
toolGroupId: 'default',
|
|
6347
|
+
allowUnmatchedView: true
|
|
6348
|
+
},
|
|
6349
|
+
displaySets: [currentDisplaySet]
|
|
6350
|
+
};
|
|
6351
|
+
const currentViewport1 = {
|
|
6352
|
+
...currentViewport0,
|
|
6353
|
+
displaySets: [{
|
|
6354
|
+
...currentDisplaySet,
|
|
6355
|
+
matchedDisplaySetsIndex: 1
|
|
6356
|
+
}]
|
|
6357
|
+
};
|
|
6358
|
+
const priorViewport0 = {
|
|
6359
|
+
...currentViewport0,
|
|
6360
|
+
displaySets: [priorDisplaySet]
|
|
6361
|
+
};
|
|
6362
|
+
const priorViewport1 = {
|
|
6363
|
+
...priorViewport0,
|
|
6364
|
+
displaySets: [{
|
|
6365
|
+
...priorDisplaySet,
|
|
6366
|
+
matchedDisplaySetsIndex: 1
|
|
6367
|
+
}]
|
|
6368
|
+
};
|
|
6369
|
+
|
|
6370
|
+
/**
|
|
6371
|
+
* This hanging protocol can be activated on the primary mode by directly
|
|
6372
|
+
* referencing it in a URL or by directly including it within a mode, e.g.:
|
|
6373
|
+
* `&hangingProtocolId=@ohif/mnGrid` added to the viewer URL
|
|
6374
|
+
* It is not included in the viewer mode by default.
|
|
6375
|
+
*/
|
|
6376
|
+
const hpMNCompare = {
|
|
6377
|
+
id: '@ohif/hpCompare',
|
|
6378
|
+
description: 'Compare two studies in various layouts',
|
|
6379
|
+
name: 'Compare Two Studies',
|
|
6380
|
+
numberOfPriorsReferenced: 1,
|
|
6381
|
+
protocolMatchingRules: [{
|
|
6382
|
+
id: 'Two Studies',
|
|
6383
|
+
weight: 1000,
|
|
6384
|
+
attribute: 'StudyInstanceUID',
|
|
6385
|
+
// The 'from' attribute says where to get the 'attribute' value from. In this case
|
|
6386
|
+
// prior means the second study in the study list.
|
|
6387
|
+
from: 'prior',
|
|
6388
|
+
required: true,
|
|
6389
|
+
constraint: {
|
|
6390
|
+
notNull: true
|
|
6391
|
+
}
|
|
6392
|
+
}],
|
|
6393
|
+
toolGroupIds: ['default'],
|
|
6394
|
+
displaySetSelectors: {
|
|
6395
|
+
defaultDisplaySetId: defaultDisplaySetSelector,
|
|
6396
|
+
priorDisplaySetId: priorDisplaySetSelector
|
|
6397
|
+
},
|
|
6398
|
+
defaultViewport: {
|
|
6399
|
+
viewportOptions: {
|
|
6400
|
+
viewportType: 'stack',
|
|
6401
|
+
toolGroupId: 'default',
|
|
6402
|
+
allowUnmatchedView: true
|
|
6403
|
+
},
|
|
6404
|
+
displaySets: [{
|
|
6405
|
+
id: 'defaultDisplaySetId',
|
|
6406
|
+
matchedDisplaySetsIndex: -1
|
|
6407
|
+
}]
|
|
6408
|
+
},
|
|
6409
|
+
stages: [{
|
|
6410
|
+
name: '2x2',
|
|
6411
|
+
stageActivation: {
|
|
6412
|
+
enabled: {
|
|
6413
|
+
minViewportsMatched: 4
|
|
6414
|
+
}
|
|
6415
|
+
},
|
|
6416
|
+
viewportStructure: {
|
|
6417
|
+
layoutType: 'grid',
|
|
6418
|
+
properties: {
|
|
6419
|
+
rows: 2,
|
|
6420
|
+
columns: 2
|
|
6421
|
+
}
|
|
6422
|
+
},
|
|
6423
|
+
viewports: [currentViewport0, priorViewport0, currentViewport1, priorViewport1]
|
|
6424
|
+
}, {
|
|
6425
|
+
name: '2x1',
|
|
6426
|
+
stageActivation: {
|
|
6427
|
+
enabled: {
|
|
6428
|
+
minViewportsMatched: 2
|
|
6429
|
+
}
|
|
6430
|
+
},
|
|
6431
|
+
viewportStructure: {
|
|
6432
|
+
layoutType: 'grid',
|
|
6433
|
+
properties: {
|
|
6434
|
+
rows: 1,
|
|
6435
|
+
columns: 2
|
|
6436
|
+
}
|
|
6437
|
+
},
|
|
6438
|
+
viewports: [currentViewport0, priorViewport0]
|
|
6439
|
+
}]
|
|
6440
|
+
};
|
|
6441
|
+
/* harmony default export */ const hpCompare = (hpMNCompare);
|
|
5611
6442
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getHangingProtocolModule.js
|
|
5612
6443
|
|
|
6444
|
+
|
|
5613
6445
|
const defaultProtocol = {
|
|
5614
6446
|
id: 'default',
|
|
5615
6447
|
locked: true,
|
|
5616
6448
|
// Don't store this hanging protocol as it applies to the currently active
|
|
5617
6449
|
// display set by default
|
|
5618
6450
|
// cacheId: null,
|
|
5619
|
-
hasUpdatedPriorsInformation: false,
|
|
5620
6451
|
name: 'Default',
|
|
5621
6452
|
createdDate: '2021-02-23T19:22:08.894Z',
|
|
5622
6453
|
modifiedDate: '2023-04-01',
|
|
@@ -5681,6 +6512,7 @@ const defaultProtocol = {
|
|
|
5681
6512
|
viewports: [{
|
|
5682
6513
|
viewportOptions: {
|
|
5683
6514
|
viewportType: 'stack',
|
|
6515
|
+
viewportId: 'default',
|
|
5684
6516
|
toolGroupId: 'default',
|
|
5685
6517
|
// This will specify the initial image options index if it matches in the URL
|
|
5686
6518
|
// and will otherwise not specify anything.
|
|
@@ -5710,6 +6542,11 @@ function getHangingProtocolModule() {
|
|
|
5710
6542
|
{
|
|
5711
6543
|
name: hpMNGrid.id,
|
|
5712
6544
|
protocol: hpMNGrid
|
|
6545
|
+
},
|
|
6546
|
+
// Create a MxN comparison hanging protocol available by default
|
|
6547
|
+
{
|
|
6548
|
+
name: hpCompare.id,
|
|
6549
|
+
protocol: hpCompare
|
|
5713
6550
|
}];
|
|
5714
6551
|
}
|
|
5715
6552
|
/* harmony default export */ const src_getHangingProtocolModule = (getHangingProtocolModule);
|
|
@@ -5732,21 +6569,22 @@ function DataSourceSelector() {
|
|
|
5732
6569
|
height: '100%'
|
|
5733
6570
|
}
|
|
5734
6571
|
}, /*#__PURE__*/react.createElement("div", {
|
|
5735
|
-
className: "h-screen w-screen
|
|
6572
|
+
className: "flex h-screen w-screen items-center justify-center "
|
|
5736
6573
|
}, /*#__PURE__*/react.createElement("div", {
|
|
5737
|
-
className: "
|
|
6574
|
+
className: "bg-secondary-dark mx-auto space-y-2 rounded-lg py-8 px-8 drop-shadow-md"
|
|
5738
6575
|
}, /*#__PURE__*/react.createElement("img", {
|
|
5739
|
-
className: "
|
|
6576
|
+
className: "mx-auto block h-14",
|
|
5740
6577
|
src: "./ohif-logo.svg",
|
|
5741
6578
|
alt: "OHIF"
|
|
5742
6579
|
}), /*#__PURE__*/react.createElement("div", {
|
|
5743
|
-
className: "
|
|
6580
|
+
className: "space-y-2 pt-4 text-center"
|
|
5744
6581
|
}, dsConfigs.filter(it => it.sourceName !== 'dicomjson' && it.sourceName !== 'dicomlocal').map(ds => /*#__PURE__*/react.createElement("div", {
|
|
5745
6582
|
key: ds.sourceName
|
|
5746
6583
|
}, /*#__PURE__*/react.createElement("h1", {
|
|
5747
6584
|
className: "text-white"
|
|
5748
|
-
}, ds.friendlyName), /*#__PURE__*/react.createElement(ui_src/* Button */.zx, {
|
|
5749
|
-
|
|
6585
|
+
}, ds.configuration?.friendlyName || ds.friendlyName), /*#__PURE__*/react.createElement(ui_src/* Button */.zx, {
|
|
6586
|
+
type: ui_src/* ButtonEnums.type */.LZ.dt.primary,
|
|
6587
|
+
className: classnames_default()('ml-2'),
|
|
5750
6588
|
onClick: () => {
|
|
5751
6589
|
navigate({
|
|
5752
6590
|
pathname: '/',
|
|
@@ -5756,10 +6594,442 @@ function DataSourceSelector() {
|
|
|
5756
6594
|
}, ds.sourceName), /*#__PURE__*/react.createElement("br", null)))))));
|
|
5757
6595
|
}
|
|
5758
6596
|
/* harmony default export */ const Panels_DataSourceSelector = (DataSourceSelector);
|
|
6597
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/Components/ItemListComponent.tsx
|
|
6598
|
+
|
|
6599
|
+
|
|
6600
|
+
|
|
6601
|
+
|
|
6602
|
+
function ItemListComponent(_ref) {
|
|
6603
|
+
let {
|
|
6604
|
+
itemLabel,
|
|
6605
|
+
itemList,
|
|
6606
|
+
onItemClicked
|
|
6607
|
+
} = _ref;
|
|
6608
|
+
const {
|
|
6609
|
+
t
|
|
6610
|
+
} = (0,es/* useTranslation */.$G)('DataSourceConfiguration');
|
|
6611
|
+
const [filterValue, setFilterValue] = (0,react.useState)('');
|
|
6612
|
+
(0,react.useEffect)(() => {
|
|
6613
|
+
setFilterValue('');
|
|
6614
|
+
}, [itemList]);
|
|
6615
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6616
|
+
className: "flex min-h-[1px] grow flex-col gap-4"
|
|
6617
|
+
}, /*#__PURE__*/react.createElement("div", {
|
|
6618
|
+
className: "flex items-center justify-between"
|
|
6619
|
+
}, /*#__PURE__*/react.createElement("div", {
|
|
6620
|
+
className: "text-primary-light text-[20px]"
|
|
6621
|
+
}, t(`Select ${itemLabel}`)), /*#__PURE__*/react.createElement(ui_src/* InputFilterText */.Xe, {
|
|
6622
|
+
className: "max-w-[40%] grow",
|
|
6623
|
+
value: filterValue,
|
|
6624
|
+
onDebounceChange: setFilterValue,
|
|
6625
|
+
placeholder: t(`Search ${itemLabel} list`)
|
|
6626
|
+
})), /*#__PURE__*/react.createElement("div", {
|
|
6627
|
+
className: "relative flex min-h-[1px] grow flex-col bg-black text-[14px]"
|
|
6628
|
+
}, itemList == null ? /*#__PURE__*/react.createElement(ui_src/* LoadingIndicatorProgress */.LE, {
|
|
6629
|
+
className: 'h-full w-full'
|
|
6630
|
+
}) : itemList.length === 0 ? /*#__PURE__*/react.createElement("div", {
|
|
6631
|
+
className: "text-primary-light flex h-full flex-col items-center justify-center px-6 py-4"
|
|
6632
|
+
}, /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
6633
|
+
name: "magnifier",
|
|
6634
|
+
className: "mb-4"
|
|
6635
|
+
}), /*#__PURE__*/react.createElement("span", null, t(`No ${itemLabel} available`))) : /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
|
|
6636
|
+
className: "bg-secondary-dark px-3 py-1.5 text-white"
|
|
6637
|
+
}, t(itemLabel)), /*#__PURE__*/react.createElement("div", {
|
|
6638
|
+
className: "ohif-scrollbar overflow-auto"
|
|
6639
|
+
}, itemList.filter(item => !filterValue || item.name.toLowerCase().includes(filterValue.toLowerCase())).map(item => {
|
|
6640
|
+
const border = 'rounded border-transparent border-b-secondary-light border-[1px] hover:border-primary-light';
|
|
6641
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6642
|
+
className: classnames_default()('hover:text-primary-light hover:bg-primary-dark group mx-2 flex items-center justify-between px-6 py-2', border),
|
|
6643
|
+
key: item.id
|
|
6644
|
+
}, /*#__PURE__*/react.createElement("div", null, item.name), /*#__PURE__*/react.createElement(ui_src/* Button */.zx, {
|
|
6645
|
+
onClick: () => onItemClicked(item),
|
|
6646
|
+
className: "invisible group-hover:visible",
|
|
6647
|
+
endIcon: /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
6648
|
+
name: "arrow-left"
|
|
6649
|
+
})
|
|
6650
|
+
}, t('Select')));
|
|
6651
|
+
})))));
|
|
6652
|
+
}
|
|
6653
|
+
/* harmony default export */ const Components_ItemListComponent = (ItemListComponent);
|
|
6654
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/Components/DataSourceConfigurationModalComponent.tsx
|
|
6655
|
+
|
|
6656
|
+
|
|
6657
|
+
|
|
6658
|
+
|
|
6659
|
+
|
|
6660
|
+
const NO_WRAP_ELLIPSIS_CLASS_NAMES = 'text-ellipsis whitespace-nowrap overflow-hidden';
|
|
6661
|
+
function DataSourceConfigurationModalComponent(_ref) {
|
|
6662
|
+
let {
|
|
6663
|
+
configurationAPI,
|
|
6664
|
+
configuredItems,
|
|
6665
|
+
onHide
|
|
6666
|
+
} = _ref;
|
|
6667
|
+
const {
|
|
6668
|
+
t
|
|
6669
|
+
} = (0,es/* useTranslation */.$G)('DataSourceConfiguration');
|
|
6670
|
+
const [itemList, setItemList] = (0,react.useState)();
|
|
6671
|
+
const [selectedItems, setSelectedItems] = (0,react.useState)(configuredItems);
|
|
6672
|
+
const [errorMessage, setErrorMessage] = (0,react.useState)();
|
|
6673
|
+
const [itemLabels] = (0,react.useState)(configurationAPI.getItemLabels());
|
|
6674
|
+
|
|
6675
|
+
// Determines whether to show the full/existing configuration for the data source.
|
|
6676
|
+
// A full or complete configuration is one where the data source (path) has the
|
|
6677
|
+
// maximum/required number of path items. Anything less is considered not complete and
|
|
6678
|
+
// the configuration starts from scratch (i.e. as if no items are configured at all).
|
|
6679
|
+
// TODO: consider configuration starting from a partial (i.e. non-empty) configuration
|
|
6680
|
+
const [showFullConfig, setShowFullConfig] = (0,react.useState)(itemLabels.length === configuredItems.length);
|
|
6681
|
+
|
|
6682
|
+
/**
|
|
6683
|
+
* The index of the selected item that is considered current and for which
|
|
6684
|
+
* its sub-items should be displayed in the items list component. When the
|
|
6685
|
+
* full/existing configuration for a data source is to be shown, the current
|
|
6686
|
+
* selected item is the second to last in the `selectedItems` list.
|
|
6687
|
+
*/
|
|
6688
|
+
const currentSelectedItemIndex = showFullConfig ? selectedItems.length - 2 : selectedItems.length - 1;
|
|
6689
|
+
(0,react.useEffect)(() => {
|
|
6690
|
+
let shouldUpdate = true;
|
|
6691
|
+
setErrorMessage(null);
|
|
6692
|
+
|
|
6693
|
+
// Clear out the former/old list while we fetch the next sub item list.
|
|
6694
|
+
setItemList(null);
|
|
6695
|
+
if (selectedItems.length === 0) {
|
|
6696
|
+
configurationAPI.initialize().then(items => {
|
|
6697
|
+
if (shouldUpdate) {
|
|
6698
|
+
setItemList(items);
|
|
6699
|
+
}
|
|
6700
|
+
}).catch(error => setErrorMessage(error.message));
|
|
6701
|
+
} else if (!showFullConfig && selectedItems.length === itemLabels.length) {
|
|
6702
|
+
// The last item to configure the data source (path) has been selected.
|
|
6703
|
+
configurationAPI.setCurrentItem(selectedItems[selectedItems.length - 1]);
|
|
6704
|
+
// We can hide the modal dialog now.
|
|
6705
|
+
onHide();
|
|
6706
|
+
} else {
|
|
6707
|
+
configurationAPI.setCurrentItem(selectedItems[currentSelectedItemIndex]).then(items => {
|
|
6708
|
+
if (shouldUpdate) {
|
|
6709
|
+
setItemList(items);
|
|
6710
|
+
}
|
|
6711
|
+
}).catch(error => setErrorMessage(error.message));
|
|
6712
|
+
}
|
|
6713
|
+
return () => {
|
|
6714
|
+
shouldUpdate = false;
|
|
6715
|
+
};
|
|
6716
|
+
}, [selectedItems, configurationAPI, onHide, itemLabels, showFullConfig, currentSelectedItemIndex]);
|
|
6717
|
+
const getSelectedItemCursorClasses = itemIndex => itemIndex !== itemLabels.length - 1 && itemIndex < selectedItems.length ? 'cursor-pointer' : 'cursor-auto';
|
|
6718
|
+
const getSelectedItemBackgroundClasses = itemIndex => itemIndex < selectedItems.length ? classnames_default()('bg-black/[.4]', itemIndex !== itemLabels.length - 1 ? 'hover:bg-transparent active:bg-secondary-dark' : '') : 'bg-transparent';
|
|
6719
|
+
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';
|
|
6720
|
+
const getSelectedItemTextClasses = itemIndex => itemIndex <= selectedItems.length ? 'text-primary-light' : 'text-primary-active';
|
|
6721
|
+
const getErrorComponent = () => {
|
|
6722
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6723
|
+
className: "flex min-h-[1px] grow flex-col gap-4"
|
|
6724
|
+
}, /*#__PURE__*/react.createElement("div", {
|
|
6725
|
+
className: "text-primary-light text-[20px]"
|
|
6726
|
+
}, t(`Error fetching ${itemLabels[selectedItems.length]} list`)), /*#__PURE__*/react.createElement("div", {
|
|
6727
|
+
className: "grow bg-black p-4 text-[14px]"
|
|
6728
|
+
}, errorMessage));
|
|
6729
|
+
};
|
|
6730
|
+
const getSelectedItemsComponent = () => {
|
|
6731
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6732
|
+
className: "flex gap-4"
|
|
6733
|
+
}, itemLabels.map((itemLabel, itemLabelIndex) => {
|
|
6734
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6735
|
+
key: itemLabel,
|
|
6736
|
+
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)),
|
|
6737
|
+
onClick: showFullConfig && itemLabelIndex < currentSelectedItemIndex || itemLabelIndex <= currentSelectedItemIndex ? () => {
|
|
6738
|
+
setShowFullConfig(false);
|
|
6739
|
+
setSelectedItems(theList => theList.slice(0, itemLabelIndex));
|
|
6740
|
+
} : undefined
|
|
6741
|
+
}, /*#__PURE__*/react.createElement("div", {
|
|
6742
|
+
className: "text- flex items-center gap-2"
|
|
6743
|
+
}, itemLabelIndex < selectedItems.length ? /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
6744
|
+
name: "status-tracked"
|
|
6745
|
+
}) : /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
6746
|
+
name: "status-untracked"
|
|
6747
|
+
}), /*#__PURE__*/react.createElement("div", {
|
|
6748
|
+
className: classnames_default()(NO_WRAP_ELLIPSIS_CLASS_NAMES)
|
|
6749
|
+
}, t(itemLabel))), itemLabelIndex < selectedItems.length ? /*#__PURE__*/react.createElement("div", {
|
|
6750
|
+
className: classnames_default()('text-[14px] text-white', NO_WRAP_ELLIPSIS_CLASS_NAMES)
|
|
6751
|
+
}, selectedItems[itemLabelIndex].name) : /*#__PURE__*/react.createElement("br", null));
|
|
6752
|
+
}));
|
|
6753
|
+
};
|
|
6754
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6755
|
+
className: "flex h-[calc(100vh-300px)] select-none flex-col gap-4 pt-0.5"
|
|
6756
|
+
}, getSelectedItemsComponent(), /*#__PURE__*/react.createElement("div", {
|
|
6757
|
+
className: "h-0.5 w-full shrink-0 bg-black"
|
|
6758
|
+
}), errorMessage ? getErrorComponent() : /*#__PURE__*/react.createElement(Components_ItemListComponent, {
|
|
6759
|
+
itemLabel: itemLabels[currentSelectedItemIndex + 1],
|
|
6760
|
+
itemList: itemList,
|
|
6761
|
+
onItemClicked: item => {
|
|
6762
|
+
setShowFullConfig(false);
|
|
6763
|
+
setSelectedItems(theList => [...theList.slice(0, currentSelectedItemIndex + 1), item]);
|
|
6764
|
+
}
|
|
6765
|
+
}));
|
|
6766
|
+
}
|
|
6767
|
+
/* harmony default export */ const Components_DataSourceConfigurationModalComponent = (DataSourceConfigurationModalComponent);
|
|
6768
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/Components/DataSourceConfigurationComponent.tsx
|
|
6769
|
+
|
|
6770
|
+
|
|
6771
|
+
|
|
6772
|
+
|
|
6773
|
+
function DataSourceConfigurationComponent(_ref) {
|
|
6774
|
+
let {
|
|
6775
|
+
servicesManager,
|
|
6776
|
+
extensionManager
|
|
6777
|
+
} = _ref;
|
|
6778
|
+
const {
|
|
6779
|
+
t
|
|
6780
|
+
} = (0,es/* useTranslation */.$G)('DataSourceConfiguration');
|
|
6781
|
+
const {
|
|
6782
|
+
show,
|
|
6783
|
+
hide
|
|
6784
|
+
} = (0,ui_src/* useModal */.dd)();
|
|
6785
|
+
const {
|
|
6786
|
+
customizationService
|
|
6787
|
+
} = servicesManager.services;
|
|
6788
|
+
const [configurationAPI, setConfigurationAPI] = (0,react.useState)();
|
|
6789
|
+
const [configuredItems, setConfiguredItems] = (0,react.useState)();
|
|
6790
|
+
(0,react.useEffect)(() => {
|
|
6791
|
+
let shouldUpdate = true;
|
|
6792
|
+
const dataSourceChangedCallback = async () => {
|
|
6793
|
+
const activeDataSourceDef = extensionManager.getActiveDataSourceDefinition();
|
|
6794
|
+
if (!activeDataSourceDef.configuration.configurationAPI) {
|
|
6795
|
+
return;
|
|
6796
|
+
}
|
|
6797
|
+
const {
|
|
6798
|
+
factory: configurationAPIFactory
|
|
6799
|
+
} = customizationService.get(activeDataSourceDef.configuration.configurationAPI) ?? {};
|
|
6800
|
+
if (!configurationAPIFactory) {
|
|
6801
|
+
return;
|
|
6802
|
+
}
|
|
6803
|
+
const configAPI = configurationAPIFactory(activeDataSourceDef.sourceName);
|
|
6804
|
+
setConfigurationAPI(configAPI);
|
|
6805
|
+
|
|
6806
|
+
// New configuration API means that the existing configured items must be cleared.
|
|
6807
|
+
setConfiguredItems(null);
|
|
6808
|
+
configAPI.getConfiguredItems().then(list => {
|
|
6809
|
+
if (shouldUpdate) {
|
|
6810
|
+
setConfiguredItems(list);
|
|
6811
|
+
}
|
|
6812
|
+
});
|
|
6813
|
+
};
|
|
6814
|
+
const sub = extensionManager.subscribe(extensionManager.EVENTS.ACTIVE_DATA_SOURCE_CHANGED, dataSourceChangedCallback);
|
|
6815
|
+
dataSourceChangedCallback();
|
|
6816
|
+
return () => {
|
|
6817
|
+
shouldUpdate = false;
|
|
6818
|
+
sub.unsubscribe();
|
|
6819
|
+
};
|
|
6820
|
+
}, []);
|
|
6821
|
+
const showConfigurationModal = (0,react.useCallback)(() => {
|
|
6822
|
+
show({
|
|
6823
|
+
content: Components_DataSourceConfigurationModalComponent,
|
|
6824
|
+
title: t('Configure Data Source'),
|
|
6825
|
+
contentProps: {
|
|
6826
|
+
configurationAPI,
|
|
6827
|
+
configuredItems,
|
|
6828
|
+
onHide: hide
|
|
6829
|
+
}
|
|
6830
|
+
});
|
|
6831
|
+
}, [configurationAPI, configuredItems]);
|
|
6832
|
+
(0,react.useEffect)(() => {
|
|
6833
|
+
if (!configurationAPI || !configuredItems) {
|
|
6834
|
+
return;
|
|
6835
|
+
}
|
|
6836
|
+
if (configuredItems.length !== configurationAPI.getItemLabels().length) {
|
|
6837
|
+
// Not the correct number of configured items, so show the modal to configure the data source.
|
|
6838
|
+
showConfigurationModal();
|
|
6839
|
+
}
|
|
6840
|
+
}, [configurationAPI, configuredItems, showConfigurationModal]);
|
|
6841
|
+
return configuredItems ? /*#__PURE__*/react.createElement("div", {
|
|
6842
|
+
className: "text-aqua-pale flex items-center overflow-hidden"
|
|
6843
|
+
}, /*#__PURE__*/react.createElement(ui_src/* Icon */.JO, {
|
|
6844
|
+
name: "settings",
|
|
6845
|
+
className: "mr-2.5 h-3.5 w-3.5 shrink-0 cursor-pointer",
|
|
6846
|
+
onClick: showConfigurationModal
|
|
6847
|
+
}), configuredItems.map((item, itemIndex) => {
|
|
6848
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
6849
|
+
key: itemIndex,
|
|
6850
|
+
className: "flex overflow-hidden"
|
|
6851
|
+
}, /*#__PURE__*/react.createElement("div", {
|
|
6852
|
+
key: itemIndex,
|
|
6853
|
+
className: "overflow-hidden text-ellipsis whitespace-nowrap"
|
|
6854
|
+
}, item.name), itemIndex !== configuredItems.length - 1 && /*#__PURE__*/react.createElement("div", {
|
|
6855
|
+
className: "px-2.5"
|
|
6856
|
+
}, "|"));
|
|
6857
|
+
})) : /*#__PURE__*/react.createElement(react.Fragment, null);
|
|
6858
|
+
}
|
|
6859
|
+
/* harmony default export */ const Components_DataSourceConfigurationComponent = (DataSourceConfigurationComponent);
|
|
6860
|
+
;// CONCATENATED MODULE: ../../../extensions/default/src/DataSourceConfigurationAPI/GoogleCloudDataSourceConfigurationAPI.ts
|
|
6861
|
+
/**
|
|
6862
|
+
* This file contains the implementations of BaseDataSourceConfigurationAPIItem
|
|
6863
|
+
* and BaseDataSourceConfigurationAPI for the Google cloud healthcare API. To
|
|
6864
|
+
* better understand this implementation and/or to implement custom implementations,
|
|
6865
|
+
* see the platform\core\src\types\DataSourceConfigurationAPI.ts and its JS doc
|
|
6866
|
+
* comments as a guide.
|
|
6867
|
+
*/
|
|
6868
|
+
/**
|
|
6869
|
+
* The various Google Cloud Healthcare path item types.
|
|
6870
|
+
*/
|
|
6871
|
+
var ItemType = /*#__PURE__*/function (ItemType) {
|
|
6872
|
+
ItemType[ItemType["projects"] = 0] = "projects";
|
|
6873
|
+
ItemType[ItemType["locations"] = 1] = "locations";
|
|
6874
|
+
ItemType[ItemType["datasets"] = 2] = "datasets";
|
|
6875
|
+
ItemType[ItemType["dicomStores"] = 3] = "dicomStores";
|
|
6876
|
+
return ItemType;
|
|
6877
|
+
}(ItemType || {});
|
|
6878
|
+
const initialUrl = 'https://cloudresourcemanager.googleapis.com/v1';
|
|
6879
|
+
const baseHealthcareUrl = 'https://healthcare.googleapis.com/v1';
|
|
6880
|
+
class GoogleCloudDataSourceConfigurationAPIItem {
|
|
6881
|
+
constructor() {
|
|
6882
|
+
this.id = void 0;
|
|
6883
|
+
this.name = void 0;
|
|
6884
|
+
this.url = void 0;
|
|
6885
|
+
this.itemType = void 0;
|
|
6886
|
+
}
|
|
6887
|
+
}
|
|
6888
|
+
class GoogleCloudDataSourceConfigurationAPI {
|
|
6889
|
+
constructor(dataSourceName, servicesManager, extensionManager) {
|
|
6890
|
+
this._extensionManager = void 0;
|
|
6891
|
+
this._fetchOptions = void 0;
|
|
6892
|
+
this._dataSourceName = void 0;
|
|
6893
|
+
this.getItemLabels = () => ['Project', 'Location', 'Data set', 'DICOM store'];
|
|
6894
|
+
this._dataSourceName = dataSourceName;
|
|
6895
|
+
this._extensionManager = extensionManager;
|
|
6896
|
+
const userAuthenticationService = servicesManager.services.userAuthenticationService;
|
|
6897
|
+
this._fetchOptions = {
|
|
6898
|
+
method: 'GET',
|
|
6899
|
+
headers: userAuthenticationService.getAuthorizationHeader()
|
|
6900
|
+
};
|
|
6901
|
+
}
|
|
6902
|
+
async initialize() {
|
|
6903
|
+
const url = `${initialUrl}/projects`;
|
|
6904
|
+
const projects = await GoogleCloudDataSourceConfigurationAPI._doFetch(url, ItemType.projects, this._fetchOptions);
|
|
6905
|
+
if (!projects?.length) {
|
|
6906
|
+
return [];
|
|
6907
|
+
}
|
|
6908
|
+
const projectItems = projects.map(project => {
|
|
6909
|
+
return {
|
|
6910
|
+
id: project.projectId,
|
|
6911
|
+
name: project.name,
|
|
6912
|
+
itemType: ItemType.projects,
|
|
6913
|
+
url: `${baseHealthcareUrl}/projects/${project.projectId}`
|
|
6914
|
+
};
|
|
6915
|
+
});
|
|
6916
|
+
return projectItems;
|
|
6917
|
+
}
|
|
6918
|
+
async setCurrentItem(anItem) {
|
|
6919
|
+
const googleCloudItem = anItem;
|
|
6920
|
+
if (googleCloudItem.itemType === ItemType.dicomStores) {
|
|
6921
|
+
// Last configurable item, so update the data source configuration.
|
|
6922
|
+
const url = `${googleCloudItem.url}/dicomWeb`;
|
|
6923
|
+
const dataSourceDefCopy = JSON.parse(JSON.stringify(this._extensionManager.getDataSourceDefinition(this._dataSourceName)));
|
|
6924
|
+
dataSourceDefCopy.configuration = {
|
|
6925
|
+
...dataSourceDefCopy.configuration,
|
|
6926
|
+
wadoUriRoot: url,
|
|
6927
|
+
qidoRoot: url,
|
|
6928
|
+
wadoRoot: url
|
|
6929
|
+
};
|
|
6930
|
+
this._extensionManager.updateDataSourceConfiguration(dataSourceDefCopy.sourceName, dataSourceDefCopy.configuration);
|
|
6931
|
+
return [];
|
|
6932
|
+
}
|
|
6933
|
+
const subItemType = googleCloudItem.itemType + 1;
|
|
6934
|
+
const subItemField = `${ItemType[subItemType]}`;
|
|
6935
|
+
const url = `${googleCloudItem.url}/${subItemField}`;
|
|
6936
|
+
const fetchedSubItems = await GoogleCloudDataSourceConfigurationAPI._doFetch(url, subItemType, this._fetchOptions);
|
|
6937
|
+
if (!fetchedSubItems?.length) {
|
|
6938
|
+
return [];
|
|
6939
|
+
}
|
|
6940
|
+
const subItems = fetchedSubItems.map(subItem => {
|
|
6941
|
+
const nameSplit = subItem.name.split('/');
|
|
6942
|
+
return {
|
|
6943
|
+
id: subItem.name,
|
|
6944
|
+
name: nameSplit[nameSplit.length - 1],
|
|
6945
|
+
itemType: subItemType,
|
|
6946
|
+
url: `${baseHealthcareUrl}/${subItem.name}`
|
|
6947
|
+
};
|
|
6948
|
+
});
|
|
6949
|
+
return subItems;
|
|
6950
|
+
}
|
|
6951
|
+
async getConfiguredItems() {
|
|
6952
|
+
const dataSourceDefinition = this._extensionManager.getDataSourceDefinition(this._dataSourceName);
|
|
6953
|
+
const url = dataSourceDefinition.configuration.wadoUriRoot;
|
|
6954
|
+
const projectsIndex = url.indexOf('projects');
|
|
6955
|
+
// Split the configured URL into (essentially) pairs (i.e. item type followed by item)
|
|
6956
|
+
// Explicitly: ['projects','aProject','locations','aLocation','datasets','aDataSet','dicomStores','aDicomStore']
|
|
6957
|
+
// Note that a partial configuration will have a subset of the above.
|
|
6958
|
+
const urlSplit = url.substring(projectsIndex).split('/');
|
|
6959
|
+
const configuredItems = [];
|
|
6960
|
+
for (let itemType = 0;
|
|
6961
|
+
// the number of configured items is either the max (4) or the number extracted from the url split
|
|
6962
|
+
itemType < 4 && (itemType + 1) * 2 < urlSplit.length; itemType += 1) {
|
|
6963
|
+
if (itemType === ItemType.projects) {
|
|
6964
|
+
const projectId = urlSplit[1];
|
|
6965
|
+
const projectUrl = `${initialUrl}/projects/${projectId}`;
|
|
6966
|
+
const data = await GoogleCloudDataSourceConfigurationAPI._doFetch(projectUrl, ItemType.projects, this._fetchOptions);
|
|
6967
|
+
const project = data[0];
|
|
6968
|
+
configuredItems.push({
|
|
6969
|
+
id: project.projectId,
|
|
6970
|
+
name: project.name,
|
|
6971
|
+
itemType: itemType,
|
|
6972
|
+
url: `${baseHealthcareUrl}/projects/${project.projectId}`
|
|
6973
|
+
});
|
|
6974
|
+
} else {
|
|
6975
|
+
const relativePath = urlSplit.slice(0, itemType * 2 + 2).join('/');
|
|
6976
|
+
configuredItems.push({
|
|
6977
|
+
id: relativePath,
|
|
6978
|
+
name: urlSplit[itemType * 2 + 1],
|
|
6979
|
+
itemType: itemType,
|
|
6980
|
+
url: `${baseHealthcareUrl}/${relativePath}`
|
|
6981
|
+
});
|
|
6982
|
+
}
|
|
6983
|
+
}
|
|
6984
|
+
return configuredItems;
|
|
6985
|
+
}
|
|
6986
|
+
|
|
6987
|
+
/**
|
|
6988
|
+
* Fetches an array of items the specified item type.
|
|
6989
|
+
* @param urlStr the fetch url
|
|
6990
|
+
* @param fetchItemType the type to fetch
|
|
6991
|
+
* @param fetchOptions the header options for the fetch (e.g. authorization header)
|
|
6992
|
+
* @param fetchSearchParams any search query params; currently only used for paging results
|
|
6993
|
+
* @returns an array of items of the specified type
|
|
6994
|
+
*/
|
|
6995
|
+
static async _doFetch(urlStr, fetchItemType) {
|
|
6996
|
+
let fetchOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
6997
|
+
let fetchSearchParams = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
6998
|
+
try {
|
|
6999
|
+
const url = new URL(urlStr);
|
|
7000
|
+
url.search = new URLSearchParams(fetchSearchParams).toString();
|
|
7001
|
+
const response = await fetch(url, fetchOptions);
|
|
7002
|
+
const data = await response.json();
|
|
7003
|
+
if (response.status >= 200 && response.status < 300 && data != null) {
|
|
7004
|
+
if (data.nextPageToken != null) {
|
|
7005
|
+
fetchSearchParams.pageToken = data.nextPageToken;
|
|
7006
|
+
const subPageData = await this._doFetch(urlStr, fetchItemType, fetchOptions, fetchSearchParams);
|
|
7007
|
+
data[ItemType[fetchItemType]] = data[ItemType[fetchItemType]].concat(subPageData);
|
|
7008
|
+
}
|
|
7009
|
+
if (data[ItemType[fetchItemType]]) {
|
|
7010
|
+
return data[ItemType[fetchItemType]];
|
|
7011
|
+
} else if (data.name) {
|
|
7012
|
+
return [data];
|
|
7013
|
+
} else {
|
|
7014
|
+
return [];
|
|
7015
|
+
}
|
|
7016
|
+
} else {
|
|
7017
|
+
const message = data?.error?.message || `Error returned from Google Cloud Healthcare: ${response.status} - ${response.statusText}`;
|
|
7018
|
+
throw new Error(message);
|
|
7019
|
+
}
|
|
7020
|
+
} catch (err) {
|
|
7021
|
+
const message = err?.message || 'Error occurred during fetch request.';
|
|
7022
|
+
throw new Error(message);
|
|
7023
|
+
}
|
|
7024
|
+
}
|
|
7025
|
+
}
|
|
7026
|
+
|
|
5759
7027
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getCustomizationModule.tsx
|
|
5760
7028
|
|
|
5761
7029
|
|
|
5762
7030
|
|
|
7031
|
+
|
|
7032
|
+
|
|
5763
7033
|
/**
|
|
5764
7034
|
*
|
|
5765
7035
|
* Note: this is an example of how the customization module can be used
|
|
@@ -5769,7 +7039,11 @@ function DataSourceSelector() {
|
|
|
5769
7039
|
* custom page for the user to view their profile, or to add a custom
|
|
5770
7040
|
* page for login etc.
|
|
5771
7041
|
*/
|
|
5772
|
-
function getCustomizationModule() {
|
|
7042
|
+
function getCustomizationModule(_ref) {
|
|
7043
|
+
let {
|
|
7044
|
+
servicesManager,
|
|
7045
|
+
extensionManager
|
|
7046
|
+
} = _ref;
|
|
5773
7047
|
return [{
|
|
5774
7048
|
name: 'helloPage',
|
|
5775
7049
|
value: {
|
|
@@ -5836,12 +7110,16 @@ function getCustomizationModule() {
|
|
|
5836
7110
|
{
|
|
5837
7111
|
id: 'ohif.overlayItem',
|
|
5838
7112
|
content: function (props) {
|
|
5839
|
-
if (this.condition && !this.condition(props))
|
|
7113
|
+
if (this.condition && !this.condition(props)) {
|
|
7114
|
+
return null;
|
|
7115
|
+
}
|
|
5840
7116
|
const {
|
|
5841
7117
|
instance
|
|
5842
7118
|
} = props;
|
|
5843
7119
|
const value = instance && this.attribute ? instance[this.attribute] : this.contentF && typeof this.contentF === 'function' ? this.contentF(props) : null;
|
|
5844
|
-
if (!value)
|
|
7120
|
+
if (!value) {
|
|
7121
|
+
return null;
|
|
7122
|
+
}
|
|
5845
7123
|
return /*#__PURE__*/react.createElement("span", {
|
|
5846
7124
|
className: "overlay-item flex flex-row",
|
|
5847
7125
|
style: {
|
|
@@ -5879,11 +7157,22 @@ function getCustomizationModule() {
|
|
|
5879
7157
|
}
|
|
5880
7158
|
return clonedObject;
|
|
5881
7159
|
}
|
|
7160
|
+
}, {
|
|
7161
|
+
// the generic GUI component to configure a data source using an instance of a BaseDataSourceConfigurationAPI
|
|
7162
|
+
id: 'ohif.dataSourceConfigurationComponent',
|
|
7163
|
+
component: Components_DataSourceConfigurationComponent.bind(null, {
|
|
7164
|
+
servicesManager,
|
|
7165
|
+
extensionManager
|
|
7166
|
+
})
|
|
7167
|
+
}, {
|
|
7168
|
+
// The factory for creating an instance of a BaseDataSourceConfigurationAPI for Google Cloud Healthcare
|
|
7169
|
+
id: 'ohif.dataSourceConfigurationAPI.google',
|
|
7170
|
+
factory: dataSourceName => new GoogleCloudDataSourceConfigurationAPI(dataSourceName, servicesManager, extensionManager)
|
|
5882
7171
|
}]
|
|
5883
7172
|
}];
|
|
5884
7173
|
}
|
|
5885
7174
|
// EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/calculate-suv/dist/calculate-suv.esm.js
|
|
5886
|
-
var calculate_suv_esm = __webpack_require__(
|
|
7175
|
+
var calculate_suv_esm = __webpack_require__(15747);
|
|
5887
7176
|
;// CONCATENATED MODULE: ../../../extensions/default/src/getPTImageIdInstanceMetadata.ts
|
|
5888
7177
|
|
|
5889
7178
|
const getPTImageIdInstanceMetadata_metadataProvider = src["default"].classes.MetadataProvider;
|
|
@@ -5892,9 +7181,12 @@ function getPTImageIdInstanceMetadata(imageId) {
|
|
|
5892
7181
|
if (!dicomMetaData) {
|
|
5893
7182
|
throw new Error('dicom metadata are required');
|
|
5894
7183
|
}
|
|
5895
|
-
if (dicomMetaData.SeriesDate === undefined || dicomMetaData.SeriesTime === undefined || dicomMetaData.
|
|
7184
|
+
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) {
|
|
5896
7185
|
throw new Error('required metadata are missing');
|
|
5897
7186
|
}
|
|
7187
|
+
if (dicomMetaData.PatientWeight === undefined) {
|
|
7188
|
+
console.warn('PatientWeight missing from PT instance metadata');
|
|
7189
|
+
}
|
|
5898
7190
|
const instanceMetadata = {
|
|
5899
7191
|
CorrectedImage: dicomMetaData.CorrectedImage,
|
|
5900
7192
|
Units: dicomMetaData.Units,
|
|
@@ -6065,6 +7357,8 @@ const handlePETImageMetadata = _ref2 => {
|
|
|
6065
7357
|
|
|
6066
7358
|
|
|
6067
7359
|
|
|
7360
|
+
|
|
7361
|
+
|
|
6068
7362
|
const defaultExtension = {
|
|
6069
7363
|
/**
|
|
6070
7364
|
* Only required property. Should be a unique value across all extensions.
|