@molgenis/vip-report-template 3.1.4 → 4.0.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/.travis.yml +2 -2
- package/README.md +1 -1
- package/package.json +18 -18
- package/src/assets/sass/main.scss +6 -0
- package/src/components/Anchor.tsx +1 -1
- package/src/components/GenomeBrowser.tsx +26 -20
- package/src/components/filter/FilterCategorical.tsx +2 -2
- package/src/components/record/Info.tsx +4 -0
- package/src/components/record/info/ClinVar.tsx +1 -1
- package/src/components/record/info/Gene.tsx +1 -1
- package/src/components/record/info/GnomAD.tsx +2 -2
- package/src/components/record/info/Hgvs.tsx +5 -1
- package/src/components/record/info/Vkgl.tsx +42 -0
- package/src/igv.d.ts +6 -2
- package/src/mocks/GRCh37/alignment.cram.blob +0 -0
- package/src/mocks/GRCh37/alignment.cram.crai.blob +0 -0
- package/src/mocks/GRCh37/static.ts +4 -2
- package/src/mocks/GRCh37/vcf/family.vcf.blob +1 -1
- package/src/mocks/GRCh38/alignment.cram.blob +0 -0
- package/src/mocks/GRCh38/alignment.cram.crai.blob +0 -0
- package/src/mocks/GRCh38/static.ts +4 -2
- package/src/mocks/MockApiClient.ts +37 -16
- package/src/utils/viewUtils.ts +7 -13
- package/src/views/SampleVariants.tsx +3 -3
- package/src/views/Samples.tsx +1 -1
- package/src/views/VariantConsequence.tsx +1 -1
- package/src/mocks/GRCh37/alignment.bam.blob +0 -0
- package/src/mocks/GRCh38/alignment.bam.blob +0 -0
package/.travis.yml
CHANGED
|
@@ -3,7 +3,7 @@ node_js:
|
|
|
3
3
|
- lts/*
|
|
4
4
|
branches:
|
|
5
5
|
only:
|
|
6
|
-
-
|
|
6
|
+
- main
|
|
7
7
|
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/
|
|
8
8
|
cache:
|
|
9
9
|
npm: false
|
|
@@ -29,7 +29,7 @@ deploy:
|
|
|
29
29
|
edge: true
|
|
30
30
|
- provider: releases
|
|
31
31
|
token:
|
|
32
|
-
secure:
|
|
32
|
+
secure: rQ19Q5xN6T+dJp4nDT+B4QREJNCc9HpOdipE7jcAP/PVD49kd3AI4joZD9nBn53a091rl7VHviqzyRvHyvBI00VWGhQOmbUqd45c5h4Vn0qUZno2Wl2M7iuUyllvovQHS0C34nLDSBkKhJv0ESit/xiyyVy8JxwO1mgFcLgsY0cKiupwbhepUw5V2S458pNLW9e4RxT7RIaQWUagYp+PJYRKAYn5AAxih65mv2+wSGQPzcOKJDRSTlDtLaCrfZCNJm/7f3iSAOm1CCA1HLxNO2ACFL4bhnghWPS7O6VyTv1POexgwbH0OQxHmO/pdm3geLrTWX7PaHaZNUB1CHoNXC5FE/J9sUSrjClfGL9qFo5WEkBAgH3a5lLwUoCWZecUJPnyeIEFieg5OSjnXFrTECWo5Ut4g5RtzOWQtTLEwOXQgDBtE3NLkH/DRayO9vliEs9/6CnZ8AndH17cj/GmB//2DTjOMr3yCQVuI5ZeANBAUoXAg/C6kQDTdP8oyLay7UBJnX1aEWWLf3Gwo0UBFE83YIuzqVzIvU8HYgFiPgjxFwKBmebS4qu1n9ils2X0nWaY9KZY4lIjzkxsgsZ2pqt1Z6a5AQsEqXv06Tjy6tB7/I9TG7vl4eTBBJBPsRKMNnTfkE6Zr3oHC+ihWIMolAqyaTriOh23Gs/xzEuK+T8=
|
|
33
33
|
file: dist/vip-report-template.html
|
|
34
34
|
on:
|
|
35
35
|
tags: true
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[](https://app.travis-ci.com/molgenis/vip-report-template)
|
|
2
2
|
# vip-report-template
|
|
3
3
|
The default report template for the [VIP report generator](https://github.com/molgenis/vip-report). This template is a good default for any .vcf file with support for .vcf files annotated with [VIP](https://github.com/molgenis/vip).
|
|
4
4
|
## Usage
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@molgenis/vip-report-template",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "Report Template for Variant Call Format (VCF) Report Generator",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "vite build",
|
|
@@ -15,32 +15,32 @@
|
|
|
15
15
|
},
|
|
16
16
|
"license": "LGPL-3.0",
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"@molgenis/vite-plugin-inline": "^1.0.
|
|
19
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
20
|
-
"@typescript-eslint/parser": "^5.
|
|
21
|
-
"@vitest/coverage-c8": "^0.
|
|
18
|
+
"@molgenis/vite-plugin-inline": "^1.0.9",
|
|
19
|
+
"@typescript-eslint/eslint-plugin": "^5.38.1",
|
|
20
|
+
"@typescript-eslint/parser": "^5.38.1",
|
|
21
|
+
"@vitest/coverage-c8": "^0.23.4",
|
|
22
22
|
"bulma": "^0.9.4",
|
|
23
|
-
"eslint": "^8.
|
|
23
|
+
"eslint": "^8.24.0",
|
|
24
24
|
"eslint-config-prettier": "^8.5.0",
|
|
25
25
|
"eslint-plugin-prettier": "^4.2.1",
|
|
26
|
-
"eslint-plugin-solid": "^0.7.
|
|
26
|
+
"eslint-plugin-solid": "^0.7.3",
|
|
27
27
|
"husky": "^8.0.1",
|
|
28
28
|
"prettier": "^2.7.1",
|
|
29
|
-
"sass": "^1.
|
|
30
|
-
"typescript": "^4.
|
|
31
|
-
"vite": "^3.
|
|
32
|
-
"vite-plugin-solid": "^2.3.
|
|
33
|
-
"vitest": "^0.
|
|
29
|
+
"sass": "^1.55.0",
|
|
30
|
+
"typescript": "^4.8.4",
|
|
31
|
+
"vite": "^3.1.3",
|
|
32
|
+
"vite-plugin-solid": "^2.3.9",
|
|
33
|
+
"vitest": "^0.23.4"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@fortawesome/fontawesome-svg-core": "^6.
|
|
37
|
-
"@fortawesome/free-solid-svg-icons": "^6.
|
|
38
|
-
"@molgenis/vip-report-api": "^
|
|
39
|
-
"@molgenis/vip-report-vcf": "^1.2.
|
|
36
|
+
"@fortawesome/fontawesome-svg-core": "^6.2.0",
|
|
37
|
+
"@fortawesome/free-solid-svg-icons": "^6.2.0",
|
|
38
|
+
"@molgenis/vip-report-api": "^4.0.1",
|
|
39
|
+
"@molgenis/vip-report-vcf": "^1.2.7",
|
|
40
40
|
"base64-js": "^1.5.1",
|
|
41
|
-
"igv": "^2.13.
|
|
41
|
+
"igv": "^2.13.3",
|
|
42
42
|
"solid-app-router": "^0.4.2",
|
|
43
|
-
"solid-js": "^1.
|
|
43
|
+
"solid-js": "^1.5.6"
|
|
44
44
|
},
|
|
45
45
|
"lint-staged": {
|
|
46
46
|
"src/**/*.{tsx,ts}": [
|
|
@@ -4,7 +4,7 @@ export const Anchor: ParentComponent<{
|
|
|
4
4
|
href: string | null | undefined;
|
|
5
5
|
}> = (props) => {
|
|
6
6
|
return (
|
|
7
|
-
<Show when={props.href} fallback={props.children}>
|
|
7
|
+
<Show when={props.href} fallback={props.children} keyed>
|
|
8
8
|
{(href) => (
|
|
9
9
|
<a href={href} target="_blank" rel="noopener noreferrer nofollow">
|
|
10
10
|
{props.children}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Component, onCleanup, onMount } from "solid-js";
|
|
2
|
-
import igv from "igv";
|
|
2
|
+
import igv, { Browser } from "igv";
|
|
3
3
|
import api from "../Api";
|
|
4
4
|
import { fromByteArray } from "base64-js";
|
|
5
5
|
import { writeVcf } from "@molgenis/vip-report-vcf/src/VcfWriter";
|
|
6
|
-
import { ComposedQuery, Sample } from "@molgenis/vip-report-api/src/Api";
|
|
6
|
+
import { ComposedQuery, Cram, Sample } from "@molgenis/vip-report-api/src/Api";
|
|
7
7
|
|
|
8
8
|
async function createVcf(contig: string, position: number, samples: Sample[]): Promise<Uint8Array> {
|
|
9
9
|
const query: ComposedQuery = {
|
|
@@ -34,12 +34,10 @@ const createBrowserConfig = async (contig: string, position: number, samples: Sa
|
|
|
34
34
|
api.getFastaGz(contig, position),
|
|
35
35
|
createVcf(contig, position, samples),
|
|
36
36
|
api.getGenesGz(),
|
|
37
|
-
...samples.map((sample) => api.getBam(sample.person.individualId)),
|
|
38
37
|
]);
|
|
39
38
|
const fastaGz = data[0];
|
|
40
39
|
const vcf = data[1];
|
|
41
40
|
const genesGz = data[2];
|
|
42
|
-
const bams = data.slice(3);
|
|
43
41
|
|
|
44
42
|
if (fastaGz === null) {
|
|
45
43
|
return null;
|
|
@@ -63,21 +61,6 @@ const createBrowserConfig = async (contig: string, position: number, samples: Sa
|
|
|
63
61
|
url: "data:application/octet-stream;base64," + fromByteArray(vcf),
|
|
64
62
|
});
|
|
65
63
|
|
|
66
|
-
for (let i = 0; i < samples.length; ++i) {
|
|
67
|
-
const bam = bams[i];
|
|
68
|
-
|
|
69
|
-
if (bam !== null) {
|
|
70
|
-
const sampleId = samples[i].person.individualId;
|
|
71
|
-
tracks.push({
|
|
72
|
-
order: order++,
|
|
73
|
-
type: "alignment",
|
|
74
|
-
format: "bam",
|
|
75
|
-
name: `Alignment (${sampleId})`,
|
|
76
|
-
url: "data:application/gzip;base64," + fromByteArray(bam),
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
64
|
const htsFileMetadata = await api.getHtsFileMetadata();
|
|
82
65
|
|
|
83
66
|
return {
|
|
@@ -94,14 +77,37 @@ const createBrowserConfig = async (contig: string, position: number, samples: Sa
|
|
|
94
77
|
};
|
|
95
78
|
};
|
|
96
79
|
|
|
80
|
+
const updateBrowser = async (browser: Browser, samples: Sample[]): Promise<void> => {
|
|
81
|
+
const data = await Promise.all([...samples.map((sample) => api.getCram(sample.person.individualId))]);
|
|
82
|
+
const crams = data.slice(0);
|
|
83
|
+
|
|
84
|
+
for (let i = 0; i < samples.length; ++i) {
|
|
85
|
+
const cram = crams[i];
|
|
86
|
+
|
|
87
|
+
if (cram !== null) {
|
|
88
|
+
const sampleId = samples[i].person.individualId;
|
|
89
|
+
await browser.loadTrack({
|
|
90
|
+
type: "alignment",
|
|
91
|
+
format: "cram",
|
|
92
|
+
name: `Alignment (${sampleId})`,
|
|
93
|
+
url: "data:application/octet-stream;base64," + fromByteArray(cram.cram),
|
|
94
|
+
indexURL: "data:application/octet-stream;base64," + fromByteArray(cram.crai),
|
|
95
|
+
checkSequenceMD5: false, // disable verifying the MD5 checksum of the reference sequence underlying a slice
|
|
96
|
+
colorBy: "strand",
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
97
102
|
export const GenomeBrowser: Component<{ contig: string; position: number; samples: Sample[] }> = (props) => {
|
|
98
103
|
let divRef: HTMLDivElement;
|
|
99
|
-
let browser:
|
|
104
|
+
let browser: Browser;
|
|
100
105
|
onMount(() => {
|
|
101
106
|
(async () => {
|
|
102
107
|
const config = await createBrowserConfig(props.contig, props.position, props.samples);
|
|
103
108
|
if (config !== null) {
|
|
104
109
|
browser = await igv.createBrowser(divRef, config);
|
|
110
|
+
await updateBrowser(browser, props.samples);
|
|
105
111
|
}
|
|
106
112
|
})().catch((err) => console.error(err));
|
|
107
113
|
});
|
|
@@ -54,7 +54,7 @@ export const FilterCategorical: Component<
|
|
|
54
54
|
<Checkbox
|
|
55
55
|
value={category}
|
|
56
56
|
label={props.labels ? props.labels[category] : category}
|
|
57
|
-
checked={props.query && (props.query.args as string[]).includes(category)}
|
|
57
|
+
checked={props.query && (props.query.args as (string | null)[]).includes(category)}
|
|
58
58
|
onChange={onChange}
|
|
59
59
|
/>
|
|
60
60
|
</div>
|
|
@@ -64,7 +64,7 @@ export const FilterCategorical: Component<
|
|
|
64
64
|
<Checkbox
|
|
65
65
|
value={nullValue}
|
|
66
66
|
label="No value"
|
|
67
|
-
checked={props.query && (props.query.args as string[]).includes(
|
|
67
|
+
checked={props.query && (props.query.args as (string | null)[]).includes(null)}
|
|
68
68
|
onChange={onChange}
|
|
69
69
|
/>
|
|
70
70
|
)}
|
|
@@ -8,6 +8,7 @@ import { Hgvs } from "./info/Hgvs";
|
|
|
8
8
|
import { ClinVar } from "./info/ClinVar";
|
|
9
9
|
import { GnomAD } from "./info/GnomAD";
|
|
10
10
|
import { isAnyCsqInfo, isCsqInfo } from "../../utils/csqUtils";
|
|
11
|
+
import { Vkgl } from "./info/Vkgl";
|
|
11
12
|
|
|
12
13
|
export const Info: Component<{
|
|
13
14
|
info: FieldValue;
|
|
@@ -34,6 +35,9 @@ export const Info: Component<{
|
|
|
34
35
|
<Match when={isCsqInfo(props.infoMeta, "clinVar_CLNSIG")}>
|
|
35
36
|
<ClinVar {...props} />
|
|
36
37
|
</Match>
|
|
38
|
+
<Match when={isCsqInfo(props.infoMeta, "VKGL_CL")}>
|
|
39
|
+
<Vkgl {...props} />
|
|
40
|
+
</Match>
|
|
37
41
|
</Switch>
|
|
38
42
|
);
|
|
39
43
|
};
|
|
@@ -70,7 +70,7 @@ export const ClinVar: Component<FieldProps> = (props) => {
|
|
|
70
70
|
};
|
|
71
71
|
|
|
72
72
|
return (
|
|
73
|
-
<Show when={label()}>
|
|
73
|
+
<Show when={label()} keyed>
|
|
74
74
|
{(label) => (
|
|
75
75
|
<Anchor href={href()}>
|
|
76
76
|
{description() ? <Abbr title={description()!} value={label} /> : <span>{label}</span>}
|
|
@@ -34,9 +34,9 @@ export const GnomAD: Component<FieldProps> = (props) => {
|
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
return (
|
|
37
|
-
<Show when={af()}>
|
|
37
|
+
<Show when={af()} keyed>
|
|
38
38
|
{(af) => (
|
|
39
|
-
<Show when={href()} fallback={<FieldValueFloat value={af} />}>
|
|
39
|
+
<Show when={href()} fallback={<FieldValueFloat value={af} />} keyed>
|
|
40
40
|
{(href) => (
|
|
41
41
|
<Anchor href={href}>
|
|
42
42
|
<FieldValueFloat value={af} />
|
|
@@ -16,5 +16,9 @@ function abbreviate(notation: string): string {
|
|
|
16
16
|
|
|
17
17
|
export const Hgvs: Component<FieldProps> = (props) => {
|
|
18
18
|
const value = () => props.info.value as ValueString;
|
|
19
|
-
return
|
|
19
|
+
return (
|
|
20
|
+
<Show when={value()} keyed>
|
|
21
|
+
{(value) => <Abbr title={value} value={abbreviate(value)} />}
|
|
22
|
+
</Show>
|
|
23
|
+
);
|
|
20
24
|
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Component, Show } from "solid-js";
|
|
2
|
+
import { Abbr } from "../../Abbr";
|
|
3
|
+
import { FieldProps } from "../field/Field";
|
|
4
|
+
import { ValueString } from "@molgenis/vip-report-vcf/src/ValueParser";
|
|
5
|
+
import { getCsqInfo, getCsqInfoIndex } from "../../../utils/csqUtils";
|
|
6
|
+
|
|
7
|
+
export const Vkgl: Component<FieldProps> = (props) => {
|
|
8
|
+
const value = () => props.info.value as ValueString;
|
|
9
|
+
const title = () => {
|
|
10
|
+
if (value() === null) return undefined;
|
|
11
|
+
|
|
12
|
+
const labs: { [key: string]: string } = {
|
|
13
|
+
VKGL_AMC: "AMC",
|
|
14
|
+
VKGL_ERASMUS: "Erasmus",
|
|
15
|
+
VKGL_LUMC: "LUMC",
|
|
16
|
+
VKGL_NKI: "NKI",
|
|
17
|
+
VKGL_RADBOUD_MUMC: "Radboud/MUMC",
|
|
18
|
+
VKGL_UMCG: "UMCG",
|
|
19
|
+
VKGL_UMCU: "UMCU",
|
|
20
|
+
VKGL_VUMC: "VUMC",
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const descriptions = [];
|
|
24
|
+
for (const key in labs) {
|
|
25
|
+
const fieldIndex = getCsqInfoIndex(props.infoMeta, key);
|
|
26
|
+
if (fieldIndex !== -1) {
|
|
27
|
+
const value = getCsqInfo(props.info, fieldIndex) as ValueString;
|
|
28
|
+
if (value !== null) descriptions.push(`${labs[key]}:${value}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return descriptions.length > 0 ? descriptions.join(", ") : null;
|
|
32
|
+
};
|
|
33
|
+
return (
|
|
34
|
+
<Show when={value()} keyed>
|
|
35
|
+
{(value) => (
|
|
36
|
+
<Show when={title()} fallback={<span>{value}</span>} keyed>
|
|
37
|
+
{(title) => <Abbr title={title} value={value} />}
|
|
38
|
+
</Show>
|
|
39
|
+
)}
|
|
40
|
+
</Show>
|
|
41
|
+
);
|
|
42
|
+
};
|
package/src/igv.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
declare module "igv" {
|
|
2
|
-
export
|
|
3
|
-
|
|
2
|
+
export class Browser {
|
|
3
|
+
loadTrack(config: unknown): Promise<unknown>;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function createBrowser(div: HTMLDivElement, config: unknown): Promise<Browser>;
|
|
7
|
+
export function removeBrowser(browser: Browser): void;
|
|
4
8
|
}
|
|
Binary file
|
|
Binary file
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import cramUrl from "./alignment.cram.blob";
|
|
2
|
+
import craiUrl from "./alignment.cram.crai.blob";
|
|
2
3
|
import decisionTreeJson from "./decisionTree.json";
|
|
3
4
|
import fastaUrl1_10042288_10042788 from "./fasta/1-10042288-10042788.fasta.gz.blob";
|
|
4
5
|
import fastaUrl1_16375333_16375833 from "./fasta/1-16375333-16375833.fasta.gz.blob";
|
|
@@ -47,7 +48,8 @@ import vcfUrlSamples100 from "./vcf/samples_100.vcf.blob";
|
|
|
47
48
|
import { fetchAsBytes } from "../utils";
|
|
48
49
|
import { DecisionTree } from "@molgenis/vip-report-api/src/Api";
|
|
49
50
|
|
|
50
|
-
export const
|
|
51
|
+
export const cram = await fetchAsBytes(cramUrl as string);
|
|
52
|
+
export const crai = await fetchAsBytes(craiUrl as string);
|
|
51
53
|
|
|
52
54
|
export const decisionTree: DecisionTree = decisionTreeJson as DecisionTree;
|
|
53
55
|
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
##VIPC=VIP decision tree classification
|
|
48
48
|
##VIPL=VIP decision tree labels (ampersand separated)
|
|
49
49
|
##VIPP=VIP decision tree path (ampersand separated)
|
|
50
|
-
##VIP_Command=nextflow run ./main.nf --input /groups/solve-rd/tmp10/bcharbon/testdata/testdata_b37.vcf --output /groups/solve-rd/tmp10/projects/vip/testdata_out --keep --pedigree /groups/solve-rd/tmp10/bcharbon/example.ped --probands Patient --phenotypes 'HP:0000951;HP:0003124' --assembly GRCh37
|
|
50
|
+
##VIP_Command=nextflow run ./main.nf --input /groups/solve-rd/tmp10/bcharbon/testdata/testdata_b37.vcf --output /groups/solve-rd/tmp10/projects/vip/testdata_out --keep --pedigree /groups/solve-rd/tmp10/bcharbon/example.ped --probands Patient --phenotypes 'HP:0000951;HP:0003124' --assembly GRCh37 --param_with_equals_sign x=y
|
|
51
51
|
##VIP_Version=4.3.0
|
|
52
52
|
##VIP_treeCommand=--input testdata_b37_chunk0_annotated.vcf.gz --config /groups/solve-rd/tmp10/projects/vip/git/vip/resources/decision_tree.json --labels 0 --path 0 --output testdata_b37_chunk0_classified.vcf.gz
|
|
53
53
|
##VIP_treeVersion=3.0.0
|
|
Binary file
|
|
Binary file
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import cramUrl from "./alignment.cram.blob";
|
|
2
|
+
import craiUrl from "./alignment.cram.crai.blob";
|
|
2
3
|
import fastaUrl_chr1_9982230_9982730 from "./fasta/chr1-9982230-9982730.fasta.gz.blob";
|
|
3
4
|
import fastaUrl_chr1_16049667_16050167 from "./fasta/chr1-16049667-16050167.fasta.gz.blob";
|
|
4
5
|
import fastaUrl_chr1_17022474_17022974 from "./fasta/chr1-17022474-17022974.fasta.gz.blob";
|
|
@@ -36,7 +37,8 @@ import { fetchAsBytes } from "../utils";
|
|
|
36
37
|
import decisionTreeJson from "./decisionTree.json";
|
|
37
38
|
import { DecisionTree } from "@molgenis/vip-report-api/src/Api";
|
|
38
39
|
|
|
39
|
-
export const
|
|
40
|
+
export const cram = await fetchAsBytes(cramUrl as string);
|
|
41
|
+
export const crai = await fetchAsBytes(craiUrl as string);
|
|
40
42
|
|
|
41
43
|
export const decisionTree: DecisionTree = decisionTreeJson as DecisionTree;
|
|
42
44
|
|
|
@@ -3,6 +3,7 @@ import { parseVcf } from "@molgenis/vip-report-vcf/src/VcfParser";
|
|
|
3
3
|
import {
|
|
4
4
|
Api,
|
|
5
5
|
AppMetadata,
|
|
6
|
+
Cram,
|
|
6
7
|
DecisionTree,
|
|
7
8
|
HtsFileMetadata,
|
|
8
9
|
Item,
|
|
@@ -14,7 +15,8 @@ import {
|
|
|
14
15
|
} from "@molgenis/vip-report-api/src/Api";
|
|
15
16
|
import { samples1, samples100 } from "./static";
|
|
16
17
|
import {
|
|
17
|
-
|
|
18
|
+
cram as cramGRCh37,
|
|
19
|
+
crai as craiGRCh37,
|
|
18
20
|
decisionTree as decisionTreeGRCh37,
|
|
19
21
|
fastaGz as fastaGzGRCh37,
|
|
20
22
|
genesGz as genesGzGRCh37,
|
|
@@ -26,7 +28,8 @@ import {
|
|
|
26
28
|
vcfSamples100 as vcfSamples100GRCh37,
|
|
27
29
|
} from "./GRCh37/static";
|
|
28
30
|
import {
|
|
29
|
-
|
|
31
|
+
cram as cramGRCh38,
|
|
32
|
+
crai as craiGRCh38,
|
|
30
33
|
decisionTree as decisionTreeGRCh38,
|
|
31
34
|
fastaGz as fastaGzGRCh38,
|
|
32
35
|
genesGz as genesGzGRCh38,
|
|
@@ -59,8 +62,8 @@ export class MockApiClient implements Api {
|
|
|
59
62
|
return this.apiClient.getGenesGz();
|
|
60
63
|
}
|
|
61
64
|
|
|
62
|
-
|
|
63
|
-
return this.apiClient.
|
|
65
|
+
getCram(sampleId: string): Promise<Cram | null> {
|
|
66
|
+
return this.apiClient.getCram(sampleId);
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
getDecisionTree(): Promise<DecisionTree | null> {
|
|
@@ -130,8 +133,11 @@ export class MockApiClient implements Api {
|
|
|
130
133
|
vcf: vcfFamilyGRCh37,
|
|
131
134
|
fastaGz: fastaGzGRCh37,
|
|
132
135
|
genesGz: genesGzGRCh37,
|
|
133
|
-
|
|
134
|
-
Patient:
|
|
136
|
+
cram: {
|
|
137
|
+
Patient: {
|
|
138
|
+
cram: cramGRCh37,
|
|
139
|
+
crai: craiGRCh37,
|
|
140
|
+
},
|
|
135
141
|
},
|
|
136
142
|
},
|
|
137
143
|
decisionTree: decisionTreeGRCh37,
|
|
@@ -155,8 +161,11 @@ export class MockApiClient implements Api {
|
|
|
155
161
|
vcf: vcfNoVepGRCh37,
|
|
156
162
|
fastaGz: fastaGzGRCh37,
|
|
157
163
|
genesGz: genesGzGRCh37,
|
|
158
|
-
|
|
159
|
-
Patient:
|
|
164
|
+
cram: {
|
|
165
|
+
Patient: {
|
|
166
|
+
cram: cramGRCh37,
|
|
167
|
+
crai: craiGRCh37,
|
|
168
|
+
},
|
|
160
169
|
},
|
|
161
170
|
},
|
|
162
171
|
decisionTree: decisionTreeGRCh37,
|
|
@@ -180,8 +189,11 @@ export class MockApiClient implements Api {
|
|
|
180
189
|
vcf: vcfSamples1GRCh37,
|
|
181
190
|
fastaGz: fastaGzGRCh37,
|
|
182
191
|
genesGz: genesGzGRCh37,
|
|
183
|
-
|
|
184
|
-
SAMPLE1:
|
|
192
|
+
cram: {
|
|
193
|
+
SAMPLE1: {
|
|
194
|
+
cram: cramGRCh37,
|
|
195
|
+
crai: craiGRCh37,
|
|
196
|
+
},
|
|
185
197
|
},
|
|
186
198
|
},
|
|
187
199
|
decisionTree: decisionTreeGRCh37,
|
|
@@ -249,8 +261,11 @@ export class MockApiClient implements Api {
|
|
|
249
261
|
vcf: vcfFamilyGRCh38,
|
|
250
262
|
fastaGz: fastaGzGRCh38,
|
|
251
263
|
genesGz: genesGzGRCh38,
|
|
252
|
-
|
|
253
|
-
Patient:
|
|
264
|
+
cram: {
|
|
265
|
+
Patient: {
|
|
266
|
+
cram: cramGRCh38,
|
|
267
|
+
crai: craiGRCh38,
|
|
268
|
+
},
|
|
254
269
|
},
|
|
255
270
|
},
|
|
256
271
|
decisionTree: decisionTreeGRCh38,
|
|
@@ -274,8 +289,11 @@ export class MockApiClient implements Api {
|
|
|
274
289
|
vcf: vcfNoVepGRCh38,
|
|
275
290
|
fastaGz: fastaGzGRCh38,
|
|
276
291
|
genesGz: genesGzGRCh38,
|
|
277
|
-
|
|
278
|
-
Patient:
|
|
292
|
+
cram: {
|
|
293
|
+
Patient: {
|
|
294
|
+
cram: cramGRCh38,
|
|
295
|
+
crai: craiGRCh38,
|
|
296
|
+
},
|
|
279
297
|
},
|
|
280
298
|
},
|
|
281
299
|
decisionTree: decisionTreeGRCh38,
|
|
@@ -299,8 +317,11 @@ export class MockApiClient implements Api {
|
|
|
299
317
|
vcf: vcfSamples1GRCh38,
|
|
300
318
|
fastaGz: fastaGzGRCh38,
|
|
301
319
|
genesGz: genesGzGRCh38,
|
|
302
|
-
|
|
303
|
-
SAMPLE1:
|
|
320
|
+
cram: {
|
|
321
|
+
SAMPLE1: {
|
|
322
|
+
cram: cramGRCh38,
|
|
323
|
+
crai: craiGRCh38,
|
|
324
|
+
},
|
|
304
325
|
},
|
|
305
326
|
},
|
|
306
327
|
decisionTree: decisionTreeGRCh38,
|
package/src/utils/viewUtils.ts
CHANGED
|
@@ -21,18 +21,12 @@ export function getRecordSamples(record: Record, sample: Sample, pedigreeSamples
|
|
|
21
21
|
return [record.s[sample.index], ...pedigreeSamples.map((pedigreeSample) => record.s[pedigreeSample.index])];
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
export function getHeaderValue(key: string, lines: string[]) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (line.startsWith(
|
|
28
|
-
|
|
29
|
-
if (splitted.length === 2) {
|
|
30
|
-
value = splitted[1];
|
|
31
|
-
return;
|
|
32
|
-
} else {
|
|
33
|
-
throw new Error("Invalid header format for key");
|
|
34
|
-
}
|
|
24
|
+
export function getHeaderValue(key: string, lines: string[]): string | null {
|
|
25
|
+
const token = `##${key}=`;
|
|
26
|
+
for (const line of lines) {
|
|
27
|
+
if (line.startsWith(token)) {
|
|
28
|
+
return line.substring(token.length);
|
|
35
29
|
}
|
|
36
|
-
}
|
|
37
|
-
return
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
38
32
|
}
|
|
@@ -210,14 +210,14 @@ export const SampleVariants: Component<{
|
|
|
210
210
|
{infoFields().length > 0 && <Sort options={sortOptions()} onChange={onSortChange} onClear={onSortClear} />}
|
|
211
211
|
</div>
|
|
212
212
|
<div class="column is-4">
|
|
213
|
-
<Show when={records()} fallback={<Loader />}>
|
|
213
|
+
<Show when={records()} fallback={<Loader />} keyed>
|
|
214
214
|
{(records) => <Pager page={records.page} onPageChange={onPageChange} />}
|
|
215
215
|
</Show>
|
|
216
216
|
</div>
|
|
217
217
|
<div class="column">
|
|
218
218
|
<div class="columns">
|
|
219
219
|
<div class="column is-10">
|
|
220
|
-
<Show when={records()} fallback={<Loader />}>
|
|
220
|
+
<Show when={records()} fallback={<Loader />} keyed>
|
|
221
221
|
{(records) => (
|
|
222
222
|
<span class="is-pulled-right" style={{ margin: "auto" }}>
|
|
223
223
|
{records.page.totalElements} records
|
|
@@ -238,7 +238,7 @@ export const SampleVariants: Component<{
|
|
|
238
238
|
</div>
|
|
239
239
|
</div>
|
|
240
240
|
<div class="columns">
|
|
241
|
-
<Show when={records()} fallback={<Loader />}>
|
|
241
|
+
<Show when={records()} fallback={<Loader />} keyed>
|
|
242
242
|
{(records) => (
|
|
243
243
|
<VariantsSampleTable
|
|
244
244
|
item={props.sample}
|
package/src/views/Samples.tsx
CHANGED
|
@@ -75,7 +75,7 @@ export const Samples: Component = () => {
|
|
|
75
75
|
return (
|
|
76
76
|
<>
|
|
77
77
|
<Breadcrumb items={[{ text: "Samples" }]} />
|
|
78
|
-
<Show when={samples()} fallback={<Loader />}>
|
|
78
|
+
<Show when={samples()} fallback={<Loader />} keyed>
|
|
79
79
|
{(samples) => (
|
|
80
80
|
<>
|
|
81
81
|
<div class="columns">
|
|
@@ -45,7 +45,7 @@ export const VariantConsequence: Component = () => {
|
|
|
45
45
|
<ConsequenceTable csqMetadata={csqFields()} csqValues={csqValues()} record={variant()} />
|
|
46
46
|
</div>
|
|
47
47
|
{hasDecisionTreePathMeta() && (
|
|
48
|
-
<Show when={!recordsMetadata.loading && !decisionTree.loading && (decisionTree() as DecisionTree)}>
|
|
48
|
+
<Show when={!recordsMetadata.loading && !decisionTree.loading && (decisionTree() as DecisionTree)} keyed>
|
|
49
49
|
{(decisionTree) => (
|
|
50
50
|
<div class="column">
|
|
51
51
|
<h1 class="title is-5">Classification tree path</h1>
|
|
Binary file
|
|
Binary file
|