@molgenis/vip-report-template 6.0.1 → 6.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/.husky/pre-commit +0 -3
- package/.travis.yml +5 -2
- package/index.html +1 -1
- package/package.json +23 -23
- package/src/App.tsx +27 -68
- package/src/__tests__/sample.test.ts +184 -0
- package/src/assets/sass/main.scss +12 -47
- package/src/components/Breadcrumb.tsx +6 -6
- package/src/components/InfoCollapsablePane.tsx +4 -4
- package/src/components/SampleTable.tsx +37 -46
- package/src/components/VariantInfoNestedTable.tsx +3 -3
- package/src/components/VariantsSampleTable.tsx +21 -44
- package/src/components/VariantsTable.tsx +2 -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/store/index.tsx +7 -10
- package/src/utils/sample.ts +63 -3
- package/src/views/Help.tsx +131 -6
- package/src/views/Home.tsx +24 -112
- package/src/views/Sample.tsx +21 -17
- package/src/views/SampleVariant.tsx +36 -21
- package/src/views/SampleVariantConsequence.tsx +44 -33
- package/src/views/SampleVariants.tsx +81 -10
- package/src/views/Samples.tsx +35 -33
- package/src/views/Variant.tsx +48 -42
- package/src/views/VariantConsequence.tsx +9 -8
- package/src/views/Variants.tsx +8 -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
|
@@ -6,7 +6,7 @@ import { FieldHeader } from "./FieldHeader";
|
|
|
6
6
|
import { Record } from "@molgenis/vip-report-vcf/src/Vcf";
|
|
7
7
|
import { Item } from "@molgenis/vip-report-api/src/Api";
|
|
8
8
|
import { isCsqInfo } from "../utils/csqUtils";
|
|
9
|
-
import {
|
|
9
|
+
import { useLocation } from "@solidjs/router";
|
|
10
10
|
|
|
11
11
|
function isNonEmptyNestedInfoItem(nestedInfoField: FieldMetadata, index: number, value: Value[] | Value[][]): boolean {
|
|
12
12
|
const infoField = nestedInfoField.nested?.items[index];
|
|
@@ -87,7 +87,7 @@ export const VariantInfoNestedTable: Component<{
|
|
|
87
87
|
{isNonEmptyNestedInfoItem(props.infoField, i(), props.infoValue) && (
|
|
88
88
|
<td>
|
|
89
89
|
{isCsqInfo(infoFieldItem, "Consequence") ? (
|
|
90
|
-
<
|
|
90
|
+
<a href={`${useLocation().pathname}/consequences/${j()}`}>
|
|
91
91
|
<Info
|
|
92
92
|
info={{
|
|
93
93
|
value: Array.isArray(value) ? value[i()] : null,
|
|
@@ -97,7 +97,7 @@ export const VariantInfoNestedTable: Component<{
|
|
|
97
97
|
infoMeta={infoFieldItem}
|
|
98
98
|
context={{}}
|
|
99
99
|
/>
|
|
100
|
-
</
|
|
100
|
+
</a>
|
|
101
101
|
) : (
|
|
102
102
|
<Info
|
|
103
103
|
info={{
|
|
@@ -2,7 +2,6 @@ import { Genotype, Metadata, Record } from "@molgenis/vip-report-vcf/src/Vcf";
|
|
|
2
2
|
import { Ref } from "./record/Ref";
|
|
3
3
|
import { Chrom } from "./record/Chrom";
|
|
4
4
|
import { Pos } from "./record/Pos";
|
|
5
|
-
import { Link } from "@solidjs/router";
|
|
6
5
|
import { HtsFileMetadata, Item, Sample } from "@molgenis/vip-report-api/src/Api";
|
|
7
6
|
import { GenotypeField } from "./record/format/GenotypeField";
|
|
8
7
|
import { InfoCollapsablePane } from "./InfoCollapsablePane";
|
|
@@ -11,6 +10,14 @@ import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
|
|
|
11
10
|
import { FieldHeader } from "./FieldHeader";
|
|
12
11
|
import { Abbr } from "./Abbr";
|
|
13
12
|
import { abbreviateHeader } from "../utils/field";
|
|
13
|
+
import {
|
|
14
|
+
getSampleAffectedStatusLabel,
|
|
15
|
+
getSampleFamilyMembersWithoutParents,
|
|
16
|
+
getSampleFather,
|
|
17
|
+
getSampleLabel,
|
|
18
|
+
getSampleMother,
|
|
19
|
+
getSampleSexLabel,
|
|
20
|
+
} from "../utils/sample";
|
|
14
21
|
|
|
15
22
|
export const VariantsSampleTable: Component<{
|
|
16
23
|
item: Item<Sample>;
|
|
@@ -28,26 +35,16 @@ export const VariantsSampleTable: Component<{
|
|
|
28
35
|
const [otherFamilyMembers, setOtherFamilyMembers] = createSignal<Sample[]>([]);
|
|
29
36
|
|
|
30
37
|
onMount(() => {
|
|
31
|
-
const familyMembers: Sample[] = [];
|
|
32
38
|
setProband(props.item.data);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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);
|
|
39
|
+
setMother(getSampleMother(proband() as Sample, samples()));
|
|
40
|
+
setFather(getSampleFather(proband() as Sample, samples()));
|
|
41
|
+
setOtherFamilyMembers(getSampleFamilyMembersWithoutParents(proband() as Sample, samples()));
|
|
49
42
|
});
|
|
50
43
|
|
|
44
|
+
function getSampleHeaderDescription(sample: Sample): string {
|
|
45
|
+
return `${getSampleLabel(sample)}: ${getSampleSexLabel(sample)}, ${getSampleAffectedStatusLabel(sample)}`;
|
|
46
|
+
}
|
|
47
|
+
|
|
51
48
|
return (
|
|
52
49
|
<div style={{ display: "grid" }}>
|
|
53
50
|
{/* workaround for https://github.com/jgthms/bulma/issues/2572#issuecomment-523099776 */}
|
|
@@ -60,48 +57,28 @@ export const VariantsSampleTable: Component<{
|
|
|
60
57
|
<Show when={proband()} keyed>
|
|
61
58
|
{(proband) => (
|
|
62
59
|
<th>
|
|
63
|
-
<Abbr
|
|
64
|
-
title={`${
|
|
65
|
-
proband.person.individualId
|
|
66
|
-
}: ${proband.person.sex.toLowerCase()}, ${proband.person.affectedStatus.toLowerCase()}`}
|
|
67
|
-
value="Proband"
|
|
68
|
-
/>
|
|
60
|
+
<Abbr title={getSampleHeaderDescription(proband)} value="Proband" />
|
|
69
61
|
</th>
|
|
70
62
|
)}
|
|
71
63
|
</Show>
|
|
72
64
|
<Show when={mother()} keyed>
|
|
73
65
|
{(mother) => (
|
|
74
66
|
<th>
|
|
75
|
-
<Abbr
|
|
76
|
-
title={`${
|
|
77
|
-
mother.person.individualId
|
|
78
|
-
}: ${mother.person.sex.toLowerCase()}, ${mother.person.affectedStatus.toLowerCase()}`}
|
|
79
|
-
value="Mother"
|
|
80
|
-
/>
|
|
67
|
+
<Abbr title={getSampleHeaderDescription(mother)} value="Mother" />
|
|
81
68
|
</th>
|
|
82
69
|
)}
|
|
83
70
|
</Show>
|
|
84
71
|
<Show when={father()} keyed>
|
|
85
72
|
{(father) => (
|
|
86
73
|
<th>
|
|
87
|
-
<Abbr
|
|
88
|
-
title={`${
|
|
89
|
-
father.person.individualId
|
|
90
|
-
}: ${father.person.sex.toLowerCase()}, ${father.person.affectedStatus.toLowerCase()}`}
|
|
91
|
-
value="Father"
|
|
92
|
-
/>
|
|
74
|
+
<Abbr title={getSampleHeaderDescription(father)} value="Father" />
|
|
93
75
|
</th>
|
|
94
76
|
)}
|
|
95
77
|
</Show>
|
|
96
78
|
<For each={otherFamilyMembers()}>
|
|
97
79
|
{(sample: Sample) => (
|
|
98
80
|
<th>
|
|
99
|
-
<Abbr
|
|
100
|
-
title={`${
|
|
101
|
-
sample.person.individualId
|
|
102
|
-
}: ${sample.person.sex.toLowerCase()}, ${sample.person.affectedStatus.toLowerCase()}`}
|
|
103
|
-
value={abbreviateHeader(sample.person.individualId)}
|
|
104
|
-
/>
|
|
81
|
+
<Abbr title={getSampleHeaderDescription(sample)} value={abbreviateHeader(getSampleLabel(sample))} />
|
|
105
82
|
</th>
|
|
106
83
|
)}
|
|
107
84
|
</For>
|
|
@@ -115,11 +92,11 @@ export const VariantsSampleTable: Component<{
|
|
|
115
92
|
{(record) => (
|
|
116
93
|
<tr>
|
|
117
94
|
<td>
|
|
118
|
-
<
|
|
95
|
+
<a href={`/samples/${props.item.id}/variants/${record.id}`}>
|
|
119
96
|
<Chrom value={record.data.c} />
|
|
120
97
|
<span>:</span>
|
|
121
98
|
<Pos value={record.data.p} />
|
|
122
|
-
</
|
|
99
|
+
</a>
|
|
123
100
|
</td>
|
|
124
101
|
<td>
|
|
125
102
|
<Ref value={record.data.r} isAbbreviate={true} />
|
|
@@ -9,7 +9,6 @@ import { Qual } from "./record/Qual";
|
|
|
9
9
|
import { Filter } from "./record/Filter";
|
|
10
10
|
import { Info } from "./record/Info";
|
|
11
11
|
import { FieldMetadata } from "@molgenis/vip-report-vcf/src/MetadataParser";
|
|
12
|
-
import { Link } from "@solidjs/router";
|
|
13
12
|
import { HtsFileMetadata, Item } from "@molgenis/vip-report-api/src/Api";
|
|
14
13
|
import { FieldHeader } from "./FieldHeader";
|
|
15
14
|
import { InfoCollapsablePane } from "./InfoCollapsablePane";
|
|
@@ -76,9 +75,9 @@ export const VariantsTable: Component<{
|
|
|
76
75
|
<Chrom value={record.data.c} />
|
|
77
76
|
</td>
|
|
78
77
|
<td>
|
|
79
|
-
<
|
|
78
|
+
<a href={`/variants/${record.id}`}>
|
|
80
79
|
<Pos value={record.data.p} />
|
|
81
|
-
</
|
|
80
|
+
</a>
|
|
82
81
|
</td>
|
|
83
82
|
<td>
|
|
84
83
|
<Id value={record.data.i} />
|
|
@@ -2,7 +2,6 @@ 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 { FilterIntegerGq } from "./FilterIntegerGq";
|
|
5
|
-
import { FilterIntegerDp } from "./FilterIntegerDp";
|
|
6
5
|
import { Item, Query, Sample } from "@molgenis/vip-report-api/src/Api";
|
|
7
6
|
import { FilterClinVar } from "./FilterClinVar";
|
|
8
7
|
import { isAnyCsqInfo } from "../../utils/csqUtils";
|
|
@@ -28,9 +27,6 @@ export const Filter: Component<FilterProps> = (props) => {
|
|
|
28
27
|
<Match when={props.field.id === "GQ"}>
|
|
29
28
|
<FilterIntegerGq {...props} />
|
|
30
29
|
</Match>
|
|
31
|
-
<Match when={props.field.id === "DP"}>
|
|
32
|
-
<FilterIntegerDp {...props} />
|
|
33
|
-
</Match>
|
|
34
30
|
<Match when={props.field.id === "VIAB"}>
|
|
35
31
|
<FilterAllelicBalance {...props} />
|
|
36
32
|
</Match>
|
|
@@ -15,18 +15,8 @@ function isAllelicImbalance(genotype: Genotype, allelicBalance: number | undefin
|
|
|
15
15
|
return false;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
function getTitle(
|
|
19
|
-
|
|
20
|
-
if (lowReadDepth) {
|
|
21
|
-
title = "Read depth < 20";
|
|
22
|
-
}
|
|
23
|
-
if (allelicImbalance) {
|
|
24
|
-
if (lowReadDepth) {
|
|
25
|
-
title = `${title}, `;
|
|
26
|
-
}
|
|
27
|
-
title = `${title}Allelic imbalance`;
|
|
28
|
-
}
|
|
29
|
-
return title;
|
|
18
|
+
function getTitle(allelicImbalance: boolean) {
|
|
19
|
+
return allelicImbalance ? `Allelic imbalance` : ``;
|
|
30
20
|
}
|
|
31
21
|
|
|
32
22
|
export const GenotypeField: Component<{
|
|
@@ -38,7 +28,6 @@ export const GenotypeField: Component<{
|
|
|
38
28
|
readDepth: number | undefined | null;
|
|
39
29
|
}> = (props) => {
|
|
40
30
|
const allelicImbalance: boolean = isAllelicImbalance(props.genotype, props.allelicBalance);
|
|
41
|
-
const lowReadDepth = props.readDepth !== undefined && props.readDepth !== null && props.readDepth < 20;
|
|
42
31
|
return (
|
|
43
32
|
<>
|
|
44
33
|
<For each={props.genotype.a}>
|
|
@@ -54,8 +43,8 @@ export const GenotypeField: Component<{
|
|
|
54
43
|
</>
|
|
55
44
|
)}
|
|
56
45
|
</For>
|
|
57
|
-
<Show when={
|
|
58
|
-
<abbr title={getTitle(
|
|
46
|
+
<Show when={allelicImbalance}>
|
|
47
|
+
<abbr title={getTitle(allelicImbalance)} class="ml-1 is-clickable">
|
|
59
48
|
<i class="fas fa-circle-exclamation has-text-danger" />
|
|
60
49
|
</abbr>
|
|
61
50
|
</Show>
|
package/src/index.tsx
CHANGED
|
@@ -18,6 +18,19 @@ import {
|
|
|
18
18
|
faSearch,
|
|
19
19
|
} from "@fortawesome/free-solid-svg-icons";
|
|
20
20
|
import { Provider } from "./store";
|
|
21
|
+
import { ErrorBoundary } from "solid-js";
|
|
22
|
+
import { Error } from "./components/Error";
|
|
23
|
+
import { HashRouter, Route } from "@solidjs/router";
|
|
24
|
+
import { Home } from "./views/Home";
|
|
25
|
+
import { Samples } from "./views/Samples";
|
|
26
|
+
import { Sample } from "./views/Sample";
|
|
27
|
+
import { SampleVariantsView } from "./views/SampleVariants";
|
|
28
|
+
import { SampleVariantView } from "./views/SampleVariant";
|
|
29
|
+
import { SampleVariantConsequenceView } from "./views/SampleVariantConsequence";
|
|
30
|
+
import { VariantsView } from "./views/Variants";
|
|
31
|
+
import { Variant } from "./views/Variant";
|
|
32
|
+
import { VariantConsequence } from "./views/VariantConsequence";
|
|
33
|
+
import { Help } from "./views/Help";
|
|
21
34
|
|
|
22
35
|
library.add(
|
|
23
36
|
faAngleDown,
|
|
@@ -46,7 +59,36 @@ if (document.readyState === "complete") {
|
|
|
46
59
|
render(
|
|
47
60
|
() => (
|
|
48
61
|
<Provider>
|
|
49
|
-
<
|
|
62
|
+
<ErrorBoundary fallback={(err) => <Error error={err as unknown} />}>
|
|
63
|
+
<HashRouter root={App}>
|
|
64
|
+
<Route path="/" component={Home} />
|
|
65
|
+
<Route path="/samples">
|
|
66
|
+
<Route path="/" component={Samples} />
|
|
67
|
+
<Route path="/:sampleId">
|
|
68
|
+
<Route path="/" component={Sample} />
|
|
69
|
+
<Route path="/variants">
|
|
70
|
+
<Route path="/" component={SampleVariantsView} />
|
|
71
|
+
<Route path="/:variantId">
|
|
72
|
+
<Route path="/" component={SampleVariantView} />
|
|
73
|
+
<Route path="/consequences">
|
|
74
|
+
<Route path="/:consequenceId" component={SampleVariantConsequenceView} />
|
|
75
|
+
</Route>
|
|
76
|
+
</Route>
|
|
77
|
+
</Route>
|
|
78
|
+
</Route>
|
|
79
|
+
</Route>
|
|
80
|
+
<Route path="/variants">
|
|
81
|
+
<Route path="/" component={VariantsView} />
|
|
82
|
+
<Route path="/:variantId">
|
|
83
|
+
<Route path="/" component={Variant} />
|
|
84
|
+
<Route path="/consequences">
|
|
85
|
+
<Route path="/:consequenceId" component={VariantConsequence} />
|
|
86
|
+
</Route>
|
|
87
|
+
</Route>
|
|
88
|
+
</Route>
|
|
89
|
+
<Route path="/help" component={Help} />
|
|
90
|
+
</HashRouter>
|
|
91
|
+
</ErrorBoundary>
|
|
50
92
|
</Provider>
|
|
51
93
|
),
|
|
52
94
|
document.body,
|
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";
|
|
@@ -67,16 +66,17 @@ export const Provider: ParentComponent = (props) => {
|
|
|
67
66
|
setState({ variants: { ...(state.variants || {}), page } });
|
|
68
67
|
},
|
|
69
68
|
setVariantsPageSize(pageSize: number) {
|
|
70
|
-
setState({ variants: { ...(state.variants || {}), pageSize } });
|
|
69
|
+
setState({ variants: { ...(state.variants || {}), pageSize, page: undefined } });
|
|
71
70
|
},
|
|
72
71
|
setVariantsSearchQuery(searchQuery: string) {
|
|
73
|
-
setState({ variants: { ...(state.variants || {}), searchQuery } });
|
|
72
|
+
setState({ variants: { ...(state.variants || {}), searchQuery, page: undefined } });
|
|
74
73
|
},
|
|
75
74
|
setVariantsFilterQuery(query: Query, key: string) {
|
|
76
75
|
setState({
|
|
77
76
|
variants: {
|
|
78
77
|
...(state.variants || {}),
|
|
79
78
|
filterQueries: { ...(state.variants?.filterQueries || {}), [key]: query },
|
|
79
|
+
page: undefined,
|
|
80
80
|
},
|
|
81
81
|
});
|
|
82
82
|
},
|
|
@@ -85,6 +85,7 @@ export const Provider: ParentComponent = (props) => {
|
|
|
85
85
|
variants: {
|
|
86
86
|
...(state.variants || {}),
|
|
87
87
|
filterQueries: { ...(state.variants?.filterQueries || {}), [key]: undefined },
|
|
88
|
+
page: undefined,
|
|
88
89
|
},
|
|
89
90
|
});
|
|
90
91
|
},
|
|
@@ -162,19 +163,15 @@ export const Provider: ParentComponent = (props) => {
|
|
|
162
163
|
setState({ samples: { ...(state.samples || {}), page } });
|
|
163
164
|
},
|
|
164
165
|
setSampleSearchQuery(searchQuery: string) {
|
|
165
|
-
setState({ samples: { ...(state.samples || {}), searchQuery } });
|
|
166
|
+
setState({ samples: { ...(state.samples || {}), searchQuery, page: undefined } });
|
|
166
167
|
},
|
|
167
168
|
setSampleProbandFilterValue(probandFilterValue: boolean) {
|
|
168
|
-
setState({ samples: { ...(state.samples || {}), probandFilterValue } });
|
|
169
|
+
setState({ samples: { ...(state.samples || {}), probandFilterValue, page: undefined } });
|
|
169
170
|
},
|
|
170
171
|
};
|
|
171
172
|
const store: AppStore = [state, actions];
|
|
172
173
|
|
|
173
|
-
return
|
|
174
|
-
<Router source={hashIntegration()}>
|
|
175
|
-
<StoreContext.Provider value={store}>{props.children}</StoreContext.Provider>
|
|
176
|
-
</Router>
|
|
177
|
-
);
|
|
174
|
+
return <StoreContext.Provider value={store}>{props.children}</StoreContext.Provider>;
|
|
178
175
|
};
|
|
179
176
|
|
|
180
177
|
export function useStore() {
|
package/src/utils/sample.ts
CHANGED
|
@@ -1,5 +1,65 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Sample } from "@molgenis/vip-report-api/src/Api";
|
|
2
2
|
|
|
3
|
-
export function getSampleLabel(sample:
|
|
4
|
-
return sample.
|
|
3
|
+
export function getSampleLabel(sample: Sample) {
|
|
4
|
+
return sample.person.individualId;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function getSampleSexLabel(sample: Sample): string {
|
|
8
|
+
switch (sample.person.sex) {
|
|
9
|
+
case "FEMALE":
|
|
10
|
+
return "female";
|
|
11
|
+
case "MALE":
|
|
12
|
+
return "male";
|
|
13
|
+
default:
|
|
14
|
+
return "?";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function getSampleAffectedStatusLabel(sample: Sample): string {
|
|
19
|
+
switch (sample.person.affectedStatus) {
|
|
20
|
+
case "AFFECTED":
|
|
21
|
+
return "affected";
|
|
22
|
+
case "UNAFFECTED":
|
|
23
|
+
return "unaffected";
|
|
24
|
+
default:
|
|
25
|
+
return "?";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function isFamily(sample: Sample, samples: Sample): boolean {
|
|
30
|
+
return sample.person.familyId === samples.person.familyId;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function isSampleMother(sample: Sample, samples: Sample): boolean {
|
|
34
|
+
return isFamily(sample, samples) && samples.person.individualId === sample.person.maternalId;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function getSampleMother(sample: Sample, samples: Sample[]): Sample | undefined {
|
|
38
|
+
if (sample.person.maternalId !== "0") {
|
|
39
|
+
for (const otherSample of samples) {
|
|
40
|
+
if (isSampleMother(sample, otherSample)) return otherSample;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function isSampleFather(sample: Sample, samples: Sample): boolean {
|
|
46
|
+
return isFamily(sample, samples) && samples.person.individualId === sample.person.paternalId;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function getSampleFather(sample: Sample, samples: Sample[]): Sample | undefined {
|
|
50
|
+
if (sample.person.paternalId !== "0") {
|
|
51
|
+
for (const otherSample of samples) {
|
|
52
|
+
if (isSampleFather(sample, otherSample)) return otherSample;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function getSampleFamilyMembersWithoutParents(sample: Sample, samples: Sample[]): Sample[] {
|
|
58
|
+
const familyMembersWithoutParents: Sample[] = [];
|
|
59
|
+
for (const otherSample of samples) {
|
|
60
|
+
if (isFamily(sample, otherSample) && !isSampleFather(sample, otherSample) && !isSampleMother(sample, otherSample)) {
|
|
61
|
+
if (sample.person.individualId !== otherSample.person.individualId) familyMembersWithoutParents.push(otherSample);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return familyMembersWithoutParents;
|
|
5
65
|
}
|
package/src/views/Help.tsx
CHANGED
|
@@ -1,13 +1,138 @@
|
|
|
1
|
-
import { Component } from "solid-js";
|
|
1
|
+
import { Component, createResource, createSignal, For, Show } from "solid-js";
|
|
2
2
|
import { Anchor } from "../components/Anchor";
|
|
3
|
+
import {
|
|
4
|
+
EMPTY_APP_METADATA,
|
|
5
|
+
EMPTY_HTS_FILE_METADATA,
|
|
6
|
+
EMPTY_PARAMS,
|
|
7
|
+
EMPTY_PHENOTYPES,
|
|
8
|
+
EMPTY_RECORDS_METADATA,
|
|
9
|
+
EMPTY_RECORDS_PAGE,
|
|
10
|
+
EMPTY_SAMPLES_PAGE,
|
|
11
|
+
fetchAppMetadata,
|
|
12
|
+
fetchHtsFileMetadata,
|
|
13
|
+
fetchPhenotypes,
|
|
14
|
+
fetchRecords,
|
|
15
|
+
fetchRecordsMeta,
|
|
16
|
+
fetchSamples,
|
|
17
|
+
} from "../utils/ApiUtils";
|
|
18
|
+
import { Loader } from "../components/Loader";
|
|
19
|
+
import { Breadcrumb } from "../components/Breadcrumb";
|
|
20
|
+
import { VcfHeaderRow } from "../components/VcfHeaderRow";
|
|
21
|
+
import { getHeaderValue } from "../utils/viewUtils";
|
|
22
|
+
import { Item, Phenotype, PhenotypicFeature } from "@molgenis/vip-report-api/src/Api";
|
|
23
|
+
import { HpoTerm } from "../components/HpoTerm";
|
|
3
24
|
export const Help: Component = () => {
|
|
25
|
+
const [params] = createSignal(EMPTY_PARAMS);
|
|
26
|
+
const [samples] = createResource(params, fetchSamples, { initialValue: EMPTY_SAMPLES_PAGE });
|
|
27
|
+
const [records] = createResource(params, fetchRecords, { initialValue: EMPTY_RECORDS_PAGE });
|
|
28
|
+
const [recordsMetadata] = createResource(params, fetchRecordsMeta, { initialValue: EMPTY_RECORDS_METADATA });
|
|
29
|
+
const [phenotypes] = createResource(params, fetchPhenotypes, { initialValue: EMPTY_PHENOTYPES });
|
|
30
|
+
const [htsFileMetadata] = createResource(params, fetchHtsFileMetadata, { initialValue: EMPTY_HTS_FILE_METADATA });
|
|
31
|
+
const [appMetadata] = createResource(params, fetchAppMetadata, { initialValue: EMPTY_APP_METADATA });
|
|
4
32
|
return (
|
|
5
33
|
<>
|
|
6
|
-
<
|
|
7
|
-
<
|
|
8
|
-
<
|
|
9
|
-
|
|
10
|
-
|
|
34
|
+
<Breadcrumb items={[{ text: "Help" }]} />
|
|
35
|
+
<div class="columns">
|
|
36
|
+
<div class="column">
|
|
37
|
+
<p class="title is-3">Documentation</p>
|
|
38
|
+
<span>The documentation for the Variant Interpretation Pipeline is located </span>
|
|
39
|
+
<Anchor href={`https://molgenis.github.io/vip/`}>
|
|
40
|
+
<span>here</span>
|
|
41
|
+
</Anchor>
|
|
42
|
+
<span>.</span>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<Show
|
|
47
|
+
when={
|
|
48
|
+
!samples.loading &&
|
|
49
|
+
!records.loading &&
|
|
50
|
+
!recordsMetadata.loading &&
|
|
51
|
+
!phenotypes.loading &&
|
|
52
|
+
!htsFileMetadata.loading &&
|
|
53
|
+
!appMetadata.loading
|
|
54
|
+
}
|
|
55
|
+
fallback={<Loader />}
|
|
56
|
+
>
|
|
57
|
+
<p class="title is-3">About</p>
|
|
58
|
+
<div class="columns">
|
|
59
|
+
<div class="column">
|
|
60
|
+
<div class="table-container">
|
|
61
|
+
<table class="table is-narrow">
|
|
62
|
+
<thead>
|
|
63
|
+
<tr>
|
|
64
|
+
<th colSpan={2}>Software metadata</th>
|
|
65
|
+
</tr>
|
|
66
|
+
</thead>
|
|
67
|
+
<tbody>
|
|
68
|
+
<tr>
|
|
69
|
+
<th>Name:</th>
|
|
70
|
+
<td>{appMetadata().name}</td>
|
|
71
|
+
</tr>
|
|
72
|
+
<tr>
|
|
73
|
+
<th>Version:</th>
|
|
74
|
+
<td>{appMetadata().version}</td>
|
|
75
|
+
</tr>
|
|
76
|
+
<tr>
|
|
77
|
+
<th>Arguments:</th>
|
|
78
|
+
<td>{appMetadata().args}</td>
|
|
79
|
+
</tr>
|
|
80
|
+
<VcfHeaderRow value={getHeaderValue("VIP_Version", recordsMetadata().lines)} title={"VIP Version"} />
|
|
81
|
+
<VcfHeaderRow value={getHeaderValue("VIP_Command", recordsMetadata().lines)} title={"VIP Command"} />
|
|
82
|
+
</tbody>
|
|
83
|
+
</table>
|
|
84
|
+
</div>
|
|
85
|
+
<div class="table-container">
|
|
86
|
+
<table class="table is-narrow">
|
|
87
|
+
<thead>
|
|
88
|
+
<tr>
|
|
89
|
+
<th colSpan={2}>Input metadata</th>
|
|
90
|
+
</tr>
|
|
91
|
+
</thead>
|
|
92
|
+
<tbody>
|
|
93
|
+
<tr>
|
|
94
|
+
<th>Filename:</th>
|
|
95
|
+
<td>{htsFileMetadata().uri}</td>
|
|
96
|
+
</tr>
|
|
97
|
+
<tr>
|
|
98
|
+
<th>Assembly:</th>
|
|
99
|
+
<td>{htsFileMetadata().genomeAssembly}</td>
|
|
100
|
+
</tr>
|
|
101
|
+
<tr>
|
|
102
|
+
<th>Number of records:</th>
|
|
103
|
+
<td>{records().total}</td>
|
|
104
|
+
</tr>
|
|
105
|
+
<tr>
|
|
106
|
+
<th>Number of samples:</th>
|
|
107
|
+
<td>{samples().total}</td>
|
|
108
|
+
</tr>
|
|
109
|
+
<tr>
|
|
110
|
+
<th>Phenotypes:</th>
|
|
111
|
+
<td>
|
|
112
|
+
<For each={phenotypes().items}>
|
|
113
|
+
{(item: Item<Phenotype>) => (
|
|
114
|
+
<>
|
|
115
|
+
<b>{item.data.subject.id}: </b>
|
|
116
|
+
<For each={item.data.phenotypicFeaturesList}>
|
|
117
|
+
{(phenotypicFeature: PhenotypicFeature, i) => (
|
|
118
|
+
<>
|
|
119
|
+
{i() > 0 ? ", " : ""}
|
|
120
|
+
<HpoTerm ontologyClass={phenotypicFeature.type} />
|
|
121
|
+
</>
|
|
122
|
+
)}
|
|
123
|
+
</For>
|
|
124
|
+
<br />
|
|
125
|
+
</>
|
|
126
|
+
)}
|
|
127
|
+
</For>
|
|
128
|
+
</td>
|
|
129
|
+
</tr>
|
|
130
|
+
</tbody>
|
|
131
|
+
</table>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
</Show>
|
|
11
136
|
</>
|
|
12
137
|
);
|
|
13
138
|
};
|