@gen-epix/ui-client-casedb 4.1.0 → 4.2.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.
Files changed (41) hide show
  1. package/dist/_chunks/AddCasesToEventDialog.js +98 -98
  2. package/dist/_chunks/AddCasesToEventDialog.js.map +1 -1
  3. package/dist/_chunks/CaseContentForm.js +10 -10
  4. package/dist/_chunks/CaseInfoDialog.js +220 -220
  5. package/dist/_chunks/CaseInfoDialog.js.map +1 -1
  6. package/dist/_chunks/CaseSetInfoDialog.js +224 -224
  7. package/dist/_chunks/CaseSetInfoDialog.js.map +1 -1
  8. package/dist/_chunks/Dashboard.js +295 -295
  9. package/dist/_chunks/Dashboard.js.map +1 -1
  10. package/dist/_chunks/FindSimilarCasesDialog.js +76 -76
  11. package/dist/_chunks/FindSimilarCasesDialog.js.map +1 -1
  12. package/dist/_chunks/LegendaItem.js.map +1 -1
  13. package/dist/_chunks/PanelSeparator.js +3 -3
  14. package/dist/_chunks/PanelSeparator.js.map +1 -1
  15. package/dist/_chunks/Upload.js +318 -318
  16. package/dist/_chunks/Upload.js.map +1 -1
  17. package/dist/_chunks/chunk-BV7QT456.js +1 -1
  18. package/dist/_chunks/chunk-BV7QT456.js.map +1 -1
  19. package/dist/_chunks/cloneDeep.js +1 -1
  20. package/dist/_chunks/cloneDeep.js.map +1 -1
  21. package/dist/_chunks/esm.js +3 -3
  22. package/dist/_chunks/esm.js.map +1 -1
  23. package/dist/_chunks/index.module.js +1 -1
  24. package/dist/_chunks/index.module.js.map +1 -1
  25. package/dist/_chunks/react.js +1 -1
  26. package/dist/_chunks/react.js.map +1 -1
  27. package/dist/_chunks/shallow.js +2 -2
  28. package/dist/_chunks/shallow.js.map +1 -1
  29. package/dist/_chunks/vanilla.js +1 -1
  30. package/dist/_chunks/vanilla.js.map +1 -1
  31. package/dist/_chunks/yup.js +24 -24
  32. package/dist/_chunks/yup.js.map +1 -1
  33. package/dist/components/form/fields/ArrangementEditor/index.js +30 -30
  34. package/dist/components/ui/CreateEventDialog/index.js +40 -40
  35. package/dist/components/ui/CreateEventDialog/index.js.map +1 -1
  36. package/dist/components/ui/SequenceDownloadDialog/index.js +22 -22
  37. package/dist/pages/UserEffectiveRightsTesterAdminPage/index.js +59 -59
  38. package/dist/pages/UserEffectiveRightsTesterAdminPage/index.js.map +1 -1
  39. package/package.json +68 -67
  40. package/dist/_chunks/index.esm.js +0 -1465
  41. 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 { c as ee, o as te, t as x } from "./index.esm.js";
11
- import { t as ne } from "./yup.js";
12
- import { mixed as re, object as ie, string as S } from "yup";
13
- import { CaseDbCaseApi as C } from "@gen-epix/api-casedb";
14
- import { QueryClientService as w } from "@gen-epix/ui-client-common/classes/services/QueryClientService";
15
- import { FORM_FIELD_DEFINITION_TYPE as T } from "@gen-epix/ui-core-form/models/form";
16
- import { DATE_FORMAT as E } from "@gen-epix/ui-core/constants/date";
17
- import { ConfigService as D } from "@gen-epix/ui-client-common/classes/services/ConfigService";
18
- import { Alert as O, AlertTitle as k, Box as A, Button as ae, Divider as oe, Typography as se, useTheme as j } from "@mui/material";
19
- import { use as M, useCallback as N, useEffect as P, useId as F, useMemo as I, useRef as L, useState as R } from "react";
20
- import { useTranslation as z } from "react-i18next";
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 { GenericForm as le } from "@gen-epix/ui-core-form/components/helpers/GenericForm";
24
- import { useQueryMemo as ue } from "@gen-epix/ui-client-common/hooks/useQueryMemo";
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 } = z(), s = I(() => t.buildChartIntervals(n), [n]), c = j(), [l, u] = R(null), d = o`Own cases`, f = o`Cases from other organizations`, p = L(s);
44
- P(() => {
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 = L(null), h = N((e) => {
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 = I(() => {
62
- let { BASE_COLORS: e } = D.getInstance().config.epi.STRATIFICATION;
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 = N((e) => {
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 = I(() => ({
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 = N(({ field: { onChange: e } }) => (m.current = e, /* @__PURE__ */ V(_, {
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__ */ H(B, { children: [/* @__PURE__ */ V(x, {
183
+ return /* @__PURE__ */ z(L, { children: [/* @__PURE__ */ R(B, {
184
184
  control: e,
185
185
  name: r,
186
186
  render: b
187
- }), l && /* @__PURE__ */ V(A, {
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 } = z(), u = F(), d = M(b), f = d.getState().getWidgetDataPersistable(a.TREE).treeConfiguration, p = v(d, (e) => e.setFindSimilarCasesResults), m = v(d, (e) => e.findSimilarCasesResults), h = I(() => i.getTreeConfigurations(c.completeCaseType), [c.completeCaseType]), [g, _] = R(null), x = I(() => ie().shape({
206
- dateRange: re().nullable().default(null),
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 || D.getInstance().config.epi.SEQDB_MAX_STORED_DISTANCE_FALLBACK) : t;
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: S().required().oneOf([
211
+ organizationFilter: x().required().oneOf([
212
212
  "all",
213
213
  "own",
214
214
  "otherOrganization"
215
215
  ]),
216
- treeColId: S().required()
217
- }), [l, h]), j = I(() => {
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]), L = te({
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: ne(x, void 0, { raw: !0 })
233
- }), { control: U, handleSubmit: G } = L, K = ee({ control: U }), pe = I(() => {
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: T.SELECT,
236
+ definition: C.SELECT,
237
237
  label: l`Tree`,
238
238
  name: "treeColId",
239
- options: j
239
+ options: P
240
240
  }, {
241
- definition: T.NUMBER,
241
+ definition: C.NUMBER,
242
242
  label: l`Max distance`,
243
- max: e?.geneticDistanceProtocol?.seqdb_max_stored_distance || D.getInstance().config.epi.SEQDB_MAX_STORED_DISTANCE_FALLBACK,
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
- j
253
+ P
254
254
  ]);
255
- P(() => {
255
+ M(() => {
256
256
  s(l`Find similar cases`);
257
257
  }, [l, s]);
258
- let me = N((e) => {
259
- L.setValue("dateRange", null), _({
258
+ let me = j((e) => {
259
+ B.setValue("dateRange", null), _({
260
260
  ...e,
261
261
  dateRange: null
262
262
  });
263
- }, [L]), he = N((e) => {
264
- L.setValue("organizationFilter", e);
265
- }, [L]), q = ue({
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 C.getInstance().retrieveSimilarCases({
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 C.getInstance().retrieveIsOwnCases({
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: [w.getInstance().getGenericKey(r.SIMILAR_CASES), JSON.stringify({
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 = I(() => q.data ? q.data.filter((e) => {
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 = I(() => {
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 = I(() => {
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), E.DATE);
311
+ let a = e(n(t.timed_at), ie.DATE);
312
312
  return a >= r && a <= i;
313
313
  });
314
- }, [K.dateRange, J]), Z = I(() => {
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 = I(() => {
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]), $ = N(async () => {
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 P(() => {
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__ */ H(A, { children: [
366
- /* @__PURE__ */ V(A, {
365
+ ]), /* @__PURE__ */ z(D, { children: [
366
+ /* @__PURE__ */ R(D, {
367
367
  sx: { marginBottom: 2 },
368
- children: /* @__PURE__ */ V(se, { children: l("Select a tree and maximum distance to find similar cases for the {{count}} selected cases.", { count: c.selectedRows.length }) })
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__ */ V(A, { children: /* @__PURE__ */ V(le, {
370
+ /* @__PURE__ */ R(D, { children: /* @__PURE__ */ R(V, {
371
371
  formFieldDefinitions: pe,
372
372
  formId: u,
373
- formMethods: L,
373
+ formMethods: B,
374
374
  onSubmit: G(me),
375
- schema: x
375
+ schema: k
376
376
  }) }),
377
- /* @__PURE__ */ V(A, {
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__ */ V(ae, {
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__ */ V(oe, { sx: { marginY: 2 } }),
392
- /* @__PURE__ */ V(ce, {
391
+ /* @__PURE__ */ R(ae, { sx: { marginY: 2 } }),
392
+ /* @__PURE__ */ R(ce, {
393
393
  inlineSpinner: !0,
394
394
  loadables: q,
395
- children: q.data && /* @__PURE__ */ H(B, { children: [
396
- /* @__PURE__ */ V(A, {
395
+ children: q.data && /* @__PURE__ */ z(L, { children: [
396
+ /* @__PURE__ */ R(D, {
397
397
  sx: { marginY: 2 },
398
- children: /* @__PURE__ */ V(O, {
398
+ children: /* @__PURE__ */ R(T, {
399
399
  severity: q.data.length > 0 ? "success" : "warning",
400
- children: /* @__PURE__ */ V(k, { children: l("Found {{count}} similar cases with a distance of {{distance}}.", {
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__ */ V(A, {
406
+ Y.length > 0 && /* @__PURE__ */ R(D, {
407
407
  sx: { marginY: 2 },
408
- children: /* @__PURE__ */ V(fe, {
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__ */ V(A, {
416
+ /* @__PURE__ */ R(D, {
417
417
  sx: { marginY: 2 },
418
- children: /* @__PURE__ */ V(O, {
418
+ children: /* @__PURE__ */ R(T, {
419
419
  severity: "info",
420
- children: /* @__PURE__ */ V(k, { children: l("{{count}} similar cases can be added to the line list.", { count: Z.length }) })
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__ */ V(O, {
423
+ Q.length > 0 && /* @__PURE__ */ R(T, {
424
424
  severity: "warning",
425
- children: /* @__PURE__ */ V(k, { children: l("{{count}} similar cases found that are already in the line list.", { count: Q.length }) })
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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"}