@molgenis/vip-report-template 6.0.2 → 6.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.
- package/.husky/pre-commit +0 -3
- package/.travis.yml +2 -1
- package/index.html +1 -1
- package/package.json +23 -23
- package/src/App.tsx +14 -65
- package/src/assets/sass/main.scss +12 -47
- package/src/components/Breadcrumb.tsx +4 -4
- package/src/components/DatasetDropdown.tsx +4 -4
- package/src/components/InfoCollapsablePane.tsx +4 -4
- package/src/components/SampleTable.tsx +2 -2
- package/src/components/VariantInfoNestedTable.tsx +3 -3
- package/src/components/VariantsSampleTable.tsx +3 -3
- package/src/components/VariantsTable.tsx +3 -3
- package/src/components/filter/Filter.tsx +0 -4
- package/src/components/record/format/GenotypeField.tsx +4 -15
- package/src/index.tsx +43 -1
- package/src/mocks/GRCh37/sampleTree.json +123 -0
- package/src/mocks/GRCh37/static.ts +2 -0
- package/src/mocks/GRCh37/vcf/family.vcf.blob +31 -31
- package/src/mocks/MockApiClient.ts +6 -0
- package/src/store/index.tsx +1 -6
- package/src/utils/ApiUtils.ts +4 -0
- package/src/utils/decisionTreeUtils.ts +17 -0
- package/src/views/Sample.tsx +21 -17
- package/src/views/SampleVariant.tsx +36 -21
- package/src/views/SampleVariantConsequence.tsx +104 -63
- package/src/views/SampleVariants.tsx +7 -7
- package/src/views/Variant.tsx +48 -42
- package/src/views/VariantConsequence.tsx +9 -8
- package/src/views/Variants.tsx +2 -2
- package/src/views/data/data.tsx +7 -0
- package/src/components/filter/FilterIntegerDp.tsx +0 -47
- package/src/views/data/SampleData.tsx +0 -13
- package/src/views/data/SampleVariantConsequenceData.tsx +0 -13
- package/src/views/data/SampleVariantData.tsx +0 -14
- package/src/views/data/VariantConsequenceData.tsx +0 -10
- package/src/views/data/VariantData.tsx +0 -13
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
cram as cramGRCh37,
|
|
19
19
|
crai as craiGRCh37,
|
|
20
20
|
decisionTree as decisionTreeGRCh37,
|
|
21
|
+
sampleTree as sampleTreeGRCh37,
|
|
21
22
|
fastaGz as fastaGzGRCh37,
|
|
22
23
|
genesGz as genesGzGRCh37,
|
|
23
24
|
samplesFamily as samplesFamilyGRCh37,
|
|
@@ -73,6 +74,10 @@ export class MockApiClient implements Api {
|
|
|
73
74
|
return this.apiClient.getDecisionTree();
|
|
74
75
|
}
|
|
75
76
|
|
|
77
|
+
getSampleTree(): Promise<DecisionTree | null> {
|
|
78
|
+
return this.apiClient.getSampleTree();
|
|
79
|
+
}
|
|
80
|
+
|
|
76
81
|
getHtsFileMetadata(): Promise<HtsFileMetadata> {
|
|
77
82
|
return this.apiClient.getHtsFileMetadata();
|
|
78
83
|
}
|
|
@@ -144,6 +149,7 @@ export class MockApiClient implements Api {
|
|
|
144
149
|
},
|
|
145
150
|
},
|
|
146
151
|
decisionTree: decisionTreeGRCh37,
|
|
152
|
+
sampleTree: sampleTreeGRCh37,
|
|
147
153
|
vcfMeta: vcfMetaGRCh37,
|
|
148
154
|
};
|
|
149
155
|
|
package/src/store/index.tsx
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { hashIntegration, Router } from "@solidjs/router";
|
|
2
1
|
import { Context, createContext, ParentComponent, useContext } from "solid-js";
|
|
3
2
|
import { createStore } from "solid-js/store";
|
|
4
3
|
import { Item, Query, Sample, SortOrder } from "@molgenis/vip-report-api/src/Api";
|
|
@@ -172,11 +171,7 @@ export const Provider: ParentComponent = (props) => {
|
|
|
172
171
|
};
|
|
173
172
|
const store: AppStore = [state, actions];
|
|
174
173
|
|
|
175
|
-
return
|
|
176
|
-
<Router source={hashIntegration()}>
|
|
177
|
-
<StoreContext.Provider value={store}>{props.children}</StoreContext.Provider>
|
|
178
|
-
</Router>
|
|
179
|
-
);
|
|
174
|
+
return <StoreContext.Provider value={store}>{props.children}</StoreContext.Provider>;
|
|
180
175
|
};
|
|
181
176
|
|
|
182
177
|
export function useStore() {
|
package/src/utils/ApiUtils.ts
CHANGED
|
@@ -161,6 +161,10 @@ export async function fetchDecisionTree() {
|
|
|
161
161
|
return await api.getDecisionTree();
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
export async function fetchSampleTree() {
|
|
165
|
+
return await api.getSampleTree();
|
|
166
|
+
}
|
|
167
|
+
|
|
164
168
|
export async function fetchSampleById(id: string) {
|
|
165
169
|
return await api.getSampleById(Number(id));
|
|
166
170
|
}
|
|
@@ -12,3 +12,20 @@ export function getDecisionTreePath(recordsMetadata: Metadata, variant: Item<Rec
|
|
|
12
12
|
recordsMetadata.info.CSQ.nested.items.findIndex((csq) => csq.id === "VIPP")
|
|
13
13
|
] as DecisionTreePath;
|
|
14
14
|
}
|
|
15
|
+
|
|
16
|
+
export function getSampleTreePath(
|
|
17
|
+
recordsMetadata: Metadata,
|
|
18
|
+
sampleIndex: number,
|
|
19
|
+
variant: Item<Record>,
|
|
20
|
+
csqId: number,
|
|
21
|
+
): DecisionTreePath {
|
|
22
|
+
const vipp_s = variant.data.s[sampleIndex].VIPP_S as ValueArray;
|
|
23
|
+
let sampleTreePath: DecisionTreePath = [];
|
|
24
|
+
if (vipp_s !== undefined) {
|
|
25
|
+
const sampleTreePathString = vipp_s[csqId] as string | null;
|
|
26
|
+
if (sampleTreePathString !== null) {
|
|
27
|
+
sampleTreePath = sampleTreePathString.split("&") as DecisionTreePath;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return sampleTreePath;
|
|
31
|
+
}
|
package/src/views/Sample.tsx
CHANGED
|
@@ -1,26 +1,30 @@
|
|
|
1
1
|
import { Component, For, Show } from "solid-js";
|
|
2
|
-
import {
|
|
2
|
+
import { createAsync, RouteSectionProps, A } from "@solidjs/router";
|
|
3
3
|
import { Loader } from "../components/Loader";
|
|
4
4
|
import { Breadcrumb } from "../components/Breadcrumb";
|
|
5
|
-
import {
|
|
5
|
+
import { getSample } from "./data/data";
|
|
6
6
|
|
|
7
|
-
export const Sample: Component = () => {
|
|
8
|
-
const
|
|
7
|
+
export const Sample: Component<RouteSectionProps> = (props) => {
|
|
8
|
+
const sample = createAsync(() => getSample(Number(props.params.sampleId)));
|
|
9
9
|
|
|
10
10
|
return (
|
|
11
|
-
<Show when={
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
11
|
+
<Show when={sample()} fallback={<Loader />}>
|
|
12
|
+
{(sample) => (
|
|
13
|
+
<>
|
|
14
|
+
<Breadcrumb items={[{ href: "/samples", text: "Samples" }, { text: sample().data.person.individualId }]} />
|
|
15
|
+
<p class="has-text-weight-semibold">Sample</p>
|
|
16
|
+
<div class="columns">
|
|
17
|
+
<div class="column is-1">
|
|
18
|
+
<For each={Object.keys(sample().data.person)}>{(key) => <p>{key}</p>}</For>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="column is-1">
|
|
21
|
+
<For each={Object.values(sample().data.person)}>{(value) => <p>{value}</p>}</For>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
<br />
|
|
25
|
+
<A href={`/samples/${sample().id}/variants`}>Variants</A>
|
|
26
|
+
</>
|
|
27
|
+
)}
|
|
24
28
|
</Show>
|
|
25
29
|
);
|
|
26
30
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Component, createResource, For, Show } from "solid-js";
|
|
2
|
-
import {
|
|
2
|
+
import { createAsync, RouteSectionProps } from "@solidjs/router";
|
|
3
3
|
import { Loader } from "../components/Loader";
|
|
4
4
|
import { GenomeBrowser } from "../components/GenomeBrowser";
|
|
5
5
|
import { fetchPedigreeSamples, fetchRecordsMeta, getRecordLabel } from "../utils/ApiUtils";
|
|
@@ -11,36 +11,51 @@ import { getNestedInfoFieldsWithValues } from "../utils/field";
|
|
|
11
11
|
import { VariantSampleTable } from "../components/VariantSampleTable";
|
|
12
12
|
import { Breadcrumb } from "../components/Breadcrumb";
|
|
13
13
|
import { getRecordSamples } from "../utils/viewUtils";
|
|
14
|
-
import { SampleVariantRouteData } from "./data/SampleVariantData";
|
|
15
14
|
import { getSampleLabel } from "../utils/sample";
|
|
16
15
|
import { Item, Sample } from "@molgenis/vip-report-api/src/Api";
|
|
17
16
|
import { Metadata, Record } from "@molgenis/vip-report-vcf/src/Vcf";
|
|
18
17
|
import { Abbr } from "../components/Abbr";
|
|
18
|
+
import { getSample, getVariant } from "./data/data";
|
|
19
19
|
|
|
20
|
-
export const SampleVariantView: Component = () => {
|
|
21
|
-
const
|
|
20
|
+
export const SampleVariantView: Component<RouteSectionProps> = (props) => {
|
|
21
|
+
const sample = createAsync(() => getSample(Number(props.params.sampleId)));
|
|
22
|
+
const variant = createAsync(() => getVariant(Number(props.params.variantId)));
|
|
22
23
|
|
|
23
24
|
const [pedigreeSamples] = createResource(sample, fetchPedigreeSamples);
|
|
24
25
|
const [recordsMeta] = createResource(fetchRecordsMeta);
|
|
25
26
|
|
|
26
27
|
return (
|
|
27
|
-
<Show when={sample()
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
{
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
28
|
+
<Show when={sample()} fallback={<Loader />}>
|
|
29
|
+
{(sample) => (
|
|
30
|
+
<Show when={variant()} fallback={<Loader />}>
|
|
31
|
+
{(variant) => (
|
|
32
|
+
<>
|
|
33
|
+
<Breadcrumb
|
|
34
|
+
items={[
|
|
35
|
+
{ href: "/samples", text: "Samples" },
|
|
36
|
+
{ href: `/samples/${sample().id}`, text: getSampleLabel(sample().data) },
|
|
37
|
+
{ href: `/samples/${sample().id}/variants`, text: "Variants" },
|
|
38
|
+
{ text: getRecordLabel(variant()) },
|
|
39
|
+
]}
|
|
40
|
+
/>
|
|
41
|
+
<Show when={pedigreeSamples()} fallback={<Loader />}>
|
|
42
|
+
{(pedigreeSamples) => (
|
|
43
|
+
<Show when={recordsMeta()} fallback={<Loader />}>
|
|
44
|
+
{(recordsMeta) => (
|
|
45
|
+
<SampleVariant
|
|
46
|
+
sample={sample()}
|
|
47
|
+
pedigreeSamples={pedigreeSamples().items}
|
|
48
|
+
recordsMeta={recordsMeta()}
|
|
49
|
+
record={variant()}
|
|
50
|
+
/>
|
|
51
|
+
)}
|
|
52
|
+
</Show>
|
|
53
|
+
)}
|
|
54
|
+
</Show>
|
|
55
|
+
</>
|
|
56
|
+
)}
|
|
57
|
+
</Show>
|
|
58
|
+
)}
|
|
44
59
|
</Show>
|
|
45
60
|
);
|
|
46
61
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Component, createResource, Show } from "solid-js";
|
|
2
|
-
import {
|
|
2
|
+
import { createAsync, RouteSectionProps } from "@solidjs/router";
|
|
3
3
|
import { Loader } from "../components/Loader";
|
|
4
4
|
import {
|
|
5
|
+
fetchSampleTree,
|
|
5
6
|
fetchDecisionTree,
|
|
6
|
-
fetchHtsFileMetadata,
|
|
7
7
|
fetchPedigreeSamples,
|
|
8
8
|
fetchRecordsMeta,
|
|
9
9
|
getRecordLabel,
|
|
@@ -15,42 +15,61 @@ import { Breadcrumb } from "../components/Breadcrumb";
|
|
|
15
15
|
import { ConsequenceTable } from "../components/ConsequenceTable";
|
|
16
16
|
import { getRecordSamples, getSpecificConsequence } from "../utils/viewUtils";
|
|
17
17
|
import { DecisionTreePath } from "../components/tree/DecisionTreePath";
|
|
18
|
-
import { getDecisionTreePath } from "../utils/decisionTreeUtils";
|
|
19
|
-
import { SampleVariantConsequenceRouteData } from "./data/SampleVariantConsequenceData";
|
|
18
|
+
import { getDecisionTreePath, getSampleTreePath } from "../utils/decisionTreeUtils";
|
|
20
19
|
import { getSampleLabel } from "../utils/sample";
|
|
21
20
|
import { DecisionTree, Item, Sample } from "@molgenis/vip-report-api/src/Api";
|
|
22
21
|
import { Metadata, Record } from "@molgenis/vip-report-vcf/src/Vcf";
|
|
23
22
|
import { ValueArray } from "@molgenis/vip-report-vcf/src/ValueParser";
|
|
23
|
+
import { getSample, getVariant } from "./data/data";
|
|
24
24
|
|
|
25
|
-
export const SampleVariantConsequenceView: Component = () => {
|
|
26
|
-
const
|
|
27
|
-
|
|
25
|
+
export const SampleVariantConsequenceView: Component<RouteSectionProps> = (props) => {
|
|
26
|
+
const sample = createAsync(() => getSample(Number(props.params.sampleId)));
|
|
27
|
+
const variant = createAsync(() => getVariant(Number(props.params.variantId)));
|
|
28
|
+
const consequenceId = () => Number(props.params.consequenceId);
|
|
28
29
|
const [pedigreeSamples] = createResource(sample, fetchPedigreeSamples);
|
|
29
30
|
const [recordsMeta] = createResource(fetchRecordsMeta);
|
|
30
31
|
const [decisionTree] = createResource(fetchDecisionTree, { initialValue: null });
|
|
31
|
-
const [
|
|
32
|
+
const [sampleTree] = createResource(fetchSampleTree, { initialValue: null });
|
|
32
33
|
|
|
33
34
|
return (
|
|
34
|
-
<Show when={sample()
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
{
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
35
|
+
<Show when={sample()} fallback={<Loader />}>
|
|
36
|
+
{(sample) => (
|
|
37
|
+
<Show when={variant()} fallback={<Loader />}>
|
|
38
|
+
{(variant) => (
|
|
39
|
+
<>
|
|
40
|
+
<Breadcrumb
|
|
41
|
+
items={[
|
|
42
|
+
{ href: "/samples", text: "Samples" },
|
|
43
|
+
{ href: `/samples/${sample().id}`, text: getSampleLabel(sample().data) },
|
|
44
|
+
{ href: `/samples/${sample().id}/variants`, text: "Variants" },
|
|
45
|
+
{
|
|
46
|
+
href: `/samples/${sample().id}/variants/${variant().id}`,
|
|
47
|
+
text: getRecordLabel(variant()),
|
|
48
|
+
},
|
|
49
|
+
{ text: `Consequence #${consequenceId()}` },
|
|
50
|
+
]}
|
|
51
|
+
/>
|
|
52
|
+
<Show when={pedigreeSamples()} fallback={<Loader />}>
|
|
53
|
+
{(pedigreeSamples) => (
|
|
54
|
+
<Show when={recordsMeta()} fallback={<Loader />}>
|
|
55
|
+
{(recordsMeta) => (
|
|
56
|
+
<SampleVariantConsequence
|
|
57
|
+
sample={sample()}
|
|
58
|
+
pedigreeSamples={pedigreeSamples().items}
|
|
59
|
+
recordsMeta={recordsMeta()}
|
|
60
|
+
variant={variant()}
|
|
61
|
+
consequenceId={consequenceId()}
|
|
62
|
+
decisionTree={decisionTree()}
|
|
63
|
+
sampleTree={sampleTree()}
|
|
64
|
+
/>
|
|
65
|
+
)}
|
|
66
|
+
</Show>
|
|
67
|
+
)}
|
|
68
|
+
</Show>
|
|
69
|
+
</>
|
|
70
|
+
)}
|
|
71
|
+
</Show>
|
|
72
|
+
)}
|
|
54
73
|
</Show>
|
|
55
74
|
);
|
|
56
75
|
};
|
|
@@ -62,52 +81,74 @@ export const SampleVariantConsequence: Component<{
|
|
|
62
81
|
variant: Item<Record>;
|
|
63
82
|
consequenceId: number;
|
|
64
83
|
decisionTree: DecisionTree | null;
|
|
84
|
+
sampleTree: DecisionTree | null;
|
|
65
85
|
}> = (props) => {
|
|
66
86
|
const hasDecisionTreePathMeta = () =>
|
|
67
87
|
(props.recordsMeta.info.CSQ?.nested?.items || []).findIndex((csq) => csq.id === "VIPP") !== -1;
|
|
88
|
+
const hasSampleTreePathMeta = () => props.recordsMeta.format.VIPP_S != null;
|
|
68
89
|
|
|
69
90
|
return (
|
|
70
91
|
<>
|
|
71
92
|
<div class="columns">
|
|
72
|
-
<div class="column is-
|
|
73
|
-
<
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
path={getDecisionTreePath(props.recordsMeta, props.variant, props.consequenceId)}
|
|
93
|
+
<div class="column is-4">
|
|
94
|
+
<div>
|
|
95
|
+
<h1 class="title is-5">Info</h1>
|
|
96
|
+
<VariantInfoTable infoFields={props.recordsMeta.info} record={props.variant} />
|
|
97
|
+
</div>
|
|
98
|
+
<div class="mt-3">
|
|
99
|
+
<h1 class="title is-5">Consequence</h1>
|
|
100
|
+
<ConsequenceTable
|
|
101
|
+
csqMetadata={
|
|
102
|
+
props.recordsMeta.info.CSQ.nested !== undefined ? props.recordsMeta.info.CSQ.nested.items : []
|
|
103
|
+
}
|
|
104
|
+
csqValues={getSpecificConsequence(props.variant.data.n.CSQ as ValueArray, props.consequenceId)}
|
|
105
|
+
record={props.variant}
|
|
86
106
|
/>
|
|
87
107
|
</div>
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
<h1 class="title is-5">Record</h1>
|
|
93
|
-
<VariantTable variant={props.variant.data} />
|
|
94
|
-
</div>
|
|
95
|
-
<div class="column is-3">
|
|
96
|
-
<h1 class="title is-5">Info</h1>
|
|
97
|
-
<VariantInfoTable infoFields={props.recordsMeta.info} record={props.variant} />
|
|
108
|
+
<div class="mt-3">
|
|
109
|
+
<h1 class="title is-5">Record</h1>
|
|
110
|
+
<VariantTable variant={props.variant.data} />
|
|
111
|
+
</div>
|
|
98
112
|
</div>
|
|
99
|
-
<div class="column">
|
|
100
|
-
<
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
113
|
+
<div class="column is-8">
|
|
114
|
+
<div>
|
|
115
|
+
<h1 class="title is-5">Samples</h1>
|
|
116
|
+
<VariantSampleTable
|
|
117
|
+
formatFields={props.recordsMeta.format}
|
|
118
|
+
samples={[props.sample.data, ...props.pedigreeSamples.map((item) => item.data)]}
|
|
119
|
+
sampleValues={getRecordSamples(
|
|
120
|
+
props.variant.data,
|
|
121
|
+
props.sample.data,
|
|
122
|
+
props.pedigreeSamples.map((item) => item.data),
|
|
123
|
+
)}
|
|
124
|
+
record={props.variant}
|
|
125
|
+
/>
|
|
126
|
+
</div>
|
|
127
|
+
<div class="columns mt-3">
|
|
128
|
+
{props.decisionTree !== null && hasDecisionTreePathMeta() && (
|
|
129
|
+
<div class="column is-6">
|
|
130
|
+
<h1 class="title is-5">Variant classification tree path</h1>
|
|
131
|
+
<DecisionTreePath
|
|
132
|
+
decisionTree={props.decisionTree}
|
|
133
|
+
path={getDecisionTreePath(props.recordsMeta, props.variant, props.consequenceId)}
|
|
134
|
+
/>
|
|
135
|
+
</div>
|
|
108
136
|
)}
|
|
109
|
-
|
|
110
|
-
|
|
137
|
+
{props.sampleTree !== null && hasSampleTreePathMeta() && (
|
|
138
|
+
<div class="column is-6">
|
|
139
|
+
<h1 class="title is-5">Sample classification tree path</h1>
|
|
140
|
+
<DecisionTreePath
|
|
141
|
+
decisionTree={props.sampleTree}
|
|
142
|
+
path={getSampleTreePath(
|
|
143
|
+
props.recordsMeta,
|
|
144
|
+
props.sample.data.index,
|
|
145
|
+
props.variant,
|
|
146
|
+
props.consequenceId,
|
|
147
|
+
)}
|
|
148
|
+
/>
|
|
149
|
+
</div>
|
|
150
|
+
)}
|
|
151
|
+
</div>
|
|
111
152
|
</div>
|
|
112
153
|
</div>
|
|
113
154
|
</>
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Component, createMemo, createResource, createSignal, onMount, Show } from "solid-js";
|
|
2
|
-
import { useRouteData } from "@solidjs/router";
|
|
3
2
|
import {
|
|
4
3
|
HtsFileMetadata,
|
|
5
4
|
Item,
|
|
@@ -35,7 +34,6 @@ import { Breadcrumb } from "../components/Breadcrumb";
|
|
|
35
34
|
import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
|
|
36
35
|
import { FilterChangeEvent, FilterClearEvent, Filters } from "../components/filter/Filters";
|
|
37
36
|
import { DIRECTION_ASCENDING, DIRECTION_DESCENDING } from "../utils/sortUtils";
|
|
38
|
-
import { SampleRouteData } from "./data/SampleData";
|
|
39
37
|
import { useStore } from "../store";
|
|
40
38
|
import { Metadata } from "@molgenis/vip-report-vcf/src/Vcf";
|
|
41
39
|
import {
|
|
@@ -49,9 +47,11 @@ import {
|
|
|
49
47
|
import { arrayEquals } from "../utils/utils";
|
|
50
48
|
import { getAllelicBalanceQuery } from "../components/filter/FilterAllelicBalance";
|
|
51
49
|
import { RecordsPerPage, RecordsPerPageEvent } from "../components/RecordsPerPage";
|
|
50
|
+
import { createAsync, RouteSectionProps } from "@solidjs/router";
|
|
51
|
+
import { getSample } from "./data/data";
|
|
52
52
|
|
|
53
|
-
export const SampleVariantsView: Component = () => {
|
|
54
|
-
const
|
|
53
|
+
export const SampleVariantsView: Component<RouteSectionProps> = (props) => {
|
|
54
|
+
const sample = createAsync(() => getSample(Number(props.params.sampleId)));
|
|
55
55
|
|
|
56
56
|
const [pedigreeSamples] = createResource(sample, fetchPedigreeSamples);
|
|
57
57
|
const [samplePhenotypes] = createResource(sample, fetchPhenotypicFeatures);
|
|
@@ -375,8 +375,8 @@ export const SampleVariants: Component<{
|
|
|
375
375
|
};
|
|
376
376
|
|
|
377
377
|
return (
|
|
378
|
-
<div class="columns is-variable is-1">
|
|
379
|
-
<div class="column is-1-fullhd is-2">
|
|
378
|
+
<div class="variants columns is-variable is-1">
|
|
379
|
+
<div class="scrolling-div column is-1-fullhd is-2">
|
|
380
380
|
<SearchBox value={searchQuery()} onInput={onSearchChange} />
|
|
381
381
|
<Filters
|
|
382
382
|
fields={filterInfoFields()}
|
|
@@ -386,7 +386,7 @@ export const SampleVariants: Component<{
|
|
|
386
386
|
onClear={onFilterClear}
|
|
387
387
|
/>
|
|
388
388
|
</div>
|
|
389
|
-
<div class="column">
|
|
389
|
+
<div class="scrolling-div column">
|
|
390
390
|
<div class="columns is-gapless">
|
|
391
391
|
<div class="column">
|
|
392
392
|
<p class="title is-3">{title()}</p>
|
package/src/views/Variant.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Component, createResource, For, Show } from "solid-js";
|
|
2
|
-
import {
|
|
2
|
+
import { createAsync, RouteSectionProps } from "@solidjs/router";
|
|
3
3
|
import { GenomeBrowser } from "../components/GenomeBrowser";
|
|
4
4
|
import { Loader } from "../components/Loader";
|
|
5
5
|
import { Value } from "@molgenis/vip-report-vcf/src/ValueParser";
|
|
@@ -9,54 +9,60 @@ import { VariantInfoNestedTable } from "../components/VariantInfoNestedTable";
|
|
|
9
9
|
import { getNestedInfoFieldsWithValues } from "../utils/field";
|
|
10
10
|
import { Breadcrumb } from "../components/Breadcrumb";
|
|
11
11
|
import { EMPTY_RECORDS_METADATA, fetchRecordsMeta, getRecordLabel } from "../utils/ApiUtils";
|
|
12
|
-
import {
|
|
12
|
+
import { getVariant } from "./data/data";
|
|
13
|
+
import { Item } from "@molgenis/vip-report-api/src/Api";
|
|
14
|
+
import { Record } from "@molgenis/vip-report-vcf/src/Vcf";
|
|
13
15
|
|
|
14
|
-
export const Variant: Component = () => {
|
|
15
|
-
const
|
|
16
|
+
export const Variant: Component<RouteSectionProps<Promise<Item<Record>>>> = (props) => {
|
|
17
|
+
const variant = createAsync(() => getVariant(Number(props.params.variantId)));
|
|
16
18
|
|
|
17
19
|
const [recordsMetadata] = createResource(fetchRecordsMeta, { initialValue: EMPTY_RECORDS_METADATA });
|
|
18
20
|
|
|
19
21
|
return (
|
|
20
22
|
<>
|
|
21
|
-
<Show when={
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
23
|
+
<Show when={variant()} fallback={<Loader />}>
|
|
24
|
+
{(variant) => (
|
|
25
|
+
<>
|
|
26
|
+
<Breadcrumb items={[{ href: "/variants", text: "Variants" }, { text: getRecordLabel(variant()) }]} />
|
|
27
|
+
<GenomeBrowser contig={variant().data.c} position={variant().data.p} samples={[]} />
|
|
28
|
+
<div class="columns">
|
|
29
|
+
<div class="column is-3">
|
|
30
|
+
<h1 class="title is-5">Record</h1>
|
|
31
|
+
<VariantTable variant={variant().data} />
|
|
32
|
+
</div>
|
|
33
|
+
<Show
|
|
34
|
+
when={
|
|
35
|
+
Object.values(recordsMetadata().info).filter(
|
|
36
|
+
(info) => !info.nested && variant().data.n[info.id] !== undefined,
|
|
37
|
+
).length > 0
|
|
38
|
+
}
|
|
39
|
+
>
|
|
40
|
+
<div class="column is-3">
|
|
41
|
+
<h1 class="title is-5">Info</h1>
|
|
42
|
+
<VariantInfoTable infoFields={recordsMetadata().info} record={variant()} />
|
|
43
|
+
</div>
|
|
44
|
+
</Show>
|
|
39
45
|
</div>
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
</
|
|
58
|
-
|
|
59
|
-
|
|
46
|
+
<div class="columns">
|
|
47
|
+
<div class="column" style={{ "max-width": "100%" }}>
|
|
48
|
+
<For each={getNestedInfoFieldsWithValues(recordsMetadata().info, variant().data.n)}>
|
|
49
|
+
{(infoField) => (
|
|
50
|
+
<>
|
|
51
|
+
<h1 class="title is-5">{infoField.id}</h1>
|
|
52
|
+
<p class="mb-4">{infoField.description}</p>
|
|
53
|
+
<VariantInfoNestedTable
|
|
54
|
+
infoValue={variant().data.n[infoField.id] as unknown as Value[][]}
|
|
55
|
+
infoField={infoField}
|
|
56
|
+
record={variant()}
|
|
57
|
+
sample={null}
|
|
58
|
+
/>
|
|
59
|
+
</>
|
|
60
|
+
)}
|
|
61
|
+
</For>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</>
|
|
65
|
+
)}
|
|
60
66
|
</Show>
|
|
61
67
|
</>
|
|
62
68
|
);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Component, createResource, Show } from "solid-js";
|
|
2
|
-
import {
|
|
2
|
+
import { createAsync, RouteSectionProps } from "@solidjs/router";
|
|
3
3
|
import { Loader } from "../components/Loader";
|
|
4
4
|
import { DecisionTree } from "@molgenis/vip-report-api/src/Api";
|
|
5
5
|
import { VariantTable } from "../components/VariantTable";
|
|
@@ -18,10 +18,11 @@ import {
|
|
|
18
18
|
} from "../utils/ApiUtils";
|
|
19
19
|
import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
|
|
20
20
|
import { ValueArray } from "@molgenis/vip-report-vcf/src/ValueParser";
|
|
21
|
-
import {
|
|
21
|
+
import { getVariant } from "./data/data";
|
|
22
22
|
|
|
23
|
-
export const VariantConsequence: Component = () => {
|
|
24
|
-
const
|
|
23
|
+
export const VariantConsequence: Component<RouteSectionProps> = (props) => {
|
|
24
|
+
const variant = createAsync(() => getVariant(Number(props.params.variantId)));
|
|
25
|
+
const consequenceId = () => Number(props.params.consequenceId);
|
|
25
26
|
|
|
26
27
|
const [recordsMetadata] = createResource(fetchRecordsMeta, { initialValue: EMPTY_RECORDS_METADATA });
|
|
27
28
|
const [decisionTree] = createResource(fetchDecisionTree, { initialValue: EMPTY_DECISION_TREE });
|
|
@@ -30,14 +31,14 @@ export const VariantConsequence: Component = () => {
|
|
|
30
31
|
|
|
31
32
|
const hasDecisionTreePathMeta = () => csqFields().findIndex((csq) => csq.id === "VIPP") !== -1;
|
|
32
33
|
return (
|
|
33
|
-
<Show when={
|
|
34
|
+
<Show when={variant()} fallback={<Loader />} keyed>
|
|
34
35
|
{(variant) => (
|
|
35
36
|
<>
|
|
36
37
|
<Breadcrumb
|
|
37
38
|
items={[
|
|
38
39
|
{ href: "/variants", text: "Variants" },
|
|
39
40
|
{ href: `/variants/${variant.id}`, text: getRecordLabel(variant) },
|
|
40
|
-
{ text: `Consequence #${consequenceId}` },
|
|
41
|
+
{ text: `Consequence #${consequenceId()}` },
|
|
41
42
|
]}
|
|
42
43
|
/>
|
|
43
44
|
<div class="columns">
|
|
@@ -45,7 +46,7 @@ export const VariantConsequence: Component = () => {
|
|
|
45
46
|
<h1 class="title is-5">Consequence</h1>
|
|
46
47
|
<ConsequenceTable
|
|
47
48
|
csqMetadata={csqFields()}
|
|
48
|
-
csqValues={getSpecificConsequence(variant.data.n.CSQ as ValueArray, consequenceId)}
|
|
49
|
+
csqValues={getSpecificConsequence(variant.data.n.CSQ as ValueArray, consequenceId())}
|
|
49
50
|
record={variant}
|
|
50
51
|
/>
|
|
51
52
|
</div>
|
|
@@ -56,7 +57,7 @@ export const VariantConsequence: Component = () => {
|
|
|
56
57
|
<h1 class="title is-5">Classification tree path</h1>
|
|
57
58
|
<DecisionTreePath
|
|
58
59
|
decisionTree={decisionTree}
|
|
59
|
-
path={getDecisionTreePath(recordsMetadata(), variant, consequenceId)}
|
|
60
|
+
path={getDecisionTreePath(recordsMetadata(), variant, consequenceId())}
|
|
60
61
|
/>
|
|
61
62
|
</div>
|
|
62
63
|
)}
|