@molgenis/vip-report-template 5.0.0 → 5.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.
- package/.travis.yml +3 -1
- package/package.json +3 -3
- package/src/components/VariantSampleTable.tsx +4 -2
- package/src/components/VariantsSampleTable.tsx +113 -7
- package/src/components/filter/Filter.tsx +31 -22
- package/src/components/filter/FilterAllelicBalance.tsx +81 -0
- package/src/components/filter/FilterCategorical.tsx +3 -2
- package/src/components/filter/FilterIntegerDp.tsx +19 -4
- package/src/components/filter/FilterIntegerGq.tsx +32 -0
- package/src/components/filter/FilterIntegerVid.tsx +13 -3
- package/src/components/filter/FilterIntegerVim.tsx +13 -3
- package/src/components/filter/Filters.tsx +7 -8
- package/src/components/filter/InfoFilter.tsx +10 -4
- package/src/components/filter/InfoFilters.tsx +1 -1
- package/src/components/filter/SampleFilters.tsx +16 -19
- package/src/components/filter/SamplesFilters.tsx +10 -8
- package/src/components/record/Format.tsx +2 -2
- package/src/components/record/format/GenotypeField.tsx +11 -10
- package/src/mocks/GRCh37/static.ts +74 -0
- package/src/mocks/GRCh37/vcf/family.vcf.blob +31 -30
- package/src/mocks/GRCh38/genes.gff.gz.blob +0 -0
- package/src/mocks/GRCh38/vcf/family.vcf.blob +25 -24
- package/src/mocks/MockApiClient.ts +2 -1
- package/src/store/index.tsx +14 -15
- package/src/views/SampleVariants.tsx +47 -24
- package/src/views/VariantConsequence.tsx +44 -37
- package/src/views/Variants.tsx +3 -3
package/.travis.yml
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
os: linux
|
|
2
|
+
dist: focal
|
|
1
3
|
language: node_js
|
|
2
4
|
node_js:
|
|
3
5
|
- lts/*
|
|
@@ -10,7 +12,7 @@ cache:
|
|
|
10
12
|
directories:
|
|
11
13
|
- "~/.pnpm-store"
|
|
12
14
|
before_install:
|
|
13
|
-
- curl -f https://get.pnpm.io/v6.
|
|
15
|
+
- curl -f https://get.pnpm.io/v6.32.js | node - add --global pnpm@7
|
|
14
16
|
- pnpm config set store-dir ~/.pnpm-store
|
|
15
17
|
install:
|
|
16
18
|
- pnpm install
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@molgenis/vip-report-template",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.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.2.0",
|
|
37
37
|
"@fortawesome/free-solid-svg-icons": "^6.2.0",
|
|
38
|
-
"@molgenis/vip-report-api": "^4.
|
|
39
|
-
"@molgenis/vip-report-vcf": "^1.
|
|
38
|
+
"@molgenis/vip-report-api": "^4.3.2",
|
|
39
|
+
"@molgenis/vip-report-vcf": "^1.3.3",
|
|
40
40
|
"base64-js": "^1.5.1",
|
|
41
41
|
"igv": "^2.13.3",
|
|
42
42
|
"solid-app-router": "^0.4.2",
|
|
@@ -39,8 +39,10 @@ export const VariantSampleTable: Component<{
|
|
|
39
39
|
formatMetadata={formatField}
|
|
40
40
|
record={props.record}
|
|
41
41
|
isAbbreviate={false}
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
allelicBalance={
|
|
43
|
+
props.record.data.s[props.samples[i()].index]["VIAB"] as number | undefined | null
|
|
44
|
+
}
|
|
45
|
+
readDepth={props.record.data.s[props.samples[i()].index]["DP"] as number | undefined}
|
|
44
46
|
/>
|
|
45
47
|
</td>
|
|
46
48
|
)}
|
|
@@ -6,7 +6,7 @@ import { Link } from "solid-app-router";
|
|
|
6
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
|
-
import { Component, createMemo, For } from "solid-js";
|
|
9
|
+
import { Component, createMemo, createSignal, For, onMount, Show } from "solid-js";
|
|
10
10
|
import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
|
|
11
11
|
import { FieldHeader } from "./FieldHeader";
|
|
12
12
|
import { Abbr } from "./Abbr";
|
|
@@ -22,6 +22,32 @@ export const VariantsSampleTable: Component<{
|
|
|
22
22
|
}> = (props) => {
|
|
23
23
|
const samples = createMemo(() => [props.item.data, ...props.pedigreeSamples.map((item) => item.data)]);
|
|
24
24
|
|
|
25
|
+
const [proband, setProband] = createSignal<Sample | undefined>();
|
|
26
|
+
const [father, setFather] = createSignal<Sample | undefined>();
|
|
27
|
+
const [mother, setMother] = createSignal<Sample | undefined>();
|
|
28
|
+
const [otherFamilyMembers, setOtherFamilyMembers] = createSignal<Sample[]>([]);
|
|
29
|
+
|
|
30
|
+
onMount(() => {
|
|
31
|
+
const familyMembers: Sample[] = [];
|
|
32
|
+
setProband(props.item.data);
|
|
33
|
+
samples().forEach((sample) => {
|
|
34
|
+
if (
|
|
35
|
+
(proband() as Sample).person.maternalId !== "0" &&
|
|
36
|
+
sample.person.individualId === (proband() as Sample).person.maternalId
|
|
37
|
+
) {
|
|
38
|
+
setMother(sample);
|
|
39
|
+
} else if (
|
|
40
|
+
(proband() as Sample).person.paternalId !== "0" &&
|
|
41
|
+
sample.person.individualId === (proband() as Sample).person.paternalId
|
|
42
|
+
) {
|
|
43
|
+
setFather(sample);
|
|
44
|
+
} else if (sample.person.individualId !== (proband() as Sample).person.individualId) {
|
|
45
|
+
familyMembers.push(sample);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
setOtherFamilyMembers(familyMembers);
|
|
49
|
+
});
|
|
50
|
+
|
|
25
51
|
return (
|
|
26
52
|
<div style={{ display: "grid" }}>
|
|
27
53
|
{/* workaround for https://github.com/jgthms/bulma/issues/2572#issuecomment-523099776 */}
|
|
@@ -31,7 +57,43 @@ export const VariantsSampleTable: Component<{
|
|
|
31
57
|
<tr>
|
|
32
58
|
<th>Position</th>
|
|
33
59
|
<th>Reference</th>
|
|
34
|
-
<
|
|
60
|
+
<Show when={proband()} keyed>
|
|
61
|
+
{(proband) => (
|
|
62
|
+
<th>
|
|
63
|
+
<Abbr
|
|
64
|
+
title={`${
|
|
65
|
+
proband.person.individualId
|
|
66
|
+
}: ${proband.person.sex.toLowerCase()}, ${proband.person.affectedStatus.toLowerCase()}`}
|
|
67
|
+
value="Proband"
|
|
68
|
+
/>
|
|
69
|
+
</th>
|
|
70
|
+
)}
|
|
71
|
+
</Show>
|
|
72
|
+
<Show when={mother()} keyed>
|
|
73
|
+
{(mother) => (
|
|
74
|
+
<th>
|
|
75
|
+
<Abbr
|
|
76
|
+
title={`${
|
|
77
|
+
mother.person.individualId
|
|
78
|
+
}: ${mother.person.sex.toLowerCase()}, ${mother.person.affectedStatus.toLowerCase()}`}
|
|
79
|
+
value="Mother"
|
|
80
|
+
/>
|
|
81
|
+
</th>
|
|
82
|
+
)}
|
|
83
|
+
</Show>
|
|
84
|
+
<Show when={father()} keyed>
|
|
85
|
+
{(father) => (
|
|
86
|
+
<th>
|
|
87
|
+
<Abbr
|
|
88
|
+
title={`${
|
|
89
|
+
father.person.individualId
|
|
90
|
+
}: ${father.person.sex.toLowerCase()}, ${father.person.affectedStatus.toLowerCase()}`}
|
|
91
|
+
value="Father"
|
|
92
|
+
/>
|
|
93
|
+
</th>
|
|
94
|
+
)}
|
|
95
|
+
</Show>
|
|
96
|
+
<For each={otherFamilyMembers()}>
|
|
35
97
|
{(sample: Sample) => (
|
|
36
98
|
<th>
|
|
37
99
|
<Abbr
|
|
@@ -62,19 +124,63 @@ export const VariantsSampleTable: Component<{
|
|
|
62
124
|
<td>
|
|
63
125
|
<Ref value={record.data.r} isAbbreviate={true} />
|
|
64
126
|
</td>
|
|
65
|
-
<
|
|
66
|
-
{(
|
|
127
|
+
<Show when={proband()} keyed>
|
|
128
|
+
{(proband) => (
|
|
129
|
+
<td>
|
|
130
|
+
<GenotypeField
|
|
131
|
+
genotype={record.data.s[proband.index]["GT"] as Genotype}
|
|
132
|
+
refAllele={record.data.r}
|
|
133
|
+
altAlleles={record.data.a}
|
|
134
|
+
isAbbreviate={true}
|
|
135
|
+
allelicBalance={record.data.s[proband.index]["VIAB"] as number | undefined | null}
|
|
136
|
+
readDepth={record.data.s[proband.index]["DP"] as number | undefined}
|
|
137
|
+
/>
|
|
138
|
+
</td>
|
|
139
|
+
)}
|
|
140
|
+
</Show>
|
|
141
|
+
<Show when={mother()} keyed>
|
|
142
|
+
{(mother) => (
|
|
67
143
|
<td>
|
|
68
144
|
<GenotypeField
|
|
69
|
-
genotype={record.data.s[
|
|
145
|
+
genotype={record.data.s[mother.index]["GT"] as Genotype}
|
|
70
146
|
refAllele={record.data.r}
|
|
71
147
|
altAlleles={record.data.a}
|
|
72
148
|
isAbbreviate={true}
|
|
73
|
-
|
|
74
|
-
readDepth={record.data.s[
|
|
149
|
+
allelicBalance={record.data.s[mother.index]["VIAB"] as number | undefined | null}
|
|
150
|
+
readDepth={record.data.s[mother.index]["DP"] as number | undefined}
|
|
75
151
|
/>
|
|
76
152
|
</td>
|
|
77
153
|
)}
|
|
154
|
+
</Show>
|
|
155
|
+
<Show when={father()} keyed>
|
|
156
|
+
{(father) => (
|
|
157
|
+
<td>
|
|
158
|
+
<GenotypeField
|
|
159
|
+
genotype={record.data.s[father.index]["GT"] as Genotype}
|
|
160
|
+
refAllele={record.data.r}
|
|
161
|
+
altAlleles={record.data.a}
|
|
162
|
+
isAbbreviate={true}
|
|
163
|
+
allelicBalance={record.data.s[father.index]["VIAB"] as number | undefined | null}
|
|
164
|
+
readDepth={record.data.s[father.index]["DP"] as number | undefined}
|
|
165
|
+
/>
|
|
166
|
+
</td>
|
|
167
|
+
)}
|
|
168
|
+
</Show>
|
|
169
|
+
<For each={otherFamilyMembers()}>
|
|
170
|
+
{(sample: Sample) => (
|
|
171
|
+
<>
|
|
172
|
+
<td>
|
|
173
|
+
<GenotypeField
|
|
174
|
+
genotype={record.data.s[sample.index]["GT"] as Genotype}
|
|
175
|
+
refAllele={record.data.r}
|
|
176
|
+
altAlleles={record.data.a}
|
|
177
|
+
isAbbreviate={true}
|
|
178
|
+
allelicBalance={record.data.s[sample.index]["VIAB"] as number | undefined | null}
|
|
179
|
+
readDepth={record.data.s[sample.index]["DP"] as number | undefined}
|
|
180
|
+
/>
|
|
181
|
+
</td>
|
|
182
|
+
</>
|
|
183
|
+
)}
|
|
78
184
|
</For>
|
|
79
185
|
<InfoCollapsablePane fields={props.nestedFields} record={record} htsFileMeta={props.htsFileMeta} />
|
|
80
186
|
</tr>
|
|
@@ -2,40 +2,49 @@ import { Component, Match, Switch } from "solid-js";
|
|
|
2
2
|
import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
|
|
3
3
|
import { FilterCategorical } from "./FilterCategorical";
|
|
4
4
|
import { FilterIntegerVim } from "./FilterIntegerVim";
|
|
5
|
+
import { FilterIntegerGq } from "./FilterIntegerGq";
|
|
5
6
|
import { FilterIntegerDp } from "./FilterIntegerDp";
|
|
6
7
|
import { FilterIntegerVid } from "./FilterIntegerVid";
|
|
7
|
-
import {
|
|
8
|
+
import { Item, Query, Sample } from "@molgenis/vip-report-api/src/Api";
|
|
8
9
|
import { FilterClinVar } from "./FilterClinVar";
|
|
9
10
|
import { isAnyCsqInfo } from "../../utils/csqUtils";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export type FilterClearEvent = { selector: Selector };
|
|
11
|
+
import { FilterChangeEvent, FilterClearEvent } from "./Filters";
|
|
12
|
+
import { FilterAllelicBalance } from "./FilterAllelicBalance";
|
|
13
13
|
|
|
14
14
|
export type FilterProps = {
|
|
15
15
|
field: FieldMetadata;
|
|
16
|
-
query?:
|
|
16
|
+
query?: Query;
|
|
17
17
|
onChange: (event: FilterChangeEvent) => void;
|
|
18
18
|
onClear: (event: FilterClearEvent) => void;
|
|
19
|
+
sample?: Item<Sample>;
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
export const Filter: Component<FilterProps> = (props) => {
|
|
22
23
|
return (
|
|
23
|
-
|
|
24
|
-
<
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
24
|
+
<>
|
|
25
|
+
<Switch>
|
|
26
|
+
<Match when={props.field.id === "GQ"}>
|
|
27
|
+
<FilterIntegerGq {...props} />
|
|
28
|
+
</Match>
|
|
29
|
+
<Match when={props.field.id === "DP"}>
|
|
30
|
+
<FilterIntegerDp {...props} />
|
|
31
|
+
</Match>
|
|
32
|
+
<Match when={props.field.id === "VID"}>
|
|
33
|
+
<FilterIntegerVid {...props} />
|
|
34
|
+
</Match>
|
|
35
|
+
<Match when={props.field.id === "VIM"}>
|
|
36
|
+
<FilterIntegerVim {...props} />
|
|
37
|
+
</Match>
|
|
38
|
+
<Match when={props.field.id === "VIAB"}>
|
|
39
|
+
<FilterAllelicBalance {...props} />
|
|
40
|
+
</Match>
|
|
41
|
+
<Match when={isAnyCsqInfo(props.field, ["clinVar_CLNSIG", "clinVar_CLNSIGINCL"])}>
|
|
42
|
+
<FilterClinVar {...props} />
|
|
43
|
+
</Match>
|
|
44
|
+
<Match when={props.field.type === "CATEGORICAL"}>
|
|
45
|
+
<FilterCategorical {...props} />
|
|
46
|
+
</Match>
|
|
47
|
+
</Switch>
|
|
48
|
+
</>
|
|
40
49
|
);
|
|
41
50
|
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Component } from "solid-js";
|
|
2
|
+
import { ComposedQuery, Item, Query, Sample, Selector } from "@molgenis/vip-report-api/src/Api";
|
|
3
|
+
import { Checkbox, CheckboxEvent } from "../Checkbox";
|
|
4
|
+
import { FilterChangeEvent, FilterClearEvent } from "./Filters";
|
|
5
|
+
import { selector, selectorKey } from "../../utils/query";
|
|
6
|
+
import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
|
|
7
|
+
|
|
8
|
+
export function getAllelicBalanceQuery(sampleIndex: number): ComposedQuery {
|
|
9
|
+
const hetQuery: ComposedQuery = {
|
|
10
|
+
operator: "and",
|
|
11
|
+
args: [
|
|
12
|
+
{ selector: ["s", sampleIndex, "GT", "t"], operator: "==", args: "het" },
|
|
13
|
+
{
|
|
14
|
+
operator: "and",
|
|
15
|
+
args: [
|
|
16
|
+
{ selector: ["s", sampleIndex, "VIAB"], operator: ">", args: 0.2 },
|
|
17
|
+
{ selector: ["s", sampleIndex, "VIAB"], operator: "<", args: 0.8 },
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
};
|
|
22
|
+
const homQuery: ComposedQuery = {
|
|
23
|
+
operator: "and",
|
|
24
|
+
args: [
|
|
25
|
+
{
|
|
26
|
+
operator: "or",
|
|
27
|
+
args: [
|
|
28
|
+
{ selector: ["s", sampleIndex, "GT", "t"], operator: "==", args: "hom_a" },
|
|
29
|
+
{ selector: ["s", sampleIndex, "GT", "t"], operator: "==", args: "hom_r" },
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
operator: "or",
|
|
34
|
+
args: [
|
|
35
|
+
{ selector: ["s", sampleIndex, "VIAB"], operator: "<", args: 0.02 },
|
|
36
|
+
{ selector: ["s", sampleIndex, "VIAB"], operator: ">", args: 0.98 },
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
const otherGtQuery: ComposedQuery = {
|
|
42
|
+
operator: "or",
|
|
43
|
+
args: [
|
|
44
|
+
{ selector: ["s", sampleIndex, "GT", "t"], operator: "==", args: "miss" },
|
|
45
|
+
{ selector: ["s", sampleIndex, "GT", "t"], operator: "==", args: "part" },
|
|
46
|
+
{ selector: ["s", sampleIndex, "VIAB"], operator: "==", args: null },
|
|
47
|
+
{ selector: ["s", sampleIndex, "VIAB"], operator: "==", args: undefined },
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
const combinedQuery: ComposedQuery = { operator: "or", args: [hetQuery, homQuery, otherGtQuery] };
|
|
51
|
+
|
|
52
|
+
return combinedQuery;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const FilterAllelicBalance: Component<{
|
|
56
|
+
field: FieldMetadata;
|
|
57
|
+
sample?: Item<Sample>;
|
|
58
|
+
query?: Query;
|
|
59
|
+
onChange: (event: FilterChangeEvent) => void;
|
|
60
|
+
onClear: (event: FilterClearEvent) => void;
|
|
61
|
+
}> = (props) => {
|
|
62
|
+
const onFilterChange = (event: CheckboxEvent) => {
|
|
63
|
+
const fieldSelector: Selector = ["s", (props.sample as Item<Sample>).data.index, ...selector(props.field)];
|
|
64
|
+
if (event.checked) {
|
|
65
|
+
props.onChange({
|
|
66
|
+
query: getAllelicBalanceQuery((props.sample?.data as Sample).index),
|
|
67
|
+
key: selectorKey(fieldSelector),
|
|
68
|
+
});
|
|
69
|
+
} else props.onClear({ key: selectorKey(fieldSelector) });
|
|
70
|
+
};
|
|
71
|
+
return (
|
|
72
|
+
<div class="control">
|
|
73
|
+
<Checkbox
|
|
74
|
+
desc="Filter variants with allelic imbalance; For hetrozygote calls: AB < 0.2 or AB > 0.8 and for homozygote calls: AB > 0.02 are consided allelic imbalance"
|
|
75
|
+
label="No allelic imbalance"
|
|
76
|
+
checked={props.query && props.query.args !== undefined}
|
|
77
|
+
onChange={onFilterChange}
|
|
78
|
+
/>
|
|
79
|
+
</div>
|
|
80
|
+
);
|
|
81
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Component, For } from "solid-js";
|
|
2
2
|
import { Checkbox, CheckboxEvent } from "../Checkbox";
|
|
3
3
|
import { FilterProps } from "./Filter";
|
|
4
|
-
import { selector } from "../../utils/query";
|
|
4
|
+
import { selector, selectorKey } from "../../utils/query";
|
|
5
5
|
|
|
6
6
|
export type CheckboxGroup = {
|
|
7
7
|
[key: string]: boolean;
|
|
@@ -35,6 +35,7 @@ export const FilterCategorical: Component<
|
|
|
35
35
|
.map((key) => (key !== nullValue ? key : null));
|
|
36
36
|
if (values.length > 0) {
|
|
37
37
|
props.onChange({
|
|
38
|
+
key: selectorKey(selector(props.field)),
|
|
38
39
|
query: {
|
|
39
40
|
selector: selector(props.field),
|
|
40
41
|
operator: props.field.number.count === 1 ? "has_any" : "any_has_any",
|
|
@@ -42,7 +43,7 @@ export const FilterCategorical: Component<
|
|
|
42
43
|
},
|
|
43
44
|
});
|
|
44
45
|
} else {
|
|
45
|
-
props.onClear({
|
|
46
|
+
props.onClear({ key: selectorKey(selector(props.field)) });
|
|
46
47
|
}
|
|
47
48
|
};
|
|
48
49
|
|
|
@@ -1,17 +1,32 @@
|
|
|
1
1
|
import { Component } from "solid-js";
|
|
2
2
|
import { FilterProps } from "./Filter";
|
|
3
3
|
import { Checkbox, CheckboxEvent } from "../Checkbox";
|
|
4
|
-
import { selector } from "../../utils/query";
|
|
4
|
+
import { selector, selectorKey } from "../../utils/query";
|
|
5
|
+
import { Item, Sample, Selector } from "@molgenis/vip-report-api/src/Api";
|
|
5
6
|
|
|
6
7
|
export const FilterIntegerDp: Component<FilterProps> = (props) => {
|
|
7
8
|
const onFilterChange = (event: CheckboxEvent) => {
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
const fieldSelector: Selector = ["s", (props.sample as Item<Sample>).data.index, ...selector(props.field)];
|
|
10
|
+
if (event.checked)
|
|
11
|
+
props.onChange({
|
|
12
|
+
key: selectorKey(fieldSelector),
|
|
13
|
+
query: {
|
|
14
|
+
selector: fieldSelector,
|
|
15
|
+
operator: ">=",
|
|
16
|
+
args: 10,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
else props.onClear({ key: selectorKey(fieldSelector) });
|
|
10
20
|
};
|
|
11
21
|
|
|
12
22
|
return (
|
|
13
23
|
<div class="control">
|
|
14
|
-
<Checkbox
|
|
24
|
+
<Checkbox
|
|
25
|
+
desc="Sequencing depth >= 10"
|
|
26
|
+
label="Depth >= 10"
|
|
27
|
+
checked={props.query && props.query.args === 10}
|
|
28
|
+
onChange={onFilterChange}
|
|
29
|
+
/>
|
|
15
30
|
</div>
|
|
16
31
|
);
|
|
17
32
|
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Component } from "solid-js";
|
|
2
|
+
import { FilterProps } from "./Filter";
|
|
3
|
+
import { Checkbox, CheckboxEvent } from "../Checkbox";
|
|
4
|
+
import { selector, selectorKey } from "../../utils/query";
|
|
5
|
+
import { Item, Sample, Selector } from "@molgenis/vip-report-api/src/Api";
|
|
6
|
+
|
|
7
|
+
export const FilterIntegerGq: Component<FilterProps> = (props) => {
|
|
8
|
+
const onFilterChange = (event: CheckboxEvent) => {
|
|
9
|
+
const fieldSelector: Selector = ["s", (props.sample as Item<Sample>).data.index, ...selector(props.field)];
|
|
10
|
+
if (event.checked)
|
|
11
|
+
props.onChange({
|
|
12
|
+
key: selectorKey(fieldSelector),
|
|
13
|
+
query: {
|
|
14
|
+
selector: fieldSelector,
|
|
15
|
+
operator: ">=",
|
|
16
|
+
args: 20,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
else props.onClear({ key: selectorKey(fieldSelector) });
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div class="control">
|
|
24
|
+
<Checkbox
|
|
25
|
+
desc="Genotype quality >= 20"
|
|
26
|
+
label="GT quality >= 20"
|
|
27
|
+
checked={props.query && props.query.args === 20}
|
|
28
|
+
onChange={onFilterChange}
|
|
29
|
+
/>
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
};
|
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import { Component } from "solid-js";
|
|
2
2
|
import { FilterProps } from "./Filter";
|
|
3
3
|
import { Checkbox, CheckboxEvent } from "../Checkbox";
|
|
4
|
-
import { selector } from "../../utils/query";
|
|
4
|
+
import { selector, selectorKey } from "../../utils/query";
|
|
5
|
+
import { Item, Sample, Selector } from "@molgenis/vip-report-api/src/Api";
|
|
5
6
|
|
|
6
7
|
export const FilterIntegerVid: Component<FilterProps> = (props) => {
|
|
7
8
|
const onFilterChange = (event: CheckboxEvent) => {
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
const fieldSelector: Selector = ["s", (props.sample as Item<Sample>).data.index, ...selector(props.field)];
|
|
10
|
+
if (event.checked)
|
|
11
|
+
props.onChange({
|
|
12
|
+
key: selectorKey(fieldSelector),
|
|
13
|
+
query: {
|
|
14
|
+
selector: fieldSelector,
|
|
15
|
+
operator: "==",
|
|
16
|
+
args: 1,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
else props.onClear({ key: selectorKey(fieldSelector) });
|
|
10
20
|
};
|
|
11
21
|
|
|
12
22
|
return (
|
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import { Component } from "solid-js";
|
|
2
2
|
import { FilterProps } from "./Filter";
|
|
3
3
|
import { Checkbox, CheckboxEvent } from "../Checkbox";
|
|
4
|
-
import { selector } from "../../utils/query";
|
|
4
|
+
import { selector, selectorKey } from "../../utils/query";
|
|
5
|
+
import { Item, Sample, Selector } from "@molgenis/vip-report-api/src/Api";
|
|
5
6
|
|
|
6
7
|
export const FilterIntegerVim: Component<FilterProps> = (props) => {
|
|
7
8
|
const onFilterChange = (event: CheckboxEvent) => {
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
const fieldSelector: Selector = ["s", (props.sample as Item<Sample>).data.index, ...selector(props.field)];
|
|
10
|
+
if (event.checked)
|
|
11
|
+
props.onChange({
|
|
12
|
+
key: selectorKey(fieldSelector),
|
|
13
|
+
query: {
|
|
14
|
+
selector: fieldSelector,
|
|
15
|
+
operator: "==",
|
|
16
|
+
args: 1,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
else props.onClear({ key: selectorKey(fieldSelector) });
|
|
10
20
|
};
|
|
11
21
|
|
|
12
22
|
return (
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Component } from "solid-js";
|
|
2
2
|
import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
|
|
3
|
-
import { Item, Sample } from "@molgenis/vip-report-api/src/Api";
|
|
3
|
+
import { Item, Query, Sample } from "@molgenis/vip-report-api/src/Api";
|
|
4
4
|
import { InfoFilters } from "./InfoFilters";
|
|
5
5
|
import { SamplesFilters } from "./SamplesFilters";
|
|
6
|
-
import { FilterChangeEvent, FilterClearEvent } from "./Filter";
|
|
7
6
|
import { FilterQueries } from "../../store";
|
|
8
7
|
|
|
8
|
+
export type FilterChangeEvent = { key: string; query: Query };
|
|
9
|
+
export type FilterClearEvent = { key: string };
|
|
10
|
+
|
|
9
11
|
export const Filters: Component<{
|
|
10
12
|
fields: FieldMetadata[];
|
|
11
13
|
samplesFields: { sample: Item<Sample>; fields: FieldMetadata[] }[];
|
|
@@ -13,17 +15,14 @@ export const Filters: Component<{
|
|
|
13
15
|
onChange: (event: FilterChangeEvent) => void;
|
|
14
16
|
onClear: (event: FilterClearEvent) => void;
|
|
15
17
|
}> = (props) => {
|
|
16
|
-
const onChange = (event: FilterChangeEvent) => props.onChange(event);
|
|
17
|
-
const onClear = (event: FilterClearEvent) => props.onClear(event);
|
|
18
|
-
|
|
19
18
|
return (
|
|
20
19
|
<>
|
|
21
|
-
<InfoFilters fields={props.fields} queries={props.queries} onChange={onChange} onClear={onClear} />
|
|
20
|
+
<InfoFilters fields={props.fields} queries={props.queries} onChange={props.onChange} onClear={props.onClear} />
|
|
22
21
|
<SamplesFilters
|
|
23
22
|
samplesFields={props.samplesFields}
|
|
24
23
|
queries={props.queries}
|
|
25
|
-
onChange={onChange}
|
|
26
|
-
onClear={onClear}
|
|
24
|
+
onChange={props.onChange}
|
|
25
|
+
onClear={props.onClear}
|
|
27
26
|
/>
|
|
28
27
|
</>
|
|
29
28
|
);
|
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
import { Component } from "solid-js";
|
|
2
|
-
import { Filter,
|
|
3
|
-
import {
|
|
2
|
+
import { Filter, FilterProps } from "./Filter";
|
|
3
|
+
import { FilterChangeEvent, FilterClearEvent } from "./Filters";
|
|
4
|
+
import { QueryClause, SelectorPart } from "@molgenis/vip-report-api/src/Api";
|
|
5
|
+
import { selectorKey } from "../../utils/query";
|
|
4
6
|
|
|
5
7
|
export const InfoFilter: Component<FilterProps> = (props) => {
|
|
6
8
|
const label = () => (props.field.label !== undefined ? props.field.label : props.field.id);
|
|
7
9
|
|
|
8
10
|
const onChange = (event: FilterChangeEvent) => {
|
|
9
11
|
props.onChange({
|
|
10
|
-
|
|
12
|
+
key: selectorKey(["n", event.key]),
|
|
13
|
+
query: {
|
|
14
|
+
...(event.query as QueryClause),
|
|
15
|
+
selector: ["n", ...((event.query as QueryClause).selector as SelectorPart[])],
|
|
16
|
+
},
|
|
11
17
|
});
|
|
12
18
|
};
|
|
13
19
|
|
|
14
20
|
const onClear = (event: FilterClearEvent) => {
|
|
15
21
|
props.onClear({
|
|
16
|
-
|
|
22
|
+
key: selectorKey(["n", event.key]),
|
|
17
23
|
});
|
|
18
24
|
};
|
|
19
25
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Component, For } from "solid-js";
|
|
2
2
|
import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
|
|
3
|
-
import { FilterChangeEvent, FilterClearEvent } from "./Filter";
|
|
4
3
|
import { InfoFilter } from "./InfoFilter";
|
|
5
4
|
import { Value } from "@molgenis/vip-report-vcf/src/ValueParser";
|
|
6
5
|
import { FilterQueries } from "../../store";
|
|
7
6
|
import { infoFieldKey } from "../../utils/query";
|
|
7
|
+
import { FilterChangeEvent, FilterClearEvent } from "./Filters";
|
|
8
8
|
|
|
9
9
|
export const InfoFilters: Component<{
|
|
10
10
|
fields: FieldMetadata[];
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Component, For } from "solid-js";
|
|
2
2
|
import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
|
|
3
|
-
import { Item, Sample
|
|
4
|
-
import { Filter
|
|
3
|
+
import { Item, Sample } from "@molgenis/vip-report-api/src/Api";
|
|
4
|
+
import { Filter } from "./Filter";
|
|
5
5
|
import { FilterQueries } from "../../store";
|
|
6
6
|
import { sampleFieldKey } from "../../utils/query";
|
|
7
|
+
import { FilterChangeEvent, FilterClearEvent } from "./Filters";
|
|
7
8
|
|
|
8
9
|
export const SampleFilters: Component<{
|
|
9
10
|
sample: Item<Sample>;
|
|
@@ -12,17 +13,9 @@ export const SampleFilters: Component<{
|
|
|
12
13
|
onChange: (event: FilterChangeEvent) => void;
|
|
13
14
|
onClear: (event: FilterClearEvent) => void;
|
|
14
15
|
}> = (props) => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
});
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const onClear = (event: FilterClearEvent) => {
|
|
22
|
-
props.onClear({
|
|
23
|
-
selector: ["s", props.sample.data.index, ...(event.selector as SelectorPart[])],
|
|
24
|
-
});
|
|
25
|
-
};
|
|
16
|
+
if (props.sample == undefined) {
|
|
17
|
+
throw Error("Cannot create Sample filters without a sample.");
|
|
18
|
+
}
|
|
26
19
|
|
|
27
20
|
return (
|
|
28
21
|
<>
|
|
@@ -30,12 +23,16 @@ export const SampleFilters: Component<{
|
|
|
30
23
|
<div class="field">
|
|
31
24
|
<For each={props.fields}>
|
|
32
25
|
{(field) => (
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
26
|
+
<>
|
|
27
|
+
{" "}
|
|
28
|
+
<Filter
|
|
29
|
+
field={field}
|
|
30
|
+
query={props.queries ? props.queries[sampleFieldKey(props.sample, field)] : undefined}
|
|
31
|
+
onChange={props.onChange}
|
|
32
|
+
onClear={props.onClear}
|
|
33
|
+
sample={props.sample}
|
|
34
|
+
/>
|
|
35
|
+
</>
|
|
39
36
|
)}
|
|
40
37
|
</For>
|
|
41
38
|
</div>
|