@gen-epix/ui-client-casedb 4.1.0 → 4.3.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/_chunks/AddCasesToEventDialog.js +98 -98
- package/dist/_chunks/AddCasesToEventDialog.js.map +1 -1
- package/dist/_chunks/CaseContentForm.js +10 -10
- package/dist/_chunks/CaseInfoDialog.js +242 -241
- package/dist/_chunks/CaseInfoDialog.js.map +1 -1
- package/dist/_chunks/CaseSetInfoDialog.js +224 -224
- package/dist/_chunks/CaseSetInfoDialog.js.map +1 -1
- package/dist/_chunks/Dashboard.js +549 -550
- package/dist/_chunks/Dashboard.js.map +1 -1
- package/dist/_chunks/FindSimilarCasesDialog.js +76 -76
- package/dist/_chunks/FindSimilarCasesDialog.js.map +1 -1
- package/dist/_chunks/LegendaItem.js.map +1 -1
- package/dist/_chunks/LineListWidget.js +138 -136
- package/dist/_chunks/LineListWidget.js.map +1 -1
- package/dist/_chunks/PanelSeparator.js +3 -3
- package/dist/_chunks/PanelSeparator.js.map +1 -1
- package/dist/_chunks/Upload.js +318 -318
- package/dist/_chunks/Upload.js.map +1 -1
- package/dist/_chunks/{chunk-BV7QT456.js → chunk-OB3PAWPO.js} +3 -3
- package/dist/_chunks/chunk-OB3PAWPO.js.map +1 -0
- package/dist/_chunks/cloneDeep.js +1 -1
- package/dist/_chunks/cloneDeep.js.map +1 -1
- package/dist/_chunks/esm.js +3 -3
- package/dist/_chunks/esm.js.map +1 -1
- package/dist/_chunks/index.module.js +1 -1
- package/dist/_chunks/index.module.js.map +1 -1
- package/dist/_chunks/react.js +1 -1
- package/dist/_chunks/react.js.map +1 -1
- package/dist/_chunks/shallow.js +2 -2
- package/dist/_chunks/shallow.js.map +1 -1
- package/dist/_chunks/vanilla.js +1 -1
- package/dist/_chunks/vanilla.js.map +1 -1
- package/dist/_chunks/yup.js +24 -24
- package/dist/_chunks/yup.js.map +1 -1
- package/dist/components/form/fields/ArrangementEditor/index.js +30 -30
- package/dist/components/ui/CreateEventDialog/index.js +40 -40
- package/dist/components/ui/CreateEventDialog/index.js.map +1 -1
- package/dist/components/ui/HistogramWidget/index.js +161 -162
- package/dist/components/ui/HistogramWidget/index.js.map +1 -1
- package/dist/components/ui/SequenceDownloadDialog/index.js +22 -22
- package/dist/locale/en.json +6 -0
- package/dist/locale/nl.json +7 -1
- package/dist/pages/CasesDetailPage/index.js +1 -1
- package/dist/pages/ColsAdminPage/index.js +1 -1
- package/dist/pages/ConceptsAdminPage/index.js +1 -1
- package/dist/pages/DimsAdminPage/index.js +1 -1
- package/dist/pages/EventsDetailPage/index.js +1 -1
- package/dist/pages/OrganizationAccessCasePoliciesAdminPage/index.js +120 -86
- package/dist/pages/OrganizationAccessCasePoliciesAdminPage/index.js.map +1 -1
- package/dist/pages/RefColsAdminPage/index.js +1 -1
- package/dist/pages/RegionSetShapesAdminPage/index.js +1 -1
- package/dist/pages/RegionsAdminPage/index.js +1 -1
- package/dist/pages/UserEffectiveRightsAdminPage/index.js +1 -1
- package/dist/pages/UserEffectiveRightsTesterAdminPage/index.js +59 -59
- package/dist/pages/UserEffectiveRightsTesterAdminPage/index.js.map +1 -1
- package/dist/routes/index.js +93 -91
- package/dist/routes/index.js.map +1 -1
- package/dist/setup/setup.js +2 -3
- package/dist/setup/setup.js.map +1 -1
- package/package.json +73 -72
- package/dist/_chunks/chunk-BV7QT456.js.map +0 -1
- package/dist/_chunks/index.esm.js +0 -1465
- package/dist/_chunks/index.esm.js.map +0 -1
|
@@ -7,21 +7,21 @@ import { DASHBOARD_COMPONENT_NAME as a } from "../constants/dashboard.js";
|
|
|
7
7
|
import { a as o, c as s, d as c, f as l, h as u, l as d, m as f, n as p, o as m, p as h, s as g, t as _ } from "./esm.js";
|
|
8
8
|
import { t as v } from "./react.js";
|
|
9
9
|
import { r as y, t as b } from "./dashboardStore.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import { Fragment as B, jsx as V, jsxs as H } from "react/jsx-runtime";
|
|
10
|
+
import { t as ee } from "./yup.js";
|
|
11
|
+
import { mixed as te, object as ne, string as x } from "yup";
|
|
12
|
+
import { CaseDbCaseApi as S } from "@gen-epix/api-casedb";
|
|
13
|
+
import { QueryClientService as re } from "@gen-epix/ui-client-common/classes/services/QueryClientService";
|
|
14
|
+
import { FORM_FIELD_DEFINITION_TYPE as C } from "@gen-epix/ui-core-form/models/form";
|
|
15
|
+
import { DATE_FORMAT as ie } from "@gen-epix/ui-core/constants/date";
|
|
16
|
+
import { ConfigService as w } from "@gen-epix/ui-client-common/classes/services/ConfigService";
|
|
17
|
+
import { Alert as T, AlertTitle as E, Box as D, Button as O, Divider as ae, Typography as oe, useTheme as k } from "@mui/material";
|
|
18
|
+
import { use as A, useCallback as j, useEffect as M, useId as se, useMemo as N, useRef as P, useState as F } from "react";
|
|
19
|
+
import { useTranslation as I } from "react-i18next";
|
|
20
|
+
import { Fragment as L, jsx as R, jsxs as z } from "react/jsx-runtime";
|
|
22
21
|
import { ResponseHandler as ce } from "@gen-epix/ui-client-common/components/ui/ResponseHandler";
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
22
|
+
import { Controller as B, useForm as le, useWatch as ue } from "react-hook-form";
|
|
23
|
+
import { GenericForm as V } from "@gen-epix/ui-core-form/components/helpers/GenericForm";
|
|
24
|
+
import { useQueryMemo as H } from "@gen-epix/ui-client-common/hooks/useQueryMemo";
|
|
25
25
|
import { withDialog as U } from "@gen-epix/ui-core-components/hoc/withDialog";
|
|
26
26
|
import { TestIdUtil as W } from "@gen-epix/ui-core/utils/TestIdUtil";
|
|
27
27
|
import { SchemaUtil as de } from "@gen-epix/ui-core-form/utils/SchemaUtil";
|
|
@@ -40,11 +40,11 @@ var G = {
|
|
|
40
40
|
getInstanceByDom: f,
|
|
41
41
|
init: u
|
|
42
42
|
}, fe = ({ control: e, data: n, name: r, onOrganizationFilterChange: i, organizationFilter: a }) => {
|
|
43
|
-
let { t: o } =
|
|
44
|
-
|
|
43
|
+
let { t: o } = I(), s = N(() => t.buildChartIntervals(n), [n]), c = k(), [l, u] = F(null), d = o`Own cases`, f = o`Cases from other organizations`, p = P(s);
|
|
44
|
+
M(() => {
|
|
45
45
|
p.current = s;
|
|
46
46
|
}, [s]);
|
|
47
|
-
let m =
|
|
47
|
+
let m = P(null), h = j((e) => {
|
|
48
48
|
let t = e, n = t.batch?.[0] ?? t, r = p.current.length - 1, i, a;
|
|
49
49
|
if (n.startValue !== void 0 && n.endValue !== void 0) i = Math.round(n.startValue), a = Math.round(n.endValue);
|
|
50
50
|
else if (n.start !== void 0 && n.end !== void 0) i = Math.round(n.start / 100 * r), a = Math.round(n.end / 100 * r);
|
|
@@ -58,8 +58,8 @@ var G = {
|
|
|
58
58
|
return;
|
|
59
59
|
}
|
|
60
60
|
m.current?.(null);
|
|
61
|
-
}, []), g =
|
|
62
|
-
let { BASE_COLORS: e } =
|
|
61
|
+
}, []), g = N(() => {
|
|
62
|
+
let { BASE_COLORS: e } = w.getInstance().config.epi.STRATIFICATION;
|
|
63
63
|
return {
|
|
64
64
|
color: e,
|
|
65
65
|
dataZoom: [{
|
|
@@ -142,7 +142,7 @@ var G = {
|
|
|
142
142
|
f,
|
|
143
143
|
d,
|
|
144
144
|
c
|
|
145
|
-
]), v =
|
|
145
|
+
]), v = j((e) => {
|
|
146
146
|
let { selected: t } = e;
|
|
147
147
|
if (!t) return;
|
|
148
148
|
let n = t[d] ?? !0, r = t[f] ?? !0;
|
|
@@ -159,7 +159,7 @@ var G = {
|
|
|
159
159
|
i,
|
|
160
160
|
f,
|
|
161
161
|
d
|
|
162
|
-
]), y =
|
|
162
|
+
]), y = N(() => ({
|
|
163
163
|
datazoom: h,
|
|
164
164
|
legendselectchanged: v,
|
|
165
165
|
mouseout: () => {
|
|
@@ -173,18 +173,18 @@ var G = {
|
|
|
173
173
|
y: n.clientY + 12
|
|
174
174
|
});
|
|
175
175
|
}
|
|
176
|
-
}), [h, v]), b =
|
|
176
|
+
}), [h, v]), b = j(({ field: { onChange: e } }) => (m.current = e, /* @__PURE__ */ R(_, {
|
|
177
177
|
echarts: G,
|
|
178
178
|
notMerge: !0,
|
|
179
179
|
onEvents: y,
|
|
180
180
|
option: g,
|
|
181
181
|
style: { height: 400 }
|
|
182
182
|
})), [y, g]);
|
|
183
|
-
return /* @__PURE__ */
|
|
183
|
+
return /* @__PURE__ */ z(L, { children: [/* @__PURE__ */ R(B, {
|
|
184
184
|
control: e,
|
|
185
185
|
name: r,
|
|
186
186
|
render: b
|
|
187
|
-
}), l && /* @__PURE__ */
|
|
187
|
+
}), l && /* @__PURE__ */ R(D, {
|
|
188
188
|
sx: {
|
|
189
189
|
bgcolor: "background.paper",
|
|
190
190
|
border: "1px solid",
|
|
@@ -202,19 +202,19 @@ var G = {
|
|
|
202
202
|
children: l.content
|
|
203
203
|
})] });
|
|
204
204
|
}, K = U(({ onActionsChange: t, onClose: o, onTitleChange: s, openProps: c }) => {
|
|
205
|
-
let { t: l } =
|
|
206
|
-
dateRange:
|
|
205
|
+
let { t: l } = I(), u = se(), d = A(b), f = d.getState().getWidgetDataPersistable(a.TREE).treeConfiguration, p = v(d, (e) => e.setFindSimilarCasesResults), m = v(d, (e) => e.findSimilarCasesResults), h = N(() => i.getTreeConfigurations(c.completeCaseType), [c.completeCaseType]), [g, _] = F(null), k = N(() => ne().shape({
|
|
206
|
+
dateRange: te().nullable().default(null),
|
|
207
207
|
maxDistance: de.number.required().positive().when("treeColId", ([e], t) => {
|
|
208
208
|
let n = h.find((t) => t.col.id === e);
|
|
209
|
-
return n ? t.integer(l`Max distance must be an integer`).max(n.geneticDistanceProtocol.seqdb_max_stored_distance ||
|
|
209
|
+
return n ? t.integer(l`Max distance must be an integer`).max(n.geneticDistanceProtocol.seqdb_max_stored_distance || w.getInstance().config.epi.SEQDB_MAX_STORED_DISTANCE_FALLBACK) : t;
|
|
210
210
|
}),
|
|
211
|
-
organizationFilter:
|
|
211
|
+
organizationFilter: x().required().oneOf([
|
|
212
212
|
"all",
|
|
213
213
|
"own",
|
|
214
214
|
"otherOrganization"
|
|
215
215
|
]),
|
|
216
|
-
treeColId:
|
|
217
|
-
}), [l, h]),
|
|
216
|
+
treeColId: x().required()
|
|
217
|
+
}), [l, h]), P = N(() => {
|
|
218
218
|
let e = /* @__PURE__ */ new Set();
|
|
219
219
|
return h.forEach((t) => {
|
|
220
220
|
e.add(t.col);
|
|
@@ -222,25 +222,25 @@ var G = {
|
|
|
222
222
|
label: e.label,
|
|
223
223
|
value: e.id
|
|
224
224
|
}));
|
|
225
|
-
}, [h]),
|
|
225
|
+
}, [h]), B = le({
|
|
226
226
|
defaultValues: {
|
|
227
227
|
dateRange: null,
|
|
228
228
|
maxDistance: 0,
|
|
229
229
|
organizationFilter: "all",
|
|
230
230
|
treeColId: f ? f.col.id : null
|
|
231
231
|
},
|
|
232
|
-
resolver:
|
|
233
|
-
}), { control: U, handleSubmit: G } =
|
|
232
|
+
resolver: ee(k, void 0, { raw: !0 })
|
|
233
|
+
}), { control: U, handleSubmit: G } = B, K = ue({ control: U }), pe = N(() => {
|
|
234
234
|
let e = h.find((e) => e.col.id === K.treeColId);
|
|
235
235
|
return [{
|
|
236
|
-
definition:
|
|
236
|
+
definition: C.SELECT,
|
|
237
237
|
label: l`Tree`,
|
|
238
238
|
name: "treeColId",
|
|
239
|
-
options:
|
|
239
|
+
options: P
|
|
240
240
|
}, {
|
|
241
|
-
definition:
|
|
241
|
+
definition: C.NUMBER,
|
|
242
242
|
label: l`Max distance`,
|
|
243
|
-
max: e?.geneticDistanceProtocol?.seqdb_max_stored_distance ||
|
|
243
|
+
max: e?.geneticDistanceProtocol?.seqdb_max_stored_distance || w.getInstance().config.epi.SEQDB_MAX_STORED_DISTANCE_FALLBACK,
|
|
244
244
|
min: 0,
|
|
245
245
|
name: "maxDistance",
|
|
246
246
|
showSlider: !0,
|
|
@@ -250,27 +250,27 @@ var G = {
|
|
|
250
250
|
K.treeColId,
|
|
251
251
|
l,
|
|
252
252
|
h,
|
|
253
|
-
|
|
253
|
+
P
|
|
254
254
|
]);
|
|
255
|
-
|
|
255
|
+
M(() => {
|
|
256
256
|
s(l`Find similar cases`);
|
|
257
257
|
}, [l, s]);
|
|
258
|
-
let me =
|
|
259
|
-
|
|
258
|
+
let me = j((e) => {
|
|
259
|
+
B.setValue("dateRange", null), _({
|
|
260
260
|
...e,
|
|
261
261
|
dateRange: null
|
|
262
262
|
});
|
|
263
|
-
}, [
|
|
264
|
-
|
|
265
|
-
}, [
|
|
263
|
+
}, [B]), he = j((e) => {
|
|
264
|
+
B.setValue("organizationFilter", e);
|
|
265
|
+
}, [B]), q = H({
|
|
266
266
|
enabled: !!g,
|
|
267
267
|
queryFn: async ({ signal: e }) => {
|
|
268
|
-
let t = await
|
|
268
|
+
let t = await S.getInstance().retrieveSimilarCases({
|
|
269
269
|
case_ids: c.selectedRows.map((e) => e.id),
|
|
270
270
|
case_type_id: c.completeCaseType.id,
|
|
271
271
|
genetic_distance_col_id: g?.treeColId,
|
|
272
272
|
max_distance: g?.maxDistance
|
|
273
|
-
}, { signal: e }), n = await
|
|
273
|
+
}, { signal: e }), n = await S.getInstance().retrieveIsOwnCases({
|
|
274
274
|
case_ids: t.data.cases.map((e) => e.id),
|
|
275
275
|
case_type_id: c.completeCaseType.id
|
|
276
276
|
}, { signal: e });
|
|
@@ -279,18 +279,18 @@ var G = {
|
|
|
279
279
|
is_own_case: n.data[e.id] || !1
|
|
280
280
|
}));
|
|
281
281
|
},
|
|
282
|
-
queryKey: [
|
|
282
|
+
queryKey: [re.getInstance().getGenericKey(r.SIMILAR_CASES), JSON.stringify({
|
|
283
283
|
formData: g,
|
|
284
284
|
rowIds: c.selectedRows.map((e) => e.id)
|
|
285
285
|
})]
|
|
286
|
-
}), J =
|
|
286
|
+
}), J = N(() => q.data ? q.data.filter((e) => {
|
|
287
287
|
switch (K.organizationFilter) {
|
|
288
288
|
case "all": return !0;
|
|
289
289
|
case "otherOrganization": return !e.is_own_case;
|
|
290
290
|
case "own": return e.is_own_case;
|
|
291
291
|
default: return !0;
|
|
292
292
|
}
|
|
293
|
-
}) : [], [q.data, K.organizationFilter]), Y =
|
|
293
|
+
}) : [], [q.data, K.organizationFilter]), Y = N(() => {
|
|
294
294
|
let e = /* @__PURE__ */ new Map();
|
|
295
295
|
for (let { is_own_case: t, timed_at: n } of q.data ?? []) if (n) {
|
|
296
296
|
let r = e.get(n) ?? {
|
|
@@ -302,28 +302,28 @@ var G = {
|
|
|
302
302
|
r.count += 1, t ? r.ownCaseCount += 1 : r.otherOrganizationCaseCount += 1, e.set(n, r);
|
|
303
303
|
}
|
|
304
304
|
return Array.from(e.values()).sort((e, t) => e.date.localeCompare(t.date));
|
|
305
|
-
}, [q.data]), X =
|
|
305
|
+
}, [q.data]), X = N(() => {
|
|
306
306
|
let t = K.dateRange;
|
|
307
307
|
if (!t) return J;
|
|
308
308
|
let [r, i] = t;
|
|
309
309
|
return J.filter((t) => {
|
|
310
310
|
if (!t.timed_at) return !1;
|
|
311
|
-
let a = e(n(t.timed_at),
|
|
311
|
+
let a = e(n(t.timed_at), ie.DATE);
|
|
312
312
|
return a >= r && a <= i;
|
|
313
313
|
});
|
|
314
|
-
}, [K.dateRange, J]), Z =
|
|
314
|
+
}, [K.dateRange, J]), Z = N(() => {
|
|
315
315
|
let e = c.allRows.map((e) => e.id);
|
|
316
316
|
return X.reduce((t, n) => {
|
|
317
317
|
let r = n.id;
|
|
318
318
|
return e.includes(r) || t.push(r), t;
|
|
319
319
|
}, []);
|
|
320
|
-
}, [X, c.allRows]), Q =
|
|
320
|
+
}, [X, c.allRows]), Q = N(() => {
|
|
321
321
|
let e = c.allRows.map((e) => e.id);
|
|
322
322
|
return X.reduce((t, n) => {
|
|
323
323
|
let r = n.id;
|
|
324
324
|
return e.includes(r) && t.push(r), t;
|
|
325
325
|
}, []);
|
|
326
|
-
}, [X, c.allRows]), $ =
|
|
326
|
+
}, [X, c.allRows]), $ = j(async () => {
|
|
327
327
|
await p(y(m, (e) => (e.push({
|
|
328
328
|
colId: g?.treeColId,
|
|
329
329
|
distance: g?.maxDistance,
|
|
@@ -340,7 +340,7 @@ var G = {
|
|
|
340
340
|
g?.treeColId,
|
|
341
341
|
c.allRows
|
|
342
342
|
]);
|
|
343
|
-
return
|
|
343
|
+
return M(() => {
|
|
344
344
|
let e = [];
|
|
345
345
|
e.push({
|
|
346
346
|
...W.createAttributes("FindSimilarCasesDialog-closeButton"),
|
|
@@ -362,25 +362,25 @@ var G = {
|
|
|
362
362
|
o,
|
|
363
363
|
Z.length,
|
|
364
364
|
l
|
|
365
|
-
]), /* @__PURE__ */
|
|
366
|
-
/* @__PURE__ */
|
|
365
|
+
]), /* @__PURE__ */ z(D, { children: [
|
|
366
|
+
/* @__PURE__ */ R(D, {
|
|
367
367
|
sx: { marginBottom: 2 },
|
|
368
|
-
children: /* @__PURE__ */
|
|
368
|
+
children: /* @__PURE__ */ R(oe, { children: l("Select a tree and maximum distance to find similar cases for the {{count}} selected cases.", { count: c.selectedRows.length }) })
|
|
369
369
|
}),
|
|
370
|
-
/* @__PURE__ */
|
|
370
|
+
/* @__PURE__ */ R(D, { children: /* @__PURE__ */ R(V, {
|
|
371
371
|
formFieldDefinitions: pe,
|
|
372
372
|
formId: u,
|
|
373
|
-
formMethods:
|
|
373
|
+
formMethods: B,
|
|
374
374
|
onSubmit: G(me),
|
|
375
|
-
schema:
|
|
375
|
+
schema: k
|
|
376
376
|
}) }),
|
|
377
|
-
/* @__PURE__ */
|
|
377
|
+
/* @__PURE__ */ R(D, {
|
|
378
378
|
sx: {
|
|
379
379
|
display: "flex",
|
|
380
380
|
justifyContent: "flex-end",
|
|
381
381
|
marginTop: 2
|
|
382
382
|
},
|
|
383
|
-
children: /* @__PURE__ */
|
|
383
|
+
children: /* @__PURE__ */ R(O, {
|
|
384
384
|
color: "secondary",
|
|
385
385
|
form: u,
|
|
386
386
|
type: "submit",
|
|
@@ -388,24 +388,24 @@ var G = {
|
|
|
388
388
|
children: g ? l`Search again` : l`Search`
|
|
389
389
|
})
|
|
390
390
|
}),
|
|
391
|
-
/* @__PURE__ */
|
|
392
|
-
/* @__PURE__ */
|
|
391
|
+
/* @__PURE__ */ R(ae, { sx: { marginY: 2 } }),
|
|
392
|
+
/* @__PURE__ */ R(ce, {
|
|
393
393
|
inlineSpinner: !0,
|
|
394
394
|
loadables: q,
|
|
395
|
-
children: q.data && /* @__PURE__ */
|
|
396
|
-
/* @__PURE__ */
|
|
395
|
+
children: q.data && /* @__PURE__ */ z(L, { children: [
|
|
396
|
+
/* @__PURE__ */ R(D, {
|
|
397
397
|
sx: { marginY: 2 },
|
|
398
|
-
children: /* @__PURE__ */
|
|
398
|
+
children: /* @__PURE__ */ R(T, {
|
|
399
399
|
severity: q.data.length > 0 ? "success" : "warning",
|
|
400
|
-
children: /* @__PURE__ */
|
|
400
|
+
children: /* @__PURE__ */ R(E, { children: l("Found {{count}} similar cases with a distance of {{distance}}.", {
|
|
401
401
|
count: q.data.length,
|
|
402
402
|
distance: g?.maxDistance
|
|
403
403
|
}) })
|
|
404
404
|
})
|
|
405
405
|
}),
|
|
406
|
-
Y.length > 0 && /* @__PURE__ */
|
|
406
|
+
Y.length > 0 && /* @__PURE__ */ R(D, {
|
|
407
407
|
sx: { marginY: 2 },
|
|
408
|
-
children: /* @__PURE__ */
|
|
408
|
+
children: /* @__PURE__ */ R(fe, {
|
|
409
409
|
control: U,
|
|
410
410
|
data: Y,
|
|
411
411
|
name: "dateRange",
|
|
@@ -413,16 +413,16 @@ var G = {
|
|
|
413
413
|
organizationFilter: K.organizationFilter
|
|
414
414
|
})
|
|
415
415
|
}),
|
|
416
|
-
/* @__PURE__ */
|
|
416
|
+
/* @__PURE__ */ R(D, {
|
|
417
417
|
sx: { marginY: 2 },
|
|
418
|
-
children: /* @__PURE__ */
|
|
418
|
+
children: /* @__PURE__ */ R(T, {
|
|
419
419
|
severity: "info",
|
|
420
|
-
children: /* @__PURE__ */
|
|
420
|
+
children: /* @__PURE__ */ R(E, { children: l("{{count}} similar cases can be added to the line list.", { count: Z.length }) })
|
|
421
421
|
})
|
|
422
422
|
}),
|
|
423
|
-
Q.length > 0 && /* @__PURE__ */
|
|
423
|
+
Q.length > 0 && /* @__PURE__ */ R(T, {
|
|
424
424
|
severity: "warning",
|
|
425
|
-
children: /* @__PURE__ */
|
|
425
|
+
children: /* @__PURE__ */ R(E, { children: l("{{count}} similar cases found that are already in the line list.", { count: Q.length }) })
|
|
426
426
|
})
|
|
427
427
|
] })
|
|
428
428
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FindSimilarCasesDialog.js","names":[],"sources":["../../src/components/ui/FindSimilarCasesDialog/FindSimilarCasesDialogDateRangeChart.tsx","../../src/components/ui/FindSimilarCasesDialog/FindSimilarCasesDialog.tsx"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport type { ReactElement } from 'react';\nimport {\n dispose,\n getInstanceByDom,\n init,\n use as registerECharts,\n} from 'echarts/core';\nimport {\n DataZoomComponent,\n GridComponent,\n LegendComponent,\n TooltipComponent,\n} from 'echarts/components';\nimport {\n BarChart,\n LineChart,\n} from 'echarts/charts';\nimport { CanvasRenderer } from 'echarts/renderers';\nimport EChartsReact from 'echarts-for-react';\nimport type {\n Control,\n FieldValues,\n Path,\n} from 'react-hook-form';\nimport { Controller } from 'react-hook-form';\nimport { useTranslation } from 'react-i18next';\nimport {\n Box,\n useTheme,\n} from '@mui/material';\nimport { ConfigService } from '@gen-epix/ui-client-common/classes/services/ConfigService';\n\nimport { FindSimilarCasesUtil } from '../../../utils/FindSimilarCasesUtil';\nimport type {\n FindSimilarCasesChartDataPoint,\n FindSimilarCasesOrganizationFilter,\n} from '../../../models/caseDb';\nimport type { CaseDbConfig } from '../../../models/config';\n\nregisterECharts([BarChart, LineChart, GridComponent, LegendComponent, TooltipComponent, DataZoomComponent, CanvasRenderer]);\n\nconst echartsCore = {\n dispose,\n getInstanceByDom,\n init,\n};\n\nexport interface FindSimilarCasesDialogDateRangeChartProps<\n TFieldValues extends FieldValues,\n TName extends Path<TFieldValues> = Path<TFieldValues>,\n> {\n control: Control<TFieldValues>;\n data: FindSimilarCasesChartDataPoint[];\n name: TName;\n onOrganizationFilterChange: (organizationFilter: FindSimilarCasesOrganizationFilter) => void;\n organizationFilter: FindSimilarCasesOrganizationFilter;\n}\n\nexport const FindSimilarCasesDialogDateRangeChart = <\n TFieldValues extends FieldValues,\n TName extends Path<TFieldValues> = Path<TFieldValues>,\n>({\n control,\n data,\n name,\n onOrganizationFilterChange,\n organizationFilter,\n}: FindSimilarCasesDialogDateRangeChartProps<TFieldValues, TName>): ReactElement => {\n const { t } = useTranslation();\n const intervals = useMemo(() => FindSimilarCasesUtil.buildChartIntervals(data), [data]);\n const theme = useTheme();\n const [tooltipState, setTooltipState] = useState<{ content: string; x: number; y: number } | null>(null);\n const ownCasesLabel = t`Own cases`;\n const otherOrganizationCasesLabel = t`Cases from other organizations`;\n\n const intervalsRef = useRef(intervals);\n useEffect(() => {\n intervalsRef.current = intervals;\n }, [intervals]);\n\n // Keeps a stable reference to the latest onChange so onDataZoom never goes stale.\n const onChangeRef = useRef<((value: [string, string] | null) => void) | null>(null);\n\n const onDataZoom = useCallback((params: unknown) => {\n type ZoomPayload = { end?: number; endValue?: number; start?: number; startValue?: number };\n const event = params as { batch?: ZoomPayload[] } & ZoomPayload;\n const base = event.batch?.[0] ?? event;\n\n const n = intervalsRef.current.length - 1;\n let startIndex: number;\n let endIndex: number;\n\n if (base.startValue !== undefined && base.endValue !== undefined) {\n // index-based (e.g. inside/wheel zoom)\n startIndex = Math.round(base.startValue);\n endIndex = Math.round(base.endValue);\n } else if (base.start !== undefined && base.end !== undefined) {\n // percentage-based (slider drag)\n startIndex = Math.round((base.start / 100) * n);\n endIndex = Math.round((base.end / 100) * n);\n } else {\n onChangeRef.current?.(null);\n return;\n }\n\n const startInterval = intervalsRef.current[startIndex];\n const endInterval = intervalsRef.current[endIndex];\n if (startInterval && endInterval) {\n onChangeRef.current?.([startInterval.startDate, endInterval.endDate]);\n return;\n }\n onChangeRef.current?.(null);\n }, []);\n\n const option = useMemo(() => {\n const { BASE_COLORS } = ConfigService.getInstance<CaseDbConfig>().config.epi.STRATIFICATION;\n return {\n color: BASE_COLORS,\n dataZoom: [{\n borderColor: theme.palette.primary.light,\n bottom: 0,\n fillerColor: `${theme.palette.primary.main}33`,\n handleStyle: { borderColor: theme.palette.primary.main, color: theme.palette.primary.main },\n height: 50,\n left: 80,\n right: 80,\n selectedDataBackground: { areaStyle: { color: theme.palette.primary.light }, lineStyle: { color: theme.palette.primary.main } },\n type: 'slider',\n }],\n grid: { bottom: 110, left: 80, right: 80, top: 40 },\n legend: {\n data: [ownCasesLabel, otherOrganizationCasesLabel],\n selected: {\n [otherOrganizationCasesLabel]: organizationFilter !== 'own',\n [ownCasesLabel]: organizationFilter !== 'otherOrganization',\n },\n top: 0,\n },\n series: [\n {\n data: intervals.map(i => i.count),\n lineStyle: { opacity: 0 },\n name: 'dataZoomShadow',\n silent: true,\n symbol: 'none',\n type: 'line',\n },\n { data: intervals.map(i => i.ownCaseCount), itemStyle: { color: BASE_COLORS[0] }, name: ownCasesLabel, stack: 'similarCases', type: 'bar' },\n { data: intervals.map(i => i.otherOrganizationCaseCount), itemStyle: { color: BASE_COLORS[1] }, name: otherOrganizationCasesLabel, stack: 'similarCases', type: 'bar' },\n ],\n tooltip: { show: false },\n xAxis: { axisLabel: {\n height: 100,\n rotate: 45,\n }, axisTick: {\n alignWithLabel: true,\n show: true,\n }, data: intervals.map(i => i.label),\n type: 'category' },\n yAxis: { max: Math.max(...intervals.map(i => i.count), 1), minInterval: 1, type: 'value' },\n };\n }, [intervals, organizationFilter, otherOrganizationCasesLabel, ownCasesLabel, theme]);\n\n const onLegendSelectChanged = useCallback((params: unknown) => {\n const { selected } = params as { selected?: Record<string, boolean> };\n if (!selected) {\n return;\n }\n const ownCasesSelected = selected[ownCasesLabel] ?? true;\n const otherOrganizationCasesSelected = selected[otherOrganizationCasesLabel] ?? true;\n if (ownCasesSelected && !otherOrganizationCasesSelected) {\n onOrganizationFilterChange('own');\n return;\n }\n if (!ownCasesSelected && otherOrganizationCasesSelected) {\n onOrganizationFilterChange('otherOrganization');\n return;\n }\n onOrganizationFilterChange('all');\n }, [onOrganizationFilterChange, otherOrganizationCasesLabel, ownCasesLabel]);\n\n const onEvents = useMemo(() => ({\n datazoom: onDataZoom,\n legendselectchanged: onLegendSelectChanged,\n mouseout: () => {\n setTooltipState(null);\n },\n mouseover: (event: unknown) => {\n const e = event as { event?: { event?: MouseEvent }; name?: string; value?: number };\n const mouseEvent = e.event?.event;\n if (mouseEvent && e.name !== null && e.name !== undefined) {\n setTooltipState({ content: `${e.name} (n=${e.value ?? 0})`, x: mouseEvent.clientX + 12, y: mouseEvent.clientY + 12 });\n }\n },\n }), [onDataZoom, onLegendSelectChanged]);\n\n const renderChart = useCallback(({ field: { onChange } }: { field: { onChange: (value: [string, string] | null) => void } }) => {\n onChangeRef.current = onChange;\n return (\n <EChartsReact\n echarts={echartsCore}\n notMerge\n onEvents={onEvents}\n option={option}\n style={{ height: 400 }}\n />\n );\n }, [onEvents, option]);\n\n return (\n <>\n <Controller\n control={control}\n name={name}\n render={renderChart}\n />\n {tooltipState && (\n <Box\n sx={{\n bgcolor: 'background.paper',\n border: '1px solid',\n borderColor: 'divider',\n borderRadius: 1,\n fontSize: 12,\n left: tooltipState.x,\n pointerEvents: 'none',\n position: 'fixed',\n px: 1,\n py: 0.5,\n top: tooltipState.y,\n zIndex: 'tooltip',\n }}\n >\n {tooltipState.content}\n </Box>\n )}\n </>\n );\n};\n","import {\n use,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useState,\n} from 'react';\nimport type { ReactElement } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport {\n mixed,\n object,\n string,\n} from 'yup';\nimport { yupResolver } from '@hookform/resolvers/yup';\nimport type { Resolver } from 'react-hook-form';\nimport {\n useForm,\n useWatch,\n} from 'react-hook-form';\nimport {\n Alert,\n AlertTitle,\n Box,\n Button,\n Divider,\n Typography,\n} from '@mui/material';\nimport { useStore } from 'zustand';\nimport { produce } from 'immer';\nimport {\n format,\n parseISO,\n} from 'date-fns';\nimport type {\n CaseDbCase,\n CaseDbCol,\n CaseDbCompleteCaseType,\n} from '@gen-epix/api-casedb';\nimport { CaseDbCaseApi } from '@gen-epix/api-casedb';\nimport type { DialogAction } from '@gen-epix/ui-core-components/components/Dialog';\nimport type {\n WithDialogRefMethods,\n WithDialogRenderProps,\n} from '@gen-epix/ui-core-components/hoc/withDialog';\nimport { ConfigService } from '@gen-epix/ui-client-common/classes/services/ConfigService';\nimport { QueryClientService } from '@gen-epix/ui-client-common/classes/services/QueryClientService';\nimport { ResponseHandler } from '@gen-epix/ui-client-common/components/ui/ResponseHandler';\nimport { useQueryMemo } from '@gen-epix/ui-client-common/hooks/useQueryMemo';\nimport { withDialog } from '@gen-epix/ui-core-components/hoc/withDialog';\nimport { TestIdUtil } from '@gen-epix/ui-core/utils/TestIdUtil';\nimport { GenericForm } from '@gen-epix/ui-core-form/components/helpers/GenericForm';\nimport type {\n AutoCompleteOption,\n FormFieldDefinition,\n} from '@gen-epix/ui-core-form/models/form';\nimport { FORM_FIELD_DEFINITION_TYPE } from '@gen-epix/ui-core-form/models/form';\nimport { SchemaUtil } from '@gen-epix/ui-core-form/utils/SchemaUtil';\nimport { DATE_FORMAT } from '@gen-epix/ui-core/constants/date';\n\nimport { CASEDB_QUERY_KEY } from '../../../constants/query';\nimport type { CaseDbConfig } from '../../../models/config';\nimport { DashboardStoreContext } from '../../../stores/dashboardStore';\nimport { TreeWidgetUtil } from '../../../utils/TreeWidgetUtil';\nimport type {\n CaseDbSimilarCaseWithIsOwnCase,\n FindSimilarCasesChartDataPoint,\n FindSimilarCasesOrganizationFilter,\n} from '../../../models/caseDb';\nimport type { TreeWidgetDataPersistable } from '../../../models/dashboard';\nimport { DASHBOARD_COMPONENT_NAME } from '../../../constants/dashboard';\n\nimport { FindSimilarCasesDialogDateRangeChart } from './FindSimilarCasesDialogDateRangeChart';\n\nexport interface FindSimilarCasesDialogOpenProps {\n allRows: CaseDbCase[];\n completeCaseType: CaseDbCompleteCaseType;\n selectedRows: CaseDbCase[];\n}\n\nexport interface FindSimilarCasesDialogProps extends WithDialogRenderProps<FindSimilarCasesDialogOpenProps> {\n //\n}\n\nexport type FindSimilarCasesDialogRefMethods = WithDialogRefMethods<FindSimilarCasesDialogProps, FindSimilarCasesDialogOpenProps>;\n\ntype FormFields = {\n dateRange: [string, string] | null;\n maxDistance: number;\n organizationFilter: FindSimilarCasesOrganizationFilter;\n treeColId: string;\n};\n\nexport const FindSimilarCasesDialog = withDialog<FindSimilarCasesDialogProps, FindSimilarCasesDialogOpenProps>((\n {\n onActionsChange,\n onClose,\n onTitleChange,\n openProps,\n }: FindSimilarCasesDialogProps,\n): ReactElement => {\n const { t } = useTranslation();\n const searchFormId = useId();\n const dashboardStore = use(DashboardStoreContext);\n const treeConfiguration = dashboardStore.getState().getWidgetDataPersistable<TreeWidgetDataPersistable>(DASHBOARD_COMPONENT_NAME.TREE).treeConfiguration;\n const setFindSimilarCasesResults = useStore(dashboardStore, (state) => state.setFindSimilarCasesResults);\n const findSimilarCasesResults = useStore(dashboardStore, (state) => state.findSimilarCasesResults);\n const treeConfigurations = useMemo(() => TreeWidgetUtil.getTreeConfigurations(openProps.completeCaseType), [openProps.completeCaseType]);\n const [formData, setFormData] = useState<FormFields>(null);\n\n const schema = useMemo(() => object<FormFields>().shape({\n dateRange: mixed<[string, string] | null>().nullable().default(null),\n maxDistance: SchemaUtil.number.required().positive().when('treeColId', ([treeColId], s) => {\n const currentTreeConfiguration = treeConfigurations.find(x => x.col.id === treeColId);\n if (!currentTreeConfiguration) {\n return s;\n }\n const sWithIntegerCheck = s.integer(t`Max distance must be an integer`);\n return sWithIntegerCheck.max(currentTreeConfiguration.geneticDistanceProtocol.seqdb_max_stored_distance || ConfigService.getInstance<CaseDbConfig>().config.epi.SEQDB_MAX_STORED_DISTANCE_FALLBACK);\n }),\n organizationFilter: string<FindSimilarCasesOrganizationFilter>().required().oneOf(['all', 'own', 'otherOrganization']),\n treeColId: string().required(),\n }), [t, treeConfigurations]);\n\n const treeOptions = useMemo<AutoCompleteOption<string>[]>(() => {\n const cols = new Set<CaseDbCol>();\n treeConfigurations.forEach(x => {\n cols.add(x.col);\n });\n return Array.from(cols).map(x => {\n return {\n label: x.label,\n value: x.id,\n } satisfies AutoCompleteOption<string>;\n });\n\n }, [treeConfigurations]);\n\n const formMethods = useForm<FormFields>({\n defaultValues: {\n dateRange: null,\n maxDistance: 0,\n organizationFilter: 'all',\n treeColId: treeConfiguration ? treeConfiguration.col.id : null,\n },\n resolver: yupResolver(schema, undefined, { raw: true }) as Resolver<FormFields>,\n });\n const { control, handleSubmit } = formMethods;\n\n const formValues = useWatch({ control });\n\n const searchFormFieldDefinitions = useMemo(() => {\n const currentTreeConfiguration = treeConfigurations.find(x => x.col.id === formValues.treeColId);\n return [\n {\n definition: FORM_FIELD_DEFINITION_TYPE.SELECT,\n label: t`Tree`,\n name: 'treeColId',\n options: treeOptions,\n } as const satisfies FormFieldDefinition<FormFields>,\n {\n definition: FORM_FIELD_DEFINITION_TYPE.NUMBER,\n label: t`Max distance`,\n max: currentTreeConfiguration?.geneticDistanceProtocol?.seqdb_max_stored_distance || ConfigService.getInstance<CaseDbConfig>().config.epi.SEQDB_MAX_STORED_DISTANCE_FALLBACK,\n min: 0,\n name: 'maxDistance',\n showSlider: true,\n step: 1,\n } as const satisfies FormFieldDefinition<FormFields>,\n ];\n }, [formValues.treeColId, t, treeConfigurations, treeOptions]);\n\n useEffect(() => {\n onTitleChange(t`Find similar cases`);\n }, [t, onTitleChange]);\n\n const onFormSubmit = useCallback((data: FormFields) => {\n formMethods.setValue('dateRange', null);\n setFormData({ ...data, dateRange: null });\n }, [formMethods]);\n\n const onOrganizationFilterChange = useCallback((organizationFilter: FindSimilarCasesOrganizationFilter) => {\n formMethods.setValue('organizationFilter', organizationFilter);\n }, [formMethods]);\n\n const query = useQueryMemo({\n enabled: !!formData,\n queryFn: async ({ signal }) => {\n const retrieveSimilarCasesResponse = await CaseDbCaseApi.getInstance().retrieveSimilarCases({\n case_ids: openProps.selectedRows.map(x => x.id),\n case_type_id: openProps.completeCaseType.id,\n genetic_distance_col_id: formData?.treeColId,\n max_distance: formData?.maxDistance,\n }, { signal });\n const retrieveIsOwnCasesResponse = await CaseDbCaseApi.getInstance().retrieveIsOwnCases({\n case_ids: retrieveSimilarCasesResponse.data.cases.map(x => x.id),\n case_type_id: openProps.completeCaseType.id,\n }, { signal });\n\n return retrieveSimilarCasesResponse.data.cases.map(caseDbCase => {\n return {\n ...caseDbCase,\n is_own_case: retrieveIsOwnCasesResponse.data[caseDbCase.id] || false,\n } satisfies CaseDbSimilarCaseWithIsOwnCase;\n });\n },\n queryKey: [QueryClientService.getInstance().getGenericKey(CASEDB_QUERY_KEY.SIMILAR_CASES), JSON.stringify({ formData, rowIds: openProps.selectedRows.map(row => row.id) })],\n });\n\n const organizationFilteredCases = useMemo<CaseDbSimilarCaseWithIsOwnCase[]>(() => {\n if (!query.data) {\n return [];\n }\n return query.data.filter(c => {\n switch (formValues.organizationFilter) {\n case 'all': return true;\n case 'otherOrganization': return !c.is_own_case;\n case 'own': return c.is_own_case;\n default: return true;\n }\n });\n }, [query.data, formValues.organizationFilter]);\n\n const chartData = useMemo<FindSimilarCasesChartDataPoint[]>(() => {\n const counts = new Map<string, FindSimilarCasesChartDataPoint>();\n for (const { is_own_case, timed_at } of query.data ?? []) {\n if (timed_at) {\n const currentCount = counts.get(timed_at) ?? {\n count: 0,\n date: timed_at,\n otherOrganizationCaseCount: 0,\n ownCaseCount: 0,\n };\n currentCount.count += 1;\n if (is_own_case) {\n currentCount.ownCaseCount += 1;\n } else {\n currentCount.otherOrganizationCaseCount += 1;\n }\n counts.set(timed_at, currentCount);\n }\n }\n return Array.from(counts.values())\n .sort((a, b) => a.date.localeCompare(b.date));\n }, [query.data]);\n\n const filteredCases = useMemo<CaseDbSimilarCaseWithIsOwnCase[]>(() => {\n const dateRange = formValues.dateRange;\n if (!dateRange) {\n return organizationFilteredCases;\n }\n const [startDate, endDate] = dateRange;\n return organizationFilteredCases.filter(c => {\n if (!c.timed_at) {\n return false;\n }\n const caseDateOnly = format(parseISO(c.timed_at), DATE_FORMAT.DATE);\n return caseDateOnly >= startDate && caseDateOnly <= endDate;\n });\n }, [formValues.dateRange, organizationFilteredCases]);\n\n const similarCaseIdsNotInLineListWithDateFilter = useMemo<string[]>(() => {\n const allRowIds = openProps.allRows.map(x => x.id);\n return filteredCases.reduce<string[]>((acc, caseIdAndDate) => {\n const caseId = caseIdAndDate.id;\n if (!allRowIds.includes(caseId)) {\n acc.push(caseId);\n }\n return acc;\n }, []);\n }, [filteredCases, openProps.allRows]);\n\n const similarCaseIdsAlreadyInLineListWithDateFilter = useMemo<string[]>(() => {\n const allRowIds = openProps.allRows.map(x => x.id);\n return filteredCases.reduce<string[]>((acc, caseIdAndDate) => {\n const caseId = caseIdAndDate.id;\n if (allRowIds.includes(caseId)) {\n acc.push(caseId);\n }\n return acc;\n }, []);\n }, [filteredCases, openProps.allRows]);\n\n const onAddToLineListButtonClick = useCallback(async () => {\n\n await setFindSimilarCasesResults(produce(findSimilarCasesResults, draft => {\n draft.push({\n colId: formData?.treeColId,\n distance: formData?.maxDistance,\n key: findSimilarCasesResults.length.toString(),\n originalCaseIds: openProps.allRows.map(x => x.id),\n similarCaseIds: similarCaseIdsNotInLineListWithDateFilter,\n });\n return draft;\n }));\n\n onClose();\n }, [setFindSimilarCasesResults, findSimilarCasesResults, onClose, similarCaseIdsNotInLineListWithDateFilter, formData?.maxDistance, formData?.treeColId, openProps.allRows]);\n\n useEffect(() => {\n const actions: DialogAction[] = [];\n actions.push({\n ...TestIdUtil.createAttributes('FindSimilarCasesDialog-closeButton'),\n color: 'primary',\n label: t`Close`,\n onClick: onClose,\n variant: 'outlined',\n });\n actions.push({\n ...TestIdUtil.createAttributes('FindSimilarCasesDialog-addSimilarCasesButton'),\n color: 'secondary',\n disabled: similarCaseIdsNotInLineListWithDateFilter.length === 0,\n label: t('Add {{count}} similar cases to line list', { count: similarCaseIdsNotInLineListWithDateFilter.length }),\n onClick: onAddToLineListButtonClick,\n variant: 'contained',\n });\n onActionsChange(actions);\n }, [onActionsChange, onAddToLineListButtonClick, onClose, similarCaseIdsNotInLineListWithDateFilter.length, t]);\n\n return (\n <Box>\n <Box\n sx={{\n marginBottom: 2,\n }}\n >\n <Typography>\n {t('Select a tree and maximum distance to find similar cases for the {{count}} selected cases.', { count: openProps.selectedRows.length })}\n </Typography>\n </Box>\n <Box>\n <GenericForm<FormFields>\n formFieldDefinitions={searchFormFieldDefinitions}\n formId={searchFormId}\n formMethods={formMethods}\n onSubmit={handleSubmit(onFormSubmit)}\n schema={schema}\n />\n </Box>\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'flex-end',\n marginTop: 2,\n }}\n >\n <Button\n color={'secondary'}\n form={searchFormId}\n type={'submit'}\n variant={'contained'}\n >\n {formData ? t`Search again` : t`Search`}\n </Button>\n </Box>\n <Divider sx={{ marginY: 2 }} />\n <ResponseHandler\n inlineSpinner\n loadables={query}\n >\n {query.data && (\n <>\n <Box\n sx={{\n marginY: 2,\n }}\n >\n <Alert\n severity={query.data.length > 0 ? 'success' : 'warning'}\n >\n <AlertTitle>\n {t('Found {{count}} similar cases with a distance of {{distance}}.', { count: query.data.length, distance: formData?.maxDistance })}\n </AlertTitle>\n </Alert>\n </Box>\n {chartData.length > 0 && (\n <Box\n sx={{\n marginY: 2,\n }}\n >\n <FindSimilarCasesDialogDateRangeChart<FormFields>\n control={control}\n data={chartData}\n name={'dateRange'}\n onOrganizationFilterChange={onOrganizationFilterChange}\n organizationFilter={formValues.organizationFilter}\n />\n </Box>\n )}\n <Box\n sx={{\n marginY: 2,\n }}\n >\n <Alert\n severity={'info'}\n >\n <AlertTitle>\n {t('{{count}} similar cases can be added to the line list.', { count: similarCaseIdsNotInLineListWithDateFilter.length })}\n </AlertTitle>\n </Alert>\n </Box>\n {similarCaseIdsAlreadyInLineListWithDateFilter.length > 0 && (\n <Alert\n severity={'warning'}\n >\n <AlertTitle>\n {t('{{count}} similar cases found that are already in the line list.', { count: similarCaseIdsAlreadyInLineListWithDateFilter.length })}\n </AlertTitle>\n </Alert>\n )}\n </>\n )}\n </ResponseHandler>\n </Box>\n );\n}, {\n defaultTitle: '',\n fullWidth: true,\n maxWidth: 'md',\n testId: 'FindSimilarCasesDialog',\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FindSimilarCasesDialog.js","names":[],"sources":["../../src/components/ui/FindSimilarCasesDialog/FindSimilarCasesDialogDateRangeChart.tsx","../../src/components/ui/FindSimilarCasesDialog/FindSimilarCasesDialog.tsx"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport type { ReactElement } from 'react';\nimport {\n dispose,\n getInstanceByDom,\n init,\n use as registerECharts,\n} from 'echarts/core';\nimport {\n DataZoomComponent,\n GridComponent,\n LegendComponent,\n TooltipComponent,\n} from 'echarts/components';\nimport {\n BarChart,\n LineChart,\n} from 'echarts/charts';\nimport { CanvasRenderer } from 'echarts/renderers';\nimport EChartsReact from 'echarts-for-react';\nimport type {\n Control,\n FieldValues,\n Path,\n} from 'react-hook-form';\nimport { Controller } from 'react-hook-form';\nimport { useTranslation } from 'react-i18next';\nimport {\n Box,\n useTheme,\n} from '@mui/material';\nimport { ConfigService } from '@gen-epix/ui-client-common/classes/services/ConfigService';\n\nimport { FindSimilarCasesUtil } from '../../../utils/FindSimilarCasesUtil';\nimport type {\n FindSimilarCasesChartDataPoint,\n FindSimilarCasesOrganizationFilter,\n} from '../../../models/caseDb';\nimport type { CaseDbConfig } from '../../../models/config';\n\nregisterECharts([BarChart, LineChart, GridComponent, LegendComponent, TooltipComponent, DataZoomComponent, CanvasRenderer]);\n\nconst echartsCore = {\n dispose,\n getInstanceByDom,\n init,\n};\n\nexport interface FindSimilarCasesDialogDateRangeChartProps<\n TFieldValues extends FieldValues,\n TName extends Path<TFieldValues> = Path<TFieldValues>,\n> {\n control: Control<TFieldValues>;\n data: FindSimilarCasesChartDataPoint[];\n name: TName;\n onOrganizationFilterChange: (organizationFilter: FindSimilarCasesOrganizationFilter) => void;\n organizationFilter: FindSimilarCasesOrganizationFilter;\n}\n\nexport const FindSimilarCasesDialogDateRangeChart = <\n TFieldValues extends FieldValues,\n TName extends Path<TFieldValues> = Path<TFieldValues>,\n>({\n control,\n data,\n name,\n onOrganizationFilterChange,\n organizationFilter,\n}: FindSimilarCasesDialogDateRangeChartProps<TFieldValues, TName>): ReactElement => {\n const { t } = useTranslation();\n const intervals = useMemo(() => FindSimilarCasesUtil.buildChartIntervals(data), [data]);\n const theme = useTheme();\n const [tooltipState, setTooltipState] = useState<{ content: string; x: number; y: number } | null>(null);\n const ownCasesLabel = t`Own cases`;\n const otherOrganizationCasesLabel = t`Cases from other organizations`;\n\n const intervalsRef = useRef(intervals);\n useEffect(() => {\n intervalsRef.current = intervals;\n }, [intervals]);\n\n // Keeps a stable reference to the latest onChange so onDataZoom never goes stale.\n const onChangeRef = useRef<((value: [string, string] | null) => void) | null>(null);\n\n const onDataZoom = useCallback((params: unknown) => {\n type ZoomPayload = { end?: number; endValue?: number; start?: number; startValue?: number };\n const event = params as { batch?: ZoomPayload[] } & ZoomPayload;\n const base = event.batch?.[0] ?? event;\n\n const n = intervalsRef.current.length - 1;\n let startIndex: number;\n let endIndex: number;\n\n if (base.startValue !== undefined && base.endValue !== undefined) {\n // index-based (e.g. inside/wheel zoom)\n startIndex = Math.round(base.startValue);\n endIndex = Math.round(base.endValue);\n } else if (base.start !== undefined && base.end !== undefined) {\n // percentage-based (slider drag)\n startIndex = Math.round((base.start / 100) * n);\n endIndex = Math.round((base.end / 100) * n);\n } else {\n onChangeRef.current?.(null);\n return;\n }\n\n const startInterval = intervalsRef.current[startIndex];\n const endInterval = intervalsRef.current[endIndex];\n if (startInterval && endInterval) {\n onChangeRef.current?.([startInterval.startDate, endInterval.endDate]);\n return;\n }\n onChangeRef.current?.(null);\n }, []);\n\n const option = useMemo(() => {\n const { BASE_COLORS } = ConfigService.getInstance<CaseDbConfig>().config.epi.STRATIFICATION;\n return {\n color: BASE_COLORS,\n dataZoom: [{\n borderColor: theme.palette.primary.light,\n bottom: 0,\n fillerColor: `${theme.palette.primary.main}33`,\n handleStyle: { borderColor: theme.palette.primary.main, color: theme.palette.primary.main },\n height: 50,\n left: 80,\n right: 80,\n selectedDataBackground: { areaStyle: { color: theme.palette.primary.light }, lineStyle: { color: theme.palette.primary.main } },\n type: 'slider',\n }],\n grid: { bottom: 110, left: 80, right: 80, top: 40 },\n legend: {\n data: [ownCasesLabel, otherOrganizationCasesLabel],\n selected: {\n [otherOrganizationCasesLabel]: organizationFilter !== 'own',\n [ownCasesLabel]: organizationFilter !== 'otherOrganization',\n },\n top: 0,\n },\n series: [\n {\n data: intervals.map(i => i.count),\n lineStyle: { opacity: 0 },\n name: 'dataZoomShadow',\n silent: true,\n symbol: 'none',\n type: 'line',\n },\n { data: intervals.map(i => i.ownCaseCount), itemStyle: { color: BASE_COLORS[0] }, name: ownCasesLabel, stack: 'similarCases', type: 'bar' },\n { data: intervals.map(i => i.otherOrganizationCaseCount), itemStyle: { color: BASE_COLORS[1] }, name: otherOrganizationCasesLabel, stack: 'similarCases', type: 'bar' },\n ],\n tooltip: { show: false },\n xAxis: { axisLabel: {\n height: 100,\n rotate: 45,\n }, axisTick: {\n alignWithLabel: true,\n show: true,\n }, data: intervals.map(i => i.label),\n type: 'category' },\n yAxis: { max: Math.max(...intervals.map(i => i.count), 1), minInterval: 1, type: 'value' },\n };\n }, [intervals, organizationFilter, otherOrganizationCasesLabel, ownCasesLabel, theme]);\n\n const onLegendSelectChanged = useCallback((params: unknown) => {\n const { selected } = params as { selected?: Record<string, boolean> };\n if (!selected) {\n return;\n }\n const ownCasesSelected = selected[ownCasesLabel] ?? true;\n const otherOrganizationCasesSelected = selected[otherOrganizationCasesLabel] ?? true;\n if (ownCasesSelected && !otherOrganizationCasesSelected) {\n onOrganizationFilterChange('own');\n return;\n }\n if (!ownCasesSelected && otherOrganizationCasesSelected) {\n onOrganizationFilterChange('otherOrganization');\n return;\n }\n onOrganizationFilterChange('all');\n }, [onOrganizationFilterChange, otherOrganizationCasesLabel, ownCasesLabel]);\n\n const onEvents = useMemo(() => ({\n datazoom: onDataZoom,\n legendselectchanged: onLegendSelectChanged,\n mouseout: () => {\n setTooltipState(null);\n },\n mouseover: (event: unknown) => {\n const e = event as { event?: { event?: MouseEvent }; name?: string; value?: number };\n const mouseEvent = e.event?.event;\n if (mouseEvent && e.name !== null && e.name !== undefined) {\n setTooltipState({ content: `${e.name} (n=${e.value ?? 0})`, x: mouseEvent.clientX + 12, y: mouseEvent.clientY + 12 });\n }\n },\n }), [onDataZoom, onLegendSelectChanged]);\n\n const renderChart = useCallback(({ field: { onChange } }: { field: { onChange: (value: [string, string] | null) => void } }) => {\n onChangeRef.current = onChange;\n return (\n <EChartsReact\n echarts={echartsCore}\n notMerge\n onEvents={onEvents}\n option={option}\n style={{ height: 400 }}\n />\n );\n }, [onEvents, option]);\n\n return (\n <>\n <Controller\n control={control}\n name={name}\n render={renderChart}\n />\n {tooltipState && (\n <Box\n sx={{\n bgcolor: 'background.paper',\n border: '1px solid',\n borderColor: 'divider',\n borderRadius: 1,\n fontSize: 12,\n left: tooltipState.x,\n pointerEvents: 'none',\n position: 'fixed',\n px: 1,\n py: 0.5,\n top: tooltipState.y,\n zIndex: 'tooltip',\n }}\n >\n {tooltipState.content}\n </Box>\n )}\n </>\n );\n};\n","import {\n use,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useState,\n} from 'react';\nimport type { ReactElement } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport {\n mixed,\n object,\n string,\n} from 'yup';\nimport { yupResolver } from '@hookform/resolvers/yup';\nimport type { Resolver } from 'react-hook-form';\nimport {\n useForm,\n useWatch,\n} from 'react-hook-form';\nimport {\n Alert,\n AlertTitle,\n Box,\n Button,\n Divider,\n Typography,\n} from '@mui/material';\nimport { useStore } from 'zustand';\nimport { produce } from 'immer';\nimport {\n format,\n parseISO,\n} from 'date-fns';\nimport type {\n CaseDbCase,\n CaseDbCol,\n CaseDbCompleteCaseType,\n} from '@gen-epix/api-casedb';\nimport { CaseDbCaseApi } from '@gen-epix/api-casedb';\nimport type { DialogAction } from '@gen-epix/ui-core-components/components/Dialog';\nimport type {\n WithDialogRefMethods,\n WithDialogRenderProps,\n} from '@gen-epix/ui-core-components/hoc/withDialog';\nimport { ConfigService } from '@gen-epix/ui-client-common/classes/services/ConfigService';\nimport { QueryClientService } from '@gen-epix/ui-client-common/classes/services/QueryClientService';\nimport { ResponseHandler } from '@gen-epix/ui-client-common/components/ui/ResponseHandler';\nimport { useQueryMemo } from '@gen-epix/ui-client-common/hooks/useQueryMemo';\nimport { withDialog } from '@gen-epix/ui-core-components/hoc/withDialog';\nimport { TestIdUtil } from '@gen-epix/ui-core/utils/TestIdUtil';\nimport { GenericForm } from '@gen-epix/ui-core-form/components/helpers/GenericForm';\nimport type {\n AutoCompleteOption,\n FormFieldDefinition,\n} from '@gen-epix/ui-core-form/models/form';\nimport { FORM_FIELD_DEFINITION_TYPE } from '@gen-epix/ui-core-form/models/form';\nimport { SchemaUtil } from '@gen-epix/ui-core-form/utils/SchemaUtil';\nimport { DATE_FORMAT } from '@gen-epix/ui-core/constants/date';\n\nimport { CASEDB_QUERY_KEY } from '../../../constants/query';\nimport type { CaseDbConfig } from '../../../models/config';\nimport { DashboardStoreContext } from '../../../stores/dashboardStore';\nimport { TreeWidgetUtil } from '../../../utils/TreeWidgetUtil';\nimport type {\n CaseDbSimilarCaseWithIsOwnCase,\n FindSimilarCasesChartDataPoint,\n FindSimilarCasesOrganizationFilter,\n} from '../../../models/caseDb';\nimport type { TreeWidgetDataPersistable } from '../../../models/dashboard';\nimport { DASHBOARD_COMPONENT_NAME } from '../../../constants/dashboard';\n\nimport { FindSimilarCasesDialogDateRangeChart } from './FindSimilarCasesDialogDateRangeChart';\n\nexport interface FindSimilarCasesDialogOpenProps {\n allRows: CaseDbCase[];\n completeCaseType: CaseDbCompleteCaseType;\n selectedRows: CaseDbCase[];\n}\n\nexport interface FindSimilarCasesDialogProps extends WithDialogRenderProps<FindSimilarCasesDialogOpenProps> {\n //\n}\n\nexport type FindSimilarCasesDialogRefMethods = WithDialogRefMethods<FindSimilarCasesDialogProps, FindSimilarCasesDialogOpenProps>;\n\ntype FormFields = {\n dateRange: [string, string] | null;\n maxDistance: number;\n organizationFilter: FindSimilarCasesOrganizationFilter;\n treeColId: string;\n};\n\nexport const FindSimilarCasesDialog = withDialog<FindSimilarCasesDialogProps, FindSimilarCasesDialogOpenProps>((\n {\n onActionsChange,\n onClose,\n onTitleChange,\n openProps,\n }: FindSimilarCasesDialogProps,\n): ReactElement => {\n const { t } = useTranslation();\n const searchFormId = useId();\n const dashboardStore = use(DashboardStoreContext);\n const treeConfiguration = dashboardStore.getState().getWidgetDataPersistable<TreeWidgetDataPersistable>(DASHBOARD_COMPONENT_NAME.TREE).treeConfiguration;\n const setFindSimilarCasesResults = useStore(dashboardStore, (state) => state.setFindSimilarCasesResults);\n const findSimilarCasesResults = useStore(dashboardStore, (state) => state.findSimilarCasesResults);\n const treeConfigurations = useMemo(() => TreeWidgetUtil.getTreeConfigurations(openProps.completeCaseType), [openProps.completeCaseType]);\n const [formData, setFormData] = useState<FormFields>(null);\n\n const schema = useMemo(() => object<FormFields>().shape({\n dateRange: mixed<[string, string] | null>().nullable().default(null),\n maxDistance: SchemaUtil.number.required().positive().when('treeColId', ([treeColId], s) => {\n const currentTreeConfiguration = treeConfigurations.find(x => x.col.id === treeColId);\n if (!currentTreeConfiguration) {\n return s;\n }\n const sWithIntegerCheck = s.integer(t`Max distance must be an integer`);\n return sWithIntegerCheck.max(currentTreeConfiguration.geneticDistanceProtocol.seqdb_max_stored_distance || ConfigService.getInstance<CaseDbConfig>().config.epi.SEQDB_MAX_STORED_DISTANCE_FALLBACK);\n }),\n organizationFilter: string<FindSimilarCasesOrganizationFilter>().required().oneOf(['all', 'own', 'otherOrganization']),\n treeColId: string().required(),\n }), [t, treeConfigurations]);\n\n const treeOptions = useMemo<AutoCompleteOption<string>[]>(() => {\n const cols = new Set<CaseDbCol>();\n treeConfigurations.forEach(x => {\n cols.add(x.col);\n });\n return Array.from(cols).map(x => {\n return {\n label: x.label,\n value: x.id,\n } satisfies AutoCompleteOption<string>;\n });\n\n }, [treeConfigurations]);\n\n const formMethods = useForm<FormFields>({\n defaultValues: {\n dateRange: null,\n maxDistance: 0,\n organizationFilter: 'all',\n treeColId: treeConfiguration ? treeConfiguration.col.id : null,\n },\n resolver: yupResolver(schema, undefined, { raw: true }) as Resolver<FormFields>,\n });\n const { control, handleSubmit } = formMethods;\n\n const formValues = useWatch({ control });\n\n const searchFormFieldDefinitions = useMemo(() => {\n const currentTreeConfiguration = treeConfigurations.find(x => x.col.id === formValues.treeColId);\n return [\n {\n definition: FORM_FIELD_DEFINITION_TYPE.SELECT,\n label: t`Tree`,\n name: 'treeColId',\n options: treeOptions,\n } as const satisfies FormFieldDefinition<FormFields>,\n {\n definition: FORM_FIELD_DEFINITION_TYPE.NUMBER,\n label: t`Max distance`,\n max: currentTreeConfiguration?.geneticDistanceProtocol?.seqdb_max_stored_distance || ConfigService.getInstance<CaseDbConfig>().config.epi.SEQDB_MAX_STORED_DISTANCE_FALLBACK,\n min: 0,\n name: 'maxDistance',\n showSlider: true,\n step: 1,\n } as const satisfies FormFieldDefinition<FormFields>,\n ];\n }, [formValues.treeColId, t, treeConfigurations, treeOptions]);\n\n useEffect(() => {\n onTitleChange(t`Find similar cases`);\n }, [t, onTitleChange]);\n\n const onFormSubmit = useCallback((data: FormFields) => {\n formMethods.setValue('dateRange', null);\n setFormData({ ...data, dateRange: null });\n }, [formMethods]);\n\n const onOrganizationFilterChange = useCallback((organizationFilter: FindSimilarCasesOrganizationFilter) => {\n formMethods.setValue('organizationFilter', organizationFilter);\n }, [formMethods]);\n\n const query = useQueryMemo({\n enabled: !!formData,\n queryFn: async ({ signal }) => {\n const retrieveSimilarCasesResponse = await CaseDbCaseApi.getInstance().retrieveSimilarCases({\n case_ids: openProps.selectedRows.map(x => x.id),\n case_type_id: openProps.completeCaseType.id,\n genetic_distance_col_id: formData?.treeColId,\n max_distance: formData?.maxDistance,\n }, { signal });\n const retrieveIsOwnCasesResponse = await CaseDbCaseApi.getInstance().retrieveIsOwnCases({\n case_ids: retrieveSimilarCasesResponse.data.cases.map(x => x.id),\n case_type_id: openProps.completeCaseType.id,\n }, { signal });\n\n return retrieveSimilarCasesResponse.data.cases.map(caseDbCase => {\n return {\n ...caseDbCase,\n is_own_case: retrieveIsOwnCasesResponse.data[caseDbCase.id] || false,\n } satisfies CaseDbSimilarCaseWithIsOwnCase;\n });\n },\n queryKey: [QueryClientService.getInstance().getGenericKey(CASEDB_QUERY_KEY.SIMILAR_CASES), JSON.stringify({ formData, rowIds: openProps.selectedRows.map(row => row.id) })],\n });\n\n const organizationFilteredCases = useMemo<CaseDbSimilarCaseWithIsOwnCase[]>(() => {\n if (!query.data) {\n return [];\n }\n return query.data.filter(c => {\n switch (formValues.organizationFilter) {\n case 'all': return true;\n case 'otherOrganization': return !c.is_own_case;\n case 'own': return c.is_own_case;\n default: return true;\n }\n });\n }, [query.data, formValues.organizationFilter]);\n\n const chartData = useMemo<FindSimilarCasesChartDataPoint[]>(() => {\n const counts = new Map<string, FindSimilarCasesChartDataPoint>();\n for (const { is_own_case, timed_at } of query.data ?? []) {\n if (timed_at) {\n const currentCount = counts.get(timed_at) ?? {\n count: 0,\n date: timed_at,\n otherOrganizationCaseCount: 0,\n ownCaseCount: 0,\n };\n currentCount.count += 1;\n if (is_own_case) {\n currentCount.ownCaseCount += 1;\n } else {\n currentCount.otherOrganizationCaseCount += 1;\n }\n counts.set(timed_at, currentCount);\n }\n }\n return Array.from(counts.values())\n .sort((a, b) => a.date.localeCompare(b.date));\n }, [query.data]);\n\n const filteredCases = useMemo<CaseDbSimilarCaseWithIsOwnCase[]>(() => {\n const dateRange = formValues.dateRange;\n if (!dateRange) {\n return organizationFilteredCases;\n }\n const [startDate, endDate] = dateRange;\n return organizationFilteredCases.filter(c => {\n if (!c.timed_at) {\n return false;\n }\n const caseDateOnly = format(parseISO(c.timed_at), DATE_FORMAT.DATE);\n return caseDateOnly >= startDate && caseDateOnly <= endDate;\n });\n }, [formValues.dateRange, organizationFilteredCases]);\n\n const similarCaseIdsNotInLineListWithDateFilter = useMemo<string[]>(() => {\n const allRowIds = openProps.allRows.map(x => x.id);\n return filteredCases.reduce<string[]>((acc, caseIdAndDate) => {\n const caseId = caseIdAndDate.id;\n if (!allRowIds.includes(caseId)) {\n acc.push(caseId);\n }\n return acc;\n }, []);\n }, [filteredCases, openProps.allRows]);\n\n const similarCaseIdsAlreadyInLineListWithDateFilter = useMemo<string[]>(() => {\n const allRowIds = openProps.allRows.map(x => x.id);\n return filteredCases.reduce<string[]>((acc, caseIdAndDate) => {\n const caseId = caseIdAndDate.id;\n if (allRowIds.includes(caseId)) {\n acc.push(caseId);\n }\n return acc;\n }, []);\n }, [filteredCases, openProps.allRows]);\n\n const onAddToLineListButtonClick = useCallback(async () => {\n\n await setFindSimilarCasesResults(produce(findSimilarCasesResults, draft => {\n draft.push({\n colId: formData?.treeColId,\n distance: formData?.maxDistance,\n key: findSimilarCasesResults.length.toString(),\n originalCaseIds: openProps.allRows.map(x => x.id),\n similarCaseIds: similarCaseIdsNotInLineListWithDateFilter,\n });\n return draft;\n }));\n\n onClose();\n }, [setFindSimilarCasesResults, findSimilarCasesResults, onClose, similarCaseIdsNotInLineListWithDateFilter, formData?.maxDistance, formData?.treeColId, openProps.allRows]);\n\n useEffect(() => {\n const actions: DialogAction[] = [];\n actions.push({\n ...TestIdUtil.createAttributes('FindSimilarCasesDialog-closeButton'),\n color: 'primary',\n label: t`Close`,\n onClick: onClose,\n variant: 'outlined',\n });\n actions.push({\n ...TestIdUtil.createAttributes('FindSimilarCasesDialog-addSimilarCasesButton'),\n color: 'secondary',\n disabled: similarCaseIdsNotInLineListWithDateFilter.length === 0,\n label: t('Add {{count}} similar cases to line list', { count: similarCaseIdsNotInLineListWithDateFilter.length }),\n onClick: onAddToLineListButtonClick,\n variant: 'contained',\n });\n onActionsChange(actions);\n }, [onActionsChange, onAddToLineListButtonClick, onClose, similarCaseIdsNotInLineListWithDateFilter.length, t]);\n\n return (\n <Box>\n <Box\n sx={{\n marginBottom: 2,\n }}\n >\n <Typography>\n {t('Select a tree and maximum distance to find similar cases for the {{count}} selected cases.', { count: openProps.selectedRows.length })}\n </Typography>\n </Box>\n <Box>\n <GenericForm<FormFields>\n formFieldDefinitions={searchFormFieldDefinitions}\n formId={searchFormId}\n formMethods={formMethods}\n onSubmit={handleSubmit(onFormSubmit)}\n schema={schema}\n />\n </Box>\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'flex-end',\n marginTop: 2,\n }}\n >\n <Button\n color={'secondary'}\n form={searchFormId}\n type={'submit'}\n variant={'contained'}\n >\n {formData ? t`Search again` : t`Search`}\n </Button>\n </Box>\n <Divider sx={{ marginY: 2 }} />\n <ResponseHandler\n inlineSpinner\n loadables={query}\n >\n {query.data && (\n <>\n <Box\n sx={{\n marginY: 2,\n }}\n >\n <Alert\n severity={query.data.length > 0 ? 'success' : 'warning'}\n >\n <AlertTitle>\n {t('Found {{count}} similar cases with a distance of {{distance}}.', { count: query.data.length, distance: formData?.maxDistance })}\n </AlertTitle>\n </Alert>\n </Box>\n {chartData.length > 0 && (\n <Box\n sx={{\n marginY: 2,\n }}\n >\n <FindSimilarCasesDialogDateRangeChart<FormFields>\n control={control}\n data={chartData}\n name={'dateRange'}\n onOrganizationFilterChange={onOrganizationFilterChange}\n organizationFilter={formValues.organizationFilter}\n />\n </Box>\n )}\n <Box\n sx={{\n marginY: 2,\n }}\n >\n <Alert\n severity={'info'}\n >\n <AlertTitle>\n {t('{{count}} similar cases can be added to the line list.', { count: similarCaseIdsNotInLineListWithDateFilter.length })}\n </AlertTitle>\n </Alert>\n </Box>\n {similarCaseIdsAlreadyInLineListWithDateFilter.length > 0 && (\n <Alert\n severity={'warning'}\n >\n <AlertTitle>\n {t('{{count}} similar cases found that are already in the line list.', { count: similarCaseIdsAlreadyInLineListWithDateFilter.length })}\n </AlertTitle>\n </Alert>\n )}\n </>\n )}\n </ResponseHandler>\n </Box>\n );\n}, {\n defaultTitle: '',\n fullWidth: true,\n maxWidth: 'md',\n testId: 'FindSimilarCasesDialog',\n});\n"],"mappings":"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"}
|