@molgenis/vip-report-template 3.0.0-beta → 3.1.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 (43) hide show
  1. package/package.json +3 -3
  2. package/src/__tests__/query.test.ts +60 -3
  3. package/src/components/Anchor.tsx +10 -7
  4. package/src/components/ConsequenceTable.tsx +11 -4
  5. package/src/components/DatasetDropdown.tsx +4 -0
  6. package/src/components/HpoTerm.tsx +13 -0
  7. package/src/components/InfoCollapsablePane.tsx +28 -22
  8. package/src/components/SampleTable.tsx +4 -3
  9. package/src/components/VariantInfoNestedTable.tsx +26 -16
  10. package/src/components/VariantInfoTable.tsx +16 -6
  11. package/src/components/VariantSampleTable.tsx +4 -4
  12. package/src/components/VariantsSampleTable.tsx +3 -2
  13. package/src/components/VariantsTable.tsx +13 -27
  14. package/src/components/filter/Filter.tsx +13 -6
  15. package/src/components/filter/FilterCategorical.tsx +17 -10
  16. package/src/components/filter/FilterClinVar.tsx +21 -0
  17. package/src/components/filter/FilterIntegerDp.tsx +2 -9
  18. package/src/components/filter/FilterIntegerVid.tsx +2 -9
  19. package/src/components/filter/FilterIntegerVim.tsx +2 -9
  20. package/src/components/filter/Filters.tsx +6 -3
  21. package/src/components/filter/InfoFilter.tsx +3 -9
  22. package/src/components/record/Format.tsx +13 -4
  23. package/src/components/record/Info.tsx +18 -32
  24. package/src/components/record/field/Field.tsx +22 -7
  25. package/src/components/record/info/ClinVar.tsx +77 -33
  26. package/src/components/record/info/Consequence.tsx +7 -8
  27. package/src/components/record/info/Gene.tsx +52 -7
  28. package/src/components/record/info/GnomAD.tsx +40 -20
  29. package/src/components/record/info/Hgvs.tsx +10 -8
  30. package/src/components/record/info/PubMed.tsx +17 -13
  31. package/src/mocks/GRCh37/static.ts +1 -14
  32. package/src/mocks/GRCh37/vcf/family.vcf.blob +39 -39
  33. package/src/store/index.tsx +27 -21
  34. package/src/utils/csqUtils.ts +27 -0
  35. package/src/views/Home.tsx +1 -1
  36. package/src/views/SampleVariant.tsx +6 -3
  37. package/src/views/SampleVariantConsequence.tsx +12 -5
  38. package/src/views/SampleVariants.tsx +28 -15
  39. package/src/views/Samples.tsx +1 -1
  40. package/src/views/Variant.tsx +1 -1
  41. package/src/views/VariantConsequence.tsx +2 -2
  42. package/src/views/Variants.tsx +16 -10
  43. package/src/components/record/info/HpoTerm.tsx +0 -12
@@ -1,7 +1,7 @@
1
1
  import { Component, createResource, createSignal, For, Show } from "solid-js";
2
2
  import { Breadcrumb } from "../components/Breadcrumb";
3
3
  import { Item, Phenotype, PhenotypicFeature } from "@molgenis/vip-report-api/src/Api";
4
- import { HpoTerm } from "../components/record/info/HpoTerm";
4
+ import { HpoTerm } from "../components/HpoTerm";
5
5
  import {
6
6
  EMPTY_APP_METADATA,
7
7
  EMPTY_HTS_FILE_METADATA,
@@ -15,6 +15,7 @@ import { SampleVariantRouteData } from "./data/SampleVariantData";
15
15
  import { getSampleLabel } from "../utils/sample";
16
16
  import { Item, Sample } from "@molgenis/vip-report-api/src/Api";
17
17
  import { Metadata, Record } from "@molgenis/vip-report-vcf/src/Vcf";
18
+ import { Abbr } from "../components/Abbr";
18
19
 
19
20
  export const SampleVariantView: Component = () => {
20
21
  const { sample, variant } = useRouteData<SampleVariantRouteData>();
@@ -75,7 +76,7 @@ export const SampleVariant: Component<{
75
76
  >
76
77
  <div class="column is-3">
77
78
  <h1 class="title is-5">Info</h1>
78
- <VariantInfoTable infoValues={props.record.data.n} infoFields={props.recordsMeta.info} />
79
+ <VariantInfoTable infoFields={props.recordsMeta.info} record={props.record} />
79
80
  </div>
80
81
  </Show>
81
82
  <div class="column">
@@ -88,7 +89,7 @@ export const SampleVariant: Component<{
88
89
  props.sample.data,
89
90
  props.pedigreeSamples.map((item) => item.data)
90
91
  )}
91
- record={props.record.data}
92
+ record={props.record}
92
93
  />
93
94
  </div>
94
95
  </div>
@@ -98,7 +99,9 @@ export const SampleVariant: Component<{
98
99
  {(infoField) => (
99
100
  <>
100
101
  <h1 class="title is-5">{infoField.id}</h1>
101
- <p class="mb-4">{infoField.description}</p>
102
+ <p class="mb-4">
103
+ <Abbr value={infoField.description as string} title={infoField.description as string} />
104
+ </p>
102
105
  <VariantInfoNestedTable
103
106
  infoValue={props.record.data.n[infoField.id] as unknown as Value[][]}
104
107
  infoField={infoField}
@@ -1,7 +1,13 @@
1
1
  import { Component, createResource, Show } from "solid-js";
2
2
  import { useRouteData } from "solid-app-router";
3
3
  import { Loader } from "../components/Loader";
4
- import { fetchDecisionTree, fetchPedigreeSamples, fetchRecordsMeta, getRecordLabel } from "../utils/ApiUtils";
4
+ import {
5
+ fetchDecisionTree,
6
+ fetchHtsFileMetadata,
7
+ fetchPedigreeSamples,
8
+ fetchRecordsMeta,
9
+ getRecordLabel,
10
+ } from "../utils/ApiUtils";
5
11
  import { VariantTable } from "../components/VariantTable";
6
12
  import { VariantInfoTable } from "../components/VariantInfoTable";
7
13
  import { VariantSampleTable } from "../components/VariantSampleTable";
@@ -22,6 +28,7 @@ export const SampleVariantConsequenceView: Component = () => {
22
28
  const [pedigreeSamples] = createResource(sample, fetchPedigreeSamples);
23
29
  const [recordsMeta] = createResource(fetchRecordsMeta);
24
30
  const [decisionTree] = createResource(fetchDecisionTree, { initialValue: null });
31
+ const [htsFileMeta] = createResource(fetchHtsFileMetadata);
25
32
 
26
33
  return (
27
34
  <Show when={sample() && variant()} fallback={<Loader />}>
@@ -34,7 +41,7 @@ export const SampleVariantConsequenceView: Component = () => {
34
41
  { text: `Consequence #${consequenceId}` },
35
42
  ]}
36
43
  />
37
- <Show when={pedigreeSamples() && recordsMeta()} fallback={<Loader />}>
44
+ <Show when={pedigreeSamples() && recordsMeta() && htsFileMeta()} fallback={<Loader />}>
38
45
  <SampleVariantConsequence
39
46
  sample={sample()!}
40
47
  pedigreeSamples={pedigreeSamples()!.items}
@@ -64,7 +71,7 @@ export const SampleVariantConsequence: Component<{
64
71
  <ConsequenceTable
65
72
  csqMetadata={props.recordsMeta.info.CSQ.nested !== undefined ? props.recordsMeta.info.CSQ.nested.items : []}
66
73
  csqValues={getSpecificConsequence(props.variant.data.n.CSQ as ValueArray, props.consequenceId)}
67
- record={props.variant.data}
74
+ record={props.variant}
68
75
  />
69
76
  </div>
70
77
  {props.decisionTree !== null && (
@@ -84,7 +91,7 @@ export const SampleVariantConsequence: Component<{
84
91
  </div>
85
92
  <div class="column is-3">
86
93
  <h1 class="title is-5">Info</h1>
87
- <VariantInfoTable infoValues={props.variant.data.n} infoFields={props.recordsMeta.info} />
94
+ <VariantInfoTable infoFields={props.recordsMeta.info} record={props.variant} />
88
95
  </div>
89
96
  <div class="column">
90
97
  <h1 class="title is-5">Samples</h1>
@@ -96,7 +103,7 @@ export const SampleVariantConsequence: Component<{
96
103
  props.sample.data,
97
104
  props.pedigreeSamples.map((item) => item.data)
98
105
  )}
99
- record={props.variant.data}
106
+ record={props.variant}
100
107
  />
101
108
  </div>
102
109
  </div>
@@ -1,6 +1,6 @@
1
1
  import { Component, createMemo, createResource, Show } from "solid-js";
2
2
  import { useRouteData } from "solid-app-router";
3
- import { Item, Params, PhenotypicFeature, Sample, SortPath } from "@molgenis/vip-report-api/src/Api";
3
+ import { HtsFileMetadata, Item, Params, PhenotypicFeature, Sample, SortPath } from "@molgenis/vip-report-api/src/Api";
4
4
  import { Loader } from "../components/Loader";
5
5
  import { SearchBox } from "../components/SearchBox";
6
6
  import { Sort, SortEvent } from "../components/Sort";
@@ -8,7 +8,13 @@ import { Pager } from "../components/record/Pager";
8
8
  import { RecordDownload } from "../components/record/RecordDownload";
9
9
  import { createQuery, infoSelector, infoSortPath, sampleSelector } from "../utils/query";
10
10
  import { VariantsSampleTable } from "../components/VariantsSampleTable";
11
- import { fetchPedigreeSamples, fetchPhenotypicFeatures, fetchRecords, fetchRecordsMeta } from "../utils/ApiUtils";
11
+ import {
12
+ fetchHtsFileMetadata,
13
+ fetchPedigreeSamples,
14
+ fetchPhenotypicFeatures,
15
+ fetchRecords,
16
+ fetchRecordsMeta,
17
+ } from "../utils/ApiUtils";
12
18
  import { Breadcrumb } from "../components/Breadcrumb";
13
19
  import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
14
20
  import { Filters } from "../components/filter/Filters";
@@ -26,6 +32,7 @@ export const SampleVariantsView: Component = () => {
26
32
  const [pedigreeSamples] = createResource(sample, fetchPedigreeSamples);
27
33
  const [samplePhenotypes] = createResource(sample, fetchPhenotypicFeatures);
28
34
  const [recordsMeta] = createResource(fetchRecordsMeta);
35
+ const [htsFileMeta] = createResource(fetchHtsFileMetadata);
29
36
 
30
37
  return (
31
38
  <Show when={sample()} fallback={<Loader />}>
@@ -36,12 +43,13 @@ export const SampleVariantsView: Component = () => {
36
43
  { text: "Variants" },
37
44
  ]}
38
45
  />
39
- <Show when={pedigreeSamples() && samplePhenotypes() && recordsMeta()} fallback={<Loader />}>
46
+ <Show when={pedigreeSamples() && samplePhenotypes() && recordsMeta() && htsFileMeta()} fallback={<Loader />}>
40
47
  <SampleVariants
41
48
  sample={sample()!}
42
49
  samplePhenotypes={samplePhenotypes()!}
43
50
  pedigreeSamples={pedigreeSamples()!.items}
44
51
  recordsMeta={recordsMeta()!}
52
+ htsFileMeta={htsFileMeta()!}
45
53
  />
46
54
  </Show>
47
55
  </Show>
@@ -53,20 +61,25 @@ export const SampleVariants: Component<{
53
61
  samplePhenotypes: PhenotypicFeature[];
54
62
  pedigreeSamples: Item<Sample>[];
55
63
  recordsMeta: Metadata;
64
+ htsFileMeta: HtsFileMetadata;
56
65
  }> = (props) => {
57
66
  const [state, actions] = useStore();
58
67
 
68
+ function getStateVariants() {
69
+ return state.samples ? state.samples[props.sample.id]?.variants : undefined;
70
+ }
71
+
59
72
  // state initialization - start
60
- if (state.samples[props.sample.id]?.variants?.page === undefined) {
73
+ if (getStateVariants()?.page === undefined) {
61
74
  actions.setSampleVariantsPage(props.sample, 0);
62
75
  }
63
- if (state.samples[props.sample.id]?.variants?.pageSize === undefined) {
76
+ if (getStateVariants()?.pageSize === undefined) {
64
77
  actions.setSampleVariantsPageSize(props.sample, 20);
65
78
  }
66
79
 
67
- if (state.samples[props.sample.id]?.variants?.filterQueries === undefined) {
80
+ if (getStateVariants()?.filterQueries === undefined) {
68
81
  const hpoField = props.recordsMeta.info?.CSQ?.nested?.items?.find((field) => field.id === "HPO");
69
- if (hpoField) {
82
+ if (hpoField && props.samplePhenotypes.length > 0) {
70
83
  actions.setSampleVariantsFilterQuery(props.sample, {
71
84
  selector: infoSelector(hpoField),
72
85
  operator: "any_has_any",
@@ -92,7 +105,7 @@ export const SampleVariants: Component<{
92
105
  }
93
106
  }
94
107
 
95
- if (state.samples[props.sample.id]?.variants?.sort === undefined) {
108
+ if (getStateVariants()?.sort === undefined) {
96
109
  const capiceScField = props.recordsMeta.info?.CSQ?.nested?.items?.find((field) => field.id === "CAPICE_SC");
97
110
  if (capiceScField) {
98
111
  actions.setSampleVariantsSort(props.sample, {
@@ -109,7 +122,6 @@ export const SampleVariants: Component<{
109
122
  "Consequence",
110
123
  "SYMBOL",
111
124
  "InheritanceModesGene",
112
- "IncompletePenetrance",
113
125
  "HPO",
114
126
  "HGVSc",
115
127
  "HGVSp",
@@ -117,7 +129,7 @@ export const SampleVariants: Component<{
117
129
  "VIPC",
118
130
  "UMCG_CL",
119
131
  "VKGL_CL",
120
- "CLIN_SIG",
132
+ "clinVar_CLNSIG",
121
133
  "gnomAD_AF",
122
134
  "gnomAD_HN",
123
135
  "PUBMED",
@@ -137,11 +149,11 @@ export const SampleVariants: Component<{
137
149
  : [];
138
150
  });
139
151
 
140
- const page = () => state.samples[props.sample.id]?.variants?.page;
141
- const pageSize = () => state.samples[props.sample.id]?.variants?.pageSize;
142
- const searchQuery = () => state.samples[props.sample.id]?.variants?.searchQuery;
143
- const filterQueries = () => state.samples[props.sample.id]?.variants?.filterQueries;
144
- const sort = () => state.samples[props.sample.id]?.variants?.sort;
152
+ const page = () => getStateVariants()?.page;
153
+ const pageSize = () => getStateVariants()?.pageSize;
154
+ const searchQuery = () => getStateVariants()?.searchQuery;
155
+ const filterQueries = () => getStateVariants()?.filterQueries;
156
+ const sort = () => getStateVariants()?.sort;
145
157
 
146
158
  const onPageChange = (page: number) => actions.setSampleVariantsPage(props.sample, page);
147
159
  const onSearchChange = (search: string) => actions.setSampleVariantsSearchQuery(props.sample, search);
@@ -234,6 +246,7 @@ export const SampleVariants: Component<{
234
246
  records={records.items}
235
247
  recordsMetadata={props.recordsMeta}
236
248
  nestedFields={infoFields()}
249
+ htsFileMeta={props.htsFileMeta}
237
250
  />
238
251
  )}
239
252
  </Show>
@@ -15,7 +15,7 @@ export const Samples: Component = () => {
15
15
  const onSearchChange = (search: string) =>
16
16
  setParams({
17
17
  page: 0,
18
- query: search !== "" ? { selector: ["person", "individualId"], operator: "==", args: search } : undefined,
18
+ query: search !== "" ? { selector: ["person", "individualId"], operator: "~=", args: search } : undefined,
19
19
  });
20
20
  const onProbandFilterChange = (event: CheckboxEvent) => {
21
21
  setParams({
@@ -35,7 +35,7 @@ export const Variant: Component = () => {
35
35
  >
36
36
  <div class="column is-3">
37
37
  <h1 class="title is-5">Info</h1>
38
- <VariantInfoTable infoValues={variant().data.n} infoFields={recordsMetadata().info} />
38
+ <VariantInfoTable infoFields={recordsMetadata().info} record={variant()} />
39
39
  </div>
40
40
  </Show>
41
41
  </div>
@@ -40,7 +40,7 @@ export const VariantConsequence: Component = () => {
40
40
  <div class="columns">
41
41
  <div class="column is-6">
42
42
  <h1 class="title is-5">Consequence</h1>
43
- <ConsequenceTable csqMetadata={csqFields()} csqValues={csqValues()} record={variant().data} />
43
+ <ConsequenceTable csqMetadata={csqFields()} csqValues={csqValues()} record={variant()} />
44
44
  </div>
45
45
  <Show when={!recordsMetadata.loading && !decisionTree.loading && (decisionTree() as DecisionTree)}>
46
46
  {(decisionTree) => (
@@ -61,7 +61,7 @@ export const VariantConsequence: Component = () => {
61
61
  </div>
62
62
  <div class="column">
63
63
  <h1 class="title is-5">Info</h1>
64
- <VariantInfoTable infoValues={variant().data.n} infoFields={recordsMetadata().info} />
64
+ <VariantInfoTable infoFields={recordsMetadata().info} record={variant()} />
65
65
  </div>
66
66
  </div>
67
67
  </Show>
@@ -6,10 +6,10 @@ import { InfoFilters } from "../components/filter/InfoFilters";
6
6
  import { Sort, SortEvent } from "../components/Sort";
7
7
  import { RecordDownload } from "../components/record/RecordDownload";
8
8
  import { Breadcrumb } from "../components/Breadcrumb";
9
- import { fetchRecords, fetchRecordsMeta } from "../utils/ApiUtils";
9
+ import { fetchHtsFileMetadata, fetchRecords, fetchRecordsMeta } from "../utils/ApiUtils";
10
10
  import { flattenFieldMetadata } from "../utils/field";
11
11
  import { DIRECTION_ASCENDING, DIRECTION_DESCENDING } from "../utils/sortUtils";
12
- import { Params, SortPath } from "@molgenis/vip-report-api/src/Api";
12
+ import { HtsFileMetadata, Params, SortPath } from "@molgenis/vip-report-api/src/Api";
13
13
  import { FilterChangeEvent, FilterClearEvent } from "../components/filter/Filter";
14
14
  import { useStore } from "../store";
15
15
  import { createQuery, infoSortPath } from "../utils/query";
@@ -19,12 +19,13 @@ import { arrayEquals } from "../utils/utils";
19
19
 
20
20
  export const VariantsView: Component = () => {
21
21
  const [recordsMeta] = createResource(fetchRecordsMeta);
22
+ const [htsFileMeta] = createResource(fetchHtsFileMetadata);
22
23
 
23
24
  return (
24
25
  <>
25
26
  <Breadcrumb items={[{ text: "Variants" }]} />
26
- <Show when={recordsMeta()} fallback={<Loader />}>
27
- <Variants recordsMeta={recordsMeta()!} />
27
+ <Show when={recordsMeta() && htsFileMeta} fallback={<Loader />}>
28
+ <Variants recordsMeta={recordsMeta()!} htsFileMeta={htsFileMeta()!} />
28
29
  </Show>
29
30
  </>
30
31
  );
@@ -32,14 +33,15 @@ export const VariantsView: Component = () => {
32
33
 
33
34
  export const Variants: Component<{
34
35
  recordsMeta: Metadata;
36
+ htsFileMeta: HtsFileMetadata;
35
37
  }> = (props) => {
36
38
  const [state, actions] = useStore();
37
39
 
38
- const page = () => state.variants.page;
39
- const pageSize = () => state.variants.pageSize;
40
- const searchQuery = () => state.variants.searchQuery;
41
- const filterQueries = () => state.variants.filterQueries;
42
- const sort = () => state.variants.sort;
40
+ const page = () => state.variants?.page;
41
+ const pageSize = () => state.variants?.pageSize;
42
+ const searchQuery = () => state.variants?.searchQuery;
43
+ const filterQueries = () => state.variants?.filterQueries;
44
+ const sort = () => state.variants?.sort;
43
45
 
44
46
  const onPageChange = (page: number) => actions.setVariantsPage(page);
45
47
  const onSearchChange = (search: string) => actions.setVariantsSearchQuery(search);
@@ -114,7 +116,11 @@ export const Variants: Component<{
114
116
  </div>
115
117
  </div>
116
118
  <div class="columns">
117
- <VariantsTable records={records()!.items} recordsMetadata={props.recordsMeta} />
119
+ <VariantsTable
120
+ records={records()!.items}
121
+ recordsMetadata={props.recordsMeta}
122
+ htsFileMeta={props.htsFileMeta}
123
+ />
118
124
  </div>
119
125
  </div>
120
126
  </div>
@@ -1,12 +0,0 @@
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
- const hpoTerm = () => props.ontologyClass.id;
9
- const label = () => props.ontologyClass.label;
10
-
11
- return <>{<Anchor href={`https://hpo.jax.org/app/browse/term/${hpoTerm()}`} value={label()} />}</>;
12
- };