@ohif/app 3.0.0 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/151.bundle.07bac9172580a60fae7a.js +2579 -0
- package/dist/192.bundle.62be5f0ef9705a485071.js +894 -0
- package/dist/199.bundle.2286f24cf0a068e7f50c.js +480 -0
- package/dist/205.bundle.39e6c847d618ad2b1b7a.js +62 -0
- package/dist/208.bundle.23748a85dfdc79c05d3a.js +864 -0
- package/dist/270.bundle.abbdb5348274bae3e8bc.js +23906 -0
- package/dist/283.bundle.33f99a75a5e2d9333da2.js +2939 -0
- package/dist/295.bundle.5105ce962be15c92484d.js +48 -0
- package/dist/331.bundle.7ac7b142d249d14fd99e.js +73034 -0
- package/dist/351.bundle.c5d7279ef42e30f61e08.js +1471 -0
- package/dist/351.css +3 -0
- package/dist/36785fbd89b0e17f6099.wasm +0 -0
- package/dist/381.bundle.0905e683605fcbc0895f.js +1009 -0
- package/dist/404.bundle.0f7a500421f246153d89.js +706 -0
- package/dist/50.bundle.4cb103cd20f5ffccf927.js +324 -0
- package/dist/5004fdc02f329ce53b69.wasm +0 -0
- package/dist/531.bundle.1bc152c87c7e2e987d2b.js +5935 -0
- package/dist/55.bundle.a5a215e13a8511f7aee7.js +685 -0
- package/dist/55.css +3 -0
- package/dist/569.bundle.d147c0aa0604f8ea2094.js +514 -0
- package/dist/581.bundle.646c89c5c3e3ee096363.js +508 -0
- package/dist/606.bundle.5d876f5f3dd8287f0a28.js +4939 -0
- package/dist/610.min.worker.js +2 -0
- package/dist/610.min.worker.js.map +1 -0
- package/dist/616.bundle.bec4736d8c9513e62856.js +686 -0
- package/dist/62ab5d58a2bea7b5a1dc.wasm +0 -0
- package/dist/642.bundle.030d908e22c8ff5611f3.js +169 -0
- package/dist/65916ef3def695744bda.wasm +0 -0
- package/dist/664.bundle.4792c88ae0d6d4b5ed13.js +901 -0
- package/dist/707.bundle.0a74aa3e61ed002eb3c6.js +9049 -0
- package/dist/707.css +1 -0
- package/dist/728.bundle.d13856835357400fef82.js +26221 -0
- package/dist/744.bundle.53b07e48e07a11e920ac.js +2355 -0
- package/dist/75788f12450d4c5ed494.wasm +0 -0
- package/dist/75a0c2dfe07b824c7d21.wasm +0 -0
- package/dist/780.bundle.f60ac1906e0ae080dee8.js +4769 -0
- package/dist/790.bundle.b4df2c5d78a2a565b150.js +454 -0
- package/dist/799.bundle.3fff638815e355b0bdfd.js +271 -0
- package/dist/806.css +1 -0
- package/dist/82.bundle.a24015533196e05d190e.js +6104 -0
- package/dist/917.bundle.a094ae9e9de6df4119ae.js +196 -0
- package/dist/926.bundle.dbc9d0e591cb9217fda2.js +72552 -0
- package/dist/935.bundle.deeffff0e4f7b528e3c3.js +1849 -0
- package/dist/945.min.worker.js +2 -0
- package/dist/945.min.worker.js.map +1 -0
- package/dist/953.bundle.c14d9eb6400f697019ee.js +449 -0
- package/dist/973.bundle.4100cf103686b64938d1.js +261 -0
- package/dist/976.bundle.2720eb892514e1818018.js +2725 -0
- package/dist/984.bundle.157fc66ea5040e1364af.js +1842 -0
- package/dist/_headers +6 -0
- package/dist/_redirects +6 -0
- package/dist/app-config.js +215 -0
- package/dist/app.bundle.253eeb2a7ee986e89c50.js +154621 -0
- package/dist/app.bundle.css +21 -0
- package/dist/assets/android-chrome-144x144.png +0 -0
- package/dist/assets/android-chrome-192x192.png +0 -0
- package/dist/assets/android-chrome-256x256.png +0 -0
- package/dist/assets/android-chrome-36x36.png +0 -0
- package/dist/assets/android-chrome-384x384.png +0 -0
- package/dist/assets/android-chrome-48x48.png +0 -0
- package/dist/assets/android-chrome-512x512.png +0 -0
- package/dist/assets/android-chrome-72x72.png +0 -0
- package/dist/assets/android-chrome-96x96.png +0 -0
- package/dist/assets/apple-touch-icon-1024x1024.png +0 -0
- package/dist/assets/apple-touch-icon-114x114.png +0 -0
- package/dist/assets/apple-touch-icon-120x120.png +0 -0
- package/dist/assets/apple-touch-icon-144x144.png +0 -0
- package/dist/assets/apple-touch-icon-152x152.png +0 -0
- package/dist/assets/apple-touch-icon-167x167.png +0 -0
- package/dist/assets/apple-touch-icon-180x180.png +0 -0
- package/dist/assets/apple-touch-icon-57x57.png +0 -0
- package/dist/assets/apple-touch-icon-60x60.png +0 -0
- package/dist/assets/apple-touch-icon-72x72.png +0 -0
- package/dist/assets/apple-touch-icon-76x76.png +0 -0
- package/dist/assets/apple-touch-icon-precomposed.png +0 -0
- package/dist/assets/apple-touch-icon.png +0 -0
- package/dist/assets/apple-touch-startup-image-1182x2208.png +0 -0
- package/dist/assets/apple-touch-startup-image-1242x2148.png +0 -0
- package/dist/assets/apple-touch-startup-image-1496x2048.png +0 -0
- package/dist/assets/apple-touch-startup-image-1536x2008.png +0 -0
- package/dist/assets/apple-touch-startup-image-320x460.png +0 -0
- package/dist/assets/apple-touch-startup-image-640x1096.png +0 -0
- package/dist/assets/apple-touch-startup-image-640x920.png +0 -0
- package/dist/assets/apple-touch-startup-image-748x1024.png +0 -0
- package/dist/assets/apple-touch-startup-image-750x1294.png +0 -0
- package/dist/assets/apple-touch-startup-image-768x1004.png +0 -0
- package/dist/assets/browserconfig.xml +12 -0
- package/dist/assets/coast-228x228.png +0 -0
- package/dist/assets/favicon-16x16.png +0 -0
- package/dist/assets/favicon-32x32.png +0 -0
- package/dist/assets/favicon.ico +0 -0
- package/dist/assets/firefox_app_128x128.png +0 -0
- package/dist/assets/firefox_app_512x512.png +0 -0
- package/dist/assets/firefox_app_60x60.png +0 -0
- package/dist/assets/manifest.webapp +14 -0
- package/dist/assets/mstile-144x144.png +0 -0
- package/dist/assets/mstile-150x150.png +0 -0
- package/dist/assets/mstile-310x150.png +0 -0
- package/dist/assets/mstile-310x310.png +0 -0
- package/dist/assets/mstile-70x70.png +0 -0
- package/dist/assets/yandex-browser-50x50.png +0 -0
- package/dist/assets/yandex-browser-manifest.json +9 -0
- package/dist/b6b803111e2d06a825bd.wasm +0 -0
- package/dist/c22b37c3488e1d6c3aa4.wasm +0 -0
- package/dist/cornerstoneDICOMImageLoader.min.js +2 -0
- package/dist/cornerstoneDICOMImageLoader.min.js.map +1 -0
- package/dist/dicom-microscopy-viewer.bundle.aa60bdf008c32c39cfd7.js +12 -0
- package/dist/dicomMicroscopyViewer.min.js +3 -0
- package/dist/dicomMicroscopyViewer.min.js.LICENSE.txt +29 -0
- package/dist/es6-shim.min.js +12 -0
- package/dist/google.js +75 -0
- package/dist/index.html +1 -0
- package/dist/index.worker.ea71efba2ce63c499055.worker.js +2 -0
- package/dist/index.worker.ea71efba2ce63c499055.worker.js.map +1 -0
- package/dist/index.worker.min.worker.js +2 -0
- package/dist/index.worker.min.worker.js.map +1 -0
- package/dist/init-service-worker.js +59 -0
- package/dist/manifest.json +59 -0
- package/dist/ohif-logo-light.svg +15 -0
- package/dist/ohif-logo.svg +15 -0
- package/dist/oidc-client.min.js +46 -0
- package/dist/polyfill.min.js +1 -0
- package/dist/silent-refresh.html +16 -0
- package/dist/sw.js +56 -0
- package/package.json +24 -23
|
@@ -0,0 +1,2355 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
(globalThis["webpackChunk"] = globalThis["webpackChunk"] || []).push([[744],{
|
|
3
|
+
|
|
4
|
+
/***/ 43418:
|
|
5
|
+
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
// EXPORTS
|
|
9
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
10
|
+
"Z": () => (/* binding */ src_getContextModule),
|
|
11
|
+
"I": () => (/* reexport */ useTrackedMeasurements)
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// EXTERNAL MODULE: ../../../node_modules/react/index.js
|
|
15
|
+
var react = __webpack_require__(32735);
|
|
16
|
+
// EXTERNAL MODULE: ../../../node_modules/prop-types/index.js
|
|
17
|
+
var prop_types = __webpack_require__(60216);
|
|
18
|
+
var prop_types_default = /*#__PURE__*/__webpack_require__.n(prop_types);
|
|
19
|
+
// EXTERNAL MODULE: ../../../node_modules/xstate/es/index.js + 22 modules
|
|
20
|
+
var es = __webpack_require__(87519);
|
|
21
|
+
// EXTERNAL MODULE: ../../../node_modules/@xstate/react/lib/index.js
|
|
22
|
+
var lib = __webpack_require__(38531);
|
|
23
|
+
// EXTERNAL MODULE: ../../ui/src/index.js + 449 modules
|
|
24
|
+
var src = __webpack_require__(43803);
|
|
25
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/measurementTrackingMachine.js
|
|
26
|
+
|
|
27
|
+
const RESPONSE = {
|
|
28
|
+
NO_NEVER: -1,
|
|
29
|
+
CANCEL: 0,
|
|
30
|
+
CREATE_REPORT: 1,
|
|
31
|
+
ADD_SERIES: 2,
|
|
32
|
+
SET_STUDY_AND_SERIES: 3,
|
|
33
|
+
NO_NOT_FOR_SERIES: 4,
|
|
34
|
+
HYDRATE_REPORT: 5
|
|
35
|
+
};
|
|
36
|
+
const machineConfiguration = {
|
|
37
|
+
id: 'measurementTracking',
|
|
38
|
+
initial: 'idle',
|
|
39
|
+
context: {
|
|
40
|
+
trackedStudy: '',
|
|
41
|
+
trackedSeries: [],
|
|
42
|
+
ignoredSeries: [],
|
|
43
|
+
//
|
|
44
|
+
prevTrackedStudy: '',
|
|
45
|
+
prevTrackedSeries: [],
|
|
46
|
+
prevIgnoredSeries: [],
|
|
47
|
+
//
|
|
48
|
+
ignoredSRSeriesForHydration: [],
|
|
49
|
+
isDirty: false
|
|
50
|
+
},
|
|
51
|
+
states: {
|
|
52
|
+
off: {
|
|
53
|
+
type: 'final'
|
|
54
|
+
},
|
|
55
|
+
idle: {
|
|
56
|
+
entry: 'clearContext',
|
|
57
|
+
on: {
|
|
58
|
+
TRACK_SERIES: 'promptBeginTracking',
|
|
59
|
+
// Unused? We may only do PROMPT_HYDRATE_SR now?
|
|
60
|
+
SET_TRACKED_SERIES: [{
|
|
61
|
+
target: 'tracking',
|
|
62
|
+
actions: ['setTrackedStudyAndMultipleSeries', 'setIsDirtyToClean']
|
|
63
|
+
}],
|
|
64
|
+
PROMPT_HYDRATE_SR: {
|
|
65
|
+
target: 'promptHydrateStructuredReport',
|
|
66
|
+
cond: 'hasNotIgnoredSRSeriesForHydration'
|
|
67
|
+
},
|
|
68
|
+
RESTORE_PROMPT_HYDRATE_SR: 'promptHydrateStructuredReport',
|
|
69
|
+
HYDRATE_SR: 'hydrateStructuredReport'
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
promptBeginTracking: {
|
|
73
|
+
invoke: {
|
|
74
|
+
src: 'promptBeginTracking',
|
|
75
|
+
onDone: [{
|
|
76
|
+
target: 'tracking',
|
|
77
|
+
actions: ['setTrackedStudyAndSeries', 'setIsDirty'],
|
|
78
|
+
cond: 'shouldSetStudyAndSeries'
|
|
79
|
+
}, {
|
|
80
|
+
target: 'off',
|
|
81
|
+
cond: 'shouldKillMachine'
|
|
82
|
+
}, {
|
|
83
|
+
target: 'idle'
|
|
84
|
+
}],
|
|
85
|
+
onError: {
|
|
86
|
+
target: 'idle'
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
tracking: {
|
|
91
|
+
on: {
|
|
92
|
+
TRACK_SERIES: [{
|
|
93
|
+
target: 'promptTrackNewStudy',
|
|
94
|
+
cond: 'isNewStudy'
|
|
95
|
+
}, {
|
|
96
|
+
target: 'promptTrackNewSeries',
|
|
97
|
+
cond: 'isNewSeries'
|
|
98
|
+
}],
|
|
99
|
+
UNTRACK_SERIES: [{
|
|
100
|
+
target: 'tracking',
|
|
101
|
+
actions: ['removeTrackedSeries', 'setIsDirty'],
|
|
102
|
+
cond: 'hasRemainingTrackedSeries'
|
|
103
|
+
}, {
|
|
104
|
+
target: 'idle'
|
|
105
|
+
}],
|
|
106
|
+
SET_TRACKED_SERIES: [{
|
|
107
|
+
target: 'tracking',
|
|
108
|
+
actions: ['setTrackedStudyAndMultipleSeries']
|
|
109
|
+
}],
|
|
110
|
+
SAVE_REPORT: 'promptSaveReport',
|
|
111
|
+
SET_DIRTY: [{
|
|
112
|
+
target: 'tracking',
|
|
113
|
+
actions: ['setIsDirty'],
|
|
114
|
+
cond: 'shouldSetDirty'
|
|
115
|
+
}, {
|
|
116
|
+
target: 'tracking'
|
|
117
|
+
}]
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
promptTrackNewSeries: {
|
|
121
|
+
invoke: {
|
|
122
|
+
src: 'promptTrackNewSeries',
|
|
123
|
+
onDone: [{
|
|
124
|
+
target: 'tracking',
|
|
125
|
+
actions: ['addTrackedSeries', 'setIsDirty'],
|
|
126
|
+
cond: 'shouldAddSeries'
|
|
127
|
+
}, {
|
|
128
|
+
target: 'tracking',
|
|
129
|
+
actions: ['discardPreviouslyTrackedMeasurements', 'setTrackedStudyAndSeries', 'setIsDirty'],
|
|
130
|
+
cond: 'shouldSetStudyAndSeries'
|
|
131
|
+
}, {
|
|
132
|
+
target: 'promptSaveReport',
|
|
133
|
+
cond: 'shouldPromptSaveReport'
|
|
134
|
+
}, {
|
|
135
|
+
target: 'tracking'
|
|
136
|
+
}],
|
|
137
|
+
onError: {
|
|
138
|
+
target: 'idle'
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
promptTrackNewStudy: {
|
|
143
|
+
invoke: {
|
|
144
|
+
src: 'promptTrackNewStudy',
|
|
145
|
+
onDone: [{
|
|
146
|
+
target: 'tracking',
|
|
147
|
+
actions: ['discardPreviouslyTrackedMeasurements', 'setTrackedStudyAndSeries', 'setIsDirty'],
|
|
148
|
+
cond: 'shouldSetStudyAndSeries'
|
|
149
|
+
}, {
|
|
150
|
+
target: 'tracking',
|
|
151
|
+
actions: ['ignoreSeries'],
|
|
152
|
+
cond: 'shouldAddIgnoredSeries'
|
|
153
|
+
}, {
|
|
154
|
+
target: 'promptSaveReport',
|
|
155
|
+
cond: 'shouldPromptSaveReport'
|
|
156
|
+
}, {
|
|
157
|
+
target: 'tracking'
|
|
158
|
+
}],
|
|
159
|
+
onError: {
|
|
160
|
+
target: 'idle'
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
promptSaveReport: {
|
|
165
|
+
invoke: {
|
|
166
|
+
src: 'promptSaveReport',
|
|
167
|
+
onDone: [
|
|
168
|
+
// "clicked the save button"
|
|
169
|
+
// - should clear all measurements
|
|
170
|
+
// - show DICOM SR
|
|
171
|
+
{
|
|
172
|
+
target: 'idle',
|
|
173
|
+
actions: ['clearAllMeasurements', 'showStructuredReportDisplaySetInActiveViewport'],
|
|
174
|
+
cond: 'shouldSaveAndContinueWithSameReport'
|
|
175
|
+
},
|
|
176
|
+
// "starting a new report"
|
|
177
|
+
// - remove "just saved" measurements
|
|
178
|
+
// - start tracking a new study + report
|
|
179
|
+
{
|
|
180
|
+
target: 'tracking',
|
|
181
|
+
actions: ['discardPreviouslyTrackedMeasurements', 'setTrackedStudyAndSeries'],
|
|
182
|
+
cond: 'shouldSaveAndStartNewReport'
|
|
183
|
+
},
|
|
184
|
+
// Cancel, back to tracking
|
|
185
|
+
{
|
|
186
|
+
target: 'tracking'
|
|
187
|
+
}],
|
|
188
|
+
onError: {
|
|
189
|
+
target: 'idle'
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
promptHydrateStructuredReport: {
|
|
194
|
+
invoke: {
|
|
195
|
+
src: 'promptHydrateStructuredReport',
|
|
196
|
+
onDone: [{
|
|
197
|
+
target: 'tracking',
|
|
198
|
+
actions: ['setTrackedStudyAndMultipleSeries', 'jumpToFirstMeasurementInActiveViewport', 'setIsDirtyToClean'],
|
|
199
|
+
cond: 'shouldHydrateStructuredReport'
|
|
200
|
+
}, {
|
|
201
|
+
target: 'idle',
|
|
202
|
+
actions: ['ignoreHydrationForSRSeries'],
|
|
203
|
+
cond: 'shouldIgnoreHydrationForSR'
|
|
204
|
+
}],
|
|
205
|
+
onError: {
|
|
206
|
+
target: 'idle'
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
hydrateStructuredReport: {
|
|
211
|
+
invoke: {
|
|
212
|
+
src: 'hydrateStructuredReport',
|
|
213
|
+
onDone: [{
|
|
214
|
+
target: 'tracking',
|
|
215
|
+
actions: ['setTrackedStudyAndMultipleSeries', 'jumpToFirstMeasurementInActiveViewport', 'setIsDirtyToClean']
|
|
216
|
+
}],
|
|
217
|
+
onError: {
|
|
218
|
+
target: 'idle'
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
strict: true
|
|
224
|
+
};
|
|
225
|
+
const defaultOptions = {
|
|
226
|
+
services: {
|
|
227
|
+
promptBeginTracking: (ctx, evt) => {
|
|
228
|
+
// return { userResponse, StudyInstanceUID, SeriesInstanceUID }
|
|
229
|
+
},
|
|
230
|
+
promptTrackNewStudy: (ctx, evt) => {
|
|
231
|
+
// return { userResponse, StudyInstanceUID, SeriesInstanceUID }
|
|
232
|
+
},
|
|
233
|
+
promptTrackNewSeries: (ctx, evt) => {
|
|
234
|
+
// return { userResponse, StudyInstanceUID, SeriesInstanceUID }
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
actions: {
|
|
238
|
+
discardPreviouslyTrackedMeasurements: (ctx, evt) => {
|
|
239
|
+
console.log('discardPreviouslyTrackedMeasurements: not implemented');
|
|
240
|
+
},
|
|
241
|
+
clearAllMeasurements: (ctx, evt) => {
|
|
242
|
+
console.log('clearAllMeasurements: not implemented');
|
|
243
|
+
},
|
|
244
|
+
jumpToFirstMeasurementInActiveViewport: (ctx, evt) => {
|
|
245
|
+
console.warn('jumpToFirstMeasurementInActiveViewport: not implemented');
|
|
246
|
+
},
|
|
247
|
+
showStructuredReportDisplaySetInActiveViewport: (ctx, evt) => {
|
|
248
|
+
console.warn('showStructuredReportDisplaySetInActiveViewport: not implemented');
|
|
249
|
+
},
|
|
250
|
+
clearContext: (0,es.assign)({
|
|
251
|
+
trackedStudy: '',
|
|
252
|
+
trackedSeries: [],
|
|
253
|
+
ignoredSeries: [],
|
|
254
|
+
prevTrackedStudy: '',
|
|
255
|
+
prevTrackedSeries: [],
|
|
256
|
+
prevIgnoredSeries: []
|
|
257
|
+
}),
|
|
258
|
+
// Promise resolves w/ `evt.data.*`
|
|
259
|
+
setTrackedStudyAndSeries: (0,es.assign)((ctx, evt) => ({
|
|
260
|
+
prevTrackedStudy: ctx.trackedStudy,
|
|
261
|
+
prevTrackedSeries: ctx.trackedSeries.slice(),
|
|
262
|
+
prevIgnoredSeries: ctx.ignoredSeries.slice(),
|
|
263
|
+
//
|
|
264
|
+
trackedStudy: evt.data.StudyInstanceUID,
|
|
265
|
+
trackedSeries: [evt.data.SeriesInstanceUID],
|
|
266
|
+
ignoredSeries: []
|
|
267
|
+
})),
|
|
268
|
+
setTrackedStudyAndMultipleSeries: (0,es.assign)((ctx, evt) => {
|
|
269
|
+
const studyInstanceUID = evt.StudyInstanceUID || evt.data.StudyInstanceUID;
|
|
270
|
+
const seriesInstanceUIDs = evt.SeriesInstanceUIDs || evt.data.SeriesInstanceUIDs;
|
|
271
|
+
return {
|
|
272
|
+
prevTrackedStudy: ctx.trackedStudy,
|
|
273
|
+
prevTrackedSeries: ctx.trackedSeries.slice(),
|
|
274
|
+
prevIgnoredSeries: ctx.ignoredSeries.slice(),
|
|
275
|
+
//
|
|
276
|
+
trackedStudy: studyInstanceUID,
|
|
277
|
+
trackedSeries: [...ctx.trackedSeries, ...seriesInstanceUIDs],
|
|
278
|
+
ignoredSeries: []
|
|
279
|
+
};
|
|
280
|
+
}),
|
|
281
|
+
setIsDirtyToClean: (0,es.assign)((ctx, evt) => ({
|
|
282
|
+
isDirty: false
|
|
283
|
+
})),
|
|
284
|
+
setIsDirty: (0,es.assign)((ctx, evt) => ({
|
|
285
|
+
isDirty: true
|
|
286
|
+
})),
|
|
287
|
+
ignoreSeries: (0,es.assign)((ctx, evt) => ({
|
|
288
|
+
prevIgnoredSeries: [...ctx.ignoredSeries],
|
|
289
|
+
ignoredSeries: [...ctx.ignoredSeries, evt.data.SeriesInstanceUID]
|
|
290
|
+
})),
|
|
291
|
+
ignoreHydrationForSRSeries: (0,es.assign)((ctx, evt) => ({
|
|
292
|
+
ignoredSRSeriesForHydration: [...ctx.ignoredSRSeriesForHydration, evt.data.srSeriesInstanceUID]
|
|
293
|
+
})),
|
|
294
|
+
addTrackedSeries: (0,es.assign)((ctx, evt) => ({
|
|
295
|
+
prevTrackedSeries: [...ctx.trackedSeries],
|
|
296
|
+
trackedSeries: [...ctx.trackedSeries, evt.data.SeriesInstanceUID]
|
|
297
|
+
})),
|
|
298
|
+
removeTrackedSeries: (0,es.assign)((ctx, evt) => ({
|
|
299
|
+
prevTrackedSeries: ctx.trackedSeries.slice().filter(ser => ser !== evt.SeriesInstanceUID),
|
|
300
|
+
trackedSeries: ctx.trackedSeries.slice().filter(ser => ser !== evt.SeriesInstanceUID)
|
|
301
|
+
}))
|
|
302
|
+
},
|
|
303
|
+
guards: {
|
|
304
|
+
// We set dirty any time we performan an action that:
|
|
305
|
+
// - Tracks a new study
|
|
306
|
+
// - Tracks a new series
|
|
307
|
+
// - Adds a measurement to an already tracked study/series
|
|
308
|
+
//
|
|
309
|
+
// We set clean any time we restore from an SR
|
|
310
|
+
//
|
|
311
|
+
// This guard/condition is specific to "new measurements"
|
|
312
|
+
// to make sure we only track dirty when the new measurement is specific
|
|
313
|
+
// to a series we're already tracking
|
|
314
|
+
//
|
|
315
|
+
// tl;dr
|
|
316
|
+
// Any report change, that is not a hydration of an existing report, should
|
|
317
|
+
// result in a "dirty" report
|
|
318
|
+
//
|
|
319
|
+
// Where dirty means there would be "loss of data" if we blew away measurements
|
|
320
|
+
// without creating a new SR.
|
|
321
|
+
shouldSetDirty: (ctx, evt) => {
|
|
322
|
+
return (
|
|
323
|
+
// When would this happen?
|
|
324
|
+
evt.SeriesInstanceUID === undefined || ctx.trackedSeries.includes(evt.SeriesInstanceUID)
|
|
325
|
+
);
|
|
326
|
+
},
|
|
327
|
+
shouldKillMachine: (ctx, evt) => evt.data && evt.data.userResponse === RESPONSE.NO_NEVER,
|
|
328
|
+
shouldAddSeries: (ctx, evt) => evt.data && evt.data.userResponse === RESPONSE.ADD_SERIES,
|
|
329
|
+
shouldSetStudyAndSeries: (ctx, evt) => evt.data && evt.data.userResponse === RESPONSE.SET_STUDY_AND_SERIES,
|
|
330
|
+
shouldAddIgnoredSeries: (ctx, evt) => evt.data && evt.data.userResponse === RESPONSE.NO_NOT_FOR_SERIES,
|
|
331
|
+
shouldPromptSaveReport: (ctx, evt) => evt.data && evt.data.userResponse === RESPONSE.CREATE_REPORT,
|
|
332
|
+
shouldIgnoreHydrationForSR: (ctx, evt) => evt.data && evt.data.userResponse === RESPONSE.CANCEL,
|
|
333
|
+
shouldSaveAndContinueWithSameReport: (ctx, evt) => evt.data && evt.data.userResponse === RESPONSE.CREATE_REPORT && evt.data.isBackupSave === true,
|
|
334
|
+
shouldSaveAndStartNewReport: (ctx, evt) => evt.data && evt.data.userResponse === RESPONSE.CREATE_REPORT && evt.data.isBackupSave === false,
|
|
335
|
+
shouldHydrateStructuredReport: (ctx, evt) => evt.data && evt.data.userResponse === RESPONSE.HYDRATE_REPORT,
|
|
336
|
+
// Has more than 1, or SeriesInstanceUID is not in list
|
|
337
|
+
// --> Post removal would have non-empty trackedSeries array
|
|
338
|
+
hasRemainingTrackedSeries: (ctx, evt) => ctx.trackedSeries.length > 1 || !ctx.trackedSeries.includes(evt.SeriesInstanceUID),
|
|
339
|
+
hasNotIgnoredSRSeriesForHydration: (ctx, evt) => {
|
|
340
|
+
return !ctx.ignoredSRSeriesForHydration.includes(evt.SeriesInstanceUID);
|
|
341
|
+
},
|
|
342
|
+
isNewStudy: (ctx, evt) => !ctx.ignoredSeries.includes(evt.SeriesInstanceUID) && ctx.trackedStudy !== evt.StudyInstanceUID,
|
|
343
|
+
isNewSeries: (ctx, evt) => !ctx.ignoredSeries.includes(evt.SeriesInstanceUID) && !ctx.trackedSeries.includes(evt.SeriesInstanceUID)
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/promptBeginTracking.js
|
|
348
|
+
const promptBeginTracking_RESPONSE = {
|
|
349
|
+
NO_NEVER: -1,
|
|
350
|
+
CANCEL: 0,
|
|
351
|
+
CREATE_REPORT: 1,
|
|
352
|
+
ADD_SERIES: 2,
|
|
353
|
+
SET_STUDY_AND_SERIES: 3
|
|
354
|
+
};
|
|
355
|
+
function promptBeginTracking(_ref, ctx, evt) {
|
|
356
|
+
let {
|
|
357
|
+
servicesManager,
|
|
358
|
+
extensionManager
|
|
359
|
+
} = _ref;
|
|
360
|
+
const {
|
|
361
|
+
uiViewportDialogService
|
|
362
|
+
} = servicesManager.services;
|
|
363
|
+
const {
|
|
364
|
+
viewportIndex,
|
|
365
|
+
StudyInstanceUID,
|
|
366
|
+
SeriesInstanceUID
|
|
367
|
+
} = evt;
|
|
368
|
+
return new Promise(async function (resolve, reject) {
|
|
369
|
+
let promptResult = await _askTrackMeasurements(uiViewportDialogService, viewportIndex);
|
|
370
|
+
resolve({
|
|
371
|
+
userResponse: promptResult,
|
|
372
|
+
StudyInstanceUID,
|
|
373
|
+
SeriesInstanceUID,
|
|
374
|
+
viewportIndex
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
function _askTrackMeasurements(uiViewportDialogService, viewportIndex) {
|
|
379
|
+
return new Promise(function (resolve, reject) {
|
|
380
|
+
const message = 'Track measurements for this series?';
|
|
381
|
+
const actions = [{
|
|
382
|
+
id: 'prompt-begin-tracking-cancel',
|
|
383
|
+
type: 'cancel',
|
|
384
|
+
text: 'No',
|
|
385
|
+
value: promptBeginTracking_RESPONSE.CANCEL
|
|
386
|
+
}, {
|
|
387
|
+
id: 'prompt-begin-tracking-no-do-not-ask-again',
|
|
388
|
+
type: 'secondary',
|
|
389
|
+
text: 'No, do not ask again',
|
|
390
|
+
value: promptBeginTracking_RESPONSE.NO_NEVER
|
|
391
|
+
}, {
|
|
392
|
+
id: 'prompt-begin-tracking-yes',
|
|
393
|
+
type: 'primary',
|
|
394
|
+
text: 'Yes',
|
|
395
|
+
value: promptBeginTracking_RESPONSE.SET_STUDY_AND_SERIES
|
|
396
|
+
}];
|
|
397
|
+
const onSubmit = result => {
|
|
398
|
+
uiViewportDialogService.hide();
|
|
399
|
+
resolve(result);
|
|
400
|
+
};
|
|
401
|
+
uiViewportDialogService.show({
|
|
402
|
+
viewportIndex,
|
|
403
|
+
id: 'measurement-tracking-prompt-begin-tracking',
|
|
404
|
+
type: 'info',
|
|
405
|
+
message,
|
|
406
|
+
actions,
|
|
407
|
+
onSubmit,
|
|
408
|
+
onOutsideClick: () => {
|
|
409
|
+
uiViewportDialogService.hide();
|
|
410
|
+
resolve(promptBeginTracking_RESPONSE.CANCEL);
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
/* harmony default export */ const TrackedMeasurementsContext_promptBeginTracking = (promptBeginTracking);
|
|
416
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/promptTrackNewSeries.js
|
|
417
|
+
const promptTrackNewSeries_RESPONSE = {
|
|
418
|
+
NO_NEVER: -1,
|
|
419
|
+
CANCEL: 0,
|
|
420
|
+
CREATE_REPORT: 1,
|
|
421
|
+
ADD_SERIES: 2,
|
|
422
|
+
SET_STUDY_AND_SERIES: 3,
|
|
423
|
+
NO_NOT_FOR_SERIES: 4
|
|
424
|
+
};
|
|
425
|
+
function promptTrackNewSeries(_ref, ctx, evt) {
|
|
426
|
+
let {
|
|
427
|
+
servicesManager,
|
|
428
|
+
extensionManager
|
|
429
|
+
} = _ref;
|
|
430
|
+
const {
|
|
431
|
+
UIViewportDialogService
|
|
432
|
+
} = servicesManager.services;
|
|
433
|
+
const {
|
|
434
|
+
viewportIndex,
|
|
435
|
+
StudyInstanceUID,
|
|
436
|
+
SeriesInstanceUID
|
|
437
|
+
} = evt;
|
|
438
|
+
return new Promise(async function (resolve, reject) {
|
|
439
|
+
let promptResult = await _askShouldAddMeasurements(UIViewportDialogService, viewportIndex);
|
|
440
|
+
if (promptResult === promptTrackNewSeries_RESPONSE.CREATE_REPORT) {
|
|
441
|
+
promptResult = ctx.isDirty ? await _askSaveDiscardOrCancel(UIViewportDialogService, viewportIndex) : promptTrackNewSeries_RESPONSE.SET_STUDY_AND_SERIES;
|
|
442
|
+
}
|
|
443
|
+
resolve({
|
|
444
|
+
userResponse: promptResult,
|
|
445
|
+
StudyInstanceUID,
|
|
446
|
+
SeriesInstanceUID,
|
|
447
|
+
viewportIndex,
|
|
448
|
+
isBackupSave: false
|
|
449
|
+
});
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
function _askShouldAddMeasurements(uiViewportDialogService, viewportIndex) {
|
|
453
|
+
return new Promise(function (resolve, reject) {
|
|
454
|
+
const message = 'Do you want to add this measurement to the existing report?';
|
|
455
|
+
const actions = [{
|
|
456
|
+
type: 'cancel',
|
|
457
|
+
text: 'Cancel',
|
|
458
|
+
value: promptTrackNewSeries_RESPONSE.CANCEL
|
|
459
|
+
}, {
|
|
460
|
+
type: 'secondary',
|
|
461
|
+
text: 'Create new report',
|
|
462
|
+
value: promptTrackNewSeries_RESPONSE.CREATE_REPORT
|
|
463
|
+
}, {
|
|
464
|
+
type: 'primary',
|
|
465
|
+
text: 'Add to existing report',
|
|
466
|
+
value: promptTrackNewSeries_RESPONSE.ADD_SERIES
|
|
467
|
+
}];
|
|
468
|
+
const onSubmit = result => {
|
|
469
|
+
uiViewportDialogService.hide();
|
|
470
|
+
resolve(result);
|
|
471
|
+
};
|
|
472
|
+
uiViewportDialogService.show({
|
|
473
|
+
viewportIndex,
|
|
474
|
+
type: 'info',
|
|
475
|
+
message,
|
|
476
|
+
actions,
|
|
477
|
+
onSubmit,
|
|
478
|
+
onOutsideClick: () => {
|
|
479
|
+
uiViewportDialogService.hide();
|
|
480
|
+
resolve(promptTrackNewSeries_RESPONSE.CANCEL);
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
function _askSaveDiscardOrCancel(UIViewportDialogService, viewportIndex) {
|
|
486
|
+
return new Promise(function (resolve, reject) {
|
|
487
|
+
const message = 'You have existing tracked measurements. What would you like to do with your existing tracked measurements?';
|
|
488
|
+
const actions = [{
|
|
489
|
+
type: 'cancel',
|
|
490
|
+
text: 'Cancel',
|
|
491
|
+
value: promptTrackNewSeries_RESPONSE.CANCEL
|
|
492
|
+
}, {
|
|
493
|
+
type: 'secondary',
|
|
494
|
+
text: 'Save',
|
|
495
|
+
value: promptTrackNewSeries_RESPONSE.CREATE_REPORT
|
|
496
|
+
}, {
|
|
497
|
+
type: 'primary',
|
|
498
|
+
text: 'Discard',
|
|
499
|
+
value: promptTrackNewSeries_RESPONSE.SET_STUDY_AND_SERIES
|
|
500
|
+
}];
|
|
501
|
+
const onSubmit = result => {
|
|
502
|
+
UIViewportDialogService.hide();
|
|
503
|
+
resolve(result);
|
|
504
|
+
};
|
|
505
|
+
UIViewportDialogService.show({
|
|
506
|
+
viewportIndex,
|
|
507
|
+
type: 'warning',
|
|
508
|
+
message,
|
|
509
|
+
actions,
|
|
510
|
+
onSubmit,
|
|
511
|
+
onOutsideClick: () => {
|
|
512
|
+
UIViewportDialogService.hide();
|
|
513
|
+
resolve(promptTrackNewSeries_RESPONSE.CANCEL);
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
/* harmony default export */ const TrackedMeasurementsContext_promptTrackNewSeries = (promptTrackNewSeries);
|
|
519
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/promptTrackNewStudy.js
|
|
520
|
+
const promptTrackNewStudy_RESPONSE = {
|
|
521
|
+
NO_NEVER: -1,
|
|
522
|
+
CANCEL: 0,
|
|
523
|
+
CREATE_REPORT: 1,
|
|
524
|
+
ADD_SERIES: 2,
|
|
525
|
+
SET_STUDY_AND_SERIES: 3,
|
|
526
|
+
NO_NOT_FOR_SERIES: 4
|
|
527
|
+
};
|
|
528
|
+
function promptTrackNewStudy(_ref, ctx, evt) {
|
|
529
|
+
let {
|
|
530
|
+
servicesManager,
|
|
531
|
+
extensionManager
|
|
532
|
+
} = _ref;
|
|
533
|
+
const {
|
|
534
|
+
UIViewportDialogService
|
|
535
|
+
} = servicesManager.services;
|
|
536
|
+
const {
|
|
537
|
+
viewportIndex,
|
|
538
|
+
StudyInstanceUID,
|
|
539
|
+
SeriesInstanceUID
|
|
540
|
+
} = evt;
|
|
541
|
+
return new Promise(async function (resolve, reject) {
|
|
542
|
+
let promptResult = await promptTrackNewStudy_askTrackMeasurements(UIViewportDialogService, viewportIndex);
|
|
543
|
+
if (promptResult === promptTrackNewStudy_RESPONSE.SET_STUDY_AND_SERIES) {
|
|
544
|
+
promptResult = ctx.isDirty ? await promptTrackNewStudy_askSaveDiscardOrCancel(UIViewportDialogService, viewportIndex) : promptTrackNewStudy_RESPONSE.SET_STUDY_AND_SERIES;
|
|
545
|
+
}
|
|
546
|
+
resolve({
|
|
547
|
+
userResponse: promptResult,
|
|
548
|
+
StudyInstanceUID,
|
|
549
|
+
SeriesInstanceUID,
|
|
550
|
+
viewportIndex,
|
|
551
|
+
isBackupSave: false
|
|
552
|
+
});
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
function promptTrackNewStudy_askTrackMeasurements(UIViewportDialogService, viewportIndex) {
|
|
556
|
+
return new Promise(function (resolve, reject) {
|
|
557
|
+
const message = 'Track measurements for this series?';
|
|
558
|
+
const actions = [{
|
|
559
|
+
type: 'cancel',
|
|
560
|
+
text: 'No',
|
|
561
|
+
value: promptTrackNewStudy_RESPONSE.CANCEL
|
|
562
|
+
}, {
|
|
563
|
+
type: 'secondary',
|
|
564
|
+
text: 'No, do not ask again for this series',
|
|
565
|
+
value: promptTrackNewStudy_RESPONSE.NO_NOT_FOR_SERIES
|
|
566
|
+
}, {
|
|
567
|
+
type: 'primary',
|
|
568
|
+
text: 'Yes',
|
|
569
|
+
value: promptTrackNewStudy_RESPONSE.SET_STUDY_AND_SERIES
|
|
570
|
+
}];
|
|
571
|
+
const onSubmit = result => {
|
|
572
|
+
UIViewportDialogService.hide();
|
|
573
|
+
resolve(result);
|
|
574
|
+
};
|
|
575
|
+
UIViewportDialogService.show({
|
|
576
|
+
viewportIndex,
|
|
577
|
+
type: 'info',
|
|
578
|
+
message,
|
|
579
|
+
actions,
|
|
580
|
+
onSubmit,
|
|
581
|
+
onOutsideClick: () => {
|
|
582
|
+
UIViewportDialogService.hide();
|
|
583
|
+
resolve(promptTrackNewStudy_RESPONSE.CANCEL);
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
function promptTrackNewStudy_askSaveDiscardOrCancel(UIViewportDialogService, viewportIndex) {
|
|
589
|
+
return new Promise(function (resolve, reject) {
|
|
590
|
+
const message = 'Measurements cannot span across multiple studies. Do you want to save your tracked measurements?';
|
|
591
|
+
const actions = [{
|
|
592
|
+
type: 'cancel',
|
|
593
|
+
text: 'Cancel',
|
|
594
|
+
value: promptTrackNewStudy_RESPONSE.CANCEL
|
|
595
|
+
}, {
|
|
596
|
+
type: 'secondary',
|
|
597
|
+
text: 'No, discard previously tracked series & measurements',
|
|
598
|
+
value: promptTrackNewStudy_RESPONSE.SET_STUDY_AND_SERIES
|
|
599
|
+
}, {
|
|
600
|
+
type: 'primary',
|
|
601
|
+
text: 'Yes',
|
|
602
|
+
value: promptTrackNewStudy_RESPONSE.CREATE_REPORT
|
|
603
|
+
}];
|
|
604
|
+
const onSubmit = result => {
|
|
605
|
+
UIViewportDialogService.hide();
|
|
606
|
+
resolve(result);
|
|
607
|
+
};
|
|
608
|
+
UIViewportDialogService.show({
|
|
609
|
+
viewportIndex,
|
|
610
|
+
type: 'warning',
|
|
611
|
+
message,
|
|
612
|
+
actions,
|
|
613
|
+
onSubmit,
|
|
614
|
+
onOutsideClick: () => {
|
|
615
|
+
UIViewportDialogService.hide();
|
|
616
|
+
resolve(promptTrackNewStudy_RESPONSE.CANCEL);
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
/* harmony default export */ const TrackedMeasurementsContext_promptTrackNewStudy = (promptTrackNewStudy);
|
|
622
|
+
// EXTERNAL MODULE: ../../core/src/index.ts + 101 modules
|
|
623
|
+
var core_src = __webpack_require__(48501);
|
|
624
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/_shared/createReportAsync.tsx
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
*
|
|
630
|
+
* @param {*} servicesManager
|
|
631
|
+
* @param {*} dataSource
|
|
632
|
+
* @param {*} measurements
|
|
633
|
+
* @param {*} options
|
|
634
|
+
* @returns {string[]} displaySetInstanceUIDs
|
|
635
|
+
*/
|
|
636
|
+
async function createReportAsync(servicesManager, commandsManager, dataSource, measurements, options) {
|
|
637
|
+
const {
|
|
638
|
+
displaySetService,
|
|
639
|
+
uiNotificationService,
|
|
640
|
+
uiDialogService
|
|
641
|
+
} = servicesManager.services;
|
|
642
|
+
const loadingDialogId = uiDialogService.create({
|
|
643
|
+
showOverlay: true,
|
|
644
|
+
isDraggable: false,
|
|
645
|
+
centralize: true,
|
|
646
|
+
// TODO: Create a loading indicator component + zeplin design?
|
|
647
|
+
content: Loading
|
|
648
|
+
});
|
|
649
|
+
try {
|
|
650
|
+
const naturalizedReport = await commandsManager.runCommand('storeMeasurements', {
|
|
651
|
+
measurementData: measurements,
|
|
652
|
+
dataSource,
|
|
653
|
+
additionalFindingTypes: ['ArrowAnnotate'],
|
|
654
|
+
options
|
|
655
|
+
}, 'CORNERSTONE_STRUCTURED_REPORT');
|
|
656
|
+
|
|
657
|
+
// The "Mode" route listens for DicomMetadataStore changes
|
|
658
|
+
// When a new instance is added, it listens and
|
|
659
|
+
// automatically calls makeDisplaySets
|
|
660
|
+
core_src.DicomMetadataStore.addInstances([naturalizedReport], true);
|
|
661
|
+
const displaySetInstanceUID = displaySetService.getMostRecentDisplaySet();
|
|
662
|
+
uiNotificationService.show({
|
|
663
|
+
title: 'Create Report',
|
|
664
|
+
message: 'Measurements saved successfully',
|
|
665
|
+
type: 'success'
|
|
666
|
+
});
|
|
667
|
+
return [displaySetInstanceUID];
|
|
668
|
+
} catch (error) {
|
|
669
|
+
uiNotificationService.show({
|
|
670
|
+
title: 'Create Report',
|
|
671
|
+
message: error.message || 'Failed to store measurements',
|
|
672
|
+
type: 'error'
|
|
673
|
+
});
|
|
674
|
+
} finally {
|
|
675
|
+
uiDialogService.dismiss({
|
|
676
|
+
id: loadingDialogId
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
function Loading() {
|
|
681
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
682
|
+
className: "text-primary-active"
|
|
683
|
+
}, "Loading...");
|
|
684
|
+
}
|
|
685
|
+
/* harmony default export */ const _shared_createReportAsync = (createReportAsync);
|
|
686
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/_shared/PROMPT_RESPONSES.js
|
|
687
|
+
const PROMPT_RESPONSES_RESPONSE = {
|
|
688
|
+
NO_NEVER: -1,
|
|
689
|
+
CANCEL: 0,
|
|
690
|
+
CREATE_REPORT: 1,
|
|
691
|
+
ADD_SERIES: 2,
|
|
692
|
+
SET_STUDY_AND_SERIES: 3,
|
|
693
|
+
NO_NOT_FOR_SERIES: 4
|
|
694
|
+
};
|
|
695
|
+
/* harmony default export */ const PROMPT_RESPONSES = (PROMPT_RESPONSES_RESPONSE);
|
|
696
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/_shared/createReportDialogPrompt.tsx
|
|
697
|
+
/* eslint-disable react/display-name */
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
function createReportDialogPrompt(uiDialogService) {
|
|
702
|
+
return new Promise(function (resolve, reject) {
|
|
703
|
+
let dialogId = undefined;
|
|
704
|
+
const _handleClose = () => {
|
|
705
|
+
// Dismiss dialog
|
|
706
|
+
uiDialogService.dismiss({
|
|
707
|
+
id: dialogId
|
|
708
|
+
});
|
|
709
|
+
// Notify of cancel action
|
|
710
|
+
resolve({
|
|
711
|
+
action: PROMPT_RESPONSES.CANCEL,
|
|
712
|
+
value: undefined
|
|
713
|
+
});
|
|
714
|
+
};
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
*
|
|
718
|
+
* @param {string} param0.action - value of action performed
|
|
719
|
+
* @param {string} param0.value - value from input field
|
|
720
|
+
*/
|
|
721
|
+
const _handleFormSubmit = _ref => {
|
|
722
|
+
let {
|
|
723
|
+
action,
|
|
724
|
+
value
|
|
725
|
+
} = _ref;
|
|
726
|
+
uiDialogService.dismiss({
|
|
727
|
+
id: dialogId
|
|
728
|
+
});
|
|
729
|
+
switch (action.id) {
|
|
730
|
+
case 'save':
|
|
731
|
+
resolve({
|
|
732
|
+
action: PROMPT_RESPONSES.CREATE_REPORT,
|
|
733
|
+
value: value.label
|
|
734
|
+
});
|
|
735
|
+
break;
|
|
736
|
+
case 'cancel':
|
|
737
|
+
resolve({
|
|
738
|
+
action: PROMPT_RESPONSES.CANCEL,
|
|
739
|
+
value: undefined
|
|
740
|
+
});
|
|
741
|
+
break;
|
|
742
|
+
}
|
|
743
|
+
};
|
|
744
|
+
dialogId = uiDialogService.create({
|
|
745
|
+
centralize: true,
|
|
746
|
+
isDraggable: false,
|
|
747
|
+
content: src/* Dialog */.Vq,
|
|
748
|
+
useLastPosition: false,
|
|
749
|
+
showOverlay: true,
|
|
750
|
+
contentProps: {
|
|
751
|
+
title: 'Provide a name for your report',
|
|
752
|
+
value: {
|
|
753
|
+
label: ''
|
|
754
|
+
},
|
|
755
|
+
noCloseButton: true,
|
|
756
|
+
onClose: _handleClose,
|
|
757
|
+
actions: [{
|
|
758
|
+
id: 'cancel',
|
|
759
|
+
text: 'Cancel',
|
|
760
|
+
type: 'primary'
|
|
761
|
+
}, {
|
|
762
|
+
id: 'save',
|
|
763
|
+
text: 'Save',
|
|
764
|
+
type: 'secondary'
|
|
765
|
+
}],
|
|
766
|
+
// TODO: Should be on button press...
|
|
767
|
+
onSubmit: _handleFormSubmit,
|
|
768
|
+
body: _ref2 => {
|
|
769
|
+
let {
|
|
770
|
+
value,
|
|
771
|
+
setValue
|
|
772
|
+
} = _ref2;
|
|
773
|
+
const onChangeHandler = event => {
|
|
774
|
+
event.persist();
|
|
775
|
+
setValue(value => ({
|
|
776
|
+
...value,
|
|
777
|
+
label: event.target.value
|
|
778
|
+
}));
|
|
779
|
+
};
|
|
780
|
+
const onKeyPressHandler = event => {
|
|
781
|
+
if (event.key === 'Enter') {
|
|
782
|
+
uiDialogService.dismiss({
|
|
783
|
+
id: dialogId
|
|
784
|
+
});
|
|
785
|
+
resolve({
|
|
786
|
+
action: PROMPT_RESPONSES.CREATE_REPORT,
|
|
787
|
+
value: value.label
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
};
|
|
791
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
792
|
+
className: "p-4 bg-primary-dark"
|
|
793
|
+
}, /*#__PURE__*/react.createElement(src/* Input */.II, {
|
|
794
|
+
autoFocus: true,
|
|
795
|
+
className: "mt-2 bg-black border-primary-main",
|
|
796
|
+
type: "text",
|
|
797
|
+
containerClassName: "mr-2",
|
|
798
|
+
value: value.label,
|
|
799
|
+
onChange: onChangeHandler,
|
|
800
|
+
onKeyPress: onKeyPressHandler
|
|
801
|
+
}));
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
});
|
|
805
|
+
});
|
|
806
|
+
}
|
|
807
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/_shared/getNextSRSeriesNumber.js
|
|
808
|
+
const MIN_SR_SERIES_NUMBER = 4700;
|
|
809
|
+
function getNextSRSeriesNumber(displaySetService) {
|
|
810
|
+
const activeDisplaySets = displaySetService.getActiveDisplaySets();
|
|
811
|
+
const srDisplaySets = activeDisplaySets.filter(ds => ds.Modality === 'SR');
|
|
812
|
+
const srSeriesNumbers = srDisplaySets.map(ds => ds.SeriesNumber);
|
|
813
|
+
const maxSeriesNumber = Math.max(...srSeriesNumbers, MIN_SR_SERIES_NUMBER);
|
|
814
|
+
return maxSeriesNumber + 1;
|
|
815
|
+
}
|
|
816
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/promptSaveReport.js
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
|
|
821
|
+
function promptSaveReport(_ref, ctx, evt) {
|
|
822
|
+
let {
|
|
823
|
+
servicesManager,
|
|
824
|
+
commandsManager,
|
|
825
|
+
extensionManager
|
|
826
|
+
} = _ref;
|
|
827
|
+
const {
|
|
828
|
+
uiDialogService,
|
|
829
|
+
measurementService,
|
|
830
|
+
displaySetService
|
|
831
|
+
} = servicesManager.services;
|
|
832
|
+
const viewportIndex = evt.viewportIndex === undefined ? evt.data.viewportIndex : evt.viewportIndex;
|
|
833
|
+
const isBackupSave = evt.isBackupSave === undefined ? evt.data.isBackupSave : evt.isBackupSave;
|
|
834
|
+
const StudyInstanceUID = evt?.data?.StudyInstanceUID;
|
|
835
|
+
const SeriesInstanceUID = evt?.data?.SeriesInstanceUID;
|
|
836
|
+
const {
|
|
837
|
+
trackedStudy,
|
|
838
|
+
trackedSeries
|
|
839
|
+
} = ctx;
|
|
840
|
+
let displaySetInstanceUIDs;
|
|
841
|
+
return new Promise(async function (resolve, reject) {
|
|
842
|
+
// TODO: Fallback if (uiDialogService) {
|
|
843
|
+
const promptResult = await createReportDialogPrompt(uiDialogService);
|
|
844
|
+
if (promptResult.action === PROMPT_RESPONSES.CREATE_REPORT) {
|
|
845
|
+
const dataSources = extensionManager.getDataSources();
|
|
846
|
+
const dataSource = dataSources[0];
|
|
847
|
+
const measurements = measurementService.getMeasurements();
|
|
848
|
+
const trackedMeasurements = measurements.filter(m => trackedStudy === m.referenceStudyUID && trackedSeries.includes(m.referenceSeriesUID));
|
|
849
|
+
const SeriesDescription =
|
|
850
|
+
// isUndefinedOrEmpty
|
|
851
|
+
promptResult.value === undefined || promptResult.value === '' ? 'Research Derived Series' // default
|
|
852
|
+
: promptResult.value; // provided value
|
|
853
|
+
|
|
854
|
+
const SeriesNumber = getNextSRSeriesNumber(displaySetService);
|
|
855
|
+
displaySetInstanceUIDs = await _shared_createReportAsync(servicesManager, commandsManager, dataSource, trackedMeasurements, {
|
|
856
|
+
SeriesDescription,
|
|
857
|
+
SeriesNumber
|
|
858
|
+
});
|
|
859
|
+
} else if (promptResult.action === PROMPT_RESPONSES.CANCEL) {
|
|
860
|
+
// Do nothing
|
|
861
|
+
}
|
|
862
|
+
resolve({
|
|
863
|
+
userResponse: promptResult.action,
|
|
864
|
+
createdDisplaySetInstanceUIDs: displaySetInstanceUIDs,
|
|
865
|
+
StudyInstanceUID,
|
|
866
|
+
SeriesInstanceUID,
|
|
867
|
+
viewportIndex,
|
|
868
|
+
isBackupSave
|
|
869
|
+
});
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
/* harmony default export */ const TrackedMeasurementsContext_promptSaveReport = (promptSaveReport);
|
|
873
|
+
// EXTERNAL MODULE: ../../../extensions/cornerstone-dicom-sr/src/index.tsx + 15 modules
|
|
874
|
+
var cornerstone_dicom_sr_src = __webpack_require__(65948);
|
|
875
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/promptHydrateStructuredReport.js
|
|
876
|
+
|
|
877
|
+
const promptHydrateStructuredReport_RESPONSE = {
|
|
878
|
+
NO_NEVER: -1,
|
|
879
|
+
CANCEL: 0,
|
|
880
|
+
CREATE_REPORT: 1,
|
|
881
|
+
ADD_SERIES: 2,
|
|
882
|
+
SET_STUDY_AND_SERIES: 3,
|
|
883
|
+
NO_NOT_FOR_SERIES: 4,
|
|
884
|
+
HYDRATE_REPORT: 5
|
|
885
|
+
};
|
|
886
|
+
function promptHydrateStructuredReport(_ref, ctx, evt) {
|
|
887
|
+
let {
|
|
888
|
+
servicesManager,
|
|
889
|
+
extensionManager
|
|
890
|
+
} = _ref;
|
|
891
|
+
const {
|
|
892
|
+
uiViewportDialogService,
|
|
893
|
+
displaySetService
|
|
894
|
+
} = servicesManager.services;
|
|
895
|
+
const {
|
|
896
|
+
viewportIndex,
|
|
897
|
+
displaySetInstanceUID
|
|
898
|
+
} = evt;
|
|
899
|
+
const srDisplaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
|
|
900
|
+
return new Promise(async function (resolve, reject) {
|
|
901
|
+
const promptResult = await promptHydrateStructuredReport_askTrackMeasurements(uiViewportDialogService, viewportIndex);
|
|
902
|
+
|
|
903
|
+
// Need to do action here... So we can set state...
|
|
904
|
+
let StudyInstanceUID, SeriesInstanceUIDs;
|
|
905
|
+
if (promptResult === promptHydrateStructuredReport_RESPONSE.HYDRATE_REPORT) {
|
|
906
|
+
console.warn('!! HYDRATING STRUCTURED REPORT');
|
|
907
|
+
const hydrationResult = (0,cornerstone_dicom_sr_src.hydrateStructuredReport)({
|
|
908
|
+
servicesManager,
|
|
909
|
+
extensionManager
|
|
910
|
+
}, displaySetInstanceUID);
|
|
911
|
+
StudyInstanceUID = hydrationResult.StudyInstanceUID;
|
|
912
|
+
SeriesInstanceUIDs = hydrationResult.SeriesInstanceUIDs;
|
|
913
|
+
}
|
|
914
|
+
resolve({
|
|
915
|
+
userResponse: promptResult,
|
|
916
|
+
displaySetInstanceUID: evt.displaySetInstanceUID,
|
|
917
|
+
srSeriesInstanceUID: srDisplaySet.SeriesInstanceUID,
|
|
918
|
+
viewportIndex,
|
|
919
|
+
StudyInstanceUID,
|
|
920
|
+
SeriesInstanceUIDs
|
|
921
|
+
});
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
function promptHydrateStructuredReport_askTrackMeasurements(uiViewportDialogService, viewportIndex) {
|
|
925
|
+
return new Promise(function (resolve, reject) {
|
|
926
|
+
const message = 'Do you want to continue tracking measurements for this study?';
|
|
927
|
+
const actions = [{
|
|
928
|
+
type: 'secondary',
|
|
929
|
+
text: 'No',
|
|
930
|
+
value: promptHydrateStructuredReport_RESPONSE.CANCEL
|
|
931
|
+
}, {
|
|
932
|
+
type: 'primary',
|
|
933
|
+
text: 'Yes',
|
|
934
|
+
value: promptHydrateStructuredReport_RESPONSE.HYDRATE_REPORT
|
|
935
|
+
}];
|
|
936
|
+
const onSubmit = result => {
|
|
937
|
+
uiViewportDialogService.hide();
|
|
938
|
+
resolve(result);
|
|
939
|
+
};
|
|
940
|
+
uiViewportDialogService.show({
|
|
941
|
+
viewportIndex,
|
|
942
|
+
type: 'info',
|
|
943
|
+
message,
|
|
944
|
+
actions,
|
|
945
|
+
onSubmit,
|
|
946
|
+
onOutsideClick: () => {
|
|
947
|
+
uiViewportDialogService.hide();
|
|
948
|
+
resolve(promptHydrateStructuredReport_RESPONSE.CANCEL);
|
|
949
|
+
}
|
|
950
|
+
});
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
/* harmony default export */ const TrackedMeasurementsContext_promptHydrateStructuredReport = (promptHydrateStructuredReport);
|
|
954
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/hydrateStructuredReport.tsx
|
|
955
|
+
|
|
956
|
+
function hydrateStructuredReport(_ref, ctx, evt) {
|
|
957
|
+
let {
|
|
958
|
+
servicesManager,
|
|
959
|
+
extensionManager
|
|
960
|
+
} = _ref;
|
|
961
|
+
const {
|
|
962
|
+
displaySetService
|
|
963
|
+
} = servicesManager.services;
|
|
964
|
+
const {
|
|
965
|
+
viewportIndex,
|
|
966
|
+
displaySetInstanceUID
|
|
967
|
+
} = evt;
|
|
968
|
+
const srDisplaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
|
|
969
|
+
return new Promise((resolve, reject) => {
|
|
970
|
+
const hydrationResult = (0,cornerstone_dicom_sr_src.hydrateStructuredReport)({
|
|
971
|
+
servicesManager,
|
|
972
|
+
extensionManager
|
|
973
|
+
}, displaySetInstanceUID);
|
|
974
|
+
const StudyInstanceUID = hydrationResult.StudyInstanceUID;
|
|
975
|
+
const SeriesInstanceUIDs = hydrationResult.SeriesInstanceUIDs;
|
|
976
|
+
resolve({
|
|
977
|
+
displaySetInstanceUID: evt.displaySetInstanceUID,
|
|
978
|
+
srSeriesInstanceUID: srDisplaySet.SeriesInstanceUID,
|
|
979
|
+
viewportIndex,
|
|
980
|
+
StudyInstanceUID,
|
|
981
|
+
SeriesInstanceUIDs
|
|
982
|
+
});
|
|
983
|
+
});
|
|
984
|
+
}
|
|
985
|
+
/* harmony default export */ const TrackedMeasurementsContext_hydrateStructuredReport = (hydrateStructuredReport);
|
|
986
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/TrackedMeasurementsContext.tsx
|
|
987
|
+
|
|
988
|
+
|
|
989
|
+
|
|
990
|
+
|
|
991
|
+
|
|
992
|
+
|
|
993
|
+
|
|
994
|
+
|
|
995
|
+
|
|
996
|
+
|
|
997
|
+
|
|
998
|
+
|
|
999
|
+
const TrackedMeasurementsContext = /*#__PURE__*/react.createContext();
|
|
1000
|
+
TrackedMeasurementsContext.displayName = 'TrackedMeasurementsContext';
|
|
1001
|
+
const useTrackedMeasurements = () => (0,react.useContext)(TrackedMeasurementsContext);
|
|
1002
|
+
const SR_SOPCLASSHANDLERID = '@ohif/extension-cornerstone-dicom-sr.sopClassHandlerModule.dicom-sr';
|
|
1003
|
+
|
|
1004
|
+
/**
|
|
1005
|
+
*
|
|
1006
|
+
* @param {*} param0
|
|
1007
|
+
*/
|
|
1008
|
+
function TrackedMeasurementsContextProvider(_ref, // Bound by consumer
|
|
1009
|
+
_ref2 // Component props
|
|
1010
|
+
) {
|
|
1011
|
+
let {
|
|
1012
|
+
servicesManager,
|
|
1013
|
+
commandsManager,
|
|
1014
|
+
extensionManager
|
|
1015
|
+
} = _ref;
|
|
1016
|
+
let {
|
|
1017
|
+
children
|
|
1018
|
+
} = _ref2;
|
|
1019
|
+
const [viewportGrid, viewportGridService] = (0,src/* useViewportGrid */.O_)();
|
|
1020
|
+
const {
|
|
1021
|
+
activeViewportIndex,
|
|
1022
|
+
viewports
|
|
1023
|
+
} = viewportGrid;
|
|
1024
|
+
const {
|
|
1025
|
+
measurementService,
|
|
1026
|
+
displaySetService
|
|
1027
|
+
} = servicesManager.services;
|
|
1028
|
+
const machineOptions = Object.assign({}, defaultOptions);
|
|
1029
|
+
machineOptions.actions = Object.assign({}, machineOptions.actions, {
|
|
1030
|
+
jumpToFirstMeasurementInActiveViewport: (ctx, evt) => {
|
|
1031
|
+
const {
|
|
1032
|
+
trackedStudy,
|
|
1033
|
+
trackedSeries
|
|
1034
|
+
} = ctx;
|
|
1035
|
+
const measurements = measurementService.getMeasurements();
|
|
1036
|
+
const trackedMeasurements = measurements.filter(m => trackedStudy === m.referenceStudyUID && trackedSeries.includes(m.referenceSeriesUID));
|
|
1037
|
+
console.log('jumping to measurement reset viewport', viewportGrid.activeViewportIndex, trackedMeasurements[0]);
|
|
1038
|
+
const referencedDisplaySetUID = trackedMeasurements[0].displaySetInstanceUID;
|
|
1039
|
+
const referencedDisplaySet = displaySetService.getDisplaySetByUID(referencedDisplaySetUID);
|
|
1040
|
+
const referencedImages = referencedDisplaySet.images;
|
|
1041
|
+
const isVolumeIdReferenced = referencedImages[0].imageId.startsWith('volumeId');
|
|
1042
|
+
const measurementData = trackedMeasurements[0].data;
|
|
1043
|
+
let imageIndex = 0;
|
|
1044
|
+
if (!isVolumeIdReferenced && measurementData) {
|
|
1045
|
+
// if it is imageId referenced find the index of the imageId, we don't have
|
|
1046
|
+
// support for volumeId referenced images yet
|
|
1047
|
+
imageIndex = referencedImages.findIndex(image => {
|
|
1048
|
+
const imageIdToUse = Object.keys(measurementData)[0].substring(8);
|
|
1049
|
+
return image.imageId === imageIdToUse;
|
|
1050
|
+
});
|
|
1051
|
+
if (imageIndex === -1) {
|
|
1052
|
+
console.warn('Could not find image index for tracked measurement, using 0');
|
|
1053
|
+
imageIndex = 0;
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
viewportGridService.setDisplaySetsForViewport({
|
|
1057
|
+
viewportIndex: viewportGrid.activeViewportIndex,
|
|
1058
|
+
displaySetInstanceUIDs: [referencedDisplaySetUID],
|
|
1059
|
+
viewportOptions: {
|
|
1060
|
+
initialImageOptions: {
|
|
1061
|
+
index: imageIndex
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
});
|
|
1065
|
+
},
|
|
1066
|
+
showStructuredReportDisplaySetInActiveViewport: (ctx, evt) => {
|
|
1067
|
+
if (evt.data.createdDisplaySetInstanceUIDs.length > 0) {
|
|
1068
|
+
const StructuredReportDisplaySetInstanceUID = evt.data.createdDisplaySetInstanceUIDs[0].displaySetInstanceUID;
|
|
1069
|
+
viewportGridService.setDisplaySetsForViewport({
|
|
1070
|
+
viewportIndex: evt.data.viewportIndex,
|
|
1071
|
+
displaySetInstanceUIDs: [StructuredReportDisplaySetInstanceUID]
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1074
|
+
},
|
|
1075
|
+
discardPreviouslyTrackedMeasurements: (ctx, evt) => {
|
|
1076
|
+
const measurements = measurementService.getMeasurements();
|
|
1077
|
+
const filteredMeasurements = measurements.filter(ms => ctx.prevTrackedSeries.includes(ms.referenceSeriesUID));
|
|
1078
|
+
const measurementIds = filteredMeasurements.map(fm => fm.id);
|
|
1079
|
+
for (let i = 0; i < measurementIds.length; i++) {
|
|
1080
|
+
measurementService.remove(measurementIds[i]);
|
|
1081
|
+
}
|
|
1082
|
+
},
|
|
1083
|
+
clearAllMeasurements: (ctx, evt) => {
|
|
1084
|
+
const measurements = measurementService.getMeasurements();
|
|
1085
|
+
const measurementIds = measurements.map(fm => fm.uid);
|
|
1086
|
+
for (let i = 0; i < measurementIds.length; i++) {
|
|
1087
|
+
measurementService.remove(measurementIds[i]);
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
});
|
|
1091
|
+
machineOptions.services = Object.assign({}, machineOptions.services, {
|
|
1092
|
+
promptBeginTracking: TrackedMeasurementsContext_promptBeginTracking.bind(null, {
|
|
1093
|
+
servicesManager,
|
|
1094
|
+
extensionManager
|
|
1095
|
+
}),
|
|
1096
|
+
promptTrackNewSeries: TrackedMeasurementsContext_promptTrackNewSeries.bind(null, {
|
|
1097
|
+
servicesManager,
|
|
1098
|
+
extensionManager
|
|
1099
|
+
}),
|
|
1100
|
+
promptTrackNewStudy: TrackedMeasurementsContext_promptTrackNewStudy.bind(null, {
|
|
1101
|
+
servicesManager,
|
|
1102
|
+
extensionManager
|
|
1103
|
+
}),
|
|
1104
|
+
promptSaveReport: TrackedMeasurementsContext_promptSaveReport.bind(null, {
|
|
1105
|
+
servicesManager,
|
|
1106
|
+
commandsManager,
|
|
1107
|
+
extensionManager
|
|
1108
|
+
}),
|
|
1109
|
+
promptHydrateStructuredReport: TrackedMeasurementsContext_promptHydrateStructuredReport.bind(null, {
|
|
1110
|
+
servicesManager,
|
|
1111
|
+
extensionManager
|
|
1112
|
+
}),
|
|
1113
|
+
hydrateStructuredReport: TrackedMeasurementsContext_hydrateStructuredReport.bind(null, {
|
|
1114
|
+
servicesManager,
|
|
1115
|
+
extensionManager
|
|
1116
|
+
})
|
|
1117
|
+
});
|
|
1118
|
+
|
|
1119
|
+
// TODO: IMPROVE
|
|
1120
|
+
// - Add measurement_updated to cornerstone; debounced? (ext side, or consumption?)
|
|
1121
|
+
// - Friendlier transition/api in front of measurementTracking machine?
|
|
1122
|
+
// - Blocked: viewport overlay shouldn't clip when resized
|
|
1123
|
+
// TODO: PRIORITY
|
|
1124
|
+
// - Fix "ellipses" series description dynamic truncate length
|
|
1125
|
+
// - Fix viewport border resize
|
|
1126
|
+
// - created/destroyed hooks for extensions (cornerstone measurement subscriptions in it's `init`)
|
|
1127
|
+
|
|
1128
|
+
const measurementTrackingMachine = (0,es.Machine)(machineConfiguration, machineOptions);
|
|
1129
|
+
const [trackedMeasurements, sendTrackedMeasurementsEvent, trackedMeasurementsService] = (0,lib.useMachine)(measurementTrackingMachine);
|
|
1130
|
+
|
|
1131
|
+
// ~~ Listen for changes to ViewportGrid for potential SRs hung in panes when idle
|
|
1132
|
+
(0,react.useEffect)(() => {
|
|
1133
|
+
if (viewports.length > 0) {
|
|
1134
|
+
const activeViewport = viewports[activeViewportIndex];
|
|
1135
|
+
if (!activeViewport || !activeViewport?.displaySetInstanceUIDs?.length) {
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
// Todo: Getting the first displaySetInstanceUID is wrong, but we don't have
|
|
1140
|
+
// tracking fusion viewports yet. This should change when we do.
|
|
1141
|
+
const {
|
|
1142
|
+
displaySetService
|
|
1143
|
+
} = servicesManager.services;
|
|
1144
|
+
const displaySet = displaySetService.getDisplaySetByUID(activeViewport.displaySetInstanceUIDs[0]);
|
|
1145
|
+
if (!displaySet) {
|
|
1146
|
+
return;
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
// If this is an SR produced by our SR SOPClassHandler,
|
|
1150
|
+
// and it hasn't been loaded yet, do that now so we
|
|
1151
|
+
// can check if it can be rehydrated or not.
|
|
1152
|
+
//
|
|
1153
|
+
// Note: This happens:
|
|
1154
|
+
// - If the viewport is not currently an OHIFCornerstoneSRViewport
|
|
1155
|
+
// - If the displaySet has never been hung
|
|
1156
|
+
//
|
|
1157
|
+
// Otherwise, the displaySet will be loaded by the useEffect handler
|
|
1158
|
+
// listening to displaySet changes inside OHIFCornerstoneSRViewport.
|
|
1159
|
+
// The issue here is that this handler in TrackedMeasurementsContext
|
|
1160
|
+
// ends up occurring before the Viewport is created, so the displaySet
|
|
1161
|
+
// is not loaded yet, and isRehydratable is undefined unless we call load().
|
|
1162
|
+
if (displaySet.SOPClassHandlerId === SR_SOPCLASSHANDLERID && !displaySet.isLoaded && displaySet.load) {
|
|
1163
|
+
displaySet.load();
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
// Magic string
|
|
1167
|
+
// load function added by our sopClassHandler module
|
|
1168
|
+
if (displaySet.SOPClassHandlerId === SR_SOPCLASSHANDLERID && displaySet.isRehydratable === true) {
|
|
1169
|
+
console.log('sending event...', trackedMeasurements);
|
|
1170
|
+
sendTrackedMeasurementsEvent('PROMPT_HYDRATE_SR', {
|
|
1171
|
+
displaySetInstanceUID: displaySet.displaySetInstanceUID,
|
|
1172
|
+
SeriesInstanceUID: displaySet.SeriesInstanceUID,
|
|
1173
|
+
viewportIndex: activeViewportIndex
|
|
1174
|
+
});
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
}, [activeViewportIndex, sendTrackedMeasurementsEvent, servicesManager.services, viewports]);
|
|
1178
|
+
return /*#__PURE__*/react.createElement(TrackedMeasurementsContext.Provider, {
|
|
1179
|
+
value: [trackedMeasurements, sendTrackedMeasurementsEvent]
|
|
1180
|
+
}, children);
|
|
1181
|
+
}
|
|
1182
|
+
TrackedMeasurementsContextProvider.propTypes = {
|
|
1183
|
+
children: prop_types_default().oneOf([(prop_types_default()).func, (prop_types_default()).node]),
|
|
1184
|
+
servicesManager: (prop_types_default()).object.isRequired,
|
|
1185
|
+
commandsManager: (prop_types_default()).object.isRequired,
|
|
1186
|
+
extensionManager: (prop_types_default()).object.isRequired
|
|
1187
|
+
};
|
|
1188
|
+
|
|
1189
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/contexts/TrackedMeasurementsContext/index.js
|
|
1190
|
+
|
|
1191
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/contexts/index.js
|
|
1192
|
+
|
|
1193
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/getContextModule.tsx
|
|
1194
|
+
|
|
1195
|
+
function getContextModule(_ref) {
|
|
1196
|
+
let {
|
|
1197
|
+
servicesManager,
|
|
1198
|
+
extensionManager,
|
|
1199
|
+
commandsManager
|
|
1200
|
+
} = _ref;
|
|
1201
|
+
const BoundTrackedMeasurementsContextProvider = TrackedMeasurementsContextProvider.bind(null, {
|
|
1202
|
+
servicesManager,
|
|
1203
|
+
extensionManager,
|
|
1204
|
+
commandsManager
|
|
1205
|
+
});
|
|
1206
|
+
return [{
|
|
1207
|
+
name: 'TrackedMeasurementsContext',
|
|
1208
|
+
context: TrackedMeasurementsContext,
|
|
1209
|
+
provider: BoundTrackedMeasurementsContextProvider
|
|
1210
|
+
}];
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
/* harmony default export */ const src_getContextModule = (getContextModule);
|
|
1214
|
+
|
|
1215
|
+
/***/ }),
|
|
1216
|
+
|
|
1217
|
+
/***/ 43744:
|
|
1218
|
+
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
1219
|
+
|
|
1220
|
+
// ESM COMPAT FLAG
|
|
1221
|
+
__webpack_require__.r(__webpack_exports__);
|
|
1222
|
+
|
|
1223
|
+
// EXPORTS
|
|
1224
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
1225
|
+
"default": () => (/* binding */ measurement_tracking_src)
|
|
1226
|
+
});
|
|
1227
|
+
|
|
1228
|
+
// EXTERNAL MODULE: ../../../extensions/measurement-tracking/src/getContextModule.tsx + 14 modules
|
|
1229
|
+
var getContextModule = __webpack_require__(43418);
|
|
1230
|
+
// EXTERNAL MODULE: ../../../node_modules/react/index.js
|
|
1231
|
+
var react = __webpack_require__(32735);
|
|
1232
|
+
// EXTERNAL MODULE: ../../../node_modules/prop-types/index.js
|
|
1233
|
+
var prop_types = __webpack_require__(60216);
|
|
1234
|
+
var prop_types_default = /*#__PURE__*/__webpack_require__.n(prop_types);
|
|
1235
|
+
// EXTERNAL MODULE: ../../core/src/index.ts + 101 modules
|
|
1236
|
+
var src = __webpack_require__(48501);
|
|
1237
|
+
// EXTERNAL MODULE: ../../ui/src/index.js + 449 modules
|
|
1238
|
+
var ui_src = __webpack_require__(43803);
|
|
1239
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/PanelStudyBrowserTracking.tsx
|
|
1240
|
+
|
|
1241
|
+
|
|
1242
|
+
|
|
1243
|
+
|
|
1244
|
+
|
|
1245
|
+
const {
|
|
1246
|
+
formatDate
|
|
1247
|
+
} = src.utils;
|
|
1248
|
+
|
|
1249
|
+
/**
|
|
1250
|
+
*
|
|
1251
|
+
* @param {*} param0
|
|
1252
|
+
*/
|
|
1253
|
+
function PanelStudyBrowserTracking(_ref) {
|
|
1254
|
+
let {
|
|
1255
|
+
servicesManager,
|
|
1256
|
+
getImageSrc,
|
|
1257
|
+
getStudiesForPatientByMRN,
|
|
1258
|
+
requestDisplaySetCreationForStudy,
|
|
1259
|
+
dataSource
|
|
1260
|
+
} = _ref;
|
|
1261
|
+
const {
|
|
1262
|
+
measurementService,
|
|
1263
|
+
displaySetService,
|
|
1264
|
+
uiDialogService,
|
|
1265
|
+
hangingProtocolService,
|
|
1266
|
+
uiNotificationService
|
|
1267
|
+
} = servicesManager.services;
|
|
1268
|
+
|
|
1269
|
+
// Normally you nest the components so the tree isn't so deep, and the data
|
|
1270
|
+
// doesn't have to have such an intense shape. This works well enough for now.
|
|
1271
|
+
// Tabs --> Studies --> DisplaySets --> Thumbnails
|
|
1272
|
+
const {
|
|
1273
|
+
StudyInstanceUIDs
|
|
1274
|
+
} = (0,ui_src/* useImageViewer */.zG)();
|
|
1275
|
+
const [{
|
|
1276
|
+
activeViewportIndex,
|
|
1277
|
+
viewports,
|
|
1278
|
+
numCols,
|
|
1279
|
+
numRows
|
|
1280
|
+
}, viewportGridService] = (0,ui_src/* useViewportGrid */.O_)();
|
|
1281
|
+
const [trackedMeasurements, sendTrackedMeasurementsEvent] = (0,getContextModule/* useTrackedMeasurements */.I)();
|
|
1282
|
+
const [activeTabName, setActiveTabName] = (0,react.useState)('primary');
|
|
1283
|
+
const [expandedStudyInstanceUIDs, setExpandedStudyInstanceUIDs] = (0,react.useState)([...StudyInstanceUIDs]);
|
|
1284
|
+
const [studyDisplayList, setStudyDisplayList] = (0,react.useState)([]);
|
|
1285
|
+
const [displaySets, setDisplaySets] = (0,react.useState)([]);
|
|
1286
|
+
const [thumbnailImageSrcMap, setThumbnailImageSrcMap] = (0,react.useState)({});
|
|
1287
|
+
const [jumpToDisplaySet, setJumpToDisplaySet] = (0,react.useState)(null);
|
|
1288
|
+
const onDoubleClickThumbnailHandler = displaySetInstanceUID => {
|
|
1289
|
+
let updatedViewports = [];
|
|
1290
|
+
const viewportIndex = activeViewportIndex;
|
|
1291
|
+
try {
|
|
1292
|
+
updatedViewports = hangingProtocolService.getViewportsRequireUpdate(viewportIndex, displaySetInstanceUID);
|
|
1293
|
+
} catch (error) {
|
|
1294
|
+
console.warn(error);
|
|
1295
|
+
uiNotificationService.show({
|
|
1296
|
+
title: 'Thumbnail Double Click',
|
|
1297
|
+
message: 'The selected display sets could not be added to the viewport due to a mismatch in the Hanging Protocol rules.',
|
|
1298
|
+
type: 'info',
|
|
1299
|
+
duration: 3000
|
|
1300
|
+
});
|
|
1301
|
+
}
|
|
1302
|
+
viewportGridService.setDisplaySetsForViewports(updatedViewports);
|
|
1303
|
+
};
|
|
1304
|
+
const activeViewportDisplaySetInstanceUIDs = viewports[activeViewportIndex]?.displaySetInstanceUIDs;
|
|
1305
|
+
(0,react.useEffect)(() => {
|
|
1306
|
+
const added = measurementService.EVENTS.MEASUREMENT_ADDED;
|
|
1307
|
+
const addedRaw = measurementService.EVENTS.RAW_MEASUREMENT_ADDED;
|
|
1308
|
+
const subscriptions = [];
|
|
1309
|
+
[added, addedRaw].forEach(evt => {
|
|
1310
|
+
subscriptions.push(measurementService.subscribe(evt, _ref2 => {
|
|
1311
|
+
let {
|
|
1312
|
+
source,
|
|
1313
|
+
measurement
|
|
1314
|
+
} = _ref2;
|
|
1315
|
+
const {
|
|
1316
|
+
referenceSeriesUID: SeriesInstanceUID,
|
|
1317
|
+
referenceStudyUID: StudyInstanceUID
|
|
1318
|
+
} = measurement;
|
|
1319
|
+
sendTrackedMeasurementsEvent('SET_DIRTY', {
|
|
1320
|
+
SeriesInstanceUID
|
|
1321
|
+
});
|
|
1322
|
+
sendTrackedMeasurementsEvent('TRACK_SERIES', {
|
|
1323
|
+
viewportIndex: activeViewportIndex,
|
|
1324
|
+
StudyInstanceUID,
|
|
1325
|
+
SeriesInstanceUID
|
|
1326
|
+
});
|
|
1327
|
+
}).unsubscribe);
|
|
1328
|
+
});
|
|
1329
|
+
return () => {
|
|
1330
|
+
subscriptions.forEach(unsub => {
|
|
1331
|
+
unsub();
|
|
1332
|
+
});
|
|
1333
|
+
};
|
|
1334
|
+
}, [measurementService, activeViewportIndex, sendTrackedMeasurementsEvent]);
|
|
1335
|
+
const {
|
|
1336
|
+
trackedSeries
|
|
1337
|
+
} = trackedMeasurements.context;
|
|
1338
|
+
|
|
1339
|
+
// ~~ studyDisplayList
|
|
1340
|
+
(0,react.useEffect)(() => {
|
|
1341
|
+
// Fetch all studies for the patient in each primary study
|
|
1342
|
+
async function fetchStudiesForPatient(StudyInstanceUID) {
|
|
1343
|
+
// current study qido
|
|
1344
|
+
const qidoForStudyUID = await dataSource.query.studies.search({
|
|
1345
|
+
studyInstanceUid: StudyInstanceUID
|
|
1346
|
+
});
|
|
1347
|
+
let qidoStudiesForPatient = qidoForStudyUID;
|
|
1348
|
+
|
|
1349
|
+
// try to fetch the prior studies based on the patientID if the
|
|
1350
|
+
// server can respond.
|
|
1351
|
+
try {
|
|
1352
|
+
qidoStudiesForPatient = await getStudiesForPatientByMRN(qidoForStudyUID);
|
|
1353
|
+
} catch (error) {
|
|
1354
|
+
console.warn(error);
|
|
1355
|
+
}
|
|
1356
|
+
const mappedStudies = _mapDataSourceStudies(qidoStudiesForPatient);
|
|
1357
|
+
const actuallyMappedStudies = mappedStudies.map(qidoStudy => {
|
|
1358
|
+
return {
|
|
1359
|
+
studyInstanceUid: qidoStudy.StudyInstanceUID,
|
|
1360
|
+
date: formatDate(qidoStudy.StudyDate),
|
|
1361
|
+
description: qidoStudy.StudyDescription,
|
|
1362
|
+
modalities: qidoStudy.ModalitiesInStudy,
|
|
1363
|
+
numInstances: qidoStudy.NumInstances
|
|
1364
|
+
};
|
|
1365
|
+
});
|
|
1366
|
+
setStudyDisplayList(prevArray => {
|
|
1367
|
+
const ret = [...prevArray];
|
|
1368
|
+
for (const study of actuallyMappedStudies) {
|
|
1369
|
+
if (!prevArray.find(it => it.studyInstanceUid === study.studyInstanceUid)) {
|
|
1370
|
+
ret.push(study);
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
return ret;
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1376
|
+
StudyInstanceUIDs.forEach(sid => fetchStudiesForPatient(sid));
|
|
1377
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1378
|
+
}, [StudyInstanceUIDs, getStudiesForPatientByMRN]);
|
|
1379
|
+
|
|
1380
|
+
// ~~ Initial Thumbnails
|
|
1381
|
+
(0,react.useEffect)(() => {
|
|
1382
|
+
const currentDisplaySets = displaySetService.activeDisplaySets;
|
|
1383
|
+
if (!currentDisplaySets.length) {
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
currentDisplaySets.forEach(async dSet => {
|
|
1387
|
+
const newImageSrcEntry = {};
|
|
1388
|
+
const displaySet = displaySetService.getDisplaySetByUID(dSet.displaySetInstanceUID);
|
|
1389
|
+
const imageIds = dataSource.getImageIdsForDisplaySet(displaySet);
|
|
1390
|
+
const imageId = imageIds[Math.floor(imageIds.length / 2)];
|
|
1391
|
+
|
|
1392
|
+
// TODO: Is it okay that imageIds are not returned here for SR displaysets?
|
|
1393
|
+
if (imageId) {
|
|
1394
|
+
// When the image arrives, render it and store the result in the thumbnailImgSrcMap
|
|
1395
|
+
newImageSrcEntry[dSet.displaySetInstanceUID] = await getImageSrc(imageId);
|
|
1396
|
+
setThumbnailImageSrcMap(prevState => {
|
|
1397
|
+
return {
|
|
1398
|
+
...prevState,
|
|
1399
|
+
...newImageSrcEntry
|
|
1400
|
+
};
|
|
1401
|
+
});
|
|
1402
|
+
}
|
|
1403
|
+
});
|
|
1404
|
+
}, [displaySetService, dataSource, getImageSrc]);
|
|
1405
|
+
|
|
1406
|
+
// ~~ displaySets
|
|
1407
|
+
(0,react.useEffect)(() => {
|
|
1408
|
+
const currentDisplaySets = displaySetService.activeDisplaySets;
|
|
1409
|
+
if (!currentDisplaySets.length) {
|
|
1410
|
+
return;
|
|
1411
|
+
}
|
|
1412
|
+
const mappedDisplaySets = _mapDisplaySets(currentDisplaySets, thumbnailImageSrcMap, trackedSeries, viewports, viewportGridService, dataSource, displaySetService, uiDialogService, uiNotificationService);
|
|
1413
|
+
setDisplaySets(mappedDisplaySets);
|
|
1414
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1415
|
+
}, [displaySetService.activeDisplaySets, trackedSeries, viewports, dataSource, thumbnailImageSrcMap]);
|
|
1416
|
+
|
|
1417
|
+
// ~~ subscriptions --> displaySets
|
|
1418
|
+
(0,react.useEffect)(() => {
|
|
1419
|
+
// DISPLAY_SETS_ADDED returns an array of DisplaySets that were added
|
|
1420
|
+
const SubscriptionDisplaySetsAdded = displaySetService.subscribe(displaySetService.EVENTS.DISPLAY_SETS_ADDED, data => {
|
|
1421
|
+
const {
|
|
1422
|
+
displaySetsAdded,
|
|
1423
|
+
options
|
|
1424
|
+
} = data;
|
|
1425
|
+
displaySetsAdded.forEach(async dSet => {
|
|
1426
|
+
const displaySetInstanceUID = dSet.displaySetInstanceUID;
|
|
1427
|
+
const newImageSrcEntry = {};
|
|
1428
|
+
const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
|
|
1429
|
+
if (options.madeInClient) {
|
|
1430
|
+
setJumpToDisplaySet(displaySetInstanceUID);
|
|
1431
|
+
}
|
|
1432
|
+
const imageIds = dataSource.getImageIdsForDisplaySet(displaySet);
|
|
1433
|
+
const imageId = imageIds[Math.floor(imageIds.length / 2)];
|
|
1434
|
+
|
|
1435
|
+
// TODO: Is it okay that imageIds are not returned here for SR displaysets?
|
|
1436
|
+
if (imageId) {
|
|
1437
|
+
// When the image arrives, render it and store the result in the thumbnailImgSrcMap
|
|
1438
|
+
newImageSrcEntry[displaySetInstanceUID] = await getImageSrc(imageId);
|
|
1439
|
+
setThumbnailImageSrcMap(prevState => {
|
|
1440
|
+
return {
|
|
1441
|
+
...prevState,
|
|
1442
|
+
...newImageSrcEntry
|
|
1443
|
+
};
|
|
1444
|
+
});
|
|
1445
|
+
}
|
|
1446
|
+
});
|
|
1447
|
+
});
|
|
1448
|
+
|
|
1449
|
+
// TODO: Will this always hold _all_ the displaySets we care about?
|
|
1450
|
+
// DISPLAY_SETS_CHANGED returns `DisplaySerService.activeDisplaySets`
|
|
1451
|
+
const SubscriptionDisplaySetsChanged = displaySetService.subscribe(displaySetService.EVENTS.DISPLAY_SETS_CHANGED, changedDisplaySets => {
|
|
1452
|
+
const mappedDisplaySets = _mapDisplaySets(changedDisplaySets, thumbnailImageSrcMap, trackedSeries, viewports, viewportGridService, dataSource, displaySetService, uiDialogService, uiNotificationService);
|
|
1453
|
+
setDisplaySets(mappedDisplaySets);
|
|
1454
|
+
});
|
|
1455
|
+
return () => {
|
|
1456
|
+
SubscriptionDisplaySetsAdded.unsubscribe();
|
|
1457
|
+
SubscriptionDisplaySetsChanged.unsubscribe();
|
|
1458
|
+
};
|
|
1459
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1460
|
+
}, [displaySetService, dataSource, getImageSrc, thumbnailImageSrcMap, trackedSeries, viewports]);
|
|
1461
|
+
const tabs = _createStudyBrowserTabs(StudyInstanceUIDs, studyDisplayList, displaySets, hangingProtocolService);
|
|
1462
|
+
|
|
1463
|
+
// TODO: Should not fire this on "close"
|
|
1464
|
+
function _handleStudyClick(StudyInstanceUID) {
|
|
1465
|
+
const shouldCollapseStudy = expandedStudyInstanceUIDs.includes(StudyInstanceUID);
|
|
1466
|
+
const updatedExpandedStudyInstanceUIDs = shouldCollapseStudy ? [...expandedStudyInstanceUIDs.filter(stdyUid => stdyUid !== StudyInstanceUID)] : [...expandedStudyInstanceUIDs, StudyInstanceUID];
|
|
1467
|
+
setExpandedStudyInstanceUIDs(updatedExpandedStudyInstanceUIDs);
|
|
1468
|
+
if (!shouldCollapseStudy) {
|
|
1469
|
+
const madeInClient = true;
|
|
1470
|
+
requestDisplaySetCreationForStudy(displaySetService, StudyInstanceUID, madeInClient);
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
(0,react.useEffect)(() => {
|
|
1474
|
+
if (jumpToDisplaySet) {
|
|
1475
|
+
// Get element by displaySetInstanceUID
|
|
1476
|
+
const displaySetInstanceUID = jumpToDisplaySet;
|
|
1477
|
+
const element = document.getElementById(`thumbnail-${displaySetInstanceUID}`);
|
|
1478
|
+
if (element && typeof element.scrollIntoView === 'function') {
|
|
1479
|
+
// TODO: Any way to support IE here?
|
|
1480
|
+
element.scrollIntoView({
|
|
1481
|
+
behavior: 'smooth'
|
|
1482
|
+
});
|
|
1483
|
+
setJumpToDisplaySet(null);
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
}, [jumpToDisplaySet, expandedStudyInstanceUIDs, activeTabName]);
|
|
1487
|
+
(0,react.useEffect)(() => {
|
|
1488
|
+
if (!jumpToDisplaySet) {
|
|
1489
|
+
return;
|
|
1490
|
+
}
|
|
1491
|
+
const displaySetInstanceUID = jumpToDisplaySet;
|
|
1492
|
+
// Set the activeTabName and expand the study
|
|
1493
|
+
const thumbnailLocation = _findTabAndStudyOfDisplaySet(displaySetInstanceUID, tabs);
|
|
1494
|
+
if (!thumbnailLocation) {
|
|
1495
|
+
console.warn('jumpToThumbnail: displaySet thumbnail not found.');
|
|
1496
|
+
return;
|
|
1497
|
+
}
|
|
1498
|
+
const {
|
|
1499
|
+
tabName,
|
|
1500
|
+
StudyInstanceUID
|
|
1501
|
+
} = thumbnailLocation;
|
|
1502
|
+
setActiveTabName(tabName);
|
|
1503
|
+
const studyExpanded = expandedStudyInstanceUIDs.includes(StudyInstanceUID);
|
|
1504
|
+
if (!studyExpanded) {
|
|
1505
|
+
const updatedExpandedStudyInstanceUIDs = [...expandedStudyInstanceUIDs, StudyInstanceUID];
|
|
1506
|
+
setExpandedStudyInstanceUIDs(updatedExpandedStudyInstanceUIDs);
|
|
1507
|
+
}
|
|
1508
|
+
}, [expandedStudyInstanceUIDs, jumpToDisplaySet, tabs]);
|
|
1509
|
+
return /*#__PURE__*/react.createElement(ui_src/* StudyBrowser */.eX, {
|
|
1510
|
+
tabs: tabs,
|
|
1511
|
+
servicesManager: servicesManager,
|
|
1512
|
+
activeTabName: activeTabName,
|
|
1513
|
+
expandedStudyInstanceUIDs: expandedStudyInstanceUIDs,
|
|
1514
|
+
onClickStudy: _handleStudyClick,
|
|
1515
|
+
onClickTab: clickedTabName => {
|
|
1516
|
+
setActiveTabName(clickedTabName);
|
|
1517
|
+
},
|
|
1518
|
+
onClickUntrack: displaySetInstanceUID => {
|
|
1519
|
+
const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
|
|
1520
|
+
// TODO: shift this somewhere else where we're centralizing this logic?
|
|
1521
|
+
// Potentially a helper from displaySetInstanceUID to this
|
|
1522
|
+
sendTrackedMeasurementsEvent('UNTRACK_SERIES', {
|
|
1523
|
+
SeriesInstanceUID: displaySet.SeriesInstanceUID
|
|
1524
|
+
});
|
|
1525
|
+
},
|
|
1526
|
+
onClickThumbnail: () => {},
|
|
1527
|
+
onDoubleClickThumbnail: onDoubleClickThumbnailHandler,
|
|
1528
|
+
activeDisplaySetInstanceUIDs: activeViewportDisplaySetInstanceUIDs
|
|
1529
|
+
});
|
|
1530
|
+
}
|
|
1531
|
+
PanelStudyBrowserTracking.propTypes = {
|
|
1532
|
+
servicesManager: (prop_types_default()).object.isRequired,
|
|
1533
|
+
dataSource: prop_types_default().shape({
|
|
1534
|
+
getImageIdsForDisplaySet: (prop_types_default()).func.isRequired
|
|
1535
|
+
}).isRequired,
|
|
1536
|
+
getImageSrc: (prop_types_default()).func.isRequired,
|
|
1537
|
+
getStudiesForPatientByMRN: (prop_types_default()).func.isRequired,
|
|
1538
|
+
requestDisplaySetCreationForStudy: (prop_types_default()).func.isRequired
|
|
1539
|
+
};
|
|
1540
|
+
/* harmony default export */ const PanelStudyBrowserTracking_PanelStudyBrowserTracking = (PanelStudyBrowserTracking);
|
|
1541
|
+
|
|
1542
|
+
/**
|
|
1543
|
+
* Maps from the DataSource's format to a naturalized object
|
|
1544
|
+
*
|
|
1545
|
+
* @param {*} studies
|
|
1546
|
+
*/
|
|
1547
|
+
function _mapDataSourceStudies(studies) {
|
|
1548
|
+
return studies.map(study => {
|
|
1549
|
+
// TODO: Why does the data source return in this format?
|
|
1550
|
+
return {
|
|
1551
|
+
AccessionNumber: study.accession,
|
|
1552
|
+
StudyDate: study.date,
|
|
1553
|
+
StudyDescription: study.description,
|
|
1554
|
+
NumInstances: study.instances,
|
|
1555
|
+
ModalitiesInStudy: study.modalities,
|
|
1556
|
+
PatientID: study.mrn,
|
|
1557
|
+
PatientName: study.patientName,
|
|
1558
|
+
StudyInstanceUID: study.studyInstanceUid,
|
|
1559
|
+
StudyTime: study.time
|
|
1560
|
+
};
|
|
1561
|
+
});
|
|
1562
|
+
}
|
|
1563
|
+
function _mapDisplaySets(displaySets, thumbnailImageSrcMap, trackedSeriesInstanceUIDs, viewports,
|
|
1564
|
+
// TODO: make array of `displaySetInstanceUIDs`?
|
|
1565
|
+
viewportGridService, dataSource, displaySetService, uiDialogService, uiNotificationService) {
|
|
1566
|
+
const thumbnailDisplaySets = [];
|
|
1567
|
+
const thumbnailNoImageDisplaySets = [];
|
|
1568
|
+
displaySets.filter(ds => !ds.excludeFromThumbnailBrowser).forEach(ds => {
|
|
1569
|
+
const imageSrc = thumbnailImageSrcMap[ds.displaySetInstanceUID];
|
|
1570
|
+
const componentType = _getComponentType(ds.Modality);
|
|
1571
|
+
const numPanes = viewportGridService.getNumViewportPanes();
|
|
1572
|
+
const viewportIdentificator = numPanes === 1 ? [] : viewports.reduce((acc, viewportData, index) => {
|
|
1573
|
+
if (index < numPanes && viewportData?.displaySetInstanceUIDs?.includes(ds.displaySetInstanceUID)) {
|
|
1574
|
+
acc.push(viewportData.viewportLabel);
|
|
1575
|
+
}
|
|
1576
|
+
return acc;
|
|
1577
|
+
}, []);
|
|
1578
|
+
const array = componentType === 'thumbnailTracked' ? thumbnailDisplaySets : thumbnailNoImageDisplaySets;
|
|
1579
|
+
const {
|
|
1580
|
+
displaySetInstanceUID
|
|
1581
|
+
} = ds;
|
|
1582
|
+
const thumbnailProps = {
|
|
1583
|
+
displaySetInstanceUID,
|
|
1584
|
+
description: ds.SeriesDescription,
|
|
1585
|
+
seriesNumber: ds.SeriesNumber,
|
|
1586
|
+
modality: ds.Modality,
|
|
1587
|
+
seriesDate: formatDate(ds.SeriesDate),
|
|
1588
|
+
numInstances: ds.numImageFrames,
|
|
1589
|
+
countIcon: ds.countIcon,
|
|
1590
|
+
StudyInstanceUID: ds.StudyInstanceUID,
|
|
1591
|
+
componentType,
|
|
1592
|
+
imageSrc,
|
|
1593
|
+
dragData: {
|
|
1594
|
+
type: 'displayset',
|
|
1595
|
+
displaySetInstanceUID
|
|
1596
|
+
// .. Any other data to pass
|
|
1597
|
+
},
|
|
1598
|
+
|
|
1599
|
+
isTracked: trackedSeriesInstanceUIDs.includes(ds.SeriesInstanceUID),
|
|
1600
|
+
viewportIdentificator
|
|
1601
|
+
};
|
|
1602
|
+
if (componentType === 'thumbnailNoImage') {
|
|
1603
|
+
if (dataSource.reject && dataSource.reject.series) {
|
|
1604
|
+
thumbnailProps.canReject = true;
|
|
1605
|
+
thumbnailProps.onReject = () => {
|
|
1606
|
+
uiDialogService.create({
|
|
1607
|
+
id: 'ds-reject-sr',
|
|
1608
|
+
centralize: true,
|
|
1609
|
+
isDraggable: false,
|
|
1610
|
+
showOverlay: true,
|
|
1611
|
+
content: ui_src/* Dialog */.Vq,
|
|
1612
|
+
contentProps: {
|
|
1613
|
+
title: 'Delete Report',
|
|
1614
|
+
body: () => /*#__PURE__*/react.createElement("div", {
|
|
1615
|
+
className: "p-4 text-white bg-primary-dark"
|
|
1616
|
+
}, /*#__PURE__*/react.createElement("p", null, "Are you sure you want to delete this report?"), /*#__PURE__*/react.createElement("p", null, "This action cannot be undone.")),
|
|
1617
|
+
actions: [{
|
|
1618
|
+
id: 'cancel',
|
|
1619
|
+
text: 'Cancel',
|
|
1620
|
+
type: 'secondary'
|
|
1621
|
+
}, {
|
|
1622
|
+
id: 'yes',
|
|
1623
|
+
text: 'Yes',
|
|
1624
|
+
type: 'primary',
|
|
1625
|
+
classes: ['reject-yes-button']
|
|
1626
|
+
}],
|
|
1627
|
+
onClose: () => uiDialogService.dismiss({
|
|
1628
|
+
id: 'ds-reject-sr'
|
|
1629
|
+
}),
|
|
1630
|
+
onShow: () => {
|
|
1631
|
+
const yesButton = document.querySelector('.reject-yes-button');
|
|
1632
|
+
yesButton.focus();
|
|
1633
|
+
},
|
|
1634
|
+
onSubmit: async _ref3 => {
|
|
1635
|
+
let {
|
|
1636
|
+
action
|
|
1637
|
+
} = _ref3;
|
|
1638
|
+
switch (action.id) {
|
|
1639
|
+
case 'yes':
|
|
1640
|
+
try {
|
|
1641
|
+
await dataSource.reject.series(ds.StudyInstanceUID, ds.SeriesInstanceUID);
|
|
1642
|
+
displaySetService.deleteDisplaySet(displaySetInstanceUID);
|
|
1643
|
+
uiDialogService.dismiss({
|
|
1644
|
+
id: 'ds-reject-sr'
|
|
1645
|
+
});
|
|
1646
|
+
uiNotificationService.show({
|
|
1647
|
+
title: 'Delete Report',
|
|
1648
|
+
message: 'Report deleted successfully',
|
|
1649
|
+
type: 'success'
|
|
1650
|
+
});
|
|
1651
|
+
} catch (error) {
|
|
1652
|
+
uiDialogService.dismiss({
|
|
1653
|
+
id: 'ds-reject-sr'
|
|
1654
|
+
});
|
|
1655
|
+
uiNotificationService.show({
|
|
1656
|
+
title: 'Delete Report',
|
|
1657
|
+
message: 'Failed to delete report',
|
|
1658
|
+
type: 'error'
|
|
1659
|
+
});
|
|
1660
|
+
}
|
|
1661
|
+
break;
|
|
1662
|
+
case 'cancel':
|
|
1663
|
+
uiDialogService.dismiss({
|
|
1664
|
+
id: 'ds-reject-sr'
|
|
1665
|
+
});
|
|
1666
|
+
break;
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
});
|
|
1671
|
+
};
|
|
1672
|
+
} else {
|
|
1673
|
+
thumbnailProps.canReject = false;
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
array.push(thumbnailProps);
|
|
1677
|
+
});
|
|
1678
|
+
return [...thumbnailDisplaySets, ...thumbnailNoImageDisplaySets];
|
|
1679
|
+
}
|
|
1680
|
+
const thumbnailNoImageModalities = ['SR', 'SEG', 'SM', 'RTSTRUCT', 'RTPLAN', 'RTDOSE', 'DOC', 'OT'];
|
|
1681
|
+
function _getComponentType(Modality) {
|
|
1682
|
+
if (thumbnailNoImageModalities.includes(Modality)) {
|
|
1683
|
+
return 'thumbnailNoImage';
|
|
1684
|
+
}
|
|
1685
|
+
return 'thumbnailTracked';
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
/**
|
|
1689
|
+
*
|
|
1690
|
+
* @param {string[]} primaryStudyInstanceUIDs
|
|
1691
|
+
* @param {object[]} studyDisplayList
|
|
1692
|
+
* @param {string} studyDisplayList.studyInstanceUid
|
|
1693
|
+
* @param {string} studyDisplayList.date
|
|
1694
|
+
* @param {string} studyDisplayList.description
|
|
1695
|
+
* @param {string} studyDisplayList.modalities
|
|
1696
|
+
* @param {number} studyDisplayList.numInstances
|
|
1697
|
+
* @param {object[]} displaySets
|
|
1698
|
+
* @returns tabs - The prop object expected by the StudyBrowser component
|
|
1699
|
+
*/
|
|
1700
|
+
function _createStudyBrowserTabs(primaryStudyInstanceUIDs, studyDisplayList, displaySets, hangingProtocolService) {
|
|
1701
|
+
const primaryStudies = [];
|
|
1702
|
+
const recentStudies = [];
|
|
1703
|
+
const allStudies = [];
|
|
1704
|
+
|
|
1705
|
+
// Iterate over each study...
|
|
1706
|
+
studyDisplayList.forEach(study => {
|
|
1707
|
+
// Find it's display sets
|
|
1708
|
+
const displaySetsForStudy = displaySets.filter(ds => ds.StudyInstanceUID === study.studyInstanceUid);
|
|
1709
|
+
|
|
1710
|
+
// Sort them
|
|
1711
|
+
const dsSortFn = hangingProtocolService.getDisplaySetSortFunction();
|
|
1712
|
+
displaySetsForStudy.sort(dsSortFn);
|
|
1713
|
+
|
|
1714
|
+
/* Sort by series number, then by series date
|
|
1715
|
+
displaySetsForStudy.sort((a, b) => {
|
|
1716
|
+
if (a.seriesNumber !== b.seriesNumber) {
|
|
1717
|
+
return a.seriesNumber - b.seriesNumber;
|
|
1718
|
+
}
|
|
1719
|
+
const seriesDateA = Date.parse(a.seriesDate);
|
|
1720
|
+
const seriesDateB = Date.parse(b.seriesDate);
|
|
1721
|
+
return seriesDateA - seriesDateB;
|
|
1722
|
+
});
|
|
1723
|
+
*/
|
|
1724
|
+
|
|
1725
|
+
// Map the study to it's tab/view representation
|
|
1726
|
+
const tabStudy = Object.assign({}, study, {
|
|
1727
|
+
displaySets: displaySetsForStudy
|
|
1728
|
+
});
|
|
1729
|
+
|
|
1730
|
+
// Add the "tab study" to the 'primary', 'recent', and/or 'all' tab group(s)
|
|
1731
|
+
if (primaryStudyInstanceUIDs.includes(study.studyInstanceUid)) {
|
|
1732
|
+
primaryStudies.push(tabStudy);
|
|
1733
|
+
allStudies.push(tabStudy);
|
|
1734
|
+
} else {
|
|
1735
|
+
// TODO: Filter allStudies to dates within one year of current date
|
|
1736
|
+
recentStudies.push(tabStudy);
|
|
1737
|
+
allStudies.push(tabStudy);
|
|
1738
|
+
}
|
|
1739
|
+
});
|
|
1740
|
+
|
|
1741
|
+
// Newest first
|
|
1742
|
+
const _byDate = (a, b) => {
|
|
1743
|
+
const dateA = Date.parse(a);
|
|
1744
|
+
const dateB = Date.parse(b);
|
|
1745
|
+
return dateB - dateA;
|
|
1746
|
+
};
|
|
1747
|
+
const tabs = [{
|
|
1748
|
+
name: 'primary',
|
|
1749
|
+
label: 'Primary',
|
|
1750
|
+
studies: primaryStudies.sort((studyA, studyB) => _byDate(studyA.date, studyB.date))
|
|
1751
|
+
}, {
|
|
1752
|
+
name: 'recent',
|
|
1753
|
+
label: 'Recent',
|
|
1754
|
+
studies: recentStudies.sort((studyA, studyB) => _byDate(studyA.date, studyB.date))
|
|
1755
|
+
}, {
|
|
1756
|
+
name: 'all',
|
|
1757
|
+
label: 'All',
|
|
1758
|
+
studies: allStudies.sort((studyA, studyB) => _byDate(studyA.date, studyB.date))
|
|
1759
|
+
}];
|
|
1760
|
+
return tabs;
|
|
1761
|
+
}
|
|
1762
|
+
function _findTabAndStudyOfDisplaySet(displaySetInstanceUID, tabs) {
|
|
1763
|
+
for (let t = 0; t < tabs.length; t++) {
|
|
1764
|
+
const {
|
|
1765
|
+
studies
|
|
1766
|
+
} = tabs[t];
|
|
1767
|
+
for (let s = 0; s < studies.length; s++) {
|
|
1768
|
+
const {
|
|
1769
|
+
displaySets
|
|
1770
|
+
} = studies[s];
|
|
1771
|
+
for (let d = 0; d < displaySets.length; d++) {
|
|
1772
|
+
const displaySet = displaySets[d];
|
|
1773
|
+
if (displaySet.displaySetInstanceUID === displaySetInstanceUID) {
|
|
1774
|
+
return {
|
|
1775
|
+
tabName: tabs[t].name,
|
|
1776
|
+
StudyInstanceUID: studies[s].studyInstanceUid
|
|
1777
|
+
};
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/getImageSrcFromImageId.js
|
|
1784
|
+
/**
|
|
1785
|
+
* @param {*} cornerstone
|
|
1786
|
+
* @param {*} imageId
|
|
1787
|
+
*/
|
|
1788
|
+
function getImageSrcFromImageId(cornerstone, imageId) {
|
|
1789
|
+
return new Promise((resolve, reject) => {
|
|
1790
|
+
const canvas = document.createElement('canvas');
|
|
1791
|
+
cornerstone.utilities.loadImageToCanvas({
|
|
1792
|
+
canvas,
|
|
1793
|
+
imageId
|
|
1794
|
+
}).then(imageId => {
|
|
1795
|
+
resolve(canvas.toDataURL());
|
|
1796
|
+
}).catch(reject);
|
|
1797
|
+
});
|
|
1798
|
+
}
|
|
1799
|
+
/* harmony default export */ const PanelStudyBrowserTracking_getImageSrcFromImageId = (getImageSrcFromImageId);
|
|
1800
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/requestDisplaySetCreationForStudy.js
|
|
1801
|
+
function requestDisplaySetCreationForStudy(dataSource, displaySetService, StudyInstanceUID, madeInClient) {
|
|
1802
|
+
if (displaySetService.activeDisplaySets.some(displaySet => displaySet.StudyInstanceUID === StudyInstanceUID)) {
|
|
1803
|
+
return;
|
|
1804
|
+
}
|
|
1805
|
+
dataSource.retrieve.series.metadata({
|
|
1806
|
+
StudyInstanceUID,
|
|
1807
|
+
madeInClient
|
|
1808
|
+
});
|
|
1809
|
+
}
|
|
1810
|
+
/* harmony default export */ const PanelStudyBrowserTracking_requestDisplaySetCreationForStudy = (requestDisplaySetCreationForStudy);
|
|
1811
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/panels/PanelStudyBrowserTracking/index.tsx
|
|
1812
|
+
|
|
1813
|
+
|
|
1814
|
+
//
|
|
1815
|
+
|
|
1816
|
+
|
|
1817
|
+
|
|
1818
|
+
function _getStudyForPatientUtility(extensionManager) {
|
|
1819
|
+
const utilityModule = extensionManager.getModuleEntry('@ohif/extension-default.utilityModule.common');
|
|
1820
|
+
const {
|
|
1821
|
+
getStudiesForPatientByMRN
|
|
1822
|
+
} = utilityModule.exports;
|
|
1823
|
+
return getStudiesForPatientByMRN;
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
/**
|
|
1827
|
+
* Wraps the PanelStudyBrowser and provides features afforded by managers/services
|
|
1828
|
+
*
|
|
1829
|
+
* @param {object} params
|
|
1830
|
+
* @param {object} commandsManager
|
|
1831
|
+
* @param {object} extensionManager
|
|
1832
|
+
*/
|
|
1833
|
+
function WrappedPanelStudyBrowserTracking(_ref) {
|
|
1834
|
+
let {
|
|
1835
|
+
commandsManager,
|
|
1836
|
+
extensionManager,
|
|
1837
|
+
servicesManager
|
|
1838
|
+
} = _ref;
|
|
1839
|
+
const dataSource = extensionManager.getActiveDataSource()[0];
|
|
1840
|
+
const getStudiesForPatientByMRN = _getStudyForPatientUtility(extensionManager);
|
|
1841
|
+
const _getStudiesForPatientByMRN = getStudiesForPatientByMRN.bind(null, dataSource);
|
|
1842
|
+
const _getImageSrcFromImageId = _createGetImageSrcFromImageIdFn(extensionManager);
|
|
1843
|
+
const _requestDisplaySetCreationForStudy = PanelStudyBrowserTracking_requestDisplaySetCreationForStudy.bind(null, dataSource);
|
|
1844
|
+
return /*#__PURE__*/react.createElement(PanelStudyBrowserTracking_PanelStudyBrowserTracking, {
|
|
1845
|
+
servicesManager: servicesManager,
|
|
1846
|
+
dataSource: dataSource,
|
|
1847
|
+
getImageSrc: _getImageSrcFromImageId,
|
|
1848
|
+
getStudiesForPatientByMRN: _getStudiesForPatientByMRN,
|
|
1849
|
+
requestDisplaySetCreationForStudy: _requestDisplaySetCreationForStudy
|
|
1850
|
+
});
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1853
|
+
/**
|
|
1854
|
+
* Grabs cornerstone library reference using a dependent command from
|
|
1855
|
+
* the @ohif/extension-cornerstone extension. Then creates a helper function
|
|
1856
|
+
* that can take an imageId and return an image src.
|
|
1857
|
+
*
|
|
1858
|
+
* @param {func} getCommand - CommandManager's getCommand method
|
|
1859
|
+
* @returns {func} getImageSrcFromImageId - A utility function powered by
|
|
1860
|
+
* cornerstone
|
|
1861
|
+
*/
|
|
1862
|
+
function _createGetImageSrcFromImageIdFn(extensionManager) {
|
|
1863
|
+
const utilities = extensionManager.getModuleEntry('@ohif/extension-cornerstone.utilityModule.common');
|
|
1864
|
+
try {
|
|
1865
|
+
const {
|
|
1866
|
+
cornerstone
|
|
1867
|
+
} = utilities.exports.getCornerstoneLibraries();
|
|
1868
|
+
return PanelStudyBrowserTracking_getImageSrcFromImageId.bind(null, cornerstone);
|
|
1869
|
+
} catch (ex) {
|
|
1870
|
+
throw new Error('Required command not found');
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
WrappedPanelStudyBrowserTracking.propTypes = {
|
|
1874
|
+
commandsManager: (prop_types_default()).object.isRequired,
|
|
1875
|
+
extensionManager: (prop_types_default()).object.isRequired,
|
|
1876
|
+
servicesManager: (prop_types_default()).object.isRequired
|
|
1877
|
+
};
|
|
1878
|
+
/* harmony default export */ const panels_PanelStudyBrowserTracking = (WrappedPanelStudyBrowserTracking);
|
|
1879
|
+
// EXTERNAL MODULE: ./hooks/index.js + 3 modules
|
|
1880
|
+
var hooks = __webpack_require__(39852);
|
|
1881
|
+
// EXTERNAL MODULE: ../../../node_modules/react-i18next/dist/es/index.js + 15 modules
|
|
1882
|
+
var es = __webpack_require__(21572);
|
|
1883
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/panels/PanelMeasurementTableTracking/ActionButtons.tsx
|
|
1884
|
+
|
|
1885
|
+
|
|
1886
|
+
|
|
1887
|
+
|
|
1888
|
+
function ActionButtons(_ref) {
|
|
1889
|
+
let {
|
|
1890
|
+
onExportClick,
|
|
1891
|
+
onCreateReportClick,
|
|
1892
|
+
disabled
|
|
1893
|
+
} = _ref;
|
|
1894
|
+
const {
|
|
1895
|
+
t
|
|
1896
|
+
} = (0,es/* useTranslation */.$G)('MeasurementTable');
|
|
1897
|
+
return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement(ui_src/* Button */.zx, {
|
|
1898
|
+
className: "text-base px-2 py-2",
|
|
1899
|
+
size: "initial",
|
|
1900
|
+
variant: disabled ? 'disabled' : 'outlined',
|
|
1901
|
+
color: "black",
|
|
1902
|
+
border: "primaryActive",
|
|
1903
|
+
onClick: onExportClick,
|
|
1904
|
+
disabled: disabled
|
|
1905
|
+
}, t('Export')), /*#__PURE__*/react.createElement(ui_src/* Button */.zx, {
|
|
1906
|
+
className: "ml-2 px-2 text-base",
|
|
1907
|
+
variant: disabled ? 'disabled' : 'outlined',
|
|
1908
|
+
size: "initial",
|
|
1909
|
+
color: "black",
|
|
1910
|
+
border: "primaryActive",
|
|
1911
|
+
onClick: onCreateReportClick,
|
|
1912
|
+
disabled: disabled
|
|
1913
|
+
}, t('Create Report')));
|
|
1914
|
+
}
|
|
1915
|
+
ActionButtons.propTypes = {
|
|
1916
|
+
onExportClick: (prop_types_default()).func,
|
|
1917
|
+
onCreateReportClick: (prop_types_default()).func,
|
|
1918
|
+
disabled: (prop_types_default()).bool
|
|
1919
|
+
};
|
|
1920
|
+
ActionButtons.defaultProps = {
|
|
1921
|
+
onExportClick: () => alert('Export'),
|
|
1922
|
+
onCreateReportClick: () => alert('Create Report'),
|
|
1923
|
+
disabled: false
|
|
1924
|
+
};
|
|
1925
|
+
/* harmony default export */ const PanelMeasurementTableTracking_ActionButtons = (ActionButtons);
|
|
1926
|
+
// EXTERNAL MODULE: ../../../node_modules/lodash.debounce/index.js
|
|
1927
|
+
var lodash_debounce = __webpack_require__(40001);
|
|
1928
|
+
var lodash_debounce_default = /*#__PURE__*/__webpack_require__.n(lodash_debounce);
|
|
1929
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/panels/PanelMeasurementTableTracking/index.tsx
|
|
1930
|
+
|
|
1931
|
+
|
|
1932
|
+
|
|
1933
|
+
|
|
1934
|
+
|
|
1935
|
+
|
|
1936
|
+
|
|
1937
|
+
|
|
1938
|
+
const {
|
|
1939
|
+
downloadCSVReport
|
|
1940
|
+
} = src.utils;
|
|
1941
|
+
const {
|
|
1942
|
+
formatDate: PanelMeasurementTableTracking_formatDate
|
|
1943
|
+
} = src.utils;
|
|
1944
|
+
const DISPLAY_STUDY_SUMMARY_INITIAL_VALUE = {
|
|
1945
|
+
key: undefined,
|
|
1946
|
+
//
|
|
1947
|
+
date: '',
|
|
1948
|
+
// '07-Sep-2010',
|
|
1949
|
+
modality: '',
|
|
1950
|
+
// 'CT',
|
|
1951
|
+
description: '' // 'CHEST/ABD/PELVIS W CONTRAST',
|
|
1952
|
+
};
|
|
1953
|
+
|
|
1954
|
+
function PanelMeasurementTableTracking(_ref) {
|
|
1955
|
+
let {
|
|
1956
|
+
servicesManager,
|
|
1957
|
+
extensionManager
|
|
1958
|
+
} = _ref;
|
|
1959
|
+
const [viewportGrid, viewportGridService] = (0,ui_src/* useViewportGrid */.O_)();
|
|
1960
|
+
const [measurementChangeTimestamp, setMeasurementsUpdated] = (0,react.useState)(Date.now().toString());
|
|
1961
|
+
const debouncedMeasurementChangeTimestamp = (0,hooks/* useDebounce */.Nr)(measurementChangeTimestamp, 200);
|
|
1962
|
+
const {
|
|
1963
|
+
measurementService,
|
|
1964
|
+
uiDialogService,
|
|
1965
|
+
displaySetService
|
|
1966
|
+
} = servicesManager.services;
|
|
1967
|
+
const [trackedMeasurements, sendTrackedMeasurementsEvent] = (0,getContextModule/* useTrackedMeasurements */.I)();
|
|
1968
|
+
const {
|
|
1969
|
+
trackedStudy,
|
|
1970
|
+
trackedSeries
|
|
1971
|
+
} = trackedMeasurements.context;
|
|
1972
|
+
const [displayStudySummary, setDisplayStudySummary] = (0,react.useState)(DISPLAY_STUDY_SUMMARY_INITIAL_VALUE);
|
|
1973
|
+
const [displayMeasurements, setDisplayMeasurements] = (0,react.useState)([]);
|
|
1974
|
+
const measurementsPanelRef = (0,react.useRef)(null);
|
|
1975
|
+
(0,react.useEffect)(() => {
|
|
1976
|
+
const measurements = measurementService.getMeasurements();
|
|
1977
|
+
const filteredMeasurements = measurements.filter(m => trackedStudy === m.referenceStudyUID && trackedSeries.includes(m.referenceSeriesUID));
|
|
1978
|
+
const mappedMeasurements = filteredMeasurements.map(m => _mapMeasurementToDisplay(m, measurementService.VALUE_TYPES, displaySetService));
|
|
1979
|
+
setDisplayMeasurements(mappedMeasurements);
|
|
1980
|
+
// eslint-ignore-next-line
|
|
1981
|
+
}, [measurementService, trackedStudy, trackedSeries, debouncedMeasurementChangeTimestamp]);
|
|
1982
|
+
const updateDisplayStudySummary = async () => {
|
|
1983
|
+
if (trackedMeasurements.matches('tracking')) {
|
|
1984
|
+
const StudyInstanceUID = trackedStudy;
|
|
1985
|
+
const studyMeta = src.DicomMetadataStore.getStudy(StudyInstanceUID);
|
|
1986
|
+
const instanceMeta = studyMeta.series[0].instances[0];
|
|
1987
|
+
const {
|
|
1988
|
+
StudyDate,
|
|
1989
|
+
StudyDescription
|
|
1990
|
+
} = instanceMeta;
|
|
1991
|
+
const modalities = new Set();
|
|
1992
|
+
studyMeta.series.forEach(series => {
|
|
1993
|
+
if (trackedSeries.includes(series.SeriesInstanceUID)) {
|
|
1994
|
+
modalities.add(series.instances[0].Modality);
|
|
1995
|
+
}
|
|
1996
|
+
});
|
|
1997
|
+
const modality = Array.from(modalities).join('/');
|
|
1998
|
+
if (displayStudySummary.key !== StudyInstanceUID) {
|
|
1999
|
+
setDisplayStudySummary({
|
|
2000
|
+
key: StudyInstanceUID,
|
|
2001
|
+
date: StudyDate,
|
|
2002
|
+
// TODO: Format: '07-Sep-2010'
|
|
2003
|
+
modality,
|
|
2004
|
+
description: StudyDescription
|
|
2005
|
+
});
|
|
2006
|
+
}
|
|
2007
|
+
} else if (trackedStudy === '' || trackedStudy === undefined) {
|
|
2008
|
+
setDisplayStudySummary(DISPLAY_STUDY_SUMMARY_INITIAL_VALUE);
|
|
2009
|
+
}
|
|
2010
|
+
};
|
|
2011
|
+
|
|
2012
|
+
// ~~ DisplayStudySummary
|
|
2013
|
+
(0,react.useEffect)(() => {
|
|
2014
|
+
updateDisplayStudySummary();
|
|
2015
|
+
}, [displayStudySummary.key, trackedMeasurements, trackedStudy, updateDisplayStudySummary]);
|
|
2016
|
+
|
|
2017
|
+
// TODO: Better way to consolidated, debounce, check on change?
|
|
2018
|
+
// Are we exposing the right API for measurementService?
|
|
2019
|
+
// This watches for ALL measurementService changes. It updates a timestamp,
|
|
2020
|
+
// which is debounced. After a brief period of inactivity, this triggers
|
|
2021
|
+
// a re-render where we grab up-to-date measurements
|
|
2022
|
+
(0,react.useEffect)(() => {
|
|
2023
|
+
const added = measurementService.EVENTS.MEASUREMENT_ADDED;
|
|
2024
|
+
const addedRaw = measurementService.EVENTS.RAW_MEASUREMENT_ADDED;
|
|
2025
|
+
const updated = measurementService.EVENTS.MEASUREMENT_UPDATED;
|
|
2026
|
+
const removed = measurementService.EVENTS.MEASUREMENT_REMOVED;
|
|
2027
|
+
const cleared = measurementService.EVENTS.MEASUREMENTS_CLEARED;
|
|
2028
|
+
const subscriptions = [];
|
|
2029
|
+
[added, addedRaw, updated, removed, cleared].forEach(evt => {
|
|
2030
|
+
subscriptions.push(measurementService.subscribe(evt, () => {
|
|
2031
|
+
setMeasurementsUpdated(Date.now().toString());
|
|
2032
|
+
if (evt === added) {
|
|
2033
|
+
lodash_debounce_default()(() => {
|
|
2034
|
+
measurementsPanelRef.current.scrollTop = measurementsPanelRef.current.scrollHeight;
|
|
2035
|
+
}, 300)();
|
|
2036
|
+
}
|
|
2037
|
+
}).unsubscribe);
|
|
2038
|
+
});
|
|
2039
|
+
return () => {
|
|
2040
|
+
subscriptions.forEach(unsub => {
|
|
2041
|
+
unsub();
|
|
2042
|
+
});
|
|
2043
|
+
};
|
|
2044
|
+
}, [measurementService, sendTrackedMeasurementsEvent]);
|
|
2045
|
+
async function exportReport() {
|
|
2046
|
+
const measurements = measurementService.getMeasurements();
|
|
2047
|
+
const trackedMeasurements = measurements.filter(m => trackedStudy === m.referenceStudyUID && trackedSeries.includes(m.referenceSeriesUID));
|
|
2048
|
+
downloadCSVReport(trackedMeasurements, measurementService);
|
|
2049
|
+
}
|
|
2050
|
+
const jumpToImage = _ref2 => {
|
|
2051
|
+
let {
|
|
2052
|
+
uid,
|
|
2053
|
+
isActive
|
|
2054
|
+
} = _ref2;
|
|
2055
|
+
measurementService.jumpToMeasurement(viewportGrid.activeViewportIndex, uid);
|
|
2056
|
+
onMeasurementItemClickHandler({
|
|
2057
|
+
uid,
|
|
2058
|
+
isActive
|
|
2059
|
+
});
|
|
2060
|
+
};
|
|
2061
|
+
const onMeasurementItemEditHandler = _ref3 => {
|
|
2062
|
+
let {
|
|
2063
|
+
uid,
|
|
2064
|
+
isActive
|
|
2065
|
+
} = _ref3;
|
|
2066
|
+
const measurement = measurementService.getMeasurement(uid);
|
|
2067
|
+
jumpToImage({
|
|
2068
|
+
uid,
|
|
2069
|
+
isActive
|
|
2070
|
+
});
|
|
2071
|
+
const onSubmitHandler = _ref4 => {
|
|
2072
|
+
let {
|
|
2073
|
+
action,
|
|
2074
|
+
value
|
|
2075
|
+
} = _ref4;
|
|
2076
|
+
switch (action.id) {
|
|
2077
|
+
case 'save':
|
|
2078
|
+
{
|
|
2079
|
+
measurementService.update(uid, {
|
|
2080
|
+
...measurement,
|
|
2081
|
+
...value
|
|
2082
|
+
}, true);
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
uiDialogService.dismiss({
|
|
2086
|
+
id: 'enter-annotation'
|
|
2087
|
+
});
|
|
2088
|
+
};
|
|
2089
|
+
uiDialogService.create({
|
|
2090
|
+
id: 'enter-annotation',
|
|
2091
|
+
centralize: true,
|
|
2092
|
+
isDraggable: false,
|
|
2093
|
+
showOverlay: true,
|
|
2094
|
+
content: ui_src/* Dialog */.Vq,
|
|
2095
|
+
contentProps: {
|
|
2096
|
+
title: 'Enter your annotation',
|
|
2097
|
+
noCloseButton: true,
|
|
2098
|
+
value: {
|
|
2099
|
+
label: measurement.label || ''
|
|
2100
|
+
},
|
|
2101
|
+
body: _ref5 => {
|
|
2102
|
+
let {
|
|
2103
|
+
value,
|
|
2104
|
+
setValue
|
|
2105
|
+
} = _ref5;
|
|
2106
|
+
const onChangeHandler = event => {
|
|
2107
|
+
event.persist();
|
|
2108
|
+
setValue(value => ({
|
|
2109
|
+
...value,
|
|
2110
|
+
label: event.target.value
|
|
2111
|
+
}));
|
|
2112
|
+
};
|
|
2113
|
+
const onKeyPressHandler = event => {
|
|
2114
|
+
if (event.key === 'Enter') {
|
|
2115
|
+
onSubmitHandler({
|
|
2116
|
+
value,
|
|
2117
|
+
action: {
|
|
2118
|
+
id: 'save'
|
|
2119
|
+
}
|
|
2120
|
+
});
|
|
2121
|
+
}
|
|
2122
|
+
};
|
|
2123
|
+
return /*#__PURE__*/react.createElement("div", {
|
|
2124
|
+
className: "p-4 bg-primary-dark"
|
|
2125
|
+
}, /*#__PURE__*/react.createElement(ui_src/* Input */.II, {
|
|
2126
|
+
autoFocus: true,
|
|
2127
|
+
id: "annotation",
|
|
2128
|
+
className: "mt-2 bg-black border-primary-main",
|
|
2129
|
+
type: "text",
|
|
2130
|
+
containerClassName: "mr-2",
|
|
2131
|
+
value: value.label,
|
|
2132
|
+
onChange: onChangeHandler,
|
|
2133
|
+
onKeyPress: onKeyPressHandler
|
|
2134
|
+
}));
|
|
2135
|
+
},
|
|
2136
|
+
actions: [
|
|
2137
|
+
// temp: swap button types until colors are updated
|
|
2138
|
+
{
|
|
2139
|
+
id: 'cancel',
|
|
2140
|
+
text: 'Cancel',
|
|
2141
|
+
type: 'primary'
|
|
2142
|
+
}, {
|
|
2143
|
+
id: 'save',
|
|
2144
|
+
text: 'Save',
|
|
2145
|
+
type: 'secondary'
|
|
2146
|
+
}],
|
|
2147
|
+
onSubmit: onSubmitHandler
|
|
2148
|
+
}
|
|
2149
|
+
});
|
|
2150
|
+
};
|
|
2151
|
+
const onMeasurementItemClickHandler = _ref6 => {
|
|
2152
|
+
let {
|
|
2153
|
+
uid,
|
|
2154
|
+
isActive
|
|
2155
|
+
} = _ref6;
|
|
2156
|
+
if (!isActive) {
|
|
2157
|
+
const measurements = [...displayMeasurements];
|
|
2158
|
+
const measurement = measurements.find(m => m.uid === uid);
|
|
2159
|
+
measurements.forEach(m => m.isActive = m.uid !== uid ? false : true);
|
|
2160
|
+
measurement.isActive = true;
|
|
2161
|
+
setDisplayMeasurements(measurements);
|
|
2162
|
+
}
|
|
2163
|
+
};
|
|
2164
|
+
const displayMeasurementsWithoutFindings = displayMeasurements.filter(dm => dm.measurementType !== measurementService.VALUE_TYPES.POINT);
|
|
2165
|
+
const additionalFindings = displayMeasurements.filter(dm => dm.measurementType === measurementService.VALUE_TYPES.POINT);
|
|
2166
|
+
return /*#__PURE__*/react.createElement(react.Fragment, null, /*#__PURE__*/react.createElement("div", {
|
|
2167
|
+
className: "overflow-x-hidden overflow-y-auto invisible-scrollbar",
|
|
2168
|
+
ref: measurementsPanelRef,
|
|
2169
|
+
"data-cy": 'trackedMeasurements-panel'
|
|
2170
|
+
}, displayStudySummary.key && /*#__PURE__*/react.createElement(ui_src/* StudySummary */.YL, {
|
|
2171
|
+
date: PanelMeasurementTableTracking_formatDate(displayStudySummary.date),
|
|
2172
|
+
modality: displayStudySummary.modality,
|
|
2173
|
+
description: displayStudySummary.description
|
|
2174
|
+
}), /*#__PURE__*/react.createElement(ui_src/* MeasurementTable */.wt, {
|
|
2175
|
+
title: "Measurements",
|
|
2176
|
+
data: displayMeasurementsWithoutFindings,
|
|
2177
|
+
servicesManager: servicesManager,
|
|
2178
|
+
onClick: jumpToImage,
|
|
2179
|
+
onEdit: onMeasurementItemEditHandler
|
|
2180
|
+
}), additionalFindings.length !== 0 && /*#__PURE__*/react.createElement(ui_src/* MeasurementTable */.wt, {
|
|
2181
|
+
title: "Additional Findings",
|
|
2182
|
+
data: additionalFindings,
|
|
2183
|
+
servicesManager: servicesManager,
|
|
2184
|
+
onClick: jumpToImage,
|
|
2185
|
+
onEdit: onMeasurementItemEditHandler
|
|
2186
|
+
})), /*#__PURE__*/react.createElement("div", {
|
|
2187
|
+
className: "flex justify-center p-4"
|
|
2188
|
+
}, /*#__PURE__*/react.createElement(PanelMeasurementTableTracking_ActionButtons, {
|
|
2189
|
+
onExportClick: exportReport,
|
|
2190
|
+
onCreateReportClick: () => {
|
|
2191
|
+
sendTrackedMeasurementsEvent('SAVE_REPORT', {
|
|
2192
|
+
viewportIndex: viewportGrid.activeViewportIndex,
|
|
2193
|
+
isBackupSave: true
|
|
2194
|
+
});
|
|
2195
|
+
},
|
|
2196
|
+
disabled: additionalFindings.length === 0 && displayMeasurementsWithoutFindings.length === 0
|
|
2197
|
+
})));
|
|
2198
|
+
}
|
|
2199
|
+
PanelMeasurementTableTracking.propTypes = {
|
|
2200
|
+
servicesManager: prop_types_default().shape({
|
|
2201
|
+
services: prop_types_default().shape({
|
|
2202
|
+
measurementService: prop_types_default().shape({
|
|
2203
|
+
getMeasurements: (prop_types_default()).func.isRequired,
|
|
2204
|
+
VALUE_TYPES: (prop_types_default()).object.isRequired
|
|
2205
|
+
}).isRequired
|
|
2206
|
+
}).isRequired
|
|
2207
|
+
}).isRequired
|
|
2208
|
+
};
|
|
2209
|
+
|
|
2210
|
+
// TODO: This could be a measurementService mapper
|
|
2211
|
+
function _mapMeasurementToDisplay(measurement, types, displaySetService) {
|
|
2212
|
+
const {
|
|
2213
|
+
referenceStudyUID,
|
|
2214
|
+
referenceSeriesUID,
|
|
2215
|
+
SOPInstanceUID
|
|
2216
|
+
} = measurement;
|
|
2217
|
+
|
|
2218
|
+
// TODO: We don't deal with multiframe well yet, would need to update
|
|
2219
|
+
// This in OHIF-312 when we add FrameIndex to measurements.
|
|
2220
|
+
|
|
2221
|
+
const instance = src.DicomMetadataStore.getInstance(referenceStudyUID, referenceSeriesUID, SOPInstanceUID);
|
|
2222
|
+
const displaySets = displaySetService.getDisplaySetsForSeries(referenceSeriesUID);
|
|
2223
|
+
if (!displaySets[0] || !displaySets[0].images) {
|
|
2224
|
+
throw new Error('The tracked measurements panel should only be tracking "stack" displaySets.');
|
|
2225
|
+
}
|
|
2226
|
+
const {
|
|
2227
|
+
displayText: baseDisplayText,
|
|
2228
|
+
uid,
|
|
2229
|
+
label: baseLabel,
|
|
2230
|
+
type,
|
|
2231
|
+
selected,
|
|
2232
|
+
findingSites,
|
|
2233
|
+
finding
|
|
2234
|
+
} = measurement;
|
|
2235
|
+
const firstSite = findingSites?.[0];
|
|
2236
|
+
const label = baseLabel || finding?.text || firstSite?.text || '(empty)';
|
|
2237
|
+
let displayText = baseDisplayText || [];
|
|
2238
|
+
if (findingSites) {
|
|
2239
|
+
const siteText = [];
|
|
2240
|
+
findingSites.forEach(site => {
|
|
2241
|
+
if (site?.text !== label) siteText.push(site.text);
|
|
2242
|
+
});
|
|
2243
|
+
displayText = [...siteText, ...displayText];
|
|
2244
|
+
}
|
|
2245
|
+
if (finding && finding?.text !== label) {
|
|
2246
|
+
displayText = [finding.text, ...displayText];
|
|
2247
|
+
}
|
|
2248
|
+
return {
|
|
2249
|
+
uid,
|
|
2250
|
+
label,
|
|
2251
|
+
baseLabel,
|
|
2252
|
+
measurementType: type,
|
|
2253
|
+
displayText,
|
|
2254
|
+
baseDisplayText,
|
|
2255
|
+
isActive: selected,
|
|
2256
|
+
finding,
|
|
2257
|
+
findingSites
|
|
2258
|
+
};
|
|
2259
|
+
}
|
|
2260
|
+
/* harmony default export */ const panels_PanelMeasurementTableTracking = (PanelMeasurementTableTracking);
|
|
2261
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/panels/index.js
|
|
2262
|
+
|
|
2263
|
+
|
|
2264
|
+
|
|
2265
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/getPanelModule.tsx
|
|
2266
|
+
|
|
2267
|
+
|
|
2268
|
+
// TODO:
|
|
2269
|
+
// - No loading UI exists yet
|
|
2270
|
+
// - cancel promises when component is destroyed
|
|
2271
|
+
// - show errors in UI for thumbnails if promise fails
|
|
2272
|
+
function getPanelModule(_ref) {
|
|
2273
|
+
let {
|
|
2274
|
+
commandsManager,
|
|
2275
|
+
extensionManager,
|
|
2276
|
+
servicesManager
|
|
2277
|
+
} = _ref;
|
|
2278
|
+
return [{
|
|
2279
|
+
name: 'seriesList',
|
|
2280
|
+
iconName: 'group-layers',
|
|
2281
|
+
iconLabel: 'Studies',
|
|
2282
|
+
label: 'Studies',
|
|
2283
|
+
component: panels_PanelStudyBrowserTracking.bind(null, {
|
|
2284
|
+
commandsManager,
|
|
2285
|
+
extensionManager,
|
|
2286
|
+
servicesManager
|
|
2287
|
+
})
|
|
2288
|
+
}, {
|
|
2289
|
+
name: 'trackedMeasurements',
|
|
2290
|
+
iconName: 'tab-linear',
|
|
2291
|
+
iconLabel: 'Measure',
|
|
2292
|
+
label: 'Measurements',
|
|
2293
|
+
component: panels_PanelMeasurementTableTracking.bind(null, {
|
|
2294
|
+
commandsManager,
|
|
2295
|
+
extensionManager,
|
|
2296
|
+
servicesManager
|
|
2297
|
+
})
|
|
2298
|
+
}];
|
|
2299
|
+
}
|
|
2300
|
+
/* harmony default export */ const src_getPanelModule = (getPanelModule);
|
|
2301
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/getViewportModule.tsx
|
|
2302
|
+
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
2303
|
+
|
|
2304
|
+
const Component = /*#__PURE__*/react.lazy(() => {
|
|
2305
|
+
return __webpack_require__.e(/* import() */ 799).then(__webpack_require__.bind(__webpack_require__, 91799));
|
|
2306
|
+
});
|
|
2307
|
+
const OHIFCornerstoneViewport = props => {
|
|
2308
|
+
return /*#__PURE__*/react.createElement(react.Suspense, {
|
|
2309
|
+
fallback: /*#__PURE__*/react.createElement("div", null, "Loading...")
|
|
2310
|
+
}, /*#__PURE__*/react.createElement(Component, props));
|
|
2311
|
+
};
|
|
2312
|
+
function getViewportModule(_ref) {
|
|
2313
|
+
let {
|
|
2314
|
+
servicesManager,
|
|
2315
|
+
commandsManager,
|
|
2316
|
+
extensionManager
|
|
2317
|
+
} = _ref;
|
|
2318
|
+
const ExtendedOHIFCornerstoneTrackingViewport = props => {
|
|
2319
|
+
return /*#__PURE__*/react.createElement(OHIFCornerstoneViewport, _extends({
|
|
2320
|
+
servicesManager: servicesManager,
|
|
2321
|
+
commandsManager: commandsManager,
|
|
2322
|
+
extensionManager: extensionManager
|
|
2323
|
+
}, props));
|
|
2324
|
+
};
|
|
2325
|
+
return [{
|
|
2326
|
+
name: 'cornerstone-tracked',
|
|
2327
|
+
component: ExtendedOHIFCornerstoneTrackingViewport
|
|
2328
|
+
}];
|
|
2329
|
+
}
|
|
2330
|
+
/* harmony default export */ const src_getViewportModule = (getViewportModule);
|
|
2331
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/package.json
|
|
2332
|
+
const package_namespaceObject = JSON.parse('{"u2":"@ohif/extension-measurement-tracking"}');
|
|
2333
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/id.js
|
|
2334
|
+
|
|
2335
|
+
const id = package_namespaceObject.u2;
|
|
2336
|
+
|
|
2337
|
+
;// CONCATENATED MODULE: ../../../extensions/measurement-tracking/src/index.tsx
|
|
2338
|
+
|
|
2339
|
+
|
|
2340
|
+
|
|
2341
|
+
|
|
2342
|
+
const measurementTrackingExtension = {
|
|
2343
|
+
/**
|
|
2344
|
+
* Only required property. Should be a unique value across all extensions.
|
|
2345
|
+
*/
|
|
2346
|
+
id: id,
|
|
2347
|
+
getContextModule: getContextModule/* default */.Z,
|
|
2348
|
+
getPanelModule: src_getPanelModule,
|
|
2349
|
+
getViewportModule: src_getViewportModule
|
|
2350
|
+
};
|
|
2351
|
+
/* harmony default export */ const measurement_tracking_src = (measurementTrackingExtension);
|
|
2352
|
+
|
|
2353
|
+
/***/ })
|
|
2354
|
+
|
|
2355
|
+
}]);
|