@ohif/app 3.8.0-beta.73 → 3.8.0-beta.74

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 (46) hide show
  1. package/dist/{121.bundle.21827fec690c01ee9ab3.js → 121.bundle.bd8acf52b6a7047ae832.js} +2 -2
  2. package/dist/141.bundle.556b4c1e4cab770417ac.js +8620 -0
  3. package/dist/{191.bundle.c0ea2d031ffddeca32c9.js → 183.bundle.25293de927ef032a6695.js} +195 -122
  4. package/dist/{188.bundle.acfe3c0e6eb9cc90aef1.js → 188.bundle.f1b3909e55be12d37c4a.js} +2 -2
  5. package/dist/{987.bundle.e19408decfd59aadd118.js → 217.bundle.9631d914f170f8d7ef63.js} +31558 -39396
  6. package/dist/{295.bundle.3a0d5062d65296c4bf5d.js → 295.bundle.688b6bbff493cd904ae7.js} +2 -2
  7. package/dist/{155.bundle.64e00e96835d61e99c0e.js → 325.bundle.3d260b1a7f80cfc892a0.js} +43 -58
  8. package/dist/{425.bundle.f796ed1020fbed0f1e71.js → 335.bundle.ec53cc58116ef1dc5fa3.js} +132 -518
  9. package/dist/{342.bundle.521c0217f82380c0c2ad.js → 342.bundle.c6165579c4ac3ef0d6a8.js} +2 -2
  10. package/dist/{41.bundle.8b3f6e6f4bd71b85ef14.js → 41.bundle.3c9bb4e3800dcea2c043.js} +28 -29
  11. package/dist/{433.bundle.6f2308ab10593784778c.js → 433.bundle.1474591f213852cffcba.js} +188 -172
  12. package/dist/{290.bundle.952de53057f98e2c5ef0.js → 445.bundle.38c6d2af64e41cd7c614.js} +1 -1049
  13. package/dist/{448.bundle.19df2fef38bb0f6a272a.js → 448.bundle.e6af6868af55a353b12b.js} +16 -22
  14. package/dist/487.bundle.de932b440ffc809978b5.js +1875 -0
  15. package/dist/{530.bundle.f4b7966fb33eafb8cd5d.js → 530.bundle.7c94543955552475c56a.js} +9 -9
  16. package/dist/{540.bundle.32224b29bfa11d1f1cec.js → 540.bundle.31780163f7065fd4d325.js} +15 -15
  17. package/dist/{544.bundle.1110b24e96863d719a95.js → 544.bundle.fcb790bae53294b49b05.js} +8 -8
  18. package/dist/{574.bundle.2b3369042aad5d553463.js → 574.bundle.b4eb8773d7741868e84b.js} +166 -45
  19. package/dist/{594.bundle.61a9f0567260e9bb4480.js → 594.bundle.6c0b915507752363e82a.js} +4 -4
  20. package/dist/{2.bundle.a849401e1fefc0898248.js → 633.bundle.7f782a390a22d9c7ec1d.js} +35 -43
  21. package/dist/{699.bundle.9f4eddf87548c0d0dca3.js → 699.bundle.7642c1505c1685f63897.js} +18 -35
  22. package/dist/702.bundle.963481fbf871984b646f.js +8426 -0
  23. package/dist/722.bundle.afab1fe6bfcd569130ac.js +1083 -0
  24. package/dist/{724.bundle.b57096deac9649aada4b.js → 724.bundle.ad52afcbec7501305d25.js} +20 -11
  25. package/dist/{90.bundle.70f4752bb4ac79aef269.js → 83.bundle.ff7db010621303a71a50.js} +419 -137
  26. package/dist/{862.bundle.47305c27f0fb939c2f97.js → 862.bundle.f49a379497bb3b43a942.js} +3 -3
  27. package/dist/{889.bundle.3816444220909bd1fc78.js → 889.bundle.67ca151a5e2d653b0021.js} +8 -8
  28. package/dist/{595.bundle.e8ff2d0672cb195d4ab8.js → 896.bundle.ba0b4c73e2331281159f.js} +686 -57
  29. package/dist/{905.bundle.2dd7f62cb6e49851926b.js → 905.bundle.e67fd55073b8ff735ed5.js} +4 -4
  30. package/dist/{907.bundle.d22edc6203167e985ab3.js → 907.bundle.0167da9471dcfa5c862e.js} +2 -2
  31. package/dist/94.bundle.ccec301dfb972a375ecc.js +784 -0
  32. package/dist/{961.bundle.f207f1ac54a174e67d82.js → 961.bundle.711da9767a4e31ea5aef.js} +2 -2
  33. package/dist/{app.bundle.5e5ee16c43a68961e8c4.js → app.bundle.c0c40b901a1bf1043f08.js} +98584 -89435
  34. package/dist/app.bundle.css +5 -4
  35. package/dist/cornerstoneDICOMImageLoader.min.js +1 -1
  36. package/dist/cornerstoneDICOMImageLoader.min.js.map +1 -1
  37. package/dist/histogram-worker.bundle.829e14ec12c2b41a4323.js +359 -0
  38. package/dist/index.html +1 -1
  39. package/dist/{polySeg.bundle.fe47718e6a8414f175b1.js → polySeg.bundle.c503e9460cef894737cd.js} +3 -6
  40. package/dist/sw.js +1 -1
  41. package/package.json +20 -19
  42. package/dist/425.css +0 -2
  43. /package/dist/{164.bundle.6b98e9caf53620fbd6ca.js → 164.bundle.55df0a2c8b3569d8e1f9.js} +0 -0
  44. /package/dist/{155.css → 325.css} +0 -0
  45. /package/dist/{2.css → 633.css} +0 -0
  46. /package/dist/{595.css → 896.css} +0 -0
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
- (globalThis["webpackChunk"] = globalThis["webpackChunk"] || []).push([[425,481],{
2
+ (globalThis["webpackChunk"] = globalThis["webpackChunk"] || []).push([[335],{
3
3
 
4
- /***/ 42048:
4
+ /***/ 27335:
5
5
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
6
6
 
7
7
  // ESM COMPAT FLAG
@@ -723,10 +723,10 @@ var react = __webpack_require__(41766);
723
723
  // EXTERNAL MODULE: ../../../node_modules/prop-types/index.js
724
724
  var prop_types = __webpack_require__(11374);
725
725
  var prop_types_default = /*#__PURE__*/__webpack_require__.n(prop_types);
726
- // EXTERNAL MODULE: ../../ui/src/index.js + 542 modules
727
- var src = __webpack_require__(48804);
728
- // EXTERNAL MODULE: ../../core/src/index.ts + 68 modules
729
- var core_src = __webpack_require__(85073);
726
+ // EXTERNAL MODULE: ../../ui/src/index.js + 785 modules
727
+ var src = __webpack_require__(5085);
728
+ // EXTERNAL MODULE: ../../core/src/index.ts + 70 modules
729
+ var core_src = __webpack_require__(55411);
730
730
  // EXTERNAL MODULE: ../../../node_modules/react-i18next/dist/es/index.js + 15 modules
731
731
  var es = __webpack_require__(80619);
732
732
  ;// CONCATENATED MODULE: ../../../extensions/tmtv/src/Panels/PanelPetSUV.tsx
@@ -970,318 +970,22 @@ PanelPetSUV.propTypes = {
970
970
  }).isRequired
971
971
  }).isRequired
972
972
  };
973
- // EXTERNAL MODULE: ../../../extensions/default/src/index.ts + 78 modules
974
- var default_src = __webpack_require__(54090);
975
- ;// CONCATENATED MODULE: ../../../extensions/tmtv/src/Panels/PanelROIThresholdSegmentation/segmentationEditHandler.tsx
976
-
977
-
978
- function segmentationItemEditHandler({
979
- id,
980
- servicesManager
981
- }) {
982
- const {
983
- segmentationService,
984
- uiDialogService
985
- } = servicesManager.services;
986
- const segmentation = segmentationService.getSegmentation(id);
987
- const onSubmitHandler = ({
988
- action,
989
- value
990
- }) => {
991
- switch (action.id) {
992
- case 'save':
993
- {
994
- segmentationService.addOrUpdateSegmentation({
995
- ...segmentation,
996
- ...value
997
- }, false,
998
- // don't suppress event
999
- true // it should update cornerstone
1000
- );
1001
- }
1002
- }
1003
- uiDialogService.dismiss({
1004
- id: 'enter-annotation'
1005
- });
1006
- };
1007
- uiDialogService.create({
1008
- id: 'enter-annotation',
1009
- centralize: true,
1010
- isDraggable: false,
1011
- showOverlay: true,
1012
- content: src/* Dialog */.lG,
1013
- contentProps: {
1014
- title: 'Enter your Segmentation',
1015
- noCloseButton: true,
1016
- value: {
1017
- label: segmentation.label || ''
1018
- },
1019
- body: ({
1020
- value,
1021
- setValue
1022
- }) => {
1023
- const onChangeHandler = event => {
1024
- event.persist();
1025
- setValue(value => ({
1026
- ...value,
1027
- label: event.target.value
1028
- }));
1029
- };
1030
- const onKeyPressHandler = event => {
1031
- if (event.key === 'Enter') {
1032
- onSubmitHandler({
1033
- value,
1034
- action: {
1035
- id: 'save'
1036
- }
1037
- });
1038
- }
1039
- };
1040
- return /*#__PURE__*/react.createElement(src/* Input */.pd, {
1041
- autoFocus: true,
1042
- className: "border-primary-main bg-black",
1043
- type: "text",
1044
- containerClassName: "mr-2",
1045
- value: value.label,
1046
- onChange: onChangeHandler,
1047
- onKeyPress: onKeyPressHandler
1048
- });
1049
- },
1050
- actions: [{
1051
- id: 'cancel',
1052
- text: 'Cancel',
1053
- type: src/* ButtonEnums.type */.Ny.NW.secondary
1054
- }, {
1055
- id: 'save',
1056
- text: 'Save',
1057
- type: src/* ButtonEnums.type */.Ny.NW.primary
1058
- }],
1059
- onSubmit: onSubmitHandler
1060
- }
1061
- });
1062
- }
1063
- /* harmony default export */ const segmentationEditHandler = (segmentationItemEditHandler);
1064
- ;// CONCATENATED MODULE: ../../../extensions/tmtv/src/Panels/PanelROIThresholdSegmentation/ExportReports.tsx
1065
-
1066
-
1067
-
1068
- function ExportReports({
1069
- segmentations,
1070
- tmtvValue,
1071
- config,
1072
- commandsManager
1073
- }) {
1074
- const {
1075
- t
1076
- } = (0,es/* useTranslation */.Bd)('PanelSUVExport');
1077
- return /*#__PURE__*/react.createElement(react.Fragment, null, segmentations?.length ? /*#__PURE__*/react.createElement("div", {
1078
- className: "mt-4 flex justify-center space-x-2"
1079
- }, /*#__PURE__*/react.createElement(src/* LegacyButtonGroup */.xA, {
1080
- color: "black",
1081
- size: "inherit"
1082
- }, /*#__PURE__*/react.createElement(src/* LegacyButton */._H, {
1083
- className: "px-2 py-2 text-base",
1084
- disabled: tmtvValue === null,
1085
- onClick: () => {
1086
- commandsManager.runCommand('exportTMTVReportCSV', {
1087
- segmentations,
1088
- tmtv: tmtvValue,
1089
- config
1090
- });
1091
- }
1092
- }, t('Export CSV'))), /*#__PURE__*/react.createElement(src/* LegacyButtonGroup */.xA, {
1093
- color: "black",
1094
- size: "inherit"
1095
- }, /*#__PURE__*/react.createElement(src/* LegacyButton */._H, {
1096
- className: "px-2 py-2 text-base",
1097
- onClick: () => {
1098
- commandsManager.runCommand('createTMTVRTReport');
1099
- },
1100
- disabled: tmtvValue === null
1101
- }, t('Create RT Report')))) : null);
1102
- }
1103
- /* harmony default export */ const PanelROIThresholdSegmentation_ExportReports = (ExportReports);
1104
- ;// CONCATENATED MODULE: ../../../extensions/tmtv/src/Panels/PanelROIThresholdSegmentation/callInputDialog.tsx
1105
-
1106
-
1107
- function callInputDialog(uiDialogService, label, callback) {
1108
- const dialogId = 'enter-segment-label';
1109
- const onSubmitHandler = ({
1110
- action,
1111
- value
1112
- }) => {
1113
- switch (action.id) {
1114
- case 'save':
1115
- callback(value.label, action.id);
1116
- break;
1117
- case 'cancel':
1118
- callback('', action.id);
1119
- break;
1120
- }
1121
- uiDialogService.dismiss({
1122
- id: dialogId
1123
- });
1124
- };
1125
- if (uiDialogService) {
1126
- uiDialogService.create({
1127
- id: dialogId,
1128
- centralize: true,
1129
- isDraggable: false,
1130
- showOverlay: true,
1131
- content: src/* Dialog */.lG,
1132
- contentProps: {
1133
- title: 'Segment',
1134
- value: {
1135
- label
1136
- },
1137
- noCloseButton: true,
1138
- onClose: () => uiDialogService.dismiss({
1139
- id: dialogId
1140
- }),
1141
- actions: [{
1142
- id: 'cancel',
1143
- text: 'Cancel',
1144
- type: src/* ButtonEnums.type */.Ny.NW.secondary
1145
- }, {
1146
- id: 'save',
1147
- text: 'Confirm',
1148
- type: src/* ButtonEnums.type */.Ny.NW.primary
1149
- }],
1150
- onSubmit: onSubmitHandler,
1151
- body: ({
1152
- value,
1153
- setValue
1154
- }) => {
1155
- return /*#__PURE__*/react.createElement(src/* Input */.pd, {
1156
- label: "Enter the segment label",
1157
- labelClassName: "text-white text-[14px] leading-[1.2]",
1158
- autoFocus: true,
1159
- className: "border-primary-main bg-black",
1160
- type: "text",
1161
- value: value.label,
1162
- onChange: event => {
1163
- event.persist();
1164
- setValue(value => ({
1165
- ...value,
1166
- label: event.target.value
1167
- }));
1168
- },
1169
- onKeyPress: event => {
1170
- if (event.key === 'Enter') {
1171
- onSubmitHandler({
1172
- value,
1173
- action: {
1174
- id: 'save'
1175
- }
1176
- });
1177
- }
1178
- }
1179
- });
1180
- }
1181
- }
1182
- });
1183
- }
1184
- }
1185
- /* harmony default export */ const PanelROIThresholdSegmentation_callInputDialog = (callInputDialog);
1186
- // EXTERNAL MODULE: ../../../node_modules/react-color/es/index.js + 219 modules
1187
- var react_color_es = __webpack_require__(13726);
1188
- ;// CONCATENATED MODULE: ../../../extensions/tmtv/src/Panels/PanelROIThresholdSegmentation/colorPickerDialog.css
1189
- // extracted by mini-css-extract-plugin
1190
-
1191
- ;// CONCATENATED MODULE: ../../../extensions/tmtv/src/Panels/PanelROIThresholdSegmentation/colorPickerDialog.tsx
1192
-
1193
-
1194
-
1195
-
1196
- function callColorPickerDialog(uiDialogService, rgbaColor, callback) {
1197
- const dialogId = 'pick-color';
1198
- const onSubmitHandler = ({
1199
- action,
1200
- value
1201
- }) => {
1202
- switch (action.id) {
1203
- case 'save':
1204
- callback(value.rgbaColor, action.id);
1205
- break;
1206
- case 'cancel':
1207
- callback('', action.id);
1208
- break;
1209
- }
1210
- uiDialogService.dismiss({
1211
- id: dialogId
1212
- });
1213
- };
1214
- if (uiDialogService) {
1215
- uiDialogService.create({
1216
- id: dialogId,
1217
- centralize: true,
1218
- isDraggable: false,
1219
- showOverlay: true,
1220
- content: src/* Dialog */.lG,
1221
- contentProps: {
1222
- title: 'Segment Color',
1223
- value: {
1224
- rgbaColor
1225
- },
1226
- noCloseButton: true,
1227
- onClose: () => uiDialogService.dismiss({
1228
- id: dialogId
1229
- }),
1230
- actions: [{
1231
- id: 'cancel',
1232
- text: 'Cancel',
1233
- type: 'primary'
1234
- }, {
1235
- id: 'save',
1236
- text: 'Save',
1237
- type: 'secondary'
1238
- }],
1239
- onSubmit: onSubmitHandler,
1240
- body: ({
1241
- value,
1242
- setValue
1243
- }) => {
1244
- const handleChange = color => {
1245
- setValue({
1246
- rgbaColor: color.rgb
1247
- });
1248
- };
1249
- return /*#__PURE__*/react.createElement(react_color_es/* ChromePicker */.xk, {
1250
- color: value.rgbaColor,
1251
- onChange: handleChange,
1252
- presetColors: [],
1253
- width: 300
1254
- });
1255
- }
1256
- }
1257
- });
1258
- }
1259
- }
1260
- /* harmony default export */ const colorPickerDialog = (callColorPickerDialog);
1261
- ;// CONCATENATED MODULE: ../../../extensions/tmtv/src/Panels/PanelROIThresholdSegmentation/PanelROIThresholdSegmentation.tsx
1262
-
1263
-
1264
-
1265
-
973
+ ;// CONCATENATED MODULE: ../../../extensions/tmtv/src/Panels/PanelROIThresholdSegmentation/PanelROIThresholdExport.tsx
1266
974
 
1267
975
 
1268
976
 
1269
977
 
1270
978
  function PanelRoiThresholdSegmentation({
1271
979
  servicesManager,
1272
- commandsManager,
1273
- extensionManager
980
+ commandsManager
1274
981
  }) {
1275
982
  const {
1276
- segmentationService,
1277
- viewportGridService,
1278
- uiDialogService
983
+ segmentationService
1279
984
  } = servicesManager.services;
1280
- const [selectedSegmentationId, setSelectedSegmentationId] = (0,react.useState)(null);
985
+ const {
986
+ t
987
+ } = (0,es/* useTranslation */.Bd)('PanelSUVExport');
1281
988
  const [segmentations, setSegmentations] = (0,react.useState)(() => segmentationService.getSegmentations());
1282
- const runCommand = (0,react.useCallback)((commandName, commandOptions = {}) => {
1283
- return commandsManager.runCommand(commandName, commandOptions);
1284
- }, [commandsManager]);
1285
989
 
1286
990
  /**
1287
991
  * Update UI based on segmentation changes (added, removed, updated)
@@ -1307,178 +1011,41 @@ function PanelRoiThresholdSegmentation({
1307
1011
  });
1308
1012
  };
1309
1013
  }, []);
1310
- const onSegmentationClick = segmentationId => {
1311
- segmentationService.setActiveSegmentationForToolGroup(segmentationId);
1312
- setSelectedSegmentationId(segmentationId);
1313
- };
1314
- const onSegmentationAdd = async () => {
1315
- runCommand('createNewLabelmapFromPT').then(segmentationId => {
1316
- setSelectedSegmentationId(segmentationId);
1317
- });
1318
- };
1319
- const onSegmentAdd = segmentationId => {
1320
- segmentationService.addSegment(segmentationId);
1321
- };
1322
- const getToolGroupIds = segmentationId => {
1323
- const toolGroupIds = segmentationService.getToolGroupIdsWithSegmentation(segmentationId);
1324
- return toolGroupIds;
1325
- };
1326
- const onSegmentClick = (segmentationId, segmentIndex) => {
1327
- segmentationService.setActiveSegment(segmentationId, segmentIndex);
1328
- const toolGroupIds = getToolGroupIds(segmentationId);
1329
- toolGroupIds.forEach(toolGroupId => {
1330
- // const toolGroupId =
1331
- segmentationService.setActiveSegmentationForToolGroup(segmentationId, toolGroupId);
1332
- segmentationService.jumpToSegmentCenter(segmentationId, segmentIndex, toolGroupId);
1333
- });
1334
- };
1335
- const _setSegmentationConfiguration = (0,react.useCallback)((segmentationId, key, value) => {
1336
- segmentationService.setConfiguration({
1337
- segmentationId,
1338
- [key]: value
1339
- });
1340
- }, [segmentationService]);
1341
- const onToggleSegmentVisibility = (segmentationId, segmentIndex) => {
1342
- const segmentation = segmentationService.getSegmentation(segmentationId);
1343
- const segmentInfo = segmentation.segments[segmentIndex];
1344
- const isVisible = !segmentInfo.isVisible;
1345
- const toolGroupIds = getToolGroupIds(segmentationId);
1346
- toolGroupIds.forEach(toolGroupId => {
1347
- segmentationService.setSegmentVisibility(segmentationId, segmentIndex, isVisible, toolGroupId);
1348
- });
1349
- };
1350
- const onSegmentDelete = (segmentationId, segmentIndex) => {
1351
- segmentationService.removeSegment(segmentationId, segmentIndex);
1352
- };
1353
- const onSegmentEdit = (segmentationId, segmentIndex) => {
1354
- const segmentation = segmentationService.getSegmentation(segmentationId);
1355
- const segment = segmentation.segments[segmentIndex];
1356
- const {
1357
- label
1358
- } = segment;
1359
- PanelROIThresholdSegmentation_callInputDialog(uiDialogService, label, (label, actionId) => {
1360
- if (label === '') {
1361
- return;
1362
- }
1363
- segmentationService.setSegmentLabel(segmentationId, segmentIndex, label);
1364
- });
1365
- };
1366
- const onToggleSegmentLock = (segmentationId, segmentIndex) => {
1367
- segmentationService.toggleSegmentLocked(segmentationId, segmentIndex);
1368
- };
1369
- const onSegmentColorClick = (segmentationId, segmentIndex) => {
1370
- const segmentation = segmentationService.getSegmentation(segmentationId);
1371
- const segment = segmentation.segments[segmentIndex];
1372
- const {
1373
- color,
1374
- opacity
1375
- } = segment;
1376
- const rgbaColor = {
1377
- r: color[0],
1378
- g: color[1],
1379
- b: color[2],
1380
- a: opacity / 255.0
1381
- };
1382
- colorPickerDialog(uiDialogService, rgbaColor, (newRgbaColor, actionId) => {
1383
- if (actionId === 'cancel') {
1384
- return;
1385
- }
1386
- segmentationService.setSegmentRGBAColor(segmentationId, segmentIndex, [newRgbaColor.r, newRgbaColor.g, newRgbaColor.b, newRgbaColor.a * 255.0]);
1387
- });
1388
- };
1389
- const storeSegmentation = async segmentationId => {
1390
- const datasources = extensionManager.getActiveDataSource();
1391
- const displaySetInstanceUIDs = await (0,default_src.createReportAsync)({
1392
- servicesManager,
1393
- getReport: () => commandsManager.runCommand('storeSegmentation', {
1394
- segmentationId,
1395
- dataSource: datasources[0]
1396
- }),
1397
- reportType: 'Segmentation'
1398
- });
1399
-
1400
- // Show the exported report in the active viewport as read only (similar to SR)
1401
- if (displaySetInstanceUIDs) {
1402
- // clear the segmentation that we exported, similar to the storeMeasurement
1403
- // where we remove the measurements and prompt again the user if they would like
1404
- // to re-read the measurements in a SR read only viewport
1405
- segmentationService.remove(segmentationId);
1406
- viewportGridService.setDisplaySetsForViewport({
1407
- viewportId: viewportGridService.getActiveViewportId(),
1408
- displaySetInstanceUIDs
1409
- });
1410
- }
1411
- };
1412
- const onSegmentationDownloadRTSS = segmentationId => {
1413
- commandsManager.runCommand('downloadRTSS', {
1414
- segmentationId
1415
- });
1416
- };
1417
- const onSegmentationDownload = segmentationId => {
1418
- commandsManager.runCommand('downloadSegmentation', {
1419
- segmentationId
1420
- });
1421
- };
1422
1014
  const tmtvValue = segmentations?.[0]?.cachedStats?.tmtv?.value || null;
1423
1015
  const config = segmentations?.[0]?.cachedStats?.tmtv?.config || {};
1424
- return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
1425
- className: "flex flex-col"
1426
- }, /*#__PURE__*/react.createElement("div", {
1427
- className: "invisible-scrollbar overflow-y-auto overflow-x-hidden"
1428
- }, /*#__PURE__*/react.createElement("div", {
1429
- className: "flex min-h-0 flex-col bg-black text-[13px] font-[300]"
1430
- }, /*#__PURE__*/react.createElement(src/* SegmentationGroupTableExpanded */.fO, {
1431
- disableEditing: false,
1432
- showAddSegmentation: true,
1433
- showAddSegment: false,
1434
- showDeleteSegment: true,
1435
- segmentations: segmentations,
1436
- onSegmentationAdd: onSegmentationAdd,
1437
- onSegmentationClick: onSegmentationClick,
1438
- onToggleSegmentationVisibility: id => {
1439
- segmentationService.toggleSegmentationVisibility(id);
1440
- },
1441
- onToggleSegmentVisibility: onToggleSegmentVisibility,
1442
- onSegmentationDelete: id => {
1443
- segmentationService.remove(id);
1444
- },
1445
- onSegmentationEdit: id => {
1446
- segmentationEditHandler({
1447
- id,
1448
- servicesManager
1016
+ const actions = [{
1017
+ label: 'Export CSV',
1018
+ onClick: () => {
1019
+ commandsManager.runCommand('exportTMTVReportCSV', {
1020
+ segmentations,
1021
+ tmtv: tmtvValue,
1022
+ config
1449
1023
  });
1450
1024
  },
1451
- segmentationConfig: {
1452
- initialConfig: segmentationService.getConfiguration()
1025
+ disabled: tmtvValue === null
1026
+ }, {
1027
+ label: 'Create RT Report',
1028
+ onClick: () => {
1029
+ commandsManager.runCommand('createTMTVRTReport');
1453
1030
  },
1454
- onSegmentAdd: onSegmentAdd,
1455
- onSegmentClick: onSegmentClick,
1456
- onSegmentDelete: onSegmentDelete,
1457
- onSegmentEdit: onSegmentEdit,
1458
- onToggleSegmentLock: onToggleSegmentLock,
1459
- onSegmentColorClick: onSegmentColorClick,
1460
- storeSegmentation: storeSegmentation,
1461
- onSegmentationDownloadRTSS: onSegmentationDownloadRTSS,
1462
- onSegmentationDownload: onSegmentationDownload,
1463
- setRenderOutline: value => _setSegmentationConfiguration(selectedSegmentationId, 'renderOutline', value),
1464
- setOutlineOpacityActive: value => _setSegmentationConfiguration(selectedSegmentationId, 'outlineOpacity', value),
1465
- setRenderFill: value => _setSegmentationConfiguration(selectedSegmentationId, 'renderFill', value),
1466
- setRenderInactiveSegmentations: value => _setSegmentationConfiguration(selectedSegmentationId, 'renderInactiveSegmentations', value),
1467
- setOutlineWidthActive: value => _setSegmentationConfiguration(selectedSegmentationId, 'outlineWidthActive', value),
1468
- setFillAlpha: value => _setSegmentationConfiguration(selectedSegmentationId, 'fillAlpha', value),
1469
- setFillAlphaInactive: value => _setSegmentationConfiguration(selectedSegmentationId, 'fillAlphaInactive', value)
1470
- })), tmtvValue !== null ? /*#__PURE__*/react.createElement("div", {
1031
+ disabled: tmtvValue === null
1032
+ }];
1033
+ return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
1034
+ className: "mt-1 flex flex-col"
1035
+ }, /*#__PURE__*/react.createElement("div", {
1036
+ className: "invisible-scrollbar overflow-y-auto overflow-x-hidden"
1037
+ }, tmtvValue !== null ? /*#__PURE__*/react.createElement("div", {
1471
1038
  className: "bg-secondary-dark mt-1 flex items-baseline justify-between px-2 py-1"
1472
1039
  }, /*#__PURE__*/react.createElement("span", {
1473
1040
  className: "text-base font-bold uppercase tracking-widest text-white"
1474
1041
  }, 'TMTV:'), /*#__PURE__*/react.createElement("div", {
1475
1042
  className: "text-white"
1476
- }, `${tmtvValue} mL`)) : null, /*#__PURE__*/react.createElement(PanelROIThresholdSegmentation_ExportReports, {
1477
- segmentations: segmentations,
1478
- tmtvValue: tmtvValue,
1479
- config: config,
1480
- commandsManager: commandsManager
1481
- }))), /*#__PURE__*/react.createElement("div", {
1043
+ }, `${tmtvValue} mL`)) : null, /*#__PURE__*/react.createElement("div", {
1044
+ className: "mt-1 flex justify-center"
1045
+ }, /*#__PURE__*/react.createElement(src/* ActionButtons */.wr, {
1046
+ actions: actions,
1047
+ t: t
1048
+ })))), /*#__PURE__*/react.createElement("div", {
1482
1049
  className: "absolute bottom-1 flex cursor-pointer items-center justify-center text-blue-400 opacity-50 hover:opacity-80",
1483
1050
  onClick: () => {
1484
1051
  // navigate to a url in a new tab
@@ -1535,17 +1102,19 @@ function getPanelModule({
1535
1102
  servicesManager: servicesManager
1536
1103
  });
1537
1104
  };
1538
- const wrappedROIThresholdSeg = () => {
1105
+ const wrappedROIThresholdToolbox = () => {
1539
1106
  return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement(src/* Toolbox */.OO, {
1540
1107
  commandsManager: commandsManager,
1541
1108
  servicesManager: servicesManager,
1542
1109
  extensionManager: extensionManager,
1543
- buttonSectionId: "tmtvToolbox",
1110
+ buttonSectionId: "ROIThresholdToolbox",
1544
1111
  title: "Threshold Tools"
1545
- }), /*#__PURE__*/react.createElement(PanelROIThresholdSegmentation, {
1112
+ }));
1113
+ };
1114
+ const wrappedROIThresholdExport = () => {
1115
+ return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement(PanelROIThresholdSegmentation, {
1546
1116
  commandsManager: commandsManager,
1547
- servicesManager: servicesManager,
1548
- extensionManager: extensionManager
1117
+ servicesManager: servicesManager
1549
1118
  }));
1550
1119
  };
1551
1120
  return [{
@@ -1555,20 +1124,26 @@ function getPanelModule({
1555
1124
  label: 'Patient Info',
1556
1125
  component: wrappedPanelPetSuv
1557
1126
  }, {
1558
- name: 'ROIThresholdSeg',
1127
+ name: 'tmtvBox',
1128
+ iconName: 'tab-segmentation',
1129
+ iconLabel: 'Segmentation',
1130
+ label: 'Segmentation Toolbox',
1131
+ component: wrappedROIThresholdToolbox
1132
+ }, {
1133
+ name: 'tmtvExport',
1559
1134
  iconName: 'tab-segmentation',
1560
1135
  iconLabel: 'Segmentation',
1561
- label: 'Segmentation',
1562
- component: wrappedROIThresholdSeg
1136
+ label: 'Segmentation Export',
1137
+ component: wrappedROIThresholdExport
1563
1138
  }];
1564
1139
  }
1565
1140
  /* harmony default export */ const src_getPanelModule = (getPanelModule);
1566
- // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/tools/dist/esm/index.js + 16 modules
1567
- var esm = __webpack_require__(20767);
1141
+ // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/tools/dist/esm/index.js + 18 modules
1142
+ var esm = __webpack_require__(24542);
1568
1143
  ;// CONCATENATED MODULE: ../../../extensions/tmtv/src/utils/measurementServiceMappings/constants/supportedTools.js
1569
1144
  /* harmony default export */ const supportedTools = (['RectangleROIStartEndThreshold']);
1570
- // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/core/dist/esm/index.js + 383 modules
1571
- var dist_esm = __webpack_require__(50719);
1145
+ // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/core/dist/esm/index.js + 327 modules
1146
+ var dist_esm = __webpack_require__(44656);
1572
1147
  ;// CONCATENATED MODULE: ../../../extensions/tmtv/src/utils/measurementServiceMappings/utils/getSOPInstanceAttributes.js
1573
1148
 
1574
1149
  function getSOPInstanceAttributes(imageId) {
@@ -1687,8 +1262,8 @@ function init({
1687
1262
  const csTools3DVer1MeasurementSource = measurementService.getSource(CORNERSTONE_3D_TOOLS_SOURCE_NAME, CORNERSTONE_3D_TOOLS_SOURCE_VERSION);
1688
1263
  measurementService.addMapping(csTools3DVer1MeasurementSource, 'RectangleROIStartEndThreshold', RectangleROIStartEndThreshold.matchingCriteria, RectangleROIStartEndThreshold.toAnnotation, RectangleROIStartEndThreshold.toMeasurement);
1689
1264
  }
1690
- // EXTERNAL MODULE: ../../../node_modules/gl-matrix/esm/index.js + 10 modules
1691
- var gl_matrix_esm = __webpack_require__(83636);
1265
+ // EXTERNAL MODULE: ../../../node_modules/gl-matrix/esm/index.js + 1 modules
1266
+ var gl_matrix_esm = __webpack_require__(44753);
1692
1267
  ;// CONCATENATED MODULE: ../../../extensions/tmtv/src/utils/getThresholdValue.ts
1693
1268
 
1694
1269
  function getRoiStats(referencedVolume, annotations) {
@@ -1770,21 +1345,21 @@ function calculateSuvPeak(labelmap, referenceVolume, annotations, segmentIndex =
1770
1345
  if (referenceVolume.metadata.Modality !== 'PT') {
1771
1346
  return;
1772
1347
  }
1773
- if (labelmap.scalarData.length !== referenceVolume.scalarData.length) {
1348
+ const labelmapData = labelmap.getScalarData();
1349
+ const referenceVolumeData = referenceVolume.getScalarData();
1350
+ if (labelmapData.length !== referenceVolumeData.length) {
1774
1351
  throw new Error('labelmap and referenceVolume must have the same number of pixels');
1775
1352
  }
1776
1353
  const {
1777
- scalarData: labelmapData,
1778
1354
  dimensions,
1779
1355
  imageData: labelmapImageData
1780
1356
  } = labelmap;
1781
1357
  const {
1782
- scalarData: referenceVolumeData,
1783
1358
  imageData: referenceVolumeImageData
1784
1359
  } = referenceVolume;
1785
1360
  let boundsIJK;
1786
1361
  // Todo: using the first annotation for now
1787
- if (annotations && annotations[0].data?.cachedStats) {
1362
+ if (annotations?.length && annotations[0].data?.cachedStats) {
1788
1363
  const {
1789
1364
  projectionPoints
1790
1365
  } = annotations[0].data.cachedStats;
@@ -1889,7 +1464,7 @@ function calculateTMTV(labelmaps, segmentIndex = 1) {
1889
1464
  }
1890
1465
  /* harmony default export */ const utils_calculateTMTV = (calculateTMTV);
1891
1466
  ;// CONCATENATED MODULE: ../../../extensions/tmtv/src/utils/createAndDownloadTMTVReport.js
1892
- function createAndDownloadTMTVReport(segReport, additionalReportRows) {
1467
+ function createAndDownloadTMTVReport(segReport, additionalReportRows, options = {}) {
1893
1468
  const firstReport = segReport[Object.keys(segReport)[0]];
1894
1469
  const columns = Object.keys(firstReport);
1895
1470
  const csv = [columns.join(',')];
@@ -1925,7 +1500,7 @@ function createAndDownloadTMTVReport(segReport, additionalReportRows) {
1925
1500
  const url = URL.createObjectURL(blob);
1926
1501
  const a = document.createElement('a');
1927
1502
  a.href = url;
1928
- a.download = `${firstReport.PatientID}_tmtv.csv`;
1503
+ a.download = options.filename ?? `${firstReport.PatientID}_tmtv.csv`;
1929
1504
  a.click();
1930
1505
  }
1931
1506
  // EXTERNAL MODULE: ../../../node_modules/dcmjs/build/dcmjs.es.js
@@ -1963,7 +1538,7 @@ function dicomRTAnnotationExport(annotations) {
1963
1538
 
1964
1539
 
1965
1540
  const commandsModule_metadataProvider = core_src.classes.MetadataProvider;
1966
- const RECTANGLE_ROI_THRESHOLD_MANUAL = 'RectangleROIStartEndThreshold';
1541
+ const RECTANGLE_ROI_THRESHOLD_MANUAL_TOOL_IDS = ['RectangleROIStartEndThreshold', 'RectangleROIThreshold'];
1967
1542
  const LABELMAP = esm.Enums.SegmentationRepresentations.Labelmap;
1968
1543
  const commandsModule = ({
1969
1544
  servicesManager,
@@ -2011,6 +1586,12 @@ const commandsModule = ({
2011
1586
  });
2012
1587
  return toolGroupIds;
2013
1588
  }
1589
+ function _getAnnotationsSelectedByToolNames(toolNames) {
1590
+ return toolNames.reduce((allAnnotationUIDs, toolName) => {
1591
+ const annotationUIDs = esm.annotation.selection.getAnnotationsSelectedByToolName(toolName);
1592
+ return allAnnotationUIDs.concat(annotationUIDs);
1593
+ }, []);
1594
+ }
2014
1595
  const actions = {
2015
1596
  getMatchingPTDisplaySet: ({
2016
1597
  viewportMatchDetails
@@ -2062,7 +1643,9 @@ const commandsModule = ({
2062
1643
  };
2063
1644
  return metadata;
2064
1645
  },
2065
- createNewLabelmapFromPT: async () => {
1646
+ createNewLabelmapFromPT: async ({
1647
+ label
1648
+ }) => {
2066
1649
  // Create a segmentation of the same resolution as the source data
2067
1650
  // using volumeLoader.createAndCacheDerivedVolume.
2068
1651
  const {
@@ -2127,23 +1710,52 @@ const commandsModule = ({
2127
1710
  const {
2128
1711
  referencedVolumeId
2129
1712
  } = dist_esm.cache.getVolume(segVolumeId);
1713
+ const annotationUIDs = _getAnnotationsSelectedByToolNames(RECTANGLE_ROI_THRESHOLD_MANUAL_TOOL_IDS);
1714
+ if (annotationUIDs.length === 0) {
1715
+ uiNotificationService.show({
1716
+ title: 'Commands Module',
1717
+ message: 'No ROIThreshold Tool is Selected',
1718
+ type: 'error'
1719
+ });
1720
+ return;
1721
+ }
2130
1722
  const labelmapVolume = dist_esm.cache.getVolume(segmentationId);
2131
- const referencedVolume = dist_esm.cache.getVolume(referencedVolumeId);
1723
+ let referencedVolume = dist_esm.cache.getVolume(referencedVolumeId);
2132
1724
  const ctReferencedVolume = dist_esm.cache.getVolume(ctVolumeId);
1725
+
1726
+ // check if viewport is
1727
+
2133
1728
  if (!referencedVolume) {
2134
1729
  throw new Error('No Reference volume found');
2135
1730
  }
2136
1731
  if (!labelmapVolume) {
2137
1732
  throw new Error('No Reference labelmap found');
2138
1733
  }
2139
- const annotationUIDs = esm.annotation.selection.getAnnotationsSelectedByToolName(RECTANGLE_ROI_THRESHOLD_MANUAL);
2140
- if (annotationUIDs.length === 0) {
2141
- uiNotificationService.show({
2142
- title: 'Commands Module',
2143
- message: 'No ROIThreshold Tool is Selected',
2144
- type: 'error'
1734
+ const annotation = esm.annotation.state.getAnnotation(annotationUIDs[0]);
1735
+ const {
1736
+ metadata: {
1737
+ enabledElement: {
1738
+ viewport
1739
+ }
1740
+ }
1741
+ } = annotation;
1742
+ const showingReferenceVolume = viewport.hasVolumeId(referencedVolumeId);
1743
+ if (!showingReferenceVolume) {
1744
+ // if the reference volume is not being displayed, we can't
1745
+ // rely on it for thresholding, we have couple of options here
1746
+ // 1. We choose whatever volume is being displayed
1747
+ // 2. We check if it is a fusion viewport, we pick the volume
1748
+ // that matches the size and dimensions of the labelmap. This might
1749
+ // happen if the 4D PT is converted to a computed volume and displayed
1750
+ // and wants to threshold the labelmap
1751
+ // 3. We throw an error
1752
+ const displaySetInstanceUIDs = viewportGridService.getDisplaySetsUIDsForViewport(viewport.id);
1753
+ displaySetInstanceUIDs.forEach(displaySetInstanceUID => {
1754
+ const volume = dist_esm.cache.getVolumes().find(volume => volume.volumeId.includes(displaySetInstanceUID));
1755
+ if (dist_esm.utilities.isEqual(volume.dimensions, labelmapVolume.dimensions) && dist_esm.utilities.isEqual(volume.spacing, labelmapVolume.spacing)) {
1756
+ referencedVolume = volume;
1757
+ }
2145
1758
  });
2146
- return;
2147
1759
  }
2148
1760
  const {
2149
1761
  ptLower,
@@ -2172,7 +1784,7 @@ const commandsModule = ({
2172
1784
  referencedVolumeId
2173
1785
  } = labelmap;
2174
1786
  const referencedVolume = dist_esm.cache.getVolume(referencedVolumeId);
2175
- const annotationUIDs = esm.annotation.selection.getAnnotationsSelectedByToolName(RECTANGLE_ROI_THRESHOLD_MANUAL);
1787
+ const annotationUIDs = _getAnnotationsSelectedByToolNames(RECTANGLE_ROI_THRESHOLD_MANUAL_TOOL_IDS);
2176
1788
  const annotations = annotationUIDs.map(annotationUID => esm.annotation.state.getAnnotation(annotationUID));
2177
1789
  const suvPeak = calculateSUVPeak(labelmap, referencedVolume, annotations, segmentIndex);
2178
1790
  return {
@@ -2190,9 +1802,7 @@ const commandsModule = ({
2190
1802
  scalarData,
2191
1803
  spacing
2192
1804
  } = labelmap;
2193
- const {
2194
- scalarData: referencedScalarData
2195
- } = dist_esm.cache.getVolume(labelmap.referencedVolumeId);
1805
+ const referencedScalarData = dist_esm.cache.getVolume(labelmap.referencedVolumeId).getScalarData();
2196
1806
  let segmentationMax = -Infinity;
2197
1807
  let segmentationMin = Infinity;
2198
1808
  let segmentationValues = [];
@@ -2242,7 +1852,8 @@ const commandsModule = ({
2242
1852
  exportTMTVReportCSV: ({
2243
1853
  segmentations,
2244
1854
  tmtv,
2245
- config
1855
+ config,
1856
+ options
2246
1857
  }) => {
2247
1858
  const segReport = commandsManager.runCommand('getSegmentationCSVReport', {
2248
1859
  segmentations
@@ -2251,11 +1862,6 @@ const commandsModule = ({
2251
1862
  segmentations
2252
1863
  });
2253
1864
  const additionalReportRows = [{
2254
- key: 'Total Metabolic Tumor Volume',
2255
- value: {
2256
- tmtv
2257
- }
2258
- }, {
2259
1865
  key: 'Total Lesion Glycolysis',
2260
1866
  value: {
2261
1867
  tlg: tlg.toFixed(4)
@@ -2266,7 +1872,15 @@ const commandsModule = ({
2266
1872
  ...config
2267
1873
  }
2268
1874
  }];
2269
- createAndDownloadTMTVReport(segReport, additionalReportRows);
1875
+ if (tmtv !== undefined) {
1876
+ additionalReportRows.unshift({
1877
+ key: 'Total Metabolic Tumor Volume',
1878
+ value: {
1879
+ tmtv
1880
+ }
1881
+ });
1882
+ }
1883
+ createAndDownloadTMTVReport(segReport, additionalReportRows, options);
2270
1884
  },
2271
1885
  getTotalLesionGlycolysis: ({
2272
1886
  segmentations
@@ -2291,8 +1905,8 @@ const commandsModule = ({
2291
1905
  console.error('commandsModule::getTotalLesionGlycolysis:No referencedVolumeId found');
2292
1906
  }
2293
1907
  const ptVolume = dist_esm.cache.getVolume(referencedVolumeId);
2294
- const mergedLabelData = mergedLabelmap.scalarData;
2295
- if (mergedLabelData.length !== ptVolume.scalarData.length) {
1908
+ const mergedLabelData = mergedLabelmap.getScalarData();
1909
+ if (mergedLabelData.length !== ptVolume.getScalarData().length) {
2296
1910
  console.error('commandsModule::getTotalLesionGlycolysis:Labelmap and ptVolume are not the same size');
2297
1911
  }
2298
1912
  let suv = 0;
@@ -2300,7 +1914,7 @@ const commandsModule = ({
2300
1914
  for (let i = 0; i < mergedLabelData.length; i++) {
2301
1915
  // if not background
2302
1916
  if (mergedLabelData[i] !== 0) {
2303
- suv += ptVolume.scalarData[i];
1917
+ suv += ptVolume.getScalarData()[i];
2304
1918
  totalLesionVoxelCount += 1;
2305
1919
  }
2306
1920
  }
@@ -2319,7 +1933,7 @@ const commandsModule = ({
2319
1933
  focalPoint,
2320
1934
  viewPlaneNormal
2321
1935
  } = viewport.getCamera();
2322
- const selectedAnnotationUIDs = esm.annotation.selection.getAnnotationsSelectedByToolName(RECTANGLE_ROI_THRESHOLD_MANUAL);
1936
+ const selectedAnnotationUIDs = _getAnnotationsSelectedByToolNames(RECTANGLE_ROI_THRESHOLD_MANUAL_TOOL_IDS);
2323
1937
  const annotationUID = selectedAnnotationUIDs[0];
2324
1938
  const annotation = esm.annotation.state.getAnnotation(annotationUID);
2325
1939
  const {
@@ -2355,7 +1969,7 @@ const commandsModule = ({
2355
1969
  const {
2356
1970
  viewport
2357
1971
  } = _getActiveViewportsEnabledElement();
2358
- const selectedAnnotationUIDs = esm.annotation.selection.getAnnotationsSelectedByToolName(RECTANGLE_ROI_THRESHOLD_MANUAL);
1972
+ const selectedAnnotationUIDs = _getAnnotationsSelectedByToolNames(RECTANGLE_ROI_THRESHOLD_MANUAL_TOOL_IDS);
2359
1973
  const annotationUID = selectedAnnotationUIDs[0];
2360
1974
  const annotation = esm.annotation.state.getAnnotation(annotationUID);
2361
1975
 
@@ -2374,7 +1988,7 @@ const commandsModule = ({
2374
1988
  const annotations = [];
2375
1989
  Object.keys(stateManager.annotations).forEach(frameOfReferenceUID => {
2376
1990
  const forAnnotations = stateManager.annotations[frameOfReferenceUID];
2377
- const ROIAnnotations = forAnnotations[RECTANGLE_ROI_THRESHOLD_MANUAL];
1991
+ const ROIAnnotations = RECTANGLE_ROI_THRESHOLD_MANUAL_TOOL_IDS.reduce((annotations, toolName) => [...annotations, ...(forAnnotations[toolName] ?? [])], []);
2378
1992
  annotations.push(...ROIAnnotations);
2379
1993
  });
2380
1994
  commandsManager.runCommand('exportRTReportForAnnotations', {
@@ -2436,7 +2050,7 @@ const commandsModule = ({
2436
2050
  }
2437
2051
  report[id] = {
2438
2052
  ...segReport,
2439
- PatientID: instance.PatientID,
2053
+ PatientID: instance.PatientID ?? '000000',
2440
2054
  PatientName: instance.PatientName.Alphabetic,
2441
2055
  StudyInstanceUID: instance.StudyInstanceUID,
2442
2056
  SeriesInstanceUID: instance.SeriesInstanceUID,