@molgenis/vip-report-template 3.0.0-beta2 → 3.1.1

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 (42) hide show
  1. package/package.json +3 -3
  2. package/src/__tests__/query.test.ts +21 -1
  3. package/src/components/Anchor.tsx +10 -7
  4. package/src/components/ConsequenceTable.tsx +11 -4
  5. package/src/components/HpoTerm.tsx +13 -0
  6. package/src/components/InfoCollapsablePane.tsx +29 -22
  7. package/src/components/SampleTable.tsx +4 -3
  8. package/src/components/VariantInfoNestedTable.tsx +26 -16
  9. package/src/components/VariantInfoTable.tsx +16 -6
  10. package/src/components/VariantSampleTable.tsx +4 -4
  11. package/src/components/VariantsSampleTable.tsx +3 -2
  12. package/src/components/VariantsTable.tsx +13 -27
  13. package/src/components/filter/Filter.tsx +12 -8
  14. package/src/components/filter/FilterCategorical.tsx +17 -10
  15. package/src/components/filter/FilterClinVar.tsx +21 -0
  16. package/src/components/filter/FilterIntegerDp.tsx +2 -9
  17. package/src/components/filter/FilterIntegerVid.tsx +2 -9
  18. package/src/components/filter/FilterIntegerVim.tsx +2 -9
  19. package/src/components/filter/InfoFilter.tsx +3 -9
  20. package/src/components/record/Format.tsx +13 -4
  21. package/src/components/record/Info.tsx +18 -32
  22. package/src/components/record/field/Field.tsx +22 -7
  23. package/src/components/record/info/ClinVar.tsx +77 -33
  24. package/src/components/record/info/Consequence.tsx +7 -8
  25. package/src/components/record/info/Gene.tsx +52 -7
  26. package/src/components/record/info/GnomAD.tsx +40 -20
  27. package/src/components/record/info/Hgvs.tsx +11 -9
  28. package/src/components/record/info/PubMed.tsx +17 -13
  29. package/src/mocks/GRCh37/static.ts +1 -14
  30. package/src/mocks/GRCh37/vcf/family.vcf.blob +39 -39
  31. package/src/utils/ApiUtils.ts +10 -9
  32. package/src/utils/csqUtils.ts +27 -0
  33. package/src/utils/query.ts +14 -0
  34. package/src/views/Home.tsx +1 -1
  35. package/src/views/SampleVariant.tsx +6 -3
  36. package/src/views/SampleVariantConsequence.tsx +12 -5
  37. package/src/views/SampleVariants.tsx +17 -8
  38. package/src/views/Samples.tsx +1 -1
  39. package/src/views/Variant.tsx +1 -1
  40. package/src/views/VariantConsequence.tsx +2 -2
  41. package/src/views/Variants.tsx +11 -5
  42. package/src/components/record/info/HpoTerm.tsx +0 -12
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molgenis/vip-report-template",
3
- "version": "3.0.0-beta2",
3
+ "version": "3.1.1",
4
4
  "description": "Report Template for Variant Call Format (VCF) Report Generator",
5
5
  "scripts": {
6
6
  "build": "vite build",
@@ -35,8 +35,8 @@
35
35
  "dependencies": {
36
36
  "@fortawesome/fontawesome-svg-core": "^6.1.1",
37
37
  "@fortawesome/free-solid-svg-icons": "^6.1.1",
38
- "@molgenis/vip-report-api": "^3.4.2",
39
- "@molgenis/vip-report-vcf": "^1.1.1",
38
+ "@molgenis/vip-report-api": "^3.5.2",
39
+ "@molgenis/vip-report-vcf": "^1.2.2",
40
40
  "base64-js": "^1.5.1",
41
41
  "igv": "^2.12.6",
42
42
  "solid-app-router": "^0.3.3",
@@ -4,6 +4,7 @@ import { Metadata } from "@molgenis/vip-report-vcf/src/Vcf";
4
4
  import { FilterQueries } from "../store";
5
5
  import {
6
6
  createQuery,
7
+ createSampleQuery,
7
8
  infoFieldKey,
8
9
  infoSelector,
9
10
  infoSortPath,
@@ -11,7 +12,7 @@ import {
11
12
  sampleSelector,
12
13
  selectorKey,
13
14
  } from "../utils/query";
14
- import { Person, QueryClause } from "@molgenis/vip-report-api/src/Api";
15
+ import { Item, Person, QueryClause, Sample } from "@molgenis/vip-report-api/src/Api";
15
16
 
16
17
  describe("query utilities", () => {
17
18
  let fieldMetaCsq: FieldMetadata = {
@@ -52,6 +53,25 @@ describe("query utilities", () => {
52
53
 
53
54
  const meta: Metadata = { info: { CSQ: fieldMetaCsq } } as unknown as Metadata;
54
55
 
56
+ test("create sample query - filters", () => {
57
+ const sample = { data: { index: 1 } } as Item<Sample>;
58
+ const queryClause: QueryClause = { selector: ["s", 1, "GT", "t"], operator: "!=", args: "hom_r" };
59
+ const filterQueryClause: QueryClause = { selector: ["n", "CSQ", "*", 0], operator: "==", args: [0] };
60
+ const filterQueries: FilterQueries = {
61
+ "CSQ/field1": filterQueryClause,
62
+ };
63
+ expect(createSampleQuery(sample, undefined, filterQueries, meta)).toStrictEqual({
64
+ operator: "and",
65
+ args: [queryClause, filterQueryClause],
66
+ });
67
+ });
68
+
69
+ test("create sample query - undefined search and undefined filters", () => {
70
+ const sample = { data: { index: 1 } } as Item<Sample>;
71
+ const queryClause: QueryClause = { selector: ["s", 1, "GT", "t"], operator: "!=", args: "hom_r" };
72
+ expect(createSampleQuery(sample, undefined, undefined, meta)).toStrictEqual(queryClause);
73
+ });
74
+
55
75
  test("create query", () => {
56
76
  const searchText = "my search text";
57
77
  const filterQueries: FilterQueries = {
@@ -1,12 +1,15 @@
1
- import { Component } from "solid-js";
1
+ import { ParentComponent, Show } from "solid-js";
2
2
 
3
- export const Anchor: Component<{
4
- href: string;
5
- value: string | number;
3
+ export const Anchor: ParentComponent<{
4
+ href: string | null | undefined;
6
5
  }> = (props) => {
7
6
  return (
8
- <a href={props.href} target="_blank" rel="noopener noreferrer nofollow">
9
- {props.value}
10
- </a>
7
+ <Show when={props.href} fallback={props.children}>
8
+ {(href) => (
9
+ <a href={href} target="_blank" rel="noopener noreferrer nofollow">
10
+ {props.children}
11
+ </a>
12
+ )}
13
+ </Show>
11
14
  );
12
15
  };
@@ -4,10 +4,13 @@ import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
4
4
  import { Info } from "./record/Info";
5
5
  import { FieldHeader } from "./FieldHeader";
6
6
  import { Record } from "@molgenis/vip-report-vcf/src/Vcf";
7
+ import { Item } from "@molgenis/vip-report-api/src/Api";
7
8
 
8
- export const ConsequenceTable: Component<{ csqMetadata: FieldMetadata[]; csqValues: ValueArray; record: Record }> = (
9
- props
10
- ) => {
9
+ export const ConsequenceTable: Component<{
10
+ csqMetadata: FieldMetadata[];
11
+ csqValues: ValueArray;
12
+ record: Item<Record>;
13
+ }> = (props) => {
11
14
  function getValues(index: number): ValueArray {
12
15
  return props.csqValues[index] !== null ? (props.csqValues[index] as ValueArray) : [];
13
16
  }
@@ -24,7 +27,11 @@ export const ConsequenceTable: Component<{ csqMetadata: FieldMetadata[]; csqValu
24
27
  <tr>
25
28
  <FieldHeader field={field} />
26
29
  <td>
27
- <Info info={props.csqValues[index()]} infoMetadata={field} variant={props.record} />
30
+ <Info
31
+ info={{ value: props.csqValues[index()], valueParent: props.csqValues, record: props.record }}
32
+ infoMeta={field}
33
+ context={{}}
34
+ />
28
35
  </td>
29
36
  </tr>
30
37
  </Show>
@@ -0,0 +1,13 @@
1
+ import { Component } from "solid-js";
2
+ import { Anchor } from "./Anchor";
3
+ import { OntologyClass } from "@molgenis/vip-report-api/src/Api";
4
+
5
+ export const HpoTerm: Component<{
6
+ ontologyClass: OntologyClass;
7
+ }> = (props) => {
8
+ return (
9
+ <Anchor href={`https://hpo.jax.org/app/browse/term/${props.ontologyClass.id}`}>
10
+ <span>{props.ontologyClass.label}</span>
11
+ </Anchor>
12
+ );
13
+ };
@@ -1,39 +1,41 @@
1
1
  import { Component, createMemo, createSignal, For, Signal } from "solid-js";
2
- import { FieldMetadata, InfoMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
2
+ import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
3
3
  import { Record } from "@molgenis/vip-report-vcf/src/Vcf";
4
- import { Item } from "@molgenis/vip-report-api/src/Api";
4
+ import { HtsFileMetadata, Item } from "@molgenis/vip-report-api/src/Api";
5
5
  import { ValueArray } from "@molgenis/vip-report-vcf/src/ValueParser";
6
6
  import { Info } from "./record/Info";
7
- import { useLocation } from "solid-app-router";
7
+ import { FieldValue } from "./record/field/Field";
8
+ import { isCsqInfo } from "../utils/csqUtils";
9
+ import { Link, useLocation } from "solid-app-router";
8
10
 
9
11
  export const InfoCollapsablePane: Component<{
10
12
  fields: FieldMetadata[];
11
13
  record: Item<Record>;
14
+ htsFileMeta: HtsFileMetadata;
12
15
  }> = (props) => {
13
16
  const [collapsed, setCollapsed]: Signal<boolean> = createSignal(false);
14
17
 
15
- function getHref(field: InfoMetadata, consequenceIndex: number): string | undefined {
16
- let href;
17
- if (field.id === "Consequence" && field.parent?.id === "CSQ") {
18
- href = `${useLocation().pathname}/${props.record.id}/consequences/${consequenceIndex}`;
19
- }
20
- return href;
21
- }
22
-
23
18
  function toggleCollapse() {
24
19
  setCollapsed(!collapsed());
25
20
  }
26
21
 
27
- const values = createMemo(() =>
22
+ const values = createMemo((): FieldValue[][] =>
28
23
  props.fields.map((field) => {
29
24
  if (field.parent) {
30
- return (props.record.data.n[field.parent.id] as ValueArray).map((nestedValues) =>
31
- field.parent && field.parent.nested
32
- ? (nestedValues as ValueArray)[
33
- field.parent.nested.items.findIndex((nestedField) => nestedField.id === field.id)
34
- ]
35
- : null
36
- );
25
+ const values = (props.record.data.n[field.parent.id] || []) as ValueArray;
26
+ return values.map((nestedValues) => {
27
+ const value =
28
+ field.parent && field.parent.nested
29
+ ? (nestedValues as ValueArray)[
30
+ field.parent.nested.items.findIndex((nestedField) => nestedField.id === field.id)
31
+ ]
32
+ : null;
33
+ return {
34
+ record: props.record,
35
+ value: value,
36
+ valueParent: nestedValues,
37
+ };
38
+ });
37
39
  }
38
40
  throw new Error(`Nested field '${field.id}' needs to have a parent field.`);
39
41
  })
@@ -54,9 +56,14 @@ export const InfoCollapsablePane: Component<{
54
56
  {(value, j) => (
55
57
  <>
56
58
  {j() != 0 && collapsed() && <br />}
57
- {(j() == 0 || collapsed()) && (
58
- <Info info={value} infoMetadata={field} href={getHref(field, j())} variant={props.record.data} />
59
- )}
59
+ {(j() == 0 || collapsed()) &&
60
+ (isCsqInfo(field, "Consequence") ? (
61
+ <Link href={`${useLocation().pathname}/${props.record.id}/consequences/${j()}`}>
62
+ <Info info={value} infoMeta={field} context={props.htsFileMeta} />
63
+ </Link>
64
+ ) : (
65
+ <Info info={value} infoMeta={field} context={props.htsFileMeta} />
66
+ ))}
60
67
  </>
61
68
  )}
62
69
  </For>
@@ -1,7 +1,8 @@
1
1
  import { Link } from "solid-app-router";
2
2
  import { Component, createMemo, For, Show } from "solid-js";
3
3
  import { Item, Phenotype, PhenotypicFeature, Sample } from "@molgenis/vip-report-api/src/Api";
4
- import { HpoTerm } from "./record/info/HpoTerm";
4
+ import { HpoTerm } from "./HpoTerm";
5
+ import { Anchor } from "./Anchor";
5
6
 
6
7
  function getAffectedStatusLabel(affectedStatus: string) {
7
8
  let label;
@@ -96,7 +97,7 @@ export const SampleTable: Component<{
96
97
  </td>
97
98
  <td>
98
99
  <Show when={getPhenotypes(sample.data.person.individualId).length > 0}>
99
- <Link
100
+ <Anchor
100
101
  href={`https://vibe.molgeniscloud.org/?phenotypes=${getPhenotypes(
101
102
  sample.data.person.individualId
102
103
  )
@@ -104,7 +105,7 @@ export const SampleTable: Component<{
104
105
  .join(",")}`}
105
106
  >
106
107
  <i class="fas fa-external-link" />
107
- </Link>
108
+ </Anchor>
108
109
  </Show>
109
110
  </td>
110
111
  </tr>
@@ -5,6 +5,8 @@ import { FieldMetadata, InfoMetadata } from "@molgenis/vip-report-vcf/src/Metada
5
5
  import { FieldHeader } from "./FieldHeader";
6
6
  import { Record } from "@molgenis/vip-report-vcf/src/Vcf";
7
7
  import { Item } from "@molgenis/vip-report-api/src/Api";
8
+ import { isCsqInfo } from "../utils/csqUtils";
9
+ import { Link, useLocation } from "solid-app-router";
8
10
 
9
11
  function isNonEmptyNestedInfoItem(nestedInfoField: FieldMetadata, index: number, value: Value[] | Value[][]): boolean {
10
12
  const infoField = nestedInfoField.nested?.items[index];
@@ -43,15 +45,6 @@ export const VariantInfoNestedTable: Component<{
43
45
  record: Item<Record>;
44
46
  sample: { id: number; label: string } | null;
45
47
  }> = (props) => {
46
- function getHref(field: InfoMetadata, consequenceIndex: number): string | undefined {
47
- let href;
48
- if (field.id === "Consequence" && field.parent?.id === "CSQ") {
49
- href = `/variants/${props.record.id}/consequences/${consequenceIndex}`;
50
- if (props.sample !== null) href = `/samples/${props.sample.id}` + href;
51
- }
52
- return href;
53
- }
54
-
55
48
  return (
56
49
  <div style={{ display: "grid" }}>
57
50
  {/* workaround for https://github.com/jgthms/bulma/issues/2572#issuecomment-523099776 */}
@@ -76,7 +69,7 @@ export const VariantInfoNestedTable: Component<{
76
69
  <>
77
70
  {isNonEmptyNestedInfoItem(props.infoField, -1, props.infoValue) && (
78
71
  <td>
79
- <Info info={value} infoMetadata={props.infoField} variant={props.record.data} />
72
+ <Info info={{ value: value, record: props.record }} infoMeta={props.infoField} context={{}} />
80
73
  </td>
81
74
  )}
82
75
  </>
@@ -93,12 +86,29 @@ export const VariantInfoNestedTable: Component<{
93
86
  <>
94
87
  {isNonEmptyNestedInfoItem(props.infoField, i(), props.infoValue) && (
95
88
  <td>
96
- <Info
97
- info={Array.isArray(value) ? value[i()] : null}
98
- infoMetadata={infoFieldItem}
99
- href={getHref(infoFieldItem, j())}
100
- variant={props.record.data}
101
- />
89
+ {isCsqInfo(infoFieldItem, "Consequence") ? (
90
+ <Link href={`${useLocation().pathname}/consequences/${j()}`}>
91
+ <Info
92
+ info={{
93
+ value: Array.isArray(value) ? value[i()] : null,
94
+ valueParent: value,
95
+ record: props.record,
96
+ }}
97
+ infoMeta={infoFieldItem}
98
+ context={{}}
99
+ />
100
+ </Link>
101
+ ) : (
102
+ <Info
103
+ info={{
104
+ value: Array.isArray(value) ? value[i()] : null,
105
+ valueParent: value,
106
+ record: props.record,
107
+ }}
108
+ infoMeta={infoFieldItem}
109
+ context={{}}
110
+ />
111
+ )}
102
112
  </td>
103
113
  )}
104
114
  </>
@@ -1,9 +1,13 @@
1
1
  import { Component, For } from "solid-js";
2
- import { FieldMetadataContainer, InfoContainer } from "@molgenis/vip-report-vcf/src/VcfParser";
2
+ import { FieldMetadataContainer } from "@molgenis/vip-report-vcf/src/VcfParser";
3
+ import { Info } from "./record/Info";
4
+ import { Record } from "@molgenis/vip-report-vcf/src/Vcf";
5
+ import { Item } from "@molgenis/vip-report-api/src/Api";
3
6
 
4
- export const VariantInfoTable: Component<{ infoValues: InfoContainer; infoFields: FieldMetadataContainer }> = (
5
- props
6
- ) => {
7
+ export const VariantInfoTable: Component<{
8
+ infoFields: FieldMetadataContainer;
9
+ record: Item<Record>;
10
+ }> = (props) => {
7
11
  return (
8
12
  <div style={{ display: "grid" }}>
9
13
  {/* workaround for https://github.com/jgthms/bulma/issues/2572#issuecomment-523099776 */}
@@ -12,13 +16,19 @@ export const VariantInfoTable: Component<{ infoValues: InfoContainer; infoFields
12
16
  <tbody>
13
17
  <For
14
18
  each={Object.values(props.infoFields).filter(
15
- (info) => !info.nested && props.infoValues[info.id] !== undefined
19
+ (info) => !info.nested && props.record.data.n[info.id] !== undefined
16
20
  )}
17
21
  >
18
22
  {(infoField) => (
19
23
  <tr>
20
24
  <td>{infoField.id}</td>
21
- <td>{props.infoValues[infoField.id] as string}</td>
25
+ <td>
26
+ <Info
27
+ info={{ value: props.record.data.n[infoField.id], record: props.record }}
28
+ infoMeta={infoField}
29
+ context={{}}
30
+ />
31
+ </td>
22
32
  </tr>
23
33
  )}
24
34
  </For>
@@ -3,14 +3,14 @@ import { Record, RecordSample } from "@molgenis/vip-report-vcf/src/Vcf";
3
3
  import { FieldMetadataContainer } from "@molgenis/vip-report-vcf/src/VcfParser";
4
4
  import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
5
5
  import { Format } from "./record/Format";
6
- import { Sample } from "@molgenis/vip-report-api/src/Api";
6
+ import { Item, Sample } from "@molgenis/vip-report-api/src/Api";
7
7
  import { FieldHeader } from "./FieldHeader";
8
8
 
9
9
  export const VariantSampleTable: Component<{
10
10
  formatFields: FieldMetadataContainer;
11
11
  samples: Sample[];
12
12
  sampleValues: RecordSample[];
13
- record: Record;
13
+ record: Item<Record>;
14
14
  }> = (props) => {
15
15
  const sampleFields = createMemo((): FieldMetadata[] =>
16
16
  Object.keys(props.sampleValues[0]).map((fieldId) => props.formatFields[fieldId])
@@ -39,8 +39,8 @@ export const VariantSampleTable: Component<{
39
39
  formatMetadata={formatField}
40
40
  record={props.record}
41
41
  isAbbreviate={false}
42
- allelicDepth={props.record.s[props.samples[i()].index]["AD"] as number[]}
43
- readDepth={props.record.s[props.samples[i()].index]["DP"] as number}
42
+ allelicDepth={props.record.data.s[props.samples[i()].index]["AD"] as number[]}
43
+ readDepth={props.record.data.s[props.samples[i()].index]["DP"] as number}
44
44
  />
45
45
  </td>
46
46
  )}
@@ -3,7 +3,7 @@ import { Ref } from "./record/Ref";
3
3
  import { Chrom } from "./record/Chrom";
4
4
  import { Pos } from "./record/Pos";
5
5
  import { Link } from "solid-app-router";
6
- import { Item, Sample } from "@molgenis/vip-report-api/src/Api";
6
+ import { HtsFileMetadata, Item, Sample } from "@molgenis/vip-report-api/src/Api";
7
7
  import { GenotypeField } from "./record/format/GenotypeField";
8
8
  import { InfoCollapsablePane } from "./InfoCollapsablePane";
9
9
  import { Component, createMemo, For } from "solid-js";
@@ -18,6 +18,7 @@ export const VariantsSampleTable: Component<{
18
18
  records: Item<Record>[];
19
19
  recordsMetadata: Metadata;
20
20
  nestedFields: FieldMetadata[];
21
+ htsFileMeta: HtsFileMetadata;
21
22
  }> = (props) => {
22
23
  const samples = createMemo(() => [props.item.data, ...props.pedigreeSamples.map((item) => item.data)]);
23
24
 
@@ -75,7 +76,7 @@ export const VariantsSampleTable: Component<{
75
76
  </td>
76
77
  )}
77
78
  </For>
78
- <InfoCollapsablePane fields={props.nestedFields} record={record} />
79
+ <InfoCollapsablePane fields={props.nestedFields} record={record} htsFileMeta={props.htsFileMeta} />
79
80
  </tr>
80
81
  )}
81
82
  </For>
@@ -8,11 +8,11 @@ import { Alt } from "./record/Alt";
8
8
  import { Qual } from "./record/Qual";
9
9
  import { Filter } from "./record/Filter";
10
10
  import { Info } from "./record/Info";
11
- import { Value } from "@molgenis/vip-report-vcf/src/ValueParser";
12
11
  import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
13
12
  import { Link } from "solid-app-router";
14
- import { Item } from "@molgenis/vip-report-api/src/Api";
13
+ import { HtsFileMetadata, Item } from "@molgenis/vip-report-api/src/Api";
15
14
  import { FieldHeader } from "./FieldHeader";
15
+ import { InfoCollapsablePane } from "./InfoCollapsablePane";
16
16
 
17
17
  const computeRowspan = (recordsMetadata: Metadata) =>
18
18
  Object.values(recordsMetadata.info).find((field) => field.nested) !== undefined ? 2 : 1;
@@ -21,6 +21,7 @@ const computeColspan = (field: FieldMetadata) => (field.nested ? field.nested.it
21
21
  export const VariantsTable: Component<{
22
22
  records: Item<Record>[];
23
23
  recordsMetadata: Metadata;
24
+ htsFileMeta: HtsFileMetadata;
24
25
  }> = (props) => {
25
26
  const infoFields = () => Object.values(props.recordsMetadata.info);
26
27
  const infoFieldsNested = () => infoFields().filter((infoField) => infoField.nested);
@@ -93,33 +94,18 @@ export const VariantsTable: Component<{
93
94
  <For each={infoFields()}>
94
95
  {(infoField) =>
95
96
  infoField.nested ? (
96
- <For each={infoField.nested.items}>
97
- {(infoFieldNested, i) => (
98
- <td>
99
- {infoField.number.count === 1 ? (
100
- <>
101
- <Info
102
- info={(record.data.n[infoField.id] as Value[])[i()]}
103
- infoMetadata={infoFieldNested}
104
- variant={record.data}
105
- />
106
- </>
107
- ) : (
108
- <For each={record.data.n[infoField.id] as unknown as Value[][]}>
109
- {(value, j) => (
110
- <>
111
- {j() !== 0 && <br />}
112
- <Info info={value[i()]} infoMetadata={infoFieldNested} variant={record.data} />
113
- </>
114
- )}
115
- </For>
116
- )}
117
- </td>
118
- )}
119
- </For>
97
+ <InfoCollapsablePane
98
+ fields={infoField.nested.items}
99
+ record={record}
100
+ htsFileMeta={props.htsFileMeta}
101
+ />
120
102
  ) : (
121
103
  <td>
122
- <Info info={record.data.n[infoField.id]} infoMetadata={infoField} variant={record.data} />
104
+ <Info
105
+ info={{ value: record.data.n[infoField.id], record: record }}
106
+ infoMeta={infoField}
107
+ context={props.htsFileMeta}
108
+ />
123
109
  </td>
124
110
  )
125
111
  }
@@ -5,32 +5,36 @@ import { FilterIntegerVim } from "./FilterIntegerVim";
5
5
  import { FilterIntegerDp } from "./FilterIntegerDp";
6
6
  import { FilterIntegerVid } from "./FilterIntegerVid";
7
7
  import { QueryClause, Selector } from "@molgenis/vip-report-api/src/Api";
8
+ import { FilterClinVar } from "./FilterClinVar";
9
+ import { isAnyCsqInfo } from "../../utils/csqUtils";
8
10
 
9
11
  export type FilterChangeEvent = { query: QueryClause };
10
12
  export type FilterClearEvent = { selector: Selector };
11
13
 
12
- export const Filter: Component<{
14
+ export type FilterProps = {
13
15
  field: FieldMetadata;
14
16
  query?: QueryClause;
15
17
  onChange: (event: FilterChangeEvent) => void;
16
18
  onClear: (event: FilterClearEvent) => void;
17
- }> = (props) => {
18
- const onChange = (event: FilterChangeEvent) => props.onChange(event);
19
- const onClear = (event: FilterClearEvent) => props.onClear(event);
19
+ };
20
20
 
21
+ export const Filter: Component<FilterProps> = (props) => {
21
22
  return (
22
23
  <Switch>
23
24
  <Match when={props.field.id === "DP"}>
24
- <FilterIntegerDp field={props.field} onChange={onChange} onClear={onClear} query={props.query} />
25
+ <FilterIntegerDp {...props} />
25
26
  </Match>
26
27
  <Match when={props.field.id === "VID"}>
27
- <FilterIntegerVid field={props.field} onChange={onChange} onClear={onClear} query={props.query} />
28
+ <FilterIntegerVid {...props} />
28
29
  </Match>
29
30
  <Match when={props.field.id === "VIM"}>
30
- <FilterIntegerVim field={props.field} onChange={onChange} onClear={onClear} query={props.query} />
31
+ <FilterIntegerVim {...props} />
32
+ </Match>
33
+ <Match when={isAnyCsqInfo(props.field, ["clinVar_CLNSIG", "clinVar_CLNSIGINCL"])}>
34
+ <FilterClinVar {...props} />
31
35
  </Match>
32
36
  <Match when={props.field.type === "CATEGORICAL"}>
33
- <FilterCategorical field={props.field} onChange={onChange} onClear={onClear} query={props.query} />
37
+ <FilterCategorical {...props} />
34
38
  </Match>
35
39
  </Switch>
36
40
  );
@@ -1,21 +1,28 @@
1
1
  import { Component, For } from "solid-js";
2
- import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
3
2
  import { Checkbox, CheckboxEvent } from "../Checkbox";
4
- import { FilterChangeEvent, FilterClearEvent } from "./Filter";
3
+ import { FilterProps } from "./Filter";
5
4
  import { selector } from "../../utils/query";
6
- import { QueryClause } from "@molgenis/vip-report-api/src/Api";
7
5
 
8
6
  export type CheckboxGroup = {
9
7
  [key: string]: boolean;
10
8
  };
11
9
 
12
- export const FilterCategorical: Component<{
13
- field: FieldMetadata;
14
- query?: QueryClause;
15
- onChange: (event: FilterChangeEvent) => void;
16
- onClear: (event: FilterClearEvent) => void;
17
- }> = (props) => {
10
+ export type CategoryLabels = {
11
+ [key: string]: string;
12
+ };
13
+
14
+ export const FilterCategorical: Component<
15
+ FilterProps & {
16
+ labels?: CategoryLabels;
17
+ }
18
+ > = (props) => {
18
19
  const group: CheckboxGroup = {};
20
+ if (props.query !== undefined) {
21
+ (props.query?.args as string[]).forEach((key) => {
22
+ group[key] = true;
23
+ });
24
+ }
25
+
19
26
  const nullValue = "__null";
20
27
 
21
28
  // enable null category for any_has_any case if someone asks for it (requires query to be composed)
@@ -46,7 +53,7 @@ export const FilterCategorical: Component<{
46
53
  <div class="control">
47
54
  <Checkbox
48
55
  value={category}
49
- label={category}
56
+ label={props.labels ? props.labels[category] : category}
50
57
  checked={props.query && (props.query.args as string[]).includes(category)}
51
58
  onChange={onChange}
52
59
  />
@@ -0,0 +1,21 @@
1
+ import { Component } from "solid-js";
2
+ import { FilterProps } from "./Filter";
3
+ import { FilterCategorical } from "./FilterCategorical";
4
+
5
+ export const FilterClinVar: Component<FilterProps> = (props) => {
6
+ return (
7
+ <FilterCategorical
8
+ field={props.field}
9
+ labels={{
10
+ Benign: "B",
11
+ Likely_benign: "LB",
12
+ Uncertain_significance: "VUS",
13
+ Likely_pathogenic: "LP",
14
+ Pathogenic: "P",
15
+ Conflicting_interpretations_of_pathogenicity: "Conflict",
16
+ }}
17
+ onChange={props.onChange}
18
+ onClear={props.onClear}
19
+ />
20
+ );
21
+ };
@@ -1,16 +1,9 @@
1
1
  import { Component } from "solid-js";
2
- import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
3
- import { FilterChangeEvent, FilterClearEvent } from "./Filter";
2
+ import { FilterProps } from "./Filter";
4
3
  import { Checkbox, CheckboxEvent } from "../Checkbox";
5
4
  import { selector } from "../../utils/query";
6
- import { QueryClause } from "@molgenis/vip-report-api/src/Api";
7
5
 
8
- export const FilterIntegerDp: Component<{
9
- field: FieldMetadata;
10
- query?: QueryClause;
11
- onChange: (event: FilterChangeEvent) => void;
12
- onClear: (event: FilterClearEvent) => void;
13
- }> = (props) => {
6
+ export const FilterIntegerDp: Component<FilterProps> = (props) => {
14
7
  const onFilterChange = (event: CheckboxEvent) => {
15
8
  if (event.checked) props.onChange({ query: { selector: selector(props.field), operator: ">=", args: 20 } });
16
9
  else props.onClear({ selector: selector(props.field) });
@@ -1,16 +1,9 @@
1
1
  import { Component } from "solid-js";
2
- import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
3
- import { FilterChangeEvent, FilterClearEvent } from "./Filter";
2
+ import { FilterProps } from "./Filter";
4
3
  import { Checkbox, CheckboxEvent } from "../Checkbox";
5
4
  import { selector } from "../../utils/query";
6
- import { QueryClause } from "@molgenis/vip-report-api/src/Api";
7
5
 
8
- export const FilterIntegerVid: Component<{
9
- field: FieldMetadata;
10
- query?: QueryClause;
11
- onChange: (event: FilterChangeEvent) => void;
12
- onClear: (event: FilterClearEvent) => void;
13
- }> = (props) => {
6
+ export const FilterIntegerVid: Component<FilterProps> = (props) => {
14
7
  const onFilterChange = (event: CheckboxEvent) => {
15
8
  if (event.checked) props.onChange({ query: { selector: selector(props.field), operator: "==", args: 1 } });
16
9
  else props.onClear({ selector: selector(props.field) });
@@ -1,16 +1,9 @@
1
1
  import { Component } from "solid-js";
2
- import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
3
- import { FilterChangeEvent, FilterClearEvent } from "./Filter";
2
+ import { FilterProps } from "./Filter";
4
3
  import { Checkbox, CheckboxEvent } from "../Checkbox";
5
4
  import { selector } from "../../utils/query";
6
- import { QueryClause } from "@molgenis/vip-report-api/src/Api";
7
5
 
8
- export const FilterIntegerVim: Component<{
9
- field: FieldMetadata;
10
- query?: QueryClause;
11
- onChange: (event: FilterChangeEvent) => void;
12
- onClear: (event: FilterClearEvent) => void;
13
- }> = (props) => {
6
+ export const FilterIntegerVim: Component<FilterProps> = (props) => {
14
7
  const onFilterChange = (event: CheckboxEvent) => {
15
8
  if (event.checked) props.onChange({ query: { selector: selector(props.field), operator: "==", args: 1 } });
16
9
  else props.onClear({ selector: selector(props.field) });