@molgenis/vip-report-template 5.5.5 → 5.7.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/.nvmrc +1 -0
- package/.travis.yml +0 -2
- package/package.json +22 -22
- package/src/App.tsx +7 -0
- package/src/components/filter/Filter.tsx +12 -0
- package/src/components/filter/FilterCategorical.tsx +26 -19
- package/src/components/filter/FilterGene.tsx +34 -0
- package/src/components/filter/FilterHpo.tsx +33 -27
- package/src/components/filter/FilterInheritance.tsx +39 -9
- package/src/components/filter/FilterIntegerDp.tsx +19 -4
- package/src/components/filter/FilterIntegerGq.tsx +19 -4
- package/src/components/filter/FilterVI.tsx +68 -0
- package/src/components/filter/FilterVariantType.tsx +148 -0
- package/src/components/filter/InfoFilter.tsx +1 -13
- package/src/components/filter/InfoFilters.tsx +4 -1
- package/src/components/filter/SampleFilters.tsx +26 -2
- package/src/components/record/RecordDownload.tsx +21 -2
- package/src/components/record/info/GnomAD.tsx +33 -28
- package/src/components/record/info/InheritanceModes.tsx +2 -2
- package/src/mocks/GRCh37/vcf/family.vcf.blob +7 -6
- package/src/utils/ApiUtils.ts +6 -1
- package/src/views/Help.tsx +13 -0
- package/src/views/SampleVariants.tsx +52 -5
- package/src/views/data/SampleData.tsx +2 -0
- package/src/views/data/SampleVariantConsequenceData.tsx +1 -0
- package/src/views/data/SampleVariantData.tsx +1 -0
- package/src/views/data/VariantConsequenceData.tsx +1 -0
- package/src/views/data/VariantData.tsx +1 -0
- package/tsconfig.json +1 -1
- package/{vite.config.ts → vite.config.mts} +2 -2
package/.nvmrc
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
18.18.2
|
package/.travis.yml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@molgenis/vip-report-template",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.7.0",
|
|
4
4
|
"description": "Report Template for Variant Call Format (VCF) Report Generator",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "vite build",
|
|
@@ -15,33 +15,33 @@
|
|
|
15
15
|
},
|
|
16
16
|
"license": "LGPL-3.0",
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"@molgenis/vite-plugin-inline": "^1.0.
|
|
19
|
-
"@typescript-eslint/eslint-plugin": "^6.
|
|
20
|
-
"@typescript-eslint/parser": "^6.
|
|
21
|
-
"@vitest/coverage-v8": "^0.
|
|
18
|
+
"@molgenis/vite-plugin-inline": "^1.0.19",
|
|
19
|
+
"@typescript-eslint/eslint-plugin": "^6.13.2",
|
|
20
|
+
"@typescript-eslint/parser": "^6.13.2",
|
|
21
|
+
"@vitest/coverage-v8": "^1.0.1",
|
|
22
22
|
"bulma": "^0.9.4",
|
|
23
|
-
"eslint": "^8.
|
|
24
|
-
"eslint-config-prettier": "^9.
|
|
25
|
-
"eslint-plugin-prettier": "^5.0.
|
|
23
|
+
"eslint": "^8.55.0",
|
|
24
|
+
"eslint-config-prettier": "^9.1.0",
|
|
25
|
+
"eslint-plugin-prettier": "^5.0.1",
|
|
26
26
|
"eslint-plugin-solid": "^0.13.0",
|
|
27
27
|
"husky": "^8.0.3",
|
|
28
|
-
"jsdom": "^
|
|
29
|
-
"prettier": "^3.0
|
|
30
|
-
"sass": "^1.
|
|
31
|
-
"typescript": "^5.
|
|
32
|
-
"vite": "^
|
|
33
|
-
"vite-plugin-solid": "^2.7.
|
|
34
|
-
"vitest": "^0.
|
|
28
|
+
"jsdom": "^23.0.1",
|
|
29
|
+
"prettier": "^3.1.0",
|
|
30
|
+
"sass": "^1.69.5",
|
|
31
|
+
"typescript": "^5.3.3",
|
|
32
|
+
"vite": "^5.0.6",
|
|
33
|
+
"vite-plugin-solid": "^2.7.2",
|
|
34
|
+
"vitest": "^1.0.1"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@fortawesome/fontawesome-svg-core": "^6.
|
|
38
|
-
"@fortawesome/free-solid-svg-icons": "^6.
|
|
39
|
-
"@molgenis/vip-report-api": "^4.
|
|
40
|
-
"@molgenis/vip-report-vcf": "^1.
|
|
41
|
-
"@solidjs/router": "^0.
|
|
37
|
+
"@fortawesome/fontawesome-svg-core": "^6.5.1",
|
|
38
|
+
"@fortawesome/free-solid-svg-icons": "^6.5.1",
|
|
39
|
+
"@molgenis/vip-report-api": "^4.7.0",
|
|
40
|
+
"@molgenis/vip-report-vcf": "^1.7.0",
|
|
41
|
+
"@solidjs/router": "^0.9.1",
|
|
42
42
|
"base64-js": "^1.5.1",
|
|
43
|
-
"igv": "^2.15.
|
|
44
|
-
"solid-js": "^1.7
|
|
43
|
+
"igv": "^2.15.11",
|
|
44
|
+
"solid-js": "^1.8.7"
|
|
45
45
|
},
|
|
46
46
|
"lint-staged": {
|
|
47
47
|
"src/**/*.{tsx,ts}": [
|
package/src/App.tsx
CHANGED
|
@@ -17,6 +17,7 @@ import api from "./Api";
|
|
|
17
17
|
import { DatasetDropdown } from "./components/DatasetDropdown";
|
|
18
18
|
import SampleVariantConsequenceData from "./views/data/SampleVariantConsequenceData";
|
|
19
19
|
import VariantConsequenceData from "./views/data/VariantConsequenceData";
|
|
20
|
+
import { Help } from "./views/Help";
|
|
20
21
|
|
|
21
22
|
const App: Component = () => {
|
|
22
23
|
const navigate = useNavigate();
|
|
@@ -57,6 +58,11 @@ const App: Component = () => {
|
|
|
57
58
|
</Link>
|
|
58
59
|
{api.isDatasetSupport() && <DatasetDropdown />}
|
|
59
60
|
</div>
|
|
61
|
+
<div class="navbar-end">
|
|
62
|
+
<Link class="navbar-item" href="/help">
|
|
63
|
+
Help
|
|
64
|
+
</Link>
|
|
65
|
+
</div>
|
|
60
66
|
</div>
|
|
61
67
|
</nav>
|
|
62
68
|
<div class="container is-fluid">
|
|
@@ -91,6 +97,7 @@ const App: Component = () => {
|
|
|
91
97
|
</Route>
|
|
92
98
|
</Route>
|
|
93
99
|
</Route>
|
|
100
|
+
<Route path="/help" element={<Help />} />
|
|
94
101
|
</Routes>
|
|
95
102
|
</ErrorBoundary>
|
|
96
103
|
</div>
|
|
@@ -9,6 +9,9 @@ import { isAnyCsqInfo } from "../../utils/csqUtils";
|
|
|
9
9
|
import { FilterChangeEvent, FilterClearEvent } from "./Filters";
|
|
10
10
|
import { FilterAllelicBalance } from "./FilterAllelicBalance";
|
|
11
11
|
import { FilterHpo } from "./FilterHpo";
|
|
12
|
+
import { FilterGene } from "./FilterGene";
|
|
13
|
+
import { FilterVI } from "./FilterVI";
|
|
14
|
+
import { FilterVariantType } from "./FilterVariantType";
|
|
12
15
|
|
|
13
16
|
export type FilterProps = {
|
|
14
17
|
field: FieldMetadata;
|
|
@@ -31,12 +34,21 @@ export const Filter: Component<FilterProps> = (props) => {
|
|
|
31
34
|
<Match when={props.field.id === "VIAB"}>
|
|
32
35
|
<FilterAllelicBalance {...props} />
|
|
33
36
|
</Match>
|
|
37
|
+
<Match when={props.field.id === "VI"}>
|
|
38
|
+
<FilterVI {...props} />
|
|
39
|
+
</Match>
|
|
40
|
+
<Match when={props.field.id === "SVTYPE"}>
|
|
41
|
+
<FilterVariantType {...props} />
|
|
42
|
+
</Match>
|
|
34
43
|
<Match when={isAnyCsqInfo(props.field, ["clinVar_CLNSIG", "clinVar_CLNSIGINCL"])}>
|
|
35
44
|
<FilterClinVar {...props} />
|
|
36
45
|
</Match>
|
|
37
46
|
<Match when={props.field.id === "HPO"}>
|
|
38
47
|
<FilterHpo {...props} />
|
|
39
48
|
</Match>
|
|
49
|
+
<Match when={props.field.id === "IncompletePenetrance"}>
|
|
50
|
+
<FilterGene {...props} />
|
|
51
|
+
</Match>
|
|
40
52
|
<Match when={props.field.type === "CATEGORICAL"}>
|
|
41
53
|
<FilterCategorical {...props} />
|
|
42
54
|
</Match>
|
|
@@ -17,6 +17,7 @@ export const FilterCategorical: Component<
|
|
|
17
17
|
}
|
|
18
18
|
> = (props) => {
|
|
19
19
|
const group: CheckboxGroup = {};
|
|
20
|
+
const label = () => (props.field.label !== undefined ? props.field.label : props.field.id);
|
|
20
21
|
if (props.query !== undefined) {
|
|
21
22
|
(props.query?.args as string[]).forEach((key) => {
|
|
22
23
|
group[key] = true;
|
|
@@ -49,26 +50,32 @@ export const FilterCategorical: Component<
|
|
|
49
50
|
|
|
50
51
|
return (
|
|
51
52
|
<>
|
|
52
|
-
<
|
|
53
|
-
{(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
53
|
+
<p class="has-text-weight-semibold">
|
|
54
|
+
{props.field.description ? <abbr title={props.field.description}>{label()}</abbr> : <span>{label()}</span>}
|
|
55
|
+
</p>
|
|
56
|
+
|
|
57
|
+
<div class="field">
|
|
58
|
+
<For each={props.field.categories}>
|
|
59
|
+
{(category) => (
|
|
60
|
+
<div class="control">
|
|
61
|
+
<Checkbox
|
|
62
|
+
value={category}
|
|
63
|
+
label={props.labels ? props.labels[category] : category}
|
|
64
|
+
checked={props.query && (props.query.args as (string | null)[]).includes(category)}
|
|
65
|
+
onChange={onChange}
|
|
66
|
+
/>
|
|
67
|
+
</div>
|
|
68
|
+
)}
|
|
69
|
+
</For>
|
|
70
|
+
{includeNullCategory() && (
|
|
71
|
+
<Checkbox
|
|
72
|
+
value={nullValue}
|
|
73
|
+
label="No value"
|
|
74
|
+
checked={props.query && (props.query.args as (string | null)[]).includes(null)}
|
|
75
|
+
onChange={onChange}
|
|
76
|
+
/>
|
|
62
77
|
)}
|
|
63
|
-
</
|
|
64
|
-
{includeNullCategory() && (
|
|
65
|
-
<Checkbox
|
|
66
|
-
value={nullValue}
|
|
67
|
-
label="No value"
|
|
68
|
-
checked={props.query && (props.query.args as (string | null)[]).includes(null)}
|
|
69
|
-
onChange={onChange}
|
|
70
|
-
/>
|
|
71
|
-
)}
|
|
78
|
+
</div>
|
|
72
79
|
</>
|
|
73
80
|
);
|
|
74
81
|
};
|
|
@@ -0,0 +1,34 @@
|
|
|
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
|
+
|
|
6
|
+
export const FilterGene: Component<FilterProps> = (props) => {
|
|
7
|
+
const onFilterChange = (event: CheckboxEvent) => {
|
|
8
|
+
const fieldSelector = selector(props.field);
|
|
9
|
+
if (event.checked) {
|
|
10
|
+
props.onChange({
|
|
11
|
+
key: selectorKey(fieldSelector),
|
|
12
|
+
query: {
|
|
13
|
+
selector: fieldSelector,
|
|
14
|
+
operator: "any_has_any",
|
|
15
|
+
args: ["1"],
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
} else props.onClear({ key: selectorKey(fieldSelector) });
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<>
|
|
23
|
+
<p class="has-text-weight-semibold">{<span>Various</span>}</p>
|
|
24
|
+
<div class="field">
|
|
25
|
+
<Checkbox
|
|
26
|
+
desc="Gene is associated with incomplete penetrance"
|
|
27
|
+
label="Inc. Penetrance"
|
|
28
|
+
checked={props.query && props.query.args !== undefined}
|
|
29
|
+
onChange={onFilterChange}
|
|
30
|
+
/>
|
|
31
|
+
</div>
|
|
32
|
+
</>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
@@ -21,6 +21,7 @@ export const FilterHpo: Component<
|
|
|
21
21
|
const group: CheckboxGroup = {};
|
|
22
22
|
const hpoSelector = selector(props.field);
|
|
23
23
|
const csqMeta = props.field.parent;
|
|
24
|
+
const label = () => (props.field.label !== undefined ? props.field.label : props.field.id);
|
|
24
25
|
let gadoHcChecked = false;
|
|
25
26
|
let gadoLcChecked = false;
|
|
26
27
|
let hpoValues: (string | null)[] = [];
|
|
@@ -118,38 +119,43 @@ export const FilterHpo: Component<
|
|
|
118
119
|
};
|
|
119
120
|
return (
|
|
120
121
|
<>
|
|
121
|
-
<
|
|
122
|
-
{(
|
|
122
|
+
<p class="has-text-weight-semibold">
|
|
123
|
+
{props.field.description ? <abbr title={props.field.description}>{label()}</abbr> : <span>{label()}</span>}
|
|
124
|
+
</p>
|
|
125
|
+
<div class="field">
|
|
126
|
+
<For each={props.field.categories}>
|
|
127
|
+
{(category) => (
|
|
128
|
+
<div class="control">
|
|
129
|
+
<Checkbox
|
|
130
|
+
value={category}
|
|
131
|
+
label={props.labels ? props.labels[category] : category}
|
|
132
|
+
checked={hpoValues && hpoValues.includes(category)}
|
|
133
|
+
onChange={onChange}
|
|
134
|
+
/>
|
|
135
|
+
</div>
|
|
136
|
+
)}
|
|
137
|
+
</For>
|
|
138
|
+
<Show when={gadoMeta !== null}>
|
|
123
139
|
<div class="control">
|
|
124
140
|
<Checkbox
|
|
125
|
-
value=
|
|
126
|
-
label=
|
|
127
|
-
|
|
141
|
+
value="gado_hc"
|
|
142
|
+
label="GADO high"
|
|
143
|
+
desc="Gene predicted to have a relation with phenotypes of the proband (phenotypes of other samples are ignored!) with high confidence (Z-Score above 5)."
|
|
144
|
+
checked={gadoHcChecked}
|
|
128
145
|
onChange={onChange}
|
|
129
146
|
/>
|
|
130
147
|
</div>
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
</div>
|
|
143
|
-
<div class="control">
|
|
144
|
-
<Checkbox
|
|
145
|
-
value="gado_lc"
|
|
146
|
-
label="GADO low"
|
|
147
|
-
desc="Gene predicted to have a relation with phenotypes of the proband (phenotypes of other samples are ignored!) with low confidence (Z-Score above 3 but below 5)."
|
|
148
|
-
checked={gadoLcChecked}
|
|
149
|
-
onChange={onChange}
|
|
150
|
-
/>
|
|
151
|
-
</div>
|
|
152
|
-
</Show>
|
|
148
|
+
<div class="control">
|
|
149
|
+
<Checkbox
|
|
150
|
+
value="gado_lc"
|
|
151
|
+
label="GADO low"
|
|
152
|
+
desc="Gene predicted to have a relation with phenotypes of the proband (phenotypes of other samples are ignored!) with low confidence (Z-Score above 3 but below 5)."
|
|
153
|
+
checked={gadoLcChecked}
|
|
154
|
+
onChange={onChange}
|
|
155
|
+
/>
|
|
156
|
+
</div>
|
|
157
|
+
</Show>
|
|
158
|
+
</div>
|
|
153
159
|
</>
|
|
154
160
|
);
|
|
155
161
|
};
|
|
@@ -17,11 +17,13 @@ export type FilterInheritanceProps = {
|
|
|
17
17
|
export const FilterInheritance: Component<FilterInheritanceProps> = (props) => {
|
|
18
18
|
const VIM_TRUE = "VIM_true";
|
|
19
19
|
const VIM_MISSING = "VIM_missing";
|
|
20
|
-
const VID = "
|
|
20
|
+
const VID = "VID_true";
|
|
21
|
+
const VID_MISSING = "VID_missing";
|
|
21
22
|
|
|
22
23
|
let isVimMissingChecked = false;
|
|
23
24
|
let isVimTrueChecked = false;
|
|
24
|
-
let
|
|
25
|
+
let isVidTrueChecked = false;
|
|
26
|
+
let isVidMissingChecked = false;
|
|
25
27
|
|
|
26
28
|
const vimFieldSelector: Selector = ["s", props.sample.data.index, ...selector(props.vimField)];
|
|
27
29
|
const vidFieldSelector: Selector = ["s", props.sample.data.index, ...selector(props.vidField)];
|
|
@@ -37,7 +39,12 @@ export const FilterInheritance: Component<FilterInheritanceProps> = (props) => {
|
|
|
37
39
|
) {
|
|
38
40
|
isVimMissingChecked = true;
|
|
39
41
|
} else if (selectorKeyValue === selectorKey(vidFieldSelector) && query.args === 1) {
|
|
40
|
-
|
|
42
|
+
isVidTrueChecked = true;
|
|
43
|
+
} else if (
|
|
44
|
+
selectorKeyValue === selectorKey(vidFieldSelector) &&
|
|
45
|
+
(query.args === null || query.args === undefined)
|
|
46
|
+
) {
|
|
47
|
+
isVidMissingChecked = true;
|
|
41
48
|
}
|
|
42
49
|
});
|
|
43
50
|
}
|
|
@@ -71,15 +78,29 @@ export const FilterInheritance: Component<FilterInheritanceProps> = (props) => {
|
|
|
71
78
|
} else if (isVimMissingChecked && event.value === VIM_MISSING && !event.checked) {
|
|
72
79
|
isVimMissingChecked = false;
|
|
73
80
|
}
|
|
74
|
-
if ((event.value === VID && event.checked) || (
|
|
81
|
+
if ((event.value === VID && event.checked) || (isVidTrueChecked && event.value !== VID)) {
|
|
75
82
|
queries.push({
|
|
76
83
|
selector: vidFieldSelector,
|
|
77
84
|
operator: "==",
|
|
78
85
|
args: 1,
|
|
79
86
|
});
|
|
80
|
-
|
|
81
|
-
} else if (
|
|
82
|
-
|
|
87
|
+
isVidTrueChecked = true;
|
|
88
|
+
} else if ((event.value === VID_MISSING && event.checked) || (isVidMissingChecked && event.value !== VID_MISSING)) {
|
|
89
|
+
queries.push(
|
|
90
|
+
{
|
|
91
|
+
selector: vidFieldSelector,
|
|
92
|
+
operator: "==",
|
|
93
|
+
args: null,
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
selector: vidFieldSelector,
|
|
97
|
+
operator: "==",
|
|
98
|
+
args: undefined,
|
|
99
|
+
},
|
|
100
|
+
);
|
|
101
|
+
isVimMissingChecked = true;
|
|
102
|
+
} else if (isVidTrueChecked && event.value === VID && !event.checked) {
|
|
103
|
+
isVidTrueChecked = false;
|
|
83
104
|
}
|
|
84
105
|
if (queries.length > 0) {
|
|
85
106
|
props.onChange({
|
|
@@ -108,7 +129,7 @@ export const FilterInheritance: Component<FilterInheritanceProps> = (props) => {
|
|
|
108
129
|
<div class="control">
|
|
109
130
|
<Checkbox
|
|
110
131
|
value={VIM_MISSING}
|
|
111
|
-
label="Match:
|
|
132
|
+
label="Match: Potential"
|
|
112
133
|
desc="Genotypes, affected statuses match but gene inheritance pattern is unknown (can include de novo variants)."
|
|
113
134
|
checked={isVimMissingChecked}
|
|
114
135
|
onChange={onFilterChange}
|
|
@@ -123,7 +144,16 @@ export const FilterInheritance: Component<FilterInheritanceProps> = (props) => {
|
|
|
123
144
|
On the X chromosome:
|
|
124
145
|
- Female proband: same as autosomes.
|
|
125
146
|
- Male proband: Mother does not have the variant, or mother genotype missing."
|
|
126
|
-
checked={
|
|
147
|
+
checked={isVidTrueChecked}
|
|
148
|
+
onChange={onFilterChange}
|
|
149
|
+
/>
|
|
150
|
+
</div>
|
|
151
|
+
<div class="control">
|
|
152
|
+
<Checkbox
|
|
153
|
+
value={VID_MISSING}
|
|
154
|
+
label="De novo: Potential"
|
|
155
|
+
desc="Variant could be denovo but some genotype data of the sample or parents is missing."
|
|
156
|
+
checked={isVidTrueChecked}
|
|
127
157
|
onChange={onFilterChange}
|
|
128
158
|
/>
|
|
129
159
|
</div>
|
|
@@ -11,9 +11,24 @@ export const FilterIntegerDp: Component<FilterProps> = (props) => {
|
|
|
11
11
|
props.onChange({
|
|
12
12
|
key: selectorKey(fieldSelector),
|
|
13
13
|
query: {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
operator: "or",
|
|
15
|
+
args: [
|
|
16
|
+
{
|
|
17
|
+
selector: fieldSelector,
|
|
18
|
+
operator: ">=",
|
|
19
|
+
args: 20,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
selector: fieldSelector,
|
|
23
|
+
operator: "==",
|
|
24
|
+
args: null,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
selector: fieldSelector,
|
|
28
|
+
operator: "==",
|
|
29
|
+
args: undefined,
|
|
30
|
+
},
|
|
31
|
+
],
|
|
17
32
|
},
|
|
18
33
|
});
|
|
19
34
|
else props.onClear({ key: selectorKey(fieldSelector) });
|
|
@@ -24,7 +39,7 @@ export const FilterIntegerDp: Component<FilterProps> = (props) => {
|
|
|
24
39
|
<Checkbox
|
|
25
40
|
desc="Sequencing depth >= 20"
|
|
26
41
|
label="Depth >= 20"
|
|
27
|
-
checked={props.query && props.query.args
|
|
42
|
+
checked={props.query && props.query.args !== undefined}
|
|
28
43
|
onChange={onFilterChange}
|
|
29
44
|
/>
|
|
30
45
|
</div>
|
|
@@ -11,9 +11,24 @@ export const FilterIntegerGq: Component<FilterProps> = (props) => {
|
|
|
11
11
|
props.onChange({
|
|
12
12
|
key: selectorKey(fieldSelector),
|
|
13
13
|
query: {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
operator: "or",
|
|
15
|
+
args: [
|
|
16
|
+
{
|
|
17
|
+
selector: fieldSelector,
|
|
18
|
+
operator: ">=",
|
|
19
|
+
args: 20,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
selector: fieldSelector,
|
|
23
|
+
operator: "==",
|
|
24
|
+
args: null,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
selector: fieldSelector,
|
|
28
|
+
operator: "==",
|
|
29
|
+
args: undefined,
|
|
30
|
+
},
|
|
31
|
+
],
|
|
17
32
|
},
|
|
18
33
|
});
|
|
19
34
|
else props.onClear({ key: selectorKey(fieldSelector) });
|
|
@@ -24,7 +39,7 @@ export const FilterIntegerGq: Component<FilterProps> = (props) => {
|
|
|
24
39
|
<Checkbox
|
|
25
40
|
desc="Genotype quality >= 20"
|
|
26
41
|
label="GT quality >= 20"
|
|
27
|
-
checked={props.query && props.query.args
|
|
42
|
+
checked={props.query && props.query.args !== undefined}
|
|
28
43
|
onChange={onFilterChange}
|
|
29
44
|
/>
|
|
30
45
|
</div>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Component, For } from "solid-js";
|
|
2
|
+
import { Checkbox, CheckboxEvent } from "../Checkbox";
|
|
3
|
+
import { FilterProps } from "./Filter";
|
|
4
|
+
import { selector, selectorKey } from "../../utils/query";
|
|
5
|
+
import { Item, Sample, Selector } from "@molgenis/vip-report-api/src/Api";
|
|
6
|
+
|
|
7
|
+
export type CheckboxGroup = {
|
|
8
|
+
[key: string]: boolean;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type CategoryDescriptions = {
|
|
12
|
+
[key: string]: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const labels: CategoryDescriptions = {
|
|
16
|
+
AR_C: "Autosomal Recessive: Compound Hetrozygote",
|
|
17
|
+
AD_IP: "Autosomal Dominant: Incomplete Penentrance",
|
|
18
|
+
AR: "Autosomal Recessive",
|
|
19
|
+
AD: "Autosomal Dominant",
|
|
20
|
+
XLD: "X-Linked Dominant",
|
|
21
|
+
XLR: "X-Linked Recessive",
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const FilterVI: Component<FilterProps> = (props) => {
|
|
25
|
+
const group: CheckboxGroup = {};
|
|
26
|
+
if (props.query !== undefined) {
|
|
27
|
+
(props.query?.args as string[]).forEach((key) => {
|
|
28
|
+
group[key] = true;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// enable null category for any_has_any case if someone asks for it (requires query to be composed)
|
|
33
|
+
const fieldSelector: Selector = ["s", (props.sample as Item<Sample>).data.index, ...selector(props.field)];
|
|
34
|
+
const onChange = (event: CheckboxEvent) => {
|
|
35
|
+
group[event.value] = event.checked;
|
|
36
|
+
const values = Object.keys(group).filter((key) => group[key]);
|
|
37
|
+
if (values.length > 0) {
|
|
38
|
+
props.onChange({
|
|
39
|
+
key: selectorKey(fieldSelector),
|
|
40
|
+
query: {
|
|
41
|
+
selector: fieldSelector,
|
|
42
|
+
operator: "has_any",
|
|
43
|
+
args: values,
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
} else {
|
|
47
|
+
props.onClear({ key: selectorKey(fieldSelector) });
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<>
|
|
53
|
+
<For each={props.field.categories}>
|
|
54
|
+
{(category) => (
|
|
55
|
+
<div class="control">
|
|
56
|
+
<Checkbox
|
|
57
|
+
value={category}
|
|
58
|
+
label={category}
|
|
59
|
+
desc={labels[category] !== undefined ? labels[category] : category}
|
|
60
|
+
checked={props.query && (props.query.args as (string | null)[]).includes(category)}
|
|
61
|
+
onChange={onChange}
|
|
62
|
+
/>
|
|
63
|
+
</div>
|
|
64
|
+
)}
|
|
65
|
+
</For>
|
|
66
|
+
</>
|
|
67
|
+
);
|
|
68
|
+
};
|