@ohif/app 3.13.0-beta.7 → 3.13.0-beta.70

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.
Files changed (72) hide show
  1. package/dist/{1459.bundle.0b4384c95c63e0d5245b.js → 1459.bundle.8df5bb7808389c8dcaa0.js} +5 -6
  2. package/dist/{1608.bundle.0687c661f1c9edfb3b8a.js → 1608.bundle.26306ea38618db59eff7.js} +12 -12
  3. package/dist/{1927.bundle.3050588e95f43cf57cdd.js → 1927.bundle.be67b3aafe238ca9f191.js} +27 -38
  4. package/dist/{1933.bundle.052fd9ab23c1236f788d.js → 1933.bundle.87b41a716353fed2610d.js} +32 -27
  5. package/dist/{2018.bundle.8d5580bd4dcea3ebaa23.js → 2018.bundle.e7a25ccc24941c9039e8.js} +18 -19
  6. package/dist/{6409.bundle.b36048896cb11c8571fb.js → 2075.bundle.23265b8e7597c398db4f.js} +327 -256
  7. package/dist/{2108.bundle.e84aa8d858d8c4f2413e.js → 2108.bundle.aea8d3b39486dd5ab39e.js} +569 -558
  8. package/dist/{213.bundle.9974b55ea267a38098f2.js → 213.bundle.ddafd3a6cc133357f03e.js} +3 -5
  9. package/dist/{2424.bundle.f62de9c66b85446b577b.js → 2424.bundle.daf0c3e78529e8aee79e.js} +3 -5
  10. package/dist/{2516.bundle.1ea0988d309a757bb6da.js → 2516.bundle.f62228e9a800de8d4b31.js} +6 -6
  11. package/dist/{2701.bundle.12bd01a80a9f8ea4cd94.js → 2701.bundle.6873805ddfdccc7a8b1e.js} +10 -10
  12. package/dist/{9195.bundle.ebe8a2e0ed02f4b5ffb6.js → 2851.bundle.51e26e3a79a24f508a03.js} +482 -177
  13. package/dist/{1730.bundle.82fdc899ec54ab6c18a0.js → 3138.bundle.1359814ebef04d7b2f2b.js} +16 -310
  14. package/dist/{3461.bundle.acbbc488820719343d48.js → 3461.bundle.522c6009f47a1a01ce47.js} +131 -107
  15. package/dist/{147.bundle.37d627289453cb6c3937.js → 3754.bundle.fd4b67c2a29c4bc4a840.js} +486 -49
  16. package/dist/{4202.bundle.5a0f8e4004c5d8a68548.js → 4202.bundle.4fcd0de412907efd5b53.js} +6 -6
  17. package/dist/{4019.bundle.83a604779f7da0101ced.js → 4287.bundle.b7840e7b94cbbc102236.js} +348 -237
  18. package/dist/{5462.bundle.21beddaca145b7465c72.js → 4406.bundle.573d234b4641d23cf8db.js} +1083 -1308
  19. package/dist/{1403.bundle.2fc4502e0990b048a4bb.js → 4507.bundle.929c147b8f17517e7769.js} +10 -305
  20. package/dist/{6347.bundle.784c48912700f281de1d.js → 4579.bundle.0a6b2f49a7e136a79e37.js} +561 -649
  21. package/dist/{4819.bundle.9fc6f913afc5f53fe33d.js → 4819.bundle.38df45ea36b450c9c236.js} +39 -39
  22. package/dist/{4775.bundle.7c0cead4a44ddc0b06d7.js → 5015.bundle.e907b7e60824e9b21863.js} +29 -333
  23. package/dist/{5028.bundle.6e48cc78ac80a3860418.js → 5028.bundle.807858e82e7c652139d9.js} +11 -13
  24. package/dist/{5261.bundle.6e1a017f8f1027557f5b.js → 5261.bundle.2655560097e9250eac44.js} +412 -345
  25. package/dist/{5457.bundle.716478f2792f83daa2bc.js → 5457.bundle.361d8d5426840a12b668.js} +16 -23
  26. package/dist/{5485.bundle.782d3f49f1020dc1f730.js → 5485.bundle.82495f29805a950f9172.js} +30 -36
  27. package/dist/{5491.bundle.2e01dd7ad29e4cc01bc1.js → 5491.bundle.4866d2ecb20dd089e071.js} +54 -51
  28. package/dist/{5802.bundle.3bf5e6b3ab330a594a47.js → 5802.bundle.26f84db0ff8851532c36.js} +79 -20
  29. package/dist/5802.css +1 -1
  30. package/dist/{5830.bundle.b073c265c4fcea1afff3.js → 5830.bundle.791019deddd536980a11.js} +3 -3
  31. package/dist/{5858.bundle.ff6b340cf7457db76a1a.js → 5858.bundle.466e58128de344ab53f3.js} +90 -86
  32. package/dist/{6027.bundle.5f39b6eb697906760a97.js → 6027.bundle.2f64fca578d9f2636144.js} +3 -5
  33. package/dist/{6354.bundle.c387737dc09c9cab4ff2.js → 6354.bundle.929febcf6d326e582e00.js} +151 -140
  34. package/dist/{6376.bundle.9cb74d7bc08476e2f1a7.js → 6376.bundle.527820a5cb1eece2a8d2.js} +6 -6
  35. package/dist/{2842.bundle.860b9f10fcdd9656947a.js → 6386.bundle.5d82d1f41d1c37a0358d.js} +904 -2298
  36. package/dist/6939.bundle.41fbdef87597b5172ec6.js +3 -3
  37. package/dist/{7159.bundle.a5991a5d4f0dd8f1c95f.js → 7159.bundle.fb9df255868960f69765.js} +7 -5
  38. package/dist/{3081.bundle.a91d88fbfb53b4f77ee4.js → 7166.bundle.5ac3827d0b367fe6bd6e.js} +1232 -470
  39. package/dist/{7190.bundle.e8f0193e0e06472f795c.js → 7190.bundle.479332d662ffe08d1f92.js} +1228 -855
  40. package/dist/{732.bundle.6978ac30a1e36abf06db.js → 732.bundle.ea6f9d8504e37e01a208.js} +5 -13
  41. package/dist/{7431.bundle.b01791d10e6cf9f503b0.js → 7431.bundle.5e14641f2c71e852abe7.js} +28 -28
  42. package/dist/{4410.bundle.c5224cd7d6238a7d4660.js → 7537.bundle.889ba5f2707418c6fd88.js} +5216 -2238
  43. package/dist/{7639.bundle.a6b187c87374ce1508bb.js → 7639.bundle.7e3a1383fb92172e8079.js} +3 -5
  44. package/dist/7758.bundle.c8d106364298e7d288f0.js +3 -3
  45. package/dist/{8094.bundle.5c44190a325ac23e3e5c.js → 8094.bundle.148a66619607e37cbf19.js} +3 -4
  46. package/dist/{8305.bundle.4e40a6d83d548535b0a4.js → 8305.bundle.1790ebf371ba9caf3a24.js} +71 -66
  47. package/dist/{6163.bundle.ad576a38d517b0031edb.js → 8499.bundle.2386efbfe1210c92d384.js} +7 -302
  48. package/dist/8499.css +2 -0
  49. package/dist/{85.bundle.29e6f5b4d8068a50e5ca.js → 85.bundle.3ebecb20682a1798dc77.js} +3 -5
  50. package/dist/{8558.bundle.0e8b808e19293cdd69a4.js → 8558.bundle.0cf331cc257bb5a04f21.js} +15 -309
  51. package/dist/{8583.bundle.9b62be9d8431e17782c8.js → 8583.bundle.1cb20f6f1e7ec1ca549c.js} +24 -27
  52. package/dist/{997.bundle.822b33e561263084e18c.js → 9039.bundle.f72736f47fedeff521e2.js} +4049 -2992
  53. package/dist/{7412.bundle.fab1742191b7fe937330.js → 9205.bundle.ed7bce8436a7a431955e.js} +6154 -3313
  54. package/dist/{3584.bundle.8cc0750425513433e9cc.js → 9567.bundle.ff782480a4c66e306027.js} +3751 -2856
  55. package/dist/{9845.bundle.255e7c7f7a88193b4e47.js → 9845.bundle.8c450e8d65a78a5afcd3.js} +10 -10
  56. package/dist/{9862.bundle.3a8958a82c572015d25d.js → 9862.bundle.a5f7925840868fa4ecdb.js} +8 -6
  57. package/dist/{9927.bundle.e0f2262ef305795ce7b1.js → 9927.bundle.e21480928d7062501426.js} +8 -6
  58. package/dist/app-config.js +12 -0
  59. package/dist/{app.bundle.4d14ef92d206bcd77aa6.js → app.bundle.3c03c873a65adf3826e0.js} +67399 -64373
  60. package/dist/app.bundle.css +3 -3
  61. package/dist/{polySeg.bundle.a5aa9130b4191253c410.js → compute.bundle.b7c2ea55f1a69f4a736b.js} +8 -20
  62. package/dist/{histogram-worker.bundle.d4e40a8018d2698b072e.js → histogram-worker.bundle.a2a50c4674d99c619ca7.js} +11 -23
  63. package/dist/index.html +1 -1
  64. package/dist/{interpolation.bundle.c70cb95d164dc494e6dc.js → interpolation.bundle.829844ff3f72f5645f29.js} +14 -26
  65. package/dist/{compute.bundle.64280c7af19ff567465f.js → polySeg.bundle.e1f6f05d81ea1352bef3.js} +10 -22
  66. package/dist/sw.js +1 -1
  67. package/package.json +23 -22
  68. package/dist/3343.bundle.d7578ce8f75d158c0bab.js +0 -297
  69. /package/dist/{1730.css → 3138.css} +0 -0
  70. /package/dist/{147.css → 3754.css} +0 -0
  71. /package/dist/{3343.css → 4972.css} +0 -0
  72. /package/dist/{6163.css → 7829.css} +0 -0
@@ -1,14 +1,14 @@
1
1
  "use strict";
2
- (globalThis["webpackChunk"] = globalThis["webpackChunk"] || []).push([[9195],{
2
+ (globalThis["webpackChunk"] = globalThis["webpackChunk"] || []).push([[2851],{
3
3
 
4
- /***/ 52675:
5
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
4
+ /***/ 52675
5
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
6
6
 
7
7
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
8
8
  /* harmony export */ A: () => (/* binding */ MoreDropdownMenu)
9
9
  /* harmony export */ });
10
10
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(86326);
11
- /* harmony import */ var _ohif_ui_next__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(12517);
11
+ /* harmony import */ var _ohif_ui_next__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(564);
12
12
  /* harmony import */ var _ohif_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(42356);
13
13
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
14
14
 
@@ -110,10 +110,10 @@ function MoreDropdownMenu(bindProps) {
110
110
  return BoundMoreDropdownMenu;
111
111
  }
112
112
 
113
- /***/ }),
113
+ /***/ },
114
114
 
115
- /***/ 40565:
116
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
115
+ /***/ 40565
116
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
117
117
 
118
118
 
119
119
  // EXPORTS
@@ -123,8 +123,8 @@ __webpack_require__.d(__webpack_exports__, {
123
123
 
124
124
  // EXTERNAL MODULE: ../../../node_modules/react/index.js
125
125
  var react = __webpack_require__(86326);
126
- // EXTERNAL MODULE: ../../ui-next/src/index.ts + 3075 modules
127
- var src = __webpack_require__(12517);
126
+ // EXTERNAL MODULE: ../../ui-next/src/index.ts + 3085 modules
127
+ var src = __webpack_require__(564);
128
128
  // EXTERNAL MODULE: ../../core/src/index.ts + 69 modules
129
129
  var core_src = __webpack_require__(42356);
130
130
  // EXTERNAL MODULE: ../../../node_modules/react-router-dom/dist/index.js
@@ -239,7 +239,7 @@ function PanelStudyBrowser({
239
239
  commandsManager,
240
240
  servicesManager,
241
241
  isHangingProtocolLayout,
242
- appConfig: extensionManager._appConfig
242
+ appConfig: extensionManager.appConfig
243
243
  };
244
244
  const handlers = customHandler?.callbacks.map(callback => callback(setupArgs));
245
245
  for (const handler of handlers) {
@@ -491,7 +491,7 @@ function PanelStudyBrowser({
491
491
  updateActionIconValue: updateActionIconValue
492
492
  }), /*#__PURE__*/react.createElement(src/* Separator */.wvv, {
493
493
  orientation: "horizontal",
494
- className: "bg-black",
494
+ className: "bg-background",
495
495
  thickness: "2px"
496
496
  })), /*#__PURE__*/react.createElement(src/* StudyBrowser */.M4o, {
497
497
  tabs: tabs,
@@ -609,16 +609,16 @@ function _findTabAndStudyOfDisplaySet(displaySetInstanceUID, tabs, currentTabNam
609
609
  }
610
610
  }
611
611
 
612
- /***/ }),
612
+ /***/ },
613
613
 
614
- /***/ 3329:
615
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
614
+ /***/ 3329
615
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
616
616
 
617
617
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
618
618
  /* harmony export */ T: () => (/* binding */ PanelStudyBrowserHeader)
619
619
  /* harmony export */ });
620
620
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(86326);
621
- /* harmony import */ var _ohif_ui_next__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(12517);
621
+ /* harmony import */ var _ohif_ui_next__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(564);
622
622
 
623
623
 
624
624
 
@@ -656,15 +656,15 @@ function PanelStudyBrowserHeader({
656
656
  key: index,
657
657
  "aria-label": viewPreset.id,
658
658
  value: viewPreset.id,
659
- className: "text-actions-primary"
659
+ className: "text-primary"
660
660
  }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement(_ohif_ui_next__WEBPACK_IMPORTED_MODULE_1__/* .Icons */ .FI1[viewPreset.iconName] || _ohif_ui_next__WEBPACK_IMPORTED_MODULE_1__/* .Icons */ .FI1.MissingIcon)))))))));
661
661
  }
662
662
 
663
663
 
664
- /***/ }),
664
+ /***/ },
665
665
 
666
- /***/ 20528:
667
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
666
+ /***/ 20528
667
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
668
668
 
669
669
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
670
670
  /* harmony export */ M: () => (/* binding */ Toolbar)
@@ -743,66 +743,41 @@ function Toolbar({
743
743
  }));
744
744
  }
745
745
 
746
- /***/ }),
746
+ /***/ },
747
747
 
748
- /***/ 39195:
749
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
748
+ /***/ 62851
749
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
750
750
 
751
- // ESM COMPAT FLAG
752
- __webpack_require__.r(__webpack_exports__);
753
751
 
754
752
  // EXPORTS
755
753
  __webpack_require__.d(__webpack_exports__, {
756
- ContextMenuController: () => (/* reexport */ ContextMenuController),
757
- CustomizableContextMenuTypes: () => (/* reexport */ types_namespaceObject),
758
- MoreDropdownMenu: () => (/* reexport */ MoreDropdownMenu/* default */.A),
759
- PanelStudyBrowserHeader: () => (/* reexport */ PanelStudyBrowserHeader/* PanelStudyBrowserHeader */.T),
760
- StaticWadoClient: () => (/* reexport */ StaticWadoClient),
761
- Toolbar: () => (/* reexport */ Toolbar/* Toolbar */.M),
762
- Toolbox: () => (/* reexport */ Toolbox),
763
- callInputDialog: () => (/* reexport */ callInputDialog),
764
- callInputDialogAutoComplete: () => (/* reexport */ callInputDialogAutoComplete),
765
- cleanDenaturalizedDataset: () => (/* reexport */ cleanDenaturalizedDataset),
766
- colorPickerDialog: () => (/* reexport */ colorPickerDialog),
767
- createReportAsync: () => (/* reexport */ Actions_createReportAsync),
768
- createReportDialogPrompt: () => (/* reexport */ CreateReportDialogPrompt),
754
+ tm: () => (/* reexport */ StaticWadoClient),
755
+ M7: () => (/* reexport */ Toolbar/* Toolbar */.M),
756
+ OO: () => (/* reexport */ Toolbox),
757
+ l5: () => (/* reexport */ callInputDialog),
758
+ fq: () => (/* reexport */ callInputDialogAutoComplete),
759
+ wZ: () => (/* reexport */ cleanDenaturalizedDataset),
760
+ wS: () => (/* reexport */ colorPickerDialog),
761
+ Vy: () => (/* reexport */ Actions_createReportAsync),
762
+ tc: () => (/* reexport */ CreateReportDialogPrompt),
769
763
  "default": () => (/* binding */ default_src),
770
- dicomWebUtils: () => (/* reexport */ utils_namespaceObject),
771
- getStudiesForPatientByMRN: () => (/* reexport */ Panels_getStudiesForPatientByMRN),
772
- promptLabelAnnotation: () => (/* reexport */ utils_promptLabelAnnotation),
773
- promptSaveReport: () => (/* reexport */ utils_promptSaveReport),
774
- requestDisplaySetCreationForStudy: () => (/* reexport */ Panels_requestDisplaySetCreationForStudy),
775
- useDisplaySetSelectorStore: () => (/* reexport */ useDisplaySetSelectorStore),
776
- useHangingProtocolStageIndexStore: () => (/* reexport */ useHangingProtocolStageIndexStore),
777
- usePatientInfo: () => (/* reexport */ hooks_usePatientInfo),
778
- useToggleHangingProtocolStore: () => (/* reexport */ useToggleHangingProtocolStore),
779
- useToggleOneUpViewportGridStore: () => (/* reexport */ useToggleOneUpViewportGridStore),
780
- useUIStateStore: () => (/* reexport */ useUIStateStore),
781
- useViewportGridStore: () => (/* reexport */ useViewportGridStore),
782
- useViewportsByPositionStore: () => (/* reexport */ useViewportsByPositionStore),
783
- utils: () => (/* reexport */ src_utils_namespaceObject)
764
+ CA: () => (/* reexport */ utils_namespaceObject),
765
+ uR: () => (/* reexport */ utils_promptLabelAnnotation),
766
+ MP: () => (/* reexport */ utils_promptSaveReport),
767
+ Z: () => (/* reexport */ Panels_requestDisplaySetCreationForStudy),
768
+ Yd: () => (/* reexport */ useToggleOneUpViewportGridStore),
769
+ FS: () => (/* reexport */ useUIStateStore)
784
770
  });
785
771
 
786
- // NAMESPACE OBJECT: ../../../extensions/default/src/CustomizableContextMenu/types.ts
787
- var types_namespaceObject = {};
788
- __webpack_require__.r(types_namespaceObject);
772
+ // UNUSED EXPORTS: ContextMenuController, CustomizableContextMenuTypes, MoreDropdownMenu, PanelStudyBrowserHeader, getStudiesForPatientByMRN, useDisplaySetSelectorStore, useHangingProtocolStageIndexStore, usePatientInfo, useToggleHangingProtocolStore, useViewportGridStore, useViewportsByPositionStore, utils
789
773
 
790
774
  // NAMESPACE OBJECT: ../../../extensions/default/src/DicomWebDataSource/utils/index.ts
791
775
  var utils_namespaceObject = {};
792
776
  __webpack_require__.r(utils_namespaceObject);
793
777
  __webpack_require__.d(utils_namespaceObject, {
794
- cleanDenaturalizedDataset: () => (cleanDenaturalizedDataset),
795
- fixBulkDataURI: () => (fixBulkDataURI),
796
- fixMultiValueKeys: () => (fixMultiValueKeys),
797
- transferDenaturalizedDataset: () => (transferDenaturalizedDataset)
798
- });
799
-
800
- // NAMESPACE OBJECT: ../../../extensions/default/src/utils/index.ts
801
- var src_utils_namespaceObject = {};
802
- __webpack_require__.r(src_utils_namespaceObject);
803
- __webpack_require__.d(src_utils_namespaceObject, {
804
- Toolbox: () => (Toolbox),
805
- addIcon: () => (addIcon)
778
+ wZ: () => (cleanDenaturalizedDataset),
779
+ Uk: () => (fixMultiValueKeys),
780
+ If: () => (transferDenaturalizedDataset)
806
781
  });
807
782
 
808
783
  // EXTERNAL MODULE: ../../../node_modules/dicomweb-client/build/dicomweb-client.es.js
@@ -2735,12 +2710,97 @@ function retrieveBulkData(value, options = {}) {
2735
2710
 
2736
2711
  // EXTERNAL MODULE: ../../../node_modules/query-string/index.js
2737
2712
  var query_string = __webpack_require__(98985);
2713
+ ;// ../../../extensions/default/src/utils/secureConfigFetch.js
2714
+ // @ts-nocheck
2715
+
2716
+ function normalizeAllowedOrigins(allowedOrigins = []) {
2717
+ if (!Array.isArray(allowedOrigins)) {
2718
+ return [];
2719
+ }
2720
+ const configuredOrigins = allowedOrigins.filter(origin => typeof origin === 'string').map(origin => origin.trim()).filter(Boolean);
2721
+ return configuredOrigins.map(origin => {
2722
+ try {
2723
+ const parsedOrigin = new URL(origin);
2724
+ if (!['http:', 'https:'].includes(parsedOrigin.protocol)) {
2725
+ console.error(`[secureConfigFetch] Ignoring misconfigured allowed origin "${origin}". ` + 'Entries must use http:// or https://.');
2726
+ return null;
2727
+ }
2728
+ if (parsedOrigin.username || parsedOrigin.password || parsedOrigin.pathname !== '/' || parsedOrigin.search || parsedOrigin.hash) {
2729
+ console.error(`[secureConfigFetch] Ignoring misconfigured allowed origin "${origin}". ` + 'Entries must be bare origins only (scheme + host + optional port), with no username/password, path, query, or hash.');
2730
+ return null;
2731
+ }
2732
+ return parsedOrigin.origin;
2733
+ } catch {
2734
+ console.error(`[secureConfigFetch] Ignoring misconfigured allowed origin "${origin}". Entry is not a valid URL.`);
2735
+ return null;
2736
+ }
2737
+ }).filter(Boolean);
2738
+ }
2739
+ function resolveConfigUrl(rawUrl) {
2740
+ if (!rawUrl || typeof rawUrl !== 'string') {
2741
+ throw new Error('Missing required "url" query parameter');
2742
+ }
2743
+ try {
2744
+ return new URL(rawUrl, window.location.href);
2745
+ } catch {
2746
+ throw new Error('Invalid URL in "url" query parameter');
2747
+ }
2748
+ }
2749
+ function resolveConfigFetchPolicy(rawUrl, policy = {}) {
2750
+ const {
2751
+ allowedOrigins = [],
2752
+ userAuthenticationService
2753
+ } = policy;
2754
+ const parsedUrl = resolveConfigUrl(rawUrl);
2755
+ const protocol = parsedUrl.protocol.toLowerCase();
2756
+ const isSameOrigin = parsedUrl.origin === window.location.origin;
2757
+ if (!['http:', 'https:'].includes(protocol)) {
2758
+ throw new Error('Only HTTP(S) URLs are allowed for dynamic datasource configuration');
2759
+ }
2760
+ if (parsedUrl.hash) {
2761
+ throw new Error('URL fragments are not allowed for dynamic datasource configuration');
2762
+ }
2763
+ if (parsedUrl.username || parsedUrl.password) {
2764
+ throw new Error('URL userinfo is not allowed for dynamic datasource configuration');
2765
+ }
2766
+ const isAuthenticated = Boolean(userAuthenticationService?.getAuthorizationHeader?.()?.Authorization);
2767
+ if (isAuthenticated && !isSameOrigin) {
2768
+ const normalizedAllowedOrigins = normalizeAllowedOrigins(allowedOrigins);
2769
+ if (!normalizedAllowedOrigins.length || !normalizedAllowedOrigins.includes(parsedUrl.origin)) {
2770
+ throw new Error(`Blocked remote configuration origin "${parsedUrl.origin}" in authenticated environment`);
2771
+ }
2772
+ }
2773
+ return {
2774
+ parsedUrl,
2775
+ normalizedUrl: parsedUrl.toString(),
2776
+ isAuthenticated,
2777
+ isSameOrigin
2778
+ };
2779
+ }
2780
+ async function fetchConfigJson(normalizedPolicy) {
2781
+ const {
2782
+ normalizedUrl
2783
+ } = normalizedPolicy;
2784
+ const response = await fetch(normalizedUrl, {
2785
+ method: 'GET',
2786
+ mode: 'cors',
2787
+ credentials: 'same-origin',
2788
+ redirect: 'error',
2789
+ referrerPolicy: 'no-referrer'
2790
+ });
2791
+ if (!response.ok) {
2792
+ throw new Error(`Failed to fetch dynamic datasource configuration (${response.status})`);
2793
+ }
2794
+ return response.json();
2795
+ }
2796
+
2738
2797
  ;// ../../../extensions/default/src/DicomJSONDataSource/index.js
2739
2798
 
2740
2799
 
2741
2800
 
2742
2801
 
2743
2802
 
2803
+
2744
2804
  const DicomJSONDataSource_metadataProvider = src/* default.classes */.Ay.classes.MetadataProvider;
2745
2805
  const mappings = {
2746
2806
  studyInstanceUid: 'StudyInstanceUID',
@@ -2787,7 +2847,10 @@ const findStudies = (key, value) => {
2787
2847
  });
2788
2848
  return studies;
2789
2849
  };
2790
- function createDicomJSONApi(dicomJsonConfig) {
2850
+ function createDicomJSONApi(dicomJsonConfig, servicesManager) {
2851
+ const {
2852
+ userAuthenticationService
2853
+ } = servicesManager.services;
2791
2854
  const implementation = {
2792
2855
  initialize: async ({
2793
2856
  query,
@@ -2796,7 +2859,11 @@ function createDicomJSONApi(dicomJsonConfig) {
2796
2859
  if (!url) {
2797
2860
  url = query.get('url');
2798
2861
  }
2799
- let metaData = getMetaDataByURL(url);
2862
+ const evaluatedUrl = resolveConfigFetchPolicy(url, {
2863
+ allowedOrigins: dicomJsonConfig.dangerouslyAllowedOriginsForAuthenticatedEnvironments,
2864
+ userAuthenticationService
2865
+ });
2866
+ let metaData = getMetaDataByURL(evaluatedUrl.normalizedUrl);
2800
2867
 
2801
2868
  // if we have already cached the data from this specific url
2802
2869
  // We are only handling one StudyInstanceUID to run; however,
@@ -2806,8 +2873,7 @@ function createDicomJSONApi(dicomJsonConfig) {
2806
2873
  return aStudy.StudyInstanceUID;
2807
2874
  });
2808
2875
  }
2809
- const response = await fetch(url);
2810
- const data = await response.json();
2876
+ const data = await fetchConfigJson(evaluatedUrl);
2811
2877
  let StudyInstanceUID;
2812
2878
  let SeriesInstanceUID;
2813
2879
  data.studies.forEach(study => {
@@ -2837,10 +2903,10 @@ function createDicomJSONApi(dicomJsonConfig) {
2837
2903
  });
2838
2904
  });
2839
2905
  _store.urls.push({
2840
- url,
2906
+ url: evaluatedUrl.normalizedUrl,
2841
2907
  studies: [...data.studies]
2842
2908
  });
2843
- _store.studyInstanceUIDMap.set(url, data.studies.map(study => study.StudyInstanceUID));
2909
+ _store.studyInstanceUIDMap.set(evaluatedUrl.normalizedUrl, data.studies.map(study => study.StudyInstanceUID));
2844
2910
  },
2845
2911
  query: {
2846
2912
  studies: {
@@ -2975,6 +3041,8 @@ function createDicomJSONApi(dicomJsonConfig) {
2975
3041
  console.warn(' DICOMJson store dicom not implemented');
2976
3042
  }
2977
3043
  },
3044
+ reject: {},
3045
+ deleteStudyMetadataPromise: () => {},
2978
3046
  getImageIdsForDisplaySet(displaySet) {
2979
3047
  const images = displaySet.images;
2980
3048
  const imageIds = [];
@@ -3033,8 +3101,20 @@ function createDicomJSONApi(dicomJsonConfig) {
3033
3101
  query
3034
3102
  }) => {
3035
3103
  const url = query.get('url');
3036
- return _store.studyInstanceUIDMap.get(url);
3037
- }
3104
+ if (!url) {
3105
+ return;
3106
+ }
3107
+ try {
3108
+ const evaluatedUrl = resolveConfigFetchPolicy(url, {
3109
+ allowedOrigins: dicomJsonConfig.dangerouslyAllowedOriginsForAuthenticatedEnvironments,
3110
+ userAuthenticationService
3111
+ });
3112
+ return _store.studyInstanceUIDMap.get(evaluatedUrl.normalizedUrl);
3113
+ } catch {
3114
+ return;
3115
+ }
3116
+ },
3117
+ getConfig: () => dicomJsonConfig
3038
3118
  };
3039
3119
  return src/* IWebApiDataSource */.pt.create(implementation);
3040
3120
  }
@@ -3303,6 +3383,7 @@ function createDicomLocalApi(dicomLocalConfig) {
3303
3383
 
3304
3384
 
3305
3385
 
3386
+
3306
3387
  /**
3307
3388
  * This datasource is initialized with a url that returns a JSON object with a
3308
3389
  * dicomWeb datasource configuration array present in a "servers" object.
@@ -3315,6 +3396,9 @@ function createDicomWebProxyApi(dicomWebProxyConfig, servicesManager) {
3315
3396
  const {
3316
3397
  name
3317
3398
  } = dicomWebProxyConfig;
3399
+ const {
3400
+ userAuthenticationService
3401
+ } = servicesManager.services;
3318
3402
  let dicomWebDelegate = undefined;
3319
3403
  const implementation = {
3320
3404
  initialize: async ({
@@ -3325,8 +3409,11 @@ function createDicomWebProxyApi(dicomWebProxyConfig, servicesManager) {
3325
3409
  if (!url) {
3326
3410
  throw new Error(`No url for '${name}'`);
3327
3411
  } else {
3328
- const response = await fetch(url);
3329
- const data = await response.json();
3412
+ const evaluatedUrl = resolveConfigFetchPolicy(url, {
3413
+ allowedOrigins: dicomWebProxyConfig.dangerouslyAllowedOriginsForAuthenticatedEnvironments,
3414
+ userAuthenticationService
3415
+ });
3416
+ const data = await fetchConfigJson(evaluatedUrl);
3330
3417
  if (!data.servers?.dicomWeb?.[0]) {
3331
3418
  throw new Error('Invalid configuration returned by url');
3332
3419
  }
@@ -3357,9 +3444,15 @@ function createDicomWebProxyApi(dicomWebProxyConfig, servicesManager) {
3357
3444
  store: {
3358
3445
  dicom: (...args) => dicomWebDelegate.store.dicom(...args)
3359
3446
  },
3360
- deleteStudyMetadataPromise: (...args) => dicomWebDelegate.deleteStudyMetadataPromise(...args),
3361
- getImageIdsForDisplaySet: (...args) => dicomWebDelegate.getImageIdsForDisplaySet(...args),
3362
- getImageIdsForInstance: (...args) => dicomWebDelegate.getImageIdsForInstance(...args),
3447
+ reject: {
3448
+ series: (...args) => dicomWebDelegate?.reject?.series?.(...args)
3449
+ },
3450
+ deleteStudyMetadataPromise: (...args) => dicomWebDelegate?.deleteStudyMetadataPromise?.(...args),
3451
+ getImageIdsForDisplaySet: (...args) => dicomWebDelegate?.getImageIdsForDisplaySet?.(...args),
3452
+ getImageIdsForInstance: (...args) => dicomWebDelegate?.getImageIdsForInstance?.(...args),
3453
+ getConfig: (...args) => dicomWebDelegate?.getConfig?.(...args) ?? {
3454
+ dicomUploadEnabled: false
3455
+ },
3363
3456
  getStudyInstanceUIDs({
3364
3457
  params,
3365
3458
  query
@@ -3697,8 +3790,8 @@ var react = __webpack_require__(86326);
3697
3790
  // EXTERNAL MODULE: ../../../node_modules/prop-types/index.js
3698
3791
  var prop_types = __webpack_require__(97598);
3699
3792
  var prop_types_default = /*#__PURE__*/__webpack_require__.n(prop_types);
3700
- // EXTERNAL MODULE: ../../ui-next/src/index.ts + 3075 modules
3701
- var ui_next_src = __webpack_require__(12517);
3793
+ // EXTERNAL MODULE: ../../ui-next/src/index.ts + 3085 modules
3794
+ var ui_next_src = __webpack_require__(564);
3702
3795
  // EXTERNAL MODULE: ./state/index.js + 1 modules
3703
3796
  var state = __webpack_require__(45981);
3704
3797
  // EXTERNAL MODULE: ../../../node_modules/react-router-dom/dist/index.js
@@ -3811,7 +3904,7 @@ function HeaderPatientInfo({
3811
3904
  const formattedPatientName = formatWithEllipsis(patientInfo.PatientName, 27);
3812
3905
  const formattedPatientID = formatWithEllipsis(patientInfo.PatientID, 15);
3813
3906
  return /*#__PURE__*/react.createElement("div", {
3814
- className: "hover:bg-primary-dark flex cursor-pointer items-center justify-center gap-1 rounded-lg",
3907
+ className: "hover:bg-muted flex cursor-pointer items-center justify-center gap-1 rounded-lg",
3815
3908
  onClick: handleOnClick
3816
3909
  }, isMixedPatients ? /*#__PURE__*/react.createElement(ui_next_src/* Icons */.FI1.MultiplePatients, {
3817
3910
  className: "text-primary"
@@ -3820,9 +3913,9 @@ function HeaderPatientInfo({
3820
3913
  }), /*#__PURE__*/react.createElement("div", {
3821
3914
  className: "flex flex-col justify-center"
3822
3915
  }, expanded ? /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
3823
- className: "self-start text-[13px] font-bold text-white"
3916
+ className: "text-foreground self-start text-[13px] font-bold"
3824
3917
  }, formattedPatientName), /*#__PURE__*/react.createElement("div", {
3825
- className: "text-aqua-pale flex gap-2 text-[11px]"
3918
+ className: "text-muted-foreground flex gap-2 text-[11px]"
3826
3919
  }, /*#__PURE__*/react.createElement("div", null, formattedPatientID), /*#__PURE__*/react.createElement("div", null, patientInfo.PatientSex), /*#__PURE__*/react.createElement("div", null, patientInfo.PatientDOB))) : /*#__PURE__*/react.createElement("div", {
3827
3920
  className: "text-primary self-center text-[13px]"
3828
3921
  }, isMixedPatients ? 'Multiple Patients' : 'Patient')), /*#__PURE__*/react.createElement(ui_next_src/* Icons */.FI1.ArrowLeft, {
@@ -3925,7 +4018,7 @@ function ViewerHeader({
3925
4018
  className: "text-primary flex cursor-pointer items-center"
3926
4019
  }, /*#__PURE__*/react.createElement(ui_next_src/* Button */.$nd, {
3927
4020
  variant: "ghost",
3928
- className: "hover:bg-primary-dark",
4021
+ className: "hover:bg-muted",
3929
4022
  onClick: () => {
3930
4023
  commandsManager.run('undo');
3931
4024
  }
@@ -3933,7 +4026,7 @@ function ViewerHeader({
3933
4026
  className: ""
3934
4027
  })), /*#__PURE__*/react.createElement(ui_next_src/* Button */.$nd, {
3935
4028
  variant: "ghost",
3936
- className: "hover:bg-primary-dark",
4029
+ className: "hover:bg-muted",
3937
4030
  onClick: () => {
3938
4031
  commandsManager.run('redo');
3939
4032
  }
@@ -4355,7 +4448,7 @@ function ViewerLayout_extends() { return ViewerLayout_extends = Object.assign ?
4355
4448
 
4356
4449
 
4357
4450
 
4358
- const resizableHandleClassName = 'mt-[1px] bg-black';
4451
+ const resizableHandleClassName = 'mt-[1px] bg-background';
4359
4452
  function ViewerLayout({
4360
4453
  // From Extension Module Params
4361
4454
  extensionManager,
@@ -4398,10 +4491,10 @@ function ViewerLayout({
4398
4491
  * is sized to our viewport.
4399
4492
  */
4400
4493
  (0,react.useEffect)(() => {
4401
- document.body.classList.add('bg-black');
4494
+ document.body.classList.add('bg-background');
4402
4495
  document.body.classList.add('overflow-hidden');
4403
4496
  return () => {
4404
- document.body.classList.remove('bg-black');
4497
+ document.body.classList.remove('bg-background');
4405
4498
  document.body.classList.remove('overflow-hidden');
4406
4499
  };
4407
4500
  }, []);
@@ -4464,12 +4557,12 @@ function ViewerLayout({
4464
4557
  servicesManager: servicesManager,
4465
4558
  appConfig: appConfig
4466
4559
  }), /*#__PURE__*/react.createElement("div", {
4467
- className: "relative flex w-full flex-row flex-nowrap items-stretch overflow-hidden bg-black",
4560
+ className: "relative flex w-full flex-row flex-nowrap items-stretch overflow-hidden bg-background",
4468
4561
  style: {
4469
4562
  height: 'calc(100vh - 52px'
4470
4563
  }
4471
4564
  }, /*#__PURE__*/react.createElement(react.Fragment, null, showLoadingIndicator && /*#__PURE__*/react.createElement(LoadingIndicatorProgress, {
4472
- className: "h-full w-full bg-black"
4565
+ className: "h-full w-full bg-background"
4473
4566
  }), /*#__PURE__*/react.createElement(ui_next_src/* ResizablePanelGroup */.HKS, resizablePanelGroupProps, hasLeftPanels ? /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement(ui_next_src/* ResizablePanel */.wVo, resizableLeftPanelProps, /*#__PURE__*/react.createElement(Components_SidePanelWithServices, ViewerLayout_extends({
4474
4567
  side: "left",
4475
4568
  isExpanded: !leftPanelClosedState,
@@ -4481,7 +4574,7 @@ function ViewerLayout({
4481
4574
  })) : null, /*#__PURE__*/react.createElement(ui_next_src/* ResizablePanel */.wVo, resizableViewportGridPanelProps, /*#__PURE__*/react.createElement("div", {
4482
4575
  className: "flex h-full flex-1 flex-col"
4483
4576
  }, /*#__PURE__*/react.createElement("div", {
4484
- className: "relative flex h-full flex-1 items-center justify-center overflow-hidden bg-black",
4577
+ className: "relative flex h-full flex-1 items-center justify-center overflow-hidden bg-background",
4485
4578
  onMouseEnter: handleMouseEnter
4486
4579
  }, /*#__PURE__*/react.createElement(ViewportGridComp, {
4487
4580
  servicesManager: servicesManager,
@@ -4688,7 +4781,8 @@ function CreateReportDialogPrompt({
4688
4781
  minSeriesNumber = 0,
4689
4782
  predecessorImageId,
4690
4783
  extensionManager,
4691
- servicesManager
4784
+ servicesManager,
4785
+ enableDownload = false
4692
4786
  }) {
4693
4787
  const {
4694
4788
  uiDialogService,
@@ -4708,6 +4802,7 @@ function CreateReportDialogPrompt({
4708
4802
  predecessorImageId,
4709
4803
  minSeriesNumber,
4710
4804
  modality,
4805
+ enableDownload,
4711
4806
  onSave: async ({
4712
4807
  reportName,
4713
4808
  dataSource: selectedDataSource,
@@ -5180,7 +5275,6 @@ var dist_esm = __webpack_require__(15327);
5180
5275
  const {
5181
5276
  isImage,
5182
5277
  sortStudyInstances,
5183
- instancesSortCriteria,
5184
5278
  sopClassDictionary,
5185
5279
  isDisplaySetReconstructable: getSopClassHandlerModule_isDisplaySetReconstructable
5186
5280
  } = src/* utils */.Wp;
@@ -5225,12 +5319,17 @@ function getDisplaySetInfo(instances) {
5225
5319
  const instancesMap = new Map();
5226
5320
  let firstTimePointInstances;
5227
5321
  if (instances[0].NumberOfFrames > 1 && timePoints.length > 1) {
5228
- // handle multiframe dynamic volume
5229
- firstTimePointInstances = timePoints[0].map(imageId => dist_esm.metaData.get('instance', imageId));
5322
+ // Handle multiframe dynamic volumes. Local file frame imageIds do not
5323
+ // always resolve to a frame-level instance object, so keep resolved
5324
+ // entries and fall back to the source multiframe instance when needed.
5325
+ firstTimePointInstances = timePoints[0].map(imageId => dist_esm.metaData.get('instance', imageId)).filter(Boolean);
5326
+ if (!firstTimePointInstances.length) {
5327
+ firstTimePointInstances = [instances[0]];
5328
+ }
5230
5329
  } else {
5231
5330
  // O(n) to convert it into a map and O(1) to find each instance
5232
5331
  instances.forEach(instance => instancesMap.set(instance.imageId, instance));
5233
- firstTimePointInstances = timePoint.map(imageId => instancesMap.get(imageId));
5332
+ firstTimePointInstances = timePoint.map(imageId => instancesMap.get(imageId)).filter(Boolean);
5234
5333
  }
5235
5334
  displaySetInfo = getSopClassHandlerModule_isDisplaySetReconstructable(firstTimePointInstances, appConfig);
5236
5335
  } else {
@@ -5393,7 +5492,7 @@ function getDisplaySetsFromSeries(instances) {
5393
5492
  }
5394
5493
  return displaySets;
5395
5494
  }
5396
- const getSopClassHandlerModule_sopClassUids = [sopClassDictionary.ComputedRadiographyImageStorage, sopClassDictionary.DigitalXRayImageStorageForPresentation, sopClassDictionary.DigitalXRayImageStorageForProcessing, sopClassDictionary.DigitalMammographyXRayImageStorageForPresentation, sopClassDictionary.DigitalMammographyXRayImageStorageForProcessing, sopClassDictionary.DigitalIntraOralXRayImageStorageForPresentation, sopClassDictionary.DigitalIntraOralXRayImageStorageForProcessing, sopClassDictionary.CTImageStorage, sopClassDictionary.EnhancedCTImageStorage, sopClassDictionary.LegacyConvertedEnhancedCTImageStorage, sopClassDictionary.UltrasoundMultiframeImageStorage, sopClassDictionary.MRImageStorage, sopClassDictionary.EnhancedMRImageStorage, sopClassDictionary.EnhancedMRColorImageStorage, sopClassDictionary.LegacyConvertedEnhancedMRImageStorage, sopClassDictionary.UltrasoundImageStorage, sopClassDictionary.UltrasoundImageStorageRET, sopClassDictionary.SecondaryCaptureImageStorage, sopClassDictionary.MultiframeSingleBitSecondaryCaptureImageStorage, sopClassDictionary.MultiframeGrayscaleByteSecondaryCaptureImageStorage, sopClassDictionary.MultiframeGrayscaleWordSecondaryCaptureImageStorage, sopClassDictionary.MultiframeTrueColorSecondaryCaptureImageStorage, sopClassDictionary.XRayAngiographicImageStorage, sopClassDictionary.EnhancedXAImageStorage, sopClassDictionary.XRayRadiofluoroscopicImageStorage, sopClassDictionary.EnhancedXRFImageStorage, sopClassDictionary.XRay3DAngiographicImageStorage, sopClassDictionary.XRay3DCraniofacialImageStorage, sopClassDictionary.BreastTomosynthesisImageStorage, sopClassDictionary.BreastProjectionXRayImageStorageForPresentation, sopClassDictionary.BreastProjectionXRayImageStorageForProcessing, sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForPresentation, sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForProcessing, sopClassDictionary.NuclearMedicineImageStorage, sopClassDictionary.VLEndoscopicImageStorage, sopClassDictionary.VideoEndoscopicImageStorage, sopClassDictionary.VLMicroscopicImageStorage, sopClassDictionary.VideoMicroscopicImageStorage, sopClassDictionary.VLSlideCoordinatesMicroscopicImageStorage, sopClassDictionary.VLPhotographicImageStorage, sopClassDictionary.VideoPhotographicImageStorage, sopClassDictionary.OphthalmicPhotography8BitImageStorage, sopClassDictionary.OphthalmicPhotography16BitImageStorage, sopClassDictionary.OphthalmicTomographyImageStorage,
5495
+ const getSopClassHandlerModule_sopClassUids = [sopClassDictionary.ComputedRadiographyImageStorage, sopClassDictionary.DigitalXRayImageStorageForPresentation, sopClassDictionary.DigitalXRayImageStorageForProcessing, sopClassDictionary.DigitalMammographyXRayImageStorageForPresentation, sopClassDictionary.DigitalMammographyXRayImageStorageForProcessing, sopClassDictionary.DigitalIntraOralXRayImageStorageForPresentation, sopClassDictionary.DigitalIntraOralXRayImageStorageForProcessing, sopClassDictionary.CTImageStorage, sopClassDictionary.EnhancedCTImageStorage, sopClassDictionary.LegacyConvertedEnhancedCTImageStorage, sopClassDictionary.UltrasoundMultiframeImageStorage, sopClassDictionary.MRImageStorage, sopClassDictionary.EnhancedMRImageStorage, sopClassDictionary.EnhancedMRColorImageStorage, sopClassDictionary.LegacyConvertedEnhancedMRImageStorage, sopClassDictionary.UltrasoundImageStorage, sopClassDictionary.UltrasoundImageStorageRET, sopClassDictionary.SecondaryCaptureImageStorage, sopClassDictionary.MultiframeSingleBitSecondaryCaptureImageStorage, sopClassDictionary.MultiframeGrayscaleByteSecondaryCaptureImageStorage, sopClassDictionary.MultiframeGrayscaleWordSecondaryCaptureImageStorage, sopClassDictionary.MultiframeTrueColorSecondaryCaptureImageStorage, sopClassDictionary.XRayAngiographicImageStorage, sopClassDictionary.EnhancedXAImageStorage, sopClassDictionary.XRayRadiofluoroscopicImageStorage, sopClassDictionary.EnhancedXRFImageStorage, sopClassDictionary.XRay3DAngiographicImageStorage, sopClassDictionary.XRay3DCraniofacialImageStorage, sopClassDictionary.BreastTomosynthesisImageStorage, sopClassDictionary.CornealTopographyMapStorage, sopClassDictionary.BreastProjectionXRayImageStorageForPresentation, sopClassDictionary.BreastProjectionXRayImageStorageForProcessing, sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForPresentation, sopClassDictionary.IntravascularOpticalCoherenceTomographyImageStorageForProcessing, sopClassDictionary.NuclearMedicineImageStorage, sopClassDictionary.VLEndoscopicImageStorage, sopClassDictionary.VideoEndoscopicImageStorage, sopClassDictionary.VLMicroscopicImageStorage, sopClassDictionary.VideoMicroscopicImageStorage, sopClassDictionary.VLSlideCoordinatesMicroscopicImageStorage, sopClassDictionary.VLPhotographicImageStorage, sopClassDictionary.VideoPhotographicImageStorage, sopClassDictionary.OphthalmicPhotography8BitImageStorage, sopClassDictionary.OphthalmicPhotography16BitImageStorage, sopClassDictionary.OphthalmicTomographyImageStorage,
5397
5496
  // Handled by another sop class module
5398
5497
  // sopClassDictionary.VLWholeSlideMicroscopyImageStorage,
5399
5498
  sopClassDictionary.PositronEmissionTomographyImageStorage, sopClassDictionary.EnhancedPETImageStorage, sopClassDictionary.LegacyConvertedEnhancedPETImageStorage, sopClassDictionary.RTImageStorage, sopClassDictionary.EnhancedUSVolumeStorage, sopClassDictionary.RTDoseStorage];
@@ -5555,7 +5654,7 @@ function ToolbarLayoutSelectorWithServices({
5555
5654
  disabled: preset.disabled,
5556
5655
  isPreset: true
5557
5656
  })))), /*#__PURE__*/react.createElement("div", {
5558
- className: "bg-muted flex flex-col gap-2.5 border-l-2 border-solid border-black p-2"
5657
+ className: "bg-muted flex flex-col gap-2.5 border-l-2 border-solid border-background p-2"
5559
5658
  }, /*#__PURE__*/react.createElement("div", {
5560
5659
  className: "text-muted-foreground text-xs"
5561
5660
  }, t('Custom')), /*#__PURE__*/react.createElement(ui_next_src/* LayoutSelector */.sG4.GridSelector, {
@@ -5843,6 +5942,7 @@ function ToolButtonWrapper(props) {
5843
5942
  }
5844
5943
 
5845
5944
  ;// ../../../extensions/default/src/Toolbar/ToolbarDivider.tsx
5945
+ /* unused harmony import specifier */ var React;
5846
5946
 
5847
5947
  function ToolbarDivider() {
5848
5948
  return /*#__PURE__*/React.createElement("span", {
@@ -6315,7 +6415,7 @@ const RowComponent = ({
6315
6415
  ...style,
6316
6416
  ...rowStyle
6317
6417
  },
6318
- className: classnames_default()('hover:bg-secondary-main border-secondary-light text-foreground flex w-full flex-row items-center break-all bg-black text-base transition duration-300', lineHeightClassName),
6418
+ className: classnames_default()('hover:bg-primary/25 border-input text-foreground flex w-full flex-row items-center break-all bg-background text-base', lineHeightClassName),
6319
6419
  key: keyPrefix
6320
6420
  }, isChildOrParent && /*#__PURE__*/react.createElement("div", {
6321
6421
  style: {
@@ -6345,34 +6445,34 @@ function ColumnHeaders({
6345
6445
  valueRef
6346
6446
  }) {
6347
6447
  return /*#__PURE__*/react.createElement("div", {
6348
- className: classnames_default()('bg-secondary-dark ohif-scrollbar flex w-full flex-row overflow-y-scroll'),
6448
+ className: classnames_default()('bg-popover ohif-scrollbar flex w-full flex-row overflow-y-scroll'),
6349
6449
  style: rowVerticalPaddingStyle
6350
6450
  }, /*#__PURE__*/react.createElement("div", {
6351
6451
  className: "w-4/24 px-3"
6352
6452
  }, /*#__PURE__*/react.createElement("label", {
6353
6453
  ref: tagRef,
6354
- className: "flex flex-1 select-none flex-col pl-1 text-lg text-white"
6454
+ className: "text-foreground flex flex-1 select-none flex-col pl-1 text-lg"
6355
6455
  }, /*#__PURE__*/react.createElement("span", {
6356
6456
  className: "flex flex-row items-center focus:outline-none"
6357
6457
  }, "Tag"))), /*#__PURE__*/react.createElement("div", {
6358
6458
  className: "w-2/24 px-3"
6359
6459
  }, /*#__PURE__*/react.createElement("label", {
6360
6460
  ref: vrRef,
6361
- className: "flex flex-1 select-none flex-col pl-1 text-lg text-white"
6461
+ className: "text-foreground flex flex-1 select-none flex-col pl-1 text-lg"
6362
6462
  }, /*#__PURE__*/react.createElement("span", {
6363
6463
  className: "flex flex-row items-center focus:outline-none"
6364
6464
  }, "VR"))), /*#__PURE__*/react.createElement("div", {
6365
6465
  className: "w-6/24 px-3"
6366
6466
  }, /*#__PURE__*/react.createElement("label", {
6367
6467
  ref: keywordRef,
6368
- className: "flex flex-1 select-none flex-col pl-1 text-lg text-white"
6468
+ className: "text-foreground flex flex-1 select-none flex-col pl-1 text-lg"
6369
6469
  }, /*#__PURE__*/react.createElement("span", {
6370
6470
  className: "flex flex-row items-center focus:outline-none"
6371
6471
  }, "Keyword"))), /*#__PURE__*/react.createElement("div", {
6372
6472
  className: "w-5/24 grow px-3"
6373
6473
  }, /*#__PURE__*/react.createElement("label", {
6374
6474
  ref: valueRef,
6375
- className: "flex flex-1 select-none flex-col pl-1 text-lg text-white"
6475
+ className: "text-foreground flex flex-1 select-none flex-col pl-1 text-lg"
6376
6476
  }, /*#__PURE__*/react.createElement("span", {
6377
6477
  className: "flex flex-row items-center focus:outline-none"
6378
6478
  }, "Value"))));
@@ -6520,7 +6620,7 @@ function DicomTagTable({
6520
6620
  keywordRef: keywordRef,
6521
6621
  valueRef: valueRef
6522
6622
  }), /*#__PURE__*/react.createElement("div", {
6523
- className: "relative m-auto border-2 border-black bg-black",
6623
+ className: "relative m-auto border-2 border-background bg-background",
6524
6624
  style: {
6525
6625
  height: '32rem'
6526
6626
  }
@@ -6635,7 +6735,7 @@ const DicomTagBrowser = ({
6635
6735
  }, /*#__PURE__*/react.createElement("div", {
6636
6736
  className: "mb-6 flex flex-row items-start pl-1"
6637
6737
  }, /*#__PURE__*/react.createElement("div", {
6638
- className: "flex w-full flex-row items-start gap-4"
6738
+ className: "flex w-full flex-row items-start gap-6"
6639
6739
  }, /*#__PURE__*/react.createElement("div", {
6640
6740
  className: "flex w-1/3 flex-col"
6641
6741
  }, /*#__PURE__*/react.createElement("span", {
@@ -6645,7 +6745,11 @@ const DicomTagBrowser = ({
6645
6745
  onValueChange: value => onSelectChange({
6646
6746
  value
6647
6747
  })
6648
- }, /*#__PURE__*/react.createElement(ui_next_src/* SelectTrigger */.bqE, null, displaySetList.find(ds => ds.value === selectedDisplaySetInstanceUID)?.label || 'Select Series'), /*#__PURE__*/react.createElement(ui_next_src/* SelectContent */.gCo, null, displaySetList.map(item => {
6748
+ }, /*#__PURE__*/react.createElement(ui_next_src/* SelectTrigger */.bqE, {
6749
+ "data-cy": "dicom-tag-series-select-trigger"
6750
+ }, /*#__PURE__*/react.createElement(ui_next_src/* SelectValue */.yvm, {
6751
+ "data-cy": "dicom-tag-series-select-value"
6752
+ }, displaySetList.find(ds => ds.value === selectedDisplaySetInstanceUID)?.label || 'Select Series')), /*#__PURE__*/react.createElement(ui_next_src/* SelectContent */.gCo, null, displaySetList.map(item => {
6649
6753
  return /*#__PURE__*/react.createElement(ui_next_src/* SelectItem */.ebT, {
6650
6754
  key: item.value,
6651
6755
  value: item.value
@@ -6664,7 +6768,7 @@ const DicomTagBrowser = ({
6664
6768
  min: 1,
6665
6769
  max: activeDisplaySet?.images?.length,
6666
6770
  step: 1,
6667
- className: "pt-4"
6771
+ className: "pt-3"
6668
6772
  })), /*#__PURE__*/react.createElement("div", {
6669
6773
  className: "ml-auto mr-1 flex w-1/3 flex-col"
6670
6774
  }, /*#__PURE__*/react.createElement("span", {
@@ -7223,8 +7327,14 @@ function configureViewportForLayerAddition(params) {
7223
7327
 
7224
7328
  // If a viewport type was already set do not reset it.
7225
7329
  if (!viewport.viewportOptions.viewportType) {
7226
- // Special handling for overlay display sets
7227
- if (requestedLayerDisplaySet.isOverlayDisplaySet) {
7330
+ // If the live Cornerstone viewport is already orthographic (volume), keep it as
7331
+ // 'volume'. Prevents accidentally downgrading a volume viewport to 'stack' when
7332
+ // viewportOptions arrives without a viewportType (e.g. from the HP overlay path).
7333
+ const csViewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
7334
+ if (csViewport?.type === 'orthographic') {
7335
+ viewport.viewportOptions.viewportType = 'volume';
7336
+ // Special handling for overlay display sets
7337
+ } else if (requestedLayerDisplaySet.isOverlayDisplaySet) {
7228
7338
  // Do not force volume for SEG and RTSTRUCT if it and all the current display sets are for the same display set
7229
7339
  const isSameDisplaySet = currentDisplaySetUIDs.every(uid => {
7230
7340
  const currentDisplaySet = displaySetService.getDisplaySetByUID(uid);
@@ -7280,7 +7390,8 @@ function configureViewportForLayerRemoval(params) {
7280
7390
  if (!viewport.viewportOptions) {
7281
7391
  viewport.viewportOptions = {};
7282
7392
  }
7283
- viewport.viewportOptions.viewportType = 'volume';
7393
+ const csViewportOrthographic = cornerstoneViewportService.getCornerstoneViewport(viewportId)?.type === 'orthographic';
7394
+ viewport.viewportOptions.viewportType = csViewportOrthographic ? 'volume' : 'stack';
7284
7395
 
7285
7396
  // orientation
7286
7397
  if (!viewport.viewportOptions.orientation) {
@@ -7537,8 +7648,6 @@ const useToggleOneUpViewportGridStore = (0,zustand_esm/* create */.vt)(set => ({
7537
7648
  })
7538
7649
  }));
7539
7650
  ;// ../../../extensions/default/src/Actions/createReportAsync.tsx
7540
-
7541
-
7542
7651
  /**
7543
7652
  *
7544
7653
  * @param {*} servicesManager
@@ -7546,7 +7655,8 @@ const useToggleOneUpViewportGridStore = (0,zustand_esm/* create */.vt)(set => ({
7546
7655
  async function createReportAsync({
7547
7656
  servicesManager,
7548
7657
  getReport,
7549
- reportType = 'measurement'
7658
+ reportType = 'Measurements',
7659
+ successMessage
7550
7660
  }) {
7551
7661
  const {
7552
7662
  displaySetService,
@@ -7559,15 +7669,13 @@ async function createReportAsync({
7559
7669
  return;
7560
7670
  }
7561
7671
 
7562
- // The "Mode" route listens for DicomMetadataStore changes
7563
- // When a new instance is added, it listens and
7564
- // automatically calls makeDisplaySets
7565
- src/* DicomMetadataStore */.H8.addInstances([naturalizedReport], true);
7672
+ // addInstances is called by the store command (storeMeasurements/storeSegmentation),
7673
+ // so the display set should already exist at this point.
7566
7674
  const displaySet = displaySetService.getMostRecentDisplaySet();
7567
7675
  const displaySetInstanceUID = displaySet.displaySetInstanceUID;
7568
7676
  uiNotificationService.show({
7569
7677
  title: 'Create Report',
7570
- message: `${reportType} saved successfully`,
7678
+ message: successMessage ?? `${reportType} saved successfully`,
7571
7679
  type: 'success'
7572
7680
  });
7573
7681
  return [displaySetInstanceUID];
@@ -7623,34 +7731,32 @@ async function promptSaveReport({
7623
7731
  predecessorImageId,
7624
7732
  minSeriesNumber: 3000,
7625
7733
  extensionManager,
7626
- servicesManager
7734
+ servicesManager,
7735
+ enableDownload: true
7627
7736
  });
7628
7737
  if (promptResult.action === PROMPT_RESPONSES/* default */.A.CREATE_REPORT) {
7629
- const dataSources = extensionManager.getDataSources(promptResult.dataSourceName);
7630
- const dataSource = dataSources[0];
7631
7738
  const {
7632
7739
  series,
7633
7740
  priorSeriesNumber,
7634
- value: reportName
7741
+ value: reportName,
7742
+ dataSourceName
7635
7743
  } = promptResult;
7636
7744
  const SeriesDescription = reportName || defaultSaveTitle;
7637
- const getReport = async () => {
7638
- return commandsManager.runCommand('storeMeasurements', {
7639
- measurementData,
7640
- dataSource,
7641
- additionalFindingTypes: ['ArrowAnnotate'],
7642
- options: {
7643
- SeriesDescription,
7644
- SeriesNumber: 1 + priorSeriesNumber,
7645
- predecessorImageId: series
7646
- }
7647
- }, 'CORNERSTONE_STRUCTURED_REPORT');
7648
- };
7745
+ const getReport = async () => commandsManager.runCommand('storeMeasurements', {
7746
+ measurementData,
7747
+ dataSource: dataSourceName,
7748
+ additionalFindingTypes: ['ArrowAnnotate'],
7749
+ options: {
7750
+ SeriesDescription,
7751
+ SeriesNumber: 1 + priorSeriesNumber,
7752
+ predecessorImageId: series
7753
+ }
7754
+ }, 'CORNERSTONE_STRUCTURED_REPORT');
7649
7755
  displaySetInstanceUIDs = await Actions_createReportAsync({
7650
7756
  servicesManager,
7651
7757
  getReport
7652
7758
  });
7653
- } else if (promptResult.action === RESPONSE.CANCEL) {
7759
+ } else if (promptResult.action === PROMPT_RESPONSES/* default */.A.CANCEL) {
7654
7760
  // Do nothing
7655
7761
  }
7656
7762
  return {
@@ -7682,6 +7788,10 @@ function findPredecessorImageId(annotations) {
7682
7788
  ;// ../../../extensions/default/src/commandsModule.ts
7683
7789
 
7684
7790
 
7791
+ const {
7792
+ downloadBlob
7793
+ } = src/* utils */.Wp;
7794
+
7685
7795
 
7686
7796
 
7687
7797
 
@@ -7811,6 +7921,19 @@ const commandsModule = ({
7811
7921
  return;
7812
7922
  }
7813
7923
 
7924
+ // Check if it's a segmentation and handle accordingly.
7925
+ // Note that for the sake of hydrated segmentations, we remove the
7926
+ // segmentation before checking if the display set is indeed in the viewport.
7927
+ // This is because hydrated segmentations are not in the viewport per se
7928
+ // {i.e. they are not layered) but are simply referenced by the display
7929
+ // set in the viewport.
7930
+ const isSegmentation = DERIVED_OVERLAY_MODALITIES.includes(displaySet.Modality);
7931
+ if (isSegmentation) {
7932
+ segmentationService.removeRepresentationsFromViewport(viewportId, {
7933
+ segmentationId: displaySetInstanceUID
7934
+ });
7935
+ }
7936
+
7814
7937
  // Get current display sets for the viewport
7815
7938
  const currentDisplaySetUIDs = viewportGridService.getDisplaySetsUIDsForViewport(viewportId);
7816
7939
 
@@ -7818,14 +7941,6 @@ const commandsModule = ({
7818
7941
  if (!currentDisplaySetUIDs.includes(displaySetInstanceUID)) {
7819
7942
  return;
7820
7943
  }
7821
-
7822
- // Check if it's a segmentation and handle accordingly
7823
- const isSegmentation = DERIVED_OVERLAY_MODALITIES.includes(displaySet.Modality);
7824
- if (isSegmentation) {
7825
- segmentationService.removeSegmentationRepresentations(viewportId, {
7826
- segmentationId: displaySetInstanceUID
7827
- });
7828
- }
7829
7944
  const updatedViewports = hangingProtocolService.getViewportsRequireUpdate(viewportId, displaySetInstanceUID);
7830
7945
 
7831
7946
  // Configure each viewport for layer removal
@@ -8310,7 +8425,7 @@ const commandsModule = ({
8310
8425
  const {
8311
8426
  UIModalService
8312
8427
  } = servicesManager.services;
8313
- const defaultDisplaySetInstanceUID = displaySetInstanceUID || displaySetInstanceUIDs[0];
8428
+ const defaultDisplaySetInstanceUID = displaySetInstanceUID || displaySetInstanceUIDs[0] || displaySets[0]?.displaySetInstanceUID;
8314
8429
  UIModalService.show({
8315
8430
  content: DicomTagBrowser_DicomTagBrowser,
8316
8431
  contentProps: {
@@ -8371,7 +8486,11 @@ const commandsModule = ({
8371
8486
  const activeDisplaySetIndex = currentDisplaySets.findIndex(displaySet => displaySetInstanceUIDs.includes(displaySet.displaySetInstanceUID));
8372
8487
  let displaySetIndexToShow;
8373
8488
  for (displaySetIndexToShow = activeDisplaySetIndex + direction; displaySetIndexToShow > -1 && displaySetIndexToShow < currentDisplaySets.length; displaySetIndexToShow += direction) {
8374
- if (!excludeNonImageModalities || !nonImageModalities.includes(currentDisplaySets[displaySetIndexToShow].Modality)) {
8489
+ const nextDisplaySet = currentDisplaySets[displaySetIndexToShow];
8490
+ if (nextDisplaySet.madeInClient) {
8491
+ continue;
8492
+ }
8493
+ if (!excludeNonImageModalities || !nonImageModalities.includes(nextDisplaySet.Modality)) {
8375
8494
  break;
8376
8495
  }
8377
8496
  }
@@ -8397,6 +8516,74 @@ const commandsModule = ({
8397
8516
  viewportsToUpdate: updatedViewports
8398
8517
  });
8399
8518
  setTimeout(() => actions.scrollActiveThumbnailIntoView(), 0);
8519
+ },
8520
+ /**
8521
+ * Creates a store function based on the data source type.
8522
+ * @param dataSource - 'download', 'copyToClipboard', or a named data source
8523
+ * @param defaultFileName - Default filename for download/clipboard
8524
+ * @param defaultContentType - Default content type for clipboard
8525
+ * @returns A store function, or null if no valid store exists
8526
+ */
8527
+ createStoreFunction: ({
8528
+ dataSource,
8529
+ defaultFileName,
8530
+ defaultContentType
8531
+ }) => {
8532
+ if (dataSource === 'download') {
8533
+ return async dicom => {
8534
+ const instances = Array.isArray(dicom) ? dicom : [dicom];
8535
+ src/* DicomMetadataStore */.H8.addInstances(instances, true);
8536
+ if (instances.length !== 1) {
8537
+ throw new Error('Download only supports a single DICOM instance');
8538
+ }
8539
+ const reportBlob = dcmjs_es/* default.data */.Ay.data.datasetToBlob(instances[0]);
8540
+ downloadBlob(reportBlob, {
8541
+ filename: defaultFileName || 'dicom.dcm'
8542
+ });
8543
+ };
8544
+ }
8545
+ if (dataSource === 'copyToClipboard') {
8546
+ return async dicom => {
8547
+ const instances = Array.isArray(dicom) ? dicom : [dicom];
8548
+ src/* DicomMetadataStore */.H8.addInstances(instances, true);
8549
+ if (instances.length !== 1) {
8550
+ throw new Error('Copy to clipboard only supports a single DICOM instance');
8551
+ }
8552
+ const reportBlob = dcmjs_es/* default.data */.Ay.data.datasetToBlob(instances[0]);
8553
+ const type = defaultContentType || 'application/dicom';
8554
+ await navigator.clipboard.write([new ClipboardItem({
8555
+ [type]: new Blob([reportBlob], {
8556
+ type
8557
+ })
8558
+ })]);
8559
+ };
8560
+ }
8561
+
8562
+ // DICOM STOW path — resolve the named data source
8563
+ const dataSources = extensionManager.getDataSources(dataSource);
8564
+ const resolvedDataSource = dataSources?.[0];
8565
+ if (!resolvedDataSource?.store?.dicom) {
8566
+ return null;
8567
+ }
8568
+ return async (dicom, {
8569
+ dicomDict
8570
+ } = {}) => {
8571
+ const instances = Array.isArray(dicom) ? dicom : [dicom];
8572
+ const config = resolvedDataSource.getConfig?.();
8573
+ if (config?.wadoRoot) {
8574
+ instances.forEach(instance => {
8575
+ instance.wadoRoot = config.wadoRoot;
8576
+ });
8577
+ }
8578
+ src/* DicomMetadataStore */.H8.addInstances(instances, true);
8579
+ for (const instance of instances) {
8580
+ await resolvedDataSource.store.dicom(instance, null, dicomDict);
8581
+ }
8582
+ const studyUIDs = new Set(instances.map(i => i.StudyInstanceUID).filter(Boolean));
8583
+ for (const uid of studyUIDs) {
8584
+ resolvedDataSource.deleteStudyMetadataPromise(uid);
8585
+ }
8586
+ };
8400
8587
  }
8401
8588
  };
8402
8589
  const definitions = {
@@ -8428,7 +8615,8 @@ const commandsModule = ({
8428
8615
  updateViewportDisplaySet: actions.updateViewportDisplaySet,
8429
8616
  scrollActiveThumbnailIntoView: actions.scrollActiveThumbnailIntoView,
8430
8617
  addDisplaySetAsLayer: actions.addDisplaySetAsLayer,
8431
- removeDisplaySetLayer: actions.removeDisplaySetLayer
8618
+ removeDisplaySetLayer: actions.removeDisplaySetLayer,
8619
+ createStoreFunction: actions.createStoreFunction
8432
8620
  };
8433
8621
  return {
8434
8622
  actions,
@@ -9605,7 +9793,7 @@ function DataSourceSelector() {
9605
9793
  }, /*#__PURE__*/react.createElement("div", {
9606
9794
  className: "flex h-screen w-screen items-center justify-center"
9607
9795
  }, /*#__PURE__*/react.createElement("div", {
9608
- className: "bg-secondary-dark mx-auto space-y-2 rounded-lg py-8 px-8 drop-shadow-md"
9796
+ className: "bg-popover mx-auto space-y-2 rounded-lg py-8 px-8 drop-shadow-md"
9609
9797
  }, /*#__PURE__*/react.createElement("img", {
9610
9798
  className: "mx-auto block h-14",
9611
9799
  src: "./ohif-logo.svg",
@@ -9615,7 +9803,7 @@ function DataSourceSelector() {
9615
9803
  }, dsConfigs.filter(it => it.sourceName !== 'dicomjson' && it.sourceName !== 'dicomlocal').map(ds => /*#__PURE__*/react.createElement("div", {
9616
9804
  key: ds.sourceName
9617
9805
  }, /*#__PURE__*/react.createElement("h1", {
9618
- className: "text-white"
9806
+ className: "text-foreground"
9619
9807
  }, ds.configuration?.friendlyName || ds.friendlyName), /*#__PURE__*/react.createElement(ui_src/* Button */.$n, {
9620
9808
  type: ui_src/* ButtonEnums.type */.Ny.NW.primary,
9621
9809
  className: classnames_default()('ml-2'),
@@ -9923,7 +10111,7 @@ function ItemListComponent({
9923
10111
  }), /*#__PURE__*/react.createElement(ui_next_src/* InputFilter */.zbB.ClearButton, {
9924
10112
  className: "text-primary mr-0.5 p-0.5"
9925
10113
  }))), /*#__PURE__*/react.createElement("div", {
9926
- className: "relative flex min-h-[1px] grow flex-col bg-black text-[14px]"
10114
+ className: "relative flex min-h-[1px] grow flex-col bg-background text-[14px]"
9927
10115
  }, itemList == null ? /*#__PURE__*/react.createElement(LoadingIndicatorProgress, {
9928
10116
  className: 'h-full w-full'
9929
10117
  }) : itemList.length === 0 ? /*#__PURE__*/react.createElement("div", {
@@ -10015,16 +10203,16 @@ function DataSourceConfigurationModalComponent({
10015
10203
  };
10016
10204
  }, [selectedItems, configurationAPI, onHide, itemLabels, showFullConfig, currentSelectedItemIndex]);
10017
10205
  const getSelectedItemCursorClasses = itemIndex => itemIndex !== itemLabels.length - 1 && itemIndex < selectedItems.length ? 'cursor-pointer' : 'cursor-auto';
10018
- const getSelectedItemBackgroundClasses = itemIndex => itemIndex < selectedItems.length ? classnames_default()('bg-black/[.4]', itemIndex !== itemLabels.length - 1 ? 'hover:bg-transparent active:bg-secondary-dark' : '') : 'bg-transparent';
10019
- 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';
10020
- const getSelectedItemTextClasses = itemIndex => itemIndex <= selectedItems.length ? 'text-primary-light' : 'text-primary';
10206
+ const getSelectedItemBackgroundClasses = itemIndex => itemIndex < selectedItems.length ? classnames_default()('bg-background/[.4]', itemIndex !== itemLabels.length - 1 ? 'hover:bg-transparent active:bg-popover' : '') : 'bg-transparent';
10207
+ const getSelectedItemBorderClasses = itemIndex => itemIndex === currentSelectedItemIndex + 1 ? classnames_default()('border-2', 'border-solid', 'border-highlight') : itemIndex < selectedItems.length ? 'border border-solid border-primary hover:border-highlight active:border-white' : 'border border-dashed border-input';
10208
+ const getSelectedItemTextClasses = itemIndex => itemIndex <= selectedItems.length ? 'text-highlight' : 'text-primary';
10021
10209
  const getErrorComponent = () => {
10022
10210
  return /*#__PURE__*/react.createElement("div", {
10023
10211
  className: "flex min-h-[1px] grow flex-col gap-4"
10024
10212
  }, /*#__PURE__*/react.createElement("div", {
10025
- className: "text-primary-light text-[20px]"
10213
+ className: "text-highlight text-[20px]"
10026
10214
  }, t(`Error fetching ${itemLabels[selectedItems.length]} list`)), /*#__PURE__*/react.createElement("div", {
10027
- className: "grow bg-black p-4 text-[14px]"
10215
+ className: "grow bg-background p-4 text-[14px]"
10028
10216
  }, errorMessage));
10029
10217
  };
10030
10218
  const getSelectedItemsComponent = () => {
@@ -10047,14 +10235,14 @@ function DataSourceConfigurationModalComponent({
10047
10235
  }), /*#__PURE__*/react.createElement("div", {
10048
10236
  className: classnames_default()(NO_WRAP_ELLIPSIS_CLASS_NAMES)
10049
10237
  }, t(itemLabel))), itemLabelIndex < selectedItems.length ? /*#__PURE__*/react.createElement("div", {
10050
- className: classnames_default()('text-[14px] text-white', NO_WRAP_ELLIPSIS_CLASS_NAMES)
10238
+ className: classnames_default()('text-foreground text-[14px]', NO_WRAP_ELLIPSIS_CLASS_NAMES)
10051
10239
  }, selectedItems[itemLabelIndex].name) : /*#__PURE__*/react.createElement("br", null));
10052
10240
  }));
10053
10241
  };
10054
10242
  return /*#__PURE__*/react.createElement("div", {
10055
10243
  className: "flex h-[calc(100vh-300px)] select-none flex-col gap-4 pt-0.5"
10056
10244
  }, getSelectedItemsComponent(), /*#__PURE__*/react.createElement("div", {
10057
- className: "h-0.5 w-full shrink-0 bg-black"
10245
+ className: "h-0.5 w-full shrink-0 bg-background"
10058
10246
  }), errorMessage ? getErrorComponent() : /*#__PURE__*/react.createElement(Components_ItemListComponent, {
10059
10247
  itemLabel: itemLabels[currentSelectedItemIndex + 1],
10060
10248
  itemList: itemList,
@@ -10137,7 +10325,7 @@ function DataSourceConfigurationComponent({
10137
10325
  }
10138
10326
  }, [configurationAPI, configuredItems, showConfigurationModal]);
10139
10327
  return configuredItems ? /*#__PURE__*/react.createElement("div", {
10140
- className: "text-aqua-pale flex items-center overflow-hidden"
10328
+ className: "text-muted-foreground flex items-center overflow-hidden"
10141
10329
  }, /*#__PURE__*/react.createElement(ui_next_src/* Icons */.FI1.Settings, {
10142
10330
  className: "mr-2.5 h-3.5 w-3.5 shrink-0 cursor-pointer",
10143
10331
  onClick: showConfigurationModal
@@ -10346,8 +10534,14 @@ function getDataSourceConfigurationCustomization({
10346
10534
  const {
10347
10535
  sortingCriteria
10348
10536
  } = src/* utils */.Wp;
10537
+ const {
10538
+ seriesSortCriteria
10539
+ } = sortingCriteria;
10540
+
10541
+ /** Stable series order for e2e (Playwright sets TEST_ENV=true via cross-env). */
10542
+ const sortingCriteriaFn = false ? 0 : seriesSortCriteria.seriesInfoSortingCriteria;
10349
10543
  /* harmony default export */ const sortingCriteriaCustomization = ({
10350
- sortingCriteria: sortingCriteria.seriesSortCriteria.seriesInfoSortingCriteria
10544
+ sortingCriteria: sortingCriteriaFn
10351
10545
  });
10352
10546
  ;// ../../../extensions/default/src/customizations/onDropHandlerCustomization.ts
10353
10547
  /* harmony default export */ const onDropHandlerCustomization = ({
@@ -10418,8 +10612,8 @@ function AboutModalDefault() {
10418
10612
  name
10419
10613
  } = (0,browser_detect_es5/* default */.A)();
10420
10614
  const browser = `${name[0].toUpperCase()}${name.substr(1)} ${version}`;
10421
- const versionNumber = "3.13.0-beta.7";
10422
- const commitHash = "fb7329f3fe0edc04833f15cd515522353d465912";
10615
+ const versionNumber = "3.13.0-beta.70";
10616
+ const commitHash = "9cf3149d2a6111d7e86cdc6ce6f80fab7cd1993d";
10423
10617
  const [main, beta] = versionNumber.split('-');
10424
10618
  return /*#__PURE__*/react.createElement(ui_next_src/* AboutModal */.VTU, {
10425
10619
  className: "w-[400px]"
@@ -10450,16 +10644,50 @@ const {
10450
10644
  defaultLanguage,
10451
10645
  currentLanguage: currentLanguageFn
10452
10646
  } = i18n_src/* default */.A;
10647
+ const MODIFIER_OPTIONS = [{
10648
+ value: '16',
10649
+ label: 'Shift'
10650
+ }, {
10651
+ value: '17',
10652
+ label: 'Ctrl'
10653
+ }, {
10654
+ value: '18',
10655
+ label: 'Alt'
10656
+ }, {
10657
+ value: '91',
10658
+ label: 'Meta'
10659
+ }];
10660
+ const DEFAULT_TOOL_BINDINGS_STORAGE_KEY = 'user-preferred-tool-bindings';
10661
+ function getToolModifier(toolGroupService, toolGroupId, toolName, mouseButton) {
10662
+ if (!toolGroupService) {
10663
+ return null;
10664
+ }
10665
+ const bindings = toolGroupService.getToolBindings(toolGroupId, toolName);
10666
+ if (!bindings?.length) {
10667
+ return null;
10668
+ }
10669
+ const modifierBinding = bindings.find(binding => binding.mouseButton === mouseButton && binding.modifierKey != null && binding.numTouchPoints == null);
10670
+ return modifierBinding?.modifierKey != null ? String(modifierBinding.modifierKey) : null;
10671
+ }
10672
+ function getModifierFromBindings(bindings, mouseButton) {
10673
+ if (!bindings?.length) {
10674
+ return null;
10675
+ }
10676
+ const modifierBinding = bindings.find(binding => binding.mouseButton === mouseButton && binding.modifierKey != null && binding.numTouchPoints == null);
10677
+ return modifierBinding?.modifierKey != null ? String(modifierBinding.modifierKey) : null;
10678
+ }
10453
10679
  function UserPreferencesModalDefault({
10454
10680
  hide
10455
10681
  }) {
10456
10682
  const {
10457
- hotkeysManager
10683
+ hotkeysManager,
10684
+ servicesManager
10458
10685
  } = (0,src/* useSystem */.Jg)();
10459
10686
  const {
10460
10687
  t,
10461
10688
  i18n: i18nextInstance
10462
10689
  } = (0,es/* useTranslation */.Bd)('UserPreferencesModal');
10690
+ const toolGroupService = servicesManager?.services?.toolGroupService;
10463
10691
  const {
10464
10692
  hotkeyDefinitions = {},
10465
10693
  hotkeyDefaults = {}
@@ -10476,9 +10704,12 @@ function UserPreferencesModalDefault({
10476
10704
  const resolvedHotkeyDefaults = Object.keys(hotkeyDefaults).length ? hotkeyDefaults : fallbackHotkeyDefinitions;
10477
10705
  const initialHotkeyDefinitions = Object.keys(hotkeyDefinitions).length ? hotkeyDefinitions : resolvedHotkeyDefaults;
10478
10706
  const currentLanguage = currentLanguageFn();
10707
+ const initialCrosshairModifier = (0,react.useMemo)(() => getToolModifier(toolGroupService, 'mpr', 'Crosshairs', 1), [toolGroupService]);
10708
+ const defaultCrosshairBindings = (0,react.useMemo)(() => toolGroupService?.getDefaultToolBindings?.('mpr', 'Crosshairs'), [toolGroupService]);
10479
10709
  const [state, setState] = (0,react.useState)({
10480
10710
  hotkeyDefinitions: initialHotkeyDefinitions,
10481
- languageValue: currentLanguage.value
10711
+ languageValue: currentLanguage.value,
10712
+ crosshairModifier: initialCrosshairModifier
10482
10713
  });
10483
10714
  const onLanguageChangeHandler = value => {
10484
10715
  setState(state => ({
@@ -10502,9 +10733,17 @@ function UserPreferencesModalDefault({
10502
10733
  setState(state => ({
10503
10734
  ...state,
10504
10735
  languageValue: defaultLanguage.value,
10505
- hotkeyDefinitions: resolvedHotkeyDefaults
10736
+ hotkeyDefinitions: resolvedHotkeyDefaults,
10737
+ crosshairModifier: getModifierFromBindings(defaultCrosshairBindings, 1)
10506
10738
  }));
10507
10739
  hotkeysManager.restoreDefaultBindings();
10740
+ if (toolGroupService && defaultCrosshairBindings?.length) {
10741
+ toolGroupService.setToolBindings('mpr', 'Crosshairs', defaultCrosshairBindings);
10742
+ toolGroupService.applyToolBindings('mpr', 'Crosshairs', {
10743
+ replaceExisting: true
10744
+ });
10745
+ }
10746
+ toolGroupService?.removePersistedToolBindings('mpr', 'Crosshairs');
10508
10747
  };
10509
10748
  const displayNames = react.useMemo(() => {
10510
10749
  if (typeof Intl === 'undefined' || typeof Intl.DisplayNames !== 'function') {
@@ -10561,7 +10800,32 @@ function UserPreferencesModalDefault({
10561
10800
  onChange: newKeys => onHotkeyChangeHandler(id, newKeys),
10562
10801
  placeholder: definition.keys,
10563
10802
  hotkeys: src/* hotkeys */.ot
10564
- })))), /*#__PURE__*/react.createElement(ui_next_src/* FooterAction */.esu, null, /*#__PURE__*/react.createElement(ui_next_src/* FooterAction */.esu.Left, null, /*#__PURE__*/react.createElement(ui_next_src/* FooterAction */.esu.Auxiliary, {
10803
+ }))), state.crosshairModifier != null && /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement(ui_next_src/* UserPreferencesModal */.xMy.SubHeading, null, t('ModifierKeys', {
10804
+ defaultValue: 'Modifier Keys'
10805
+ })), /*#__PURE__*/react.createElement(ui_next_src/* UserPreferencesModal */.xMy.HotkeysGrid, null, /*#__PURE__*/react.createElement("div", {
10806
+ className: "flex items-center justify-between gap-2"
10807
+ }, /*#__PURE__*/react.createElement("span", {
10808
+ className: "text-foreground text-base"
10809
+ }, t('CrosshairsModifier', {
10810
+ defaultValue: 'Crosshairs'
10811
+ })), /*#__PURE__*/react.createElement("div", {
10812
+ className: "flex items-center gap-1.5"
10813
+ }, /*#__PURE__*/react.createElement("span", {
10814
+ className: "text-muted-foreground text-sm"
10815
+ }, t('PlusLeftClick', {
10816
+ defaultValue: 'Left Click +'
10817
+ })), /*#__PURE__*/react.createElement(ui_next_src/* Select */.l6P, {
10818
+ value: state.crosshairModifier,
10819
+ onValueChange: val => setState(s => ({
10820
+ ...s,
10821
+ crosshairModifier: val
10822
+ }))
10823
+ }, /*#__PURE__*/react.createElement(ui_next_src/* SelectTrigger */.bqE, {
10824
+ className: "w-16"
10825
+ }, /*#__PURE__*/react.createElement(ui_next_src/* SelectValue */.yvm, null)), /*#__PURE__*/react.createElement(ui_next_src/* SelectContent */.gCo, null, MODIFIER_OPTIONS.map(opt => /*#__PURE__*/react.createElement(ui_next_src/* SelectItem */.ebT, {
10826
+ key: opt.value,
10827
+ value: opt.value
10828
+ }, opt.label))))))))), /*#__PURE__*/react.createElement(ui_next_src/* FooterAction */.esu, null, /*#__PURE__*/react.createElement(ui_next_src/* FooterAction */.esu.Left, null, /*#__PURE__*/react.createElement(ui_next_src/* FooterAction */.esu.Auxiliary, {
10565
10829
  onClick: onResetHandler
10566
10830
  }, t('Reset to defaults'))), /*#__PURE__*/react.createElement(ui_next_src/* FooterAction */.esu.Right, null, /*#__PURE__*/react.createElement(ui_next_src/* FooterAction */.esu.Secondary, {
10567
10831
  onClick: () => {
@@ -10578,6 +10842,17 @@ function UserPreferencesModalDefault({
10578
10842
  return; // Exit early since we're reloading
10579
10843
  }
10580
10844
  hotkeysManager.setHotkeys(state.hotkeyDefinitions);
10845
+ if (toolGroupService && state.crosshairModifier != null) {
10846
+ const bindings = [{
10847
+ mouseButton: 1,
10848
+ modifierKey: Number(state.crosshairModifier)
10849
+ }];
10850
+ toolGroupService.setToolBindings('mpr', 'Crosshairs', bindings);
10851
+ toolGroupService.applyToolBindings('mpr', 'Crosshairs', {
10852
+ replaceExisting: true
10853
+ });
10854
+ toolGroupService.persistToolBindings('mpr', 'Crosshairs', bindings);
10855
+ }
10581
10856
  src/* hotkeys */.ot.stopRecord();
10582
10857
  src/* hotkeys */.ot.unpause();
10583
10858
  hide();
@@ -10585,13 +10860,15 @@ function UserPreferencesModalDefault({
10585
10860
  }, t('Save')))));
10586
10861
  }
10587
10862
  /* harmony default export */ const userPreferencesCustomization = ({
10588
- 'ohif.userPreferencesModal': UserPreferencesModalDefault
10863
+ 'ohif.userPreferencesModal': UserPreferencesModalDefault,
10864
+ 'ohif.userPreferences.toolBindingsStorageKey': DEFAULT_TOOL_BINDINGS_STORAGE_KEY
10589
10865
  });
10590
10866
  ;// ../../../extensions/default/src/customizations/reportDialogCustomization.tsx
10591
10867
 
10592
10868
 
10593
10869
 
10594
10870
 
10871
+
10595
10872
  function ReportDialog({
10596
10873
  dataSources,
10597
10874
  modality = 'SR',
@@ -10599,11 +10876,16 @@ function ReportDialog({
10599
10876
  minSeriesNumber = 3000,
10600
10877
  hide,
10601
10878
  onSave,
10602
- onCancel
10879
+ onCancel,
10880
+ enableDownload = false
10603
10881
  }) {
10882
+ const {
10883
+ t
10884
+ } = (0,es/* useTranslation */.Bd)('Buttons');
10604
10885
  const {
10605
10886
  servicesManager
10606
10887
  } = (0,src/* useSystem */.Jg)();
10888
+ const actionTakenRef = (0,react.useRef)(false);
10607
10889
  const [selectedDataSource, setSelectedDataSource] = (0,react.useState)(dataSources?.[0]?.value ?? null);
10608
10890
  const {
10609
10891
  displaySetService
@@ -10632,6 +10914,7 @@ function ReportDialog({
10632
10914
  setReportName(newReportName);
10633
10915
  }, [selectedSeries, seriesOptions]);
10634
10916
  const handleSave = (0,react.useCallback)(() => {
10917
+ actionTakenRef.current = true;
10635
10918
  onSave({
10636
10919
  reportName,
10637
10920
  dataSource: selectedDataSource,
@@ -10641,10 +10924,31 @@ function ReportDialog({
10641
10924
  hide();
10642
10925
  }, [selectedDataSource, selectedSeries, reportName, hide, onSave]);
10643
10926
  const handleCancel = (0,react.useCallback)(() => {
10927
+ actionTakenRef.current = true;
10644
10928
  onCancel();
10645
10929
  hide();
10646
10930
  }, [onCancel, hide]);
10931
+ const handleDownload = (0,react.useCallback)(() => {
10932
+ actionTakenRef.current = true;
10933
+ onSave({
10934
+ reportName,
10935
+ dataSource: 'download',
10936
+ priorSeriesNumber: Math.max(...seriesOptions.map(it => it.seriesNumber)),
10937
+ series: selectedSeries
10938
+ });
10939
+ hide();
10940
+ }, [selectedDataSource, selectedSeries, reportName, hide, onSave]);
10941
+
10942
+ // Handles the close dialog button/external close as a cancel
10943
+ (0,react.useEffect)(() => {
10944
+ return () => {
10945
+ if (!actionTakenRef.current) {
10946
+ onCancel();
10947
+ }
10948
+ };
10949
+ }, [onCancel]);
10647
10950
  const showDataSourceSelect = dataSources?.length > 1;
10951
+ const showDownloadButton = enableDownload;
10648
10952
  return /*#__PURE__*/react.createElement("div", {
10649
10953
  className: "text-foreground flex min-w-[400px] max-w-md flex-col"
10650
10954
  }, /*#__PURE__*/react.createElement("div", {
@@ -10701,9 +11005,9 @@ function ReportDialog({
10701
11005
  disabled: !!selectedSeries
10702
11006
  })))), /*#__PURE__*/react.createElement("div", {
10703
11007
  className: "flex justify-end gap-2"
10704
- }, /*#__PURE__*/react.createElement(ui_next_src/* InputDialog */.fa0, null, /*#__PURE__*/react.createElement(ui_next_src/* InputDialog */.fa0.Actions, null, /*#__PURE__*/react.createElement(ui_next_src/* InputDialog */.fa0.ActionsSecondary, {
10705
- onClick: handleCancel
10706
- }, "Cancel"), /*#__PURE__*/react.createElement(ui_next_src/* InputDialog */.fa0.ActionsPrimary, {
11008
+ }, /*#__PURE__*/react.createElement(ui_next_src/* InputDialog */.fa0, null, /*#__PURE__*/react.createElement(ui_next_src/* InputDialog */.fa0.Actions, null, showDownloadButton && /*#__PURE__*/react.createElement(ui_next_src/* InputDialog */.fa0.ActionsSecondary, {
11009
+ onClick: handleDownload
11010
+ }, t('Download')), /*#__PURE__*/react.createElement(ui_next_src/* InputDialog */.fa0.ActionsPrimary, {
10707
11011
  onClick: handleSave
10708
11012
  }, "Save"))))));
10709
11013
  }
@@ -11611,11 +11915,12 @@ function promptLabelAnnotation({
11611
11915
  // EXTERNAL MODULE: ../../../extensions/default/src/Panels/StudyBrowser/PanelStudyBrowserHeader.tsx
11612
11916
  var PanelStudyBrowserHeader = __webpack_require__(3329);
11613
11917
  ;// ../../../extensions/default/src/utils/addIcon.ts
11918
+ /* unused harmony import specifier */ var Icons;
11614
11919
 
11615
11920
 
11616
11921
  /** Adds the icon to both ui and ui-next */
11617
11922
  function addIcon(name, icon) {
11618
- ui_next_src/* Icons */.FI1.addIcon(name, icon);
11923
+ Icons.addIcon(name, icon);
11619
11924
  }
11620
11925
  ;// ../../../extensions/default/src/utils/Toolbox.tsx
11621
11926
  function Toolbox_extends() { return Toolbox_extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, Toolbox_extends.apply(null, arguments); }
@@ -11723,7 +12028,7 @@ function Toolbox({
11723
12028
  })));
11724
12029
  }));
11725
12030
  }), activeToolOptions && /*#__PURE__*/react.createElement("div", {
11726
- className: "bg-primary-dark mt-1 h-auto px-2"
12031
+ className: "bg-muted mt-1 h-auto px-2"
11727
12032
  }, /*#__PURE__*/react.createElement(ui_next_src/* ToolSettings */.k_3, {
11728
12033
  options: activeToolOptions
11729
12034
  }))));
@@ -11807,10 +12112,10 @@ const defaultExtension = {
11807
12112
  /* harmony default export */ const default_src = (defaultExtension);
11808
12113
 
11809
12114
 
11810
- /***/ }),
12115
+ /***/ },
11811
12116
 
11812
- /***/ 96357:
11813
- /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
12117
+ /***/ 96357
12118
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
11814
12119
 
11815
12120
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
11816
12121
  /* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__)
@@ -11825,6 +12130,6 @@ const RESPONSE = {
11825
12130
  };
11826
12131
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (RESPONSE);
11827
12132
 
11828
- /***/ })
12133
+ /***/ }
11829
12134
 
11830
12135
  }]);