@molgenis/vip-report-template 7.1.3 → 8.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/.gitattributes +3 -1
- package/README.md +13 -0
- package/eslint.config.mjs +6 -1
- package/package.json +6 -5
- package/scripts/validateConfig/README.txt +5 -0
- package/scripts/validateConfig/compileValidator.ts +17 -0
- package/scripts/validateConfig/createSchema.ts +6 -0
- package/scripts/validateConfig/schema.ts +370 -0
- package/src/App.tsx +2 -1
- package/src/components/DatasetDropdown.tsx +1 -1
- package/src/components/GenomeBrowser.tsx +14 -4
- package/src/components/RecordsTable.tsx +23 -6
- package/src/components/VariantConsequenceContainer.tsx +9 -2
- package/src/components/VariantInfoTable.tsx +1 -1
- package/src/components/VariantsContainer.tsx +47 -9
- package/src/components/VariantsContainerHeader.tsx +1 -8
- package/src/components/field/composed/FieldGenotype.tsx +1 -1
- package/src/components/field/composed/FieldGenotypeStr.tsx +18 -10
- package/src/components/field/composed/FieldGnomAd.tsx +1 -1
- package/src/components/field/composed/FieldInheritanceModes.tsx +1 -4
- package/src/components/field/composed/FieldVkgl.tsx +1 -1
- package/src/components/field/typed/FieldCategorical.tsx +1 -1
- package/src/components/field/typed/FieldCharacter.tsx +1 -1
- package/src/components/field/typed/FieldFlag.tsx +1 -1
- package/src/components/field/typed/FieldFloat.tsx +1 -1
- package/src/components/field/typed/FieldInteger.tsx +1 -1
- package/src/components/field/typed/FieldString.tsx +1 -1
- package/src/components/filter/Filter.tsx +1 -0
- package/src/components/filter/composed/FilterAllelicImbalance.tsx +1 -0
- package/src/components/filter/composed/FilterComposed.tsx +7 -0
- package/src/components/filter/composed/FilterDeNovo.tsx +1 -0
- package/src/components/filter/composed/FilterHpo.tsx +1 -0
- package/src/components/filter/composed/FilterInheritance.tsx +1 -0
- package/src/components/filter/composed/FilterLocus.tsx +17 -3
- package/src/components/filter/composed/FilterPick.tsx +30 -0
- package/src/components/filter/composed/FilterVipC.tsx +1 -0
- package/src/components/filter/composed/FilterVipCS.tsx +1 -0
- package/src/components/filter/fixed/FilterFixed.tsx +7 -0
- package/src/components/filter/typed/FilterCategorical.tsx +18 -1
- package/src/components/filter/typed/FilterFlag.tsx +2 -0
- package/src/components/filter/typed/FilterInterval.tsx +29 -1
- package/src/components/filter/typed/FilterString.tsx +8 -1
- package/src/components/filter/typed/FilterTyped.tsx +1 -0
- package/src/components/form/ButtonApply.tsx +6 -2
- package/src/mocks/GRCh38/README.txt +15 -0
- package/src/mocks/GRCh38/decisionTree.json +201 -0
- package/src/mocks/GRCh38/family.ped +6 -0
- package/src/mocks/GRCh38/field_metadata.json +36 -11
- package/src/mocks/GRCh38/sample1.ped +1 -0
- package/src/mocks/GRCh38/static.ts +36 -148
- package/src/mocks/GRCh38/str.ped +1 -0
- package/src/mocks/GRCh38/vcf/family.db.blob +0 -0
- package/src/mocks/GRCh38/vcf/family.vcf +312 -0
- package/src/mocks/GRCh38/vcf/fixPaths.sql +7 -0
- package/src/mocks/GRCh38/vcf/no_vep.db.blob +0 -0
- package/src/mocks/GRCh38/vcf/{no_vep.vcf.blob → no_vep.vcf} +1 -1
- package/src/mocks/GRCh38/vcf/samples_0.db.blob +0 -0
- package/src/mocks/GRCh38/vcf/samples_1.db.blob +0 -0
- package/src/mocks/GRCh38/vcf/samples_100.db.blob +0 -0
- package/src/mocks/GRCh38/vcf/{samples_100.vcf.blob → samples_100.vcf} +6 -6
- package/src/mocks/GRCh38/vcf/str.db.blob +0 -0
- package/src/mocks/GRCh38/vcf/{str.vcf.blob → str.vcf} +17 -17
- package/src/mocks/MockApiClient.ts +60 -226
- package/src/mocks/config_cram.json +4 -0
- package/src/mocks/config_default_values.json +722 -0
- package/src/mocks/config_vcf.json +15 -1
- package/src/mocks/sql-wasm.wasm.blob +0 -0
- package/src/types/config.d.ts +9 -5
- package/src/types/configCells.d.ts +1 -0
- package/src/types/configFilter.d.ts +1 -0
- package/src/types/configFilterComposed.d.ts +3 -0
- package/src/utils/api.ts +21 -49
- package/src/utils/config/configCellsComposed.ts +1 -1
- package/src/utils/config/configCellsField.ts +2 -0
- package/src/utils/config/configFiltersComposed.ts +7 -0
- package/src/utils/config/configFiltersField.ts +3 -2
- package/src/utils/config/configFiltersFixed.ts +7 -0
- package/src/utils/config/configValidator.precompiled.ts +83402 -0
- package/src/utils/config/configValidator.ts +3 -368
- package/src/utils/csq.ts +5 -10
- package/src/utils/decisionTree.ts +8 -9
- package/src/utils/query/query.ts +3 -2
- package/src/utils/query/queryFilter.ts +2 -3
- package/src/utils/query/queryFilterComposed.ts +12 -12
- package/src/utils/query/queryFilterField.ts +14 -7
- package/src/utils/query/queryFilterFixed.ts +5 -5
- package/src/utils/query/querySample.ts +15 -4
- package/src/utils/query/selector.ts +5 -20
- package/src/utils/query/sort.ts +4 -4
- package/src/utils/vcf.ts +20 -11
- package/src/views/Help.tsx +2 -2
- package/src/views/SampleVariant.tsx +4 -1
- package/src/views/Samples.tsx +10 -3
- package/src/views/data/data.tsx +2 -2
- package/tests/utils/config/configFiltersComposed.test.ts +2 -0
- package/tests/utils/config/configFiltersField.test.ts +4 -2
- package/tests/utils/config/configFiltersFixed.test.ts +23 -6
- package/tests/utils/query/query.test.ts +34 -6
- package/tests/utils/query/queryFilter.test.ts +4 -31
- package/tests/utils/query/queryFilterComposed.test.ts +13 -13
- package/tests/utils/query/queryFilterField.test.ts +5 -5
- package/tests/utils/query/queryFilterFixed.test.ts +5 -5
- package/tests/utils/query/querySample.test.ts +50 -10
- package/tests/utils/query/sort.test.ts +1 -1
- package/tests/utils/vcf.test.ts +1 -0
- package/vite.config.mts +2 -1
- package/src/mocks/GRCh37/alignment.cram.blob +0 -0
- package/src/mocks/GRCh37/alignment.cram.crai.blob +0 -0
- package/src/mocks/GRCh37/decisionTree.json +0 -355
- package/src/mocks/GRCh37/fasta/1-10042288-10042788.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/1-152520538-152521038.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/1-16375333-16375833.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/1-16376162-16376662.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/1-17348965-17349469.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/1-17348969-17349469.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/1-17354844-17355344.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/10-126091249-126091749.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/11-134013975-134014475.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/13-77569878-77570378.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/14-105167610-105168110.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/14-89307588-89308088.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/14-89309945-89310445.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/14-89336157-89336657.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/17-29555814-29556314.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/17-29585172-29585672.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/17-29663629-29664129.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/17-29675976-29676476.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/17-29683733-29684233.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/19-11215896-11216396.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/19-11223801-11224301.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/19-17449149-17449649.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/19-17451747-17452247.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/2-47635417-47635917.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/20-62326742-62327242.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/22-50627343-50627843.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/22-50721296-50721796.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/4-106320044-106320544.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/7-42017061-42017561.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/7-42064707-42065207.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/8-145140250-145140750.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/8-61764893-61765393.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/9-107546383-107546883.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/9-107584614-107585114.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/MT-15076-15576.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/X-48932771-48933271.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/fasta/Y-2655391-2655891.fasta.gz.blob +0 -0
- package/src/mocks/GRCh37/field_metadata.json +0 -794
- package/src/mocks/GRCh37/genes.gff.gz.blob +0 -0
- package/src/mocks/GRCh37/sampleTree.json +0 -143
- package/src/mocks/GRCh37/static.ts +0 -189
- package/src/mocks/GRCh37/vcf/family.vcf.blob +0 -134
- package/src/mocks/GRCh38/vcf/family.vcf.blob +0 -272
- package/src/mocks/static.ts +0 -1636
- /package/src/mocks/GRCh38/vcf/{samples_0.vcf.blob → samples_0.vcf} +0 -0
- /package/src/mocks/GRCh38/vcf/{samples_1.vcf.blob → samples_1.vcf} +0 -0
package/.gitattributes
CHANGED
package/README.md
CHANGED
|
@@ -158,6 +158,19 @@ The following composed filters are available:
|
|
|
158
158
|
| vipC | `INFO/CSQ/VIPC`, parameter `vcf.filter.consequences=true`, `vcf.filter.classes` > 0 | | Filter on the VIP classification value stored in INFO/CSQ/VIPC, but only includes categories defined in the VIP configuration parameter `vcf.filter.classes` |
|
|
159
159
|
| vipCS | `FORMAT/VIPC_S`, `sample` exists, `sample.proband=true`, parameter `vcf.filter.sample_classes` > 0 | | Filter on the VIP sample classification value stored in FORMAT/VIPC_S, but only includes categories defined in the VIP configuration parameter `vcf.filter_samples.classes` |
|
|
160
160
|
|
|
161
|
+
##### Default values
|
|
162
|
+
Filters can be given a default value using the "defaultValue" property.
|
|
163
|
+
|
|
164
|
+
The defaultValue is a string that should be properly formatted for the type of filters / values:
|
|
165
|
+
|
|
166
|
+
| filter / value type | format | examples |
|
|
167
|
+
|---------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------|
|
|
168
|
+
| string | any string. | "test" |
|
|
169
|
+
| interval (numbers) | comma separated string with a from and to value, if no comma is provided the value is used as the 'from' value. If only the 'to' value should be provided the string should start with a comma. | "1,100", ",100", "1" |
|
|
170
|
+
| locus | the format for this filter is: 'contig:form-to' or a string providing only the contig . | "chr1:1-10000000", "chrX" |
|
|
171
|
+
| categorical | comma separated string with the id's of the categories, '__null' is used for the 'unspecified' checkbox. | "LP,P", "cat1,cat2,__null" |
|
|
172
|
+
| flag / boolean | this is a special case of 'categorical' with categories 'true', 'false' and optionally '__null' | "true", "true,false,__null" |
|
|
173
|
+
|
|
161
174
|
#### Sorts
|
|
162
175
|
|
|
163
176
|
Via this section available sort options and the default sort of the different views can be configured.
|
package/eslint.config.mjs
CHANGED
|
@@ -4,8 +4,13 @@ import solid from "eslint-plugin-solid/configs/typescript";
|
|
|
4
4
|
import tseslint from "typescript-eslint";
|
|
5
5
|
|
|
6
6
|
export default [
|
|
7
|
+
{
|
|
8
|
+
ignores: [
|
|
9
|
+
"**/*.precompiled.ts"
|
|
10
|
+
]
|
|
11
|
+
},
|
|
7
12
|
{ files: ["**/*.{js,mjs,cjs,ts,tsx}"] },
|
|
8
13
|
pluginJs.configs.recommended,
|
|
9
14
|
solid,
|
|
10
15
|
...tseslint.configs.recommended,
|
|
11
|
-
];
|
|
16
|
+
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@molgenis/vip-report-template",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.0",
|
|
4
4
|
"description": "Report Template for Variant Call Format (VCF) Report Generator",
|
|
5
5
|
"license": "LGPL-3.0",
|
|
6
6
|
"devDependencies": {
|
|
@@ -19,20 +19,21 @@
|
|
|
19
19
|
"sass": "^1.85.0",
|
|
20
20
|
"typescript": "^5.7.3",
|
|
21
21
|
"typescript-eslint": "^8.24.0",
|
|
22
|
-
"vite": "^6.1
|
|
22
|
+
"vite": "^6.4.1",
|
|
23
23
|
"vite-plugin-solid": "^2.11.1",
|
|
24
24
|
"vitest": "^3.0.5"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
|
28
28
|
"@fortawesome/free-solid-svg-icons": "^6.7.2",
|
|
29
|
-
"@molgenis/vip-report-api": "^
|
|
30
|
-
"@molgenis/vip-report-vcf": "^
|
|
29
|
+
"@molgenis/vip-report-api": "^7.0.1",
|
|
30
|
+
"@molgenis/vip-report-vcf": "^4.0.2",
|
|
31
31
|
"@solidjs/router": "^0.15.3",
|
|
32
32
|
"ajv": "^8.17.1",
|
|
33
33
|
"base64-js": "^1.5.1",
|
|
34
34
|
"igv": "^3.1.4",
|
|
35
|
-
"solid-js": "^1.9.4"
|
|
35
|
+
"solid-js": "^1.9.4",
|
|
36
|
+
"sql.js": "^1.13.0"
|
|
36
37
|
},
|
|
37
38
|
"lint-staged": {
|
|
38
39
|
"src/**/*.{tsx,ts}": [
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
If the schema is updated, either the schema.ts or its dependencies, run the following to generate a new validator:
|
|
2
|
+
"npx tsx .\scripts\validateConfig\createSchema.ts"
|
|
3
|
+
and
|
|
4
|
+
"npx tsx .\scripts\validateConfig\compileValidator.ts"
|
|
5
|
+
this will create a new version of the validator in: src/utils/config/configValidator.precompiled.ts
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import Ajv from "ajv/dist/jtd";
|
|
2
|
+
import { readFileSync, writeFileSync } from "fs";
|
|
3
|
+
|
|
4
|
+
const schema = JSON.parse(readFileSync("schemaConfigJson.jtd.json", "utf-8"));
|
|
5
|
+
const ajv = new Ajv();
|
|
6
|
+
const validateCode = ajv.compile(schema).toString();
|
|
7
|
+
|
|
8
|
+
writeFileSync(
|
|
9
|
+
"src/utils/config/configValidator.precompiled.ts",
|
|
10
|
+
`import { ValidateFunction } from "ajv/dist/jtd";
|
|
11
|
+
import type { ConfigJson } from "../../types/config";
|
|
12
|
+
|
|
13
|
+
const validate: ValidateFunction<ConfigJson> = ${validateCode};
|
|
14
|
+
export default validate;`
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
console.log("Wrote validateConfig.precompiled.js");
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
// noinspection TypeScriptUnresolvedReference
|
|
2
|
+
|
|
3
|
+
import { JTDSchemaType } from "ajv/dist/types/jtd-schema";
|
|
4
|
+
import {
|
|
5
|
+
ConfigJson,
|
|
6
|
+
ConfigJsonField,
|
|
7
|
+
ConfigJsonFilter,
|
|
8
|
+
ConfigJsonRecordsPerPageOption,
|
|
9
|
+
ConfigJsonSort,
|
|
10
|
+
ConfigJsonSortOrder, ConfigJsonVariant, ConfigJsonVariantConsequence,
|
|
11
|
+
ConfigJsonVariants,
|
|
12
|
+
ConfigJsonVip,
|
|
13
|
+
ConfigJsonVipParams,
|
|
14
|
+
ConfigJsonVipParamsCram,
|
|
15
|
+
ConfigJsonVipParamsVcf
|
|
16
|
+
} from "../../src/types/config";
|
|
17
|
+
|
|
18
|
+
// allow additional properties so we can extend config in vip without updating vip-report-template
|
|
19
|
+
const schemaConfigJsonVipParamsVcf: JTDSchemaType<ConfigJsonVipParamsVcf> = {
|
|
20
|
+
properties: {
|
|
21
|
+
filter: {
|
|
22
|
+
properties: { classes: { type: "string" }, consequences: { type: "boolean" } },
|
|
23
|
+
additionalProperties: true,
|
|
24
|
+
},
|
|
25
|
+
filter_samples: {
|
|
26
|
+
properties: { classes: { type: "string" } },
|
|
27
|
+
additionalProperties: true,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
additionalProperties: true,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// allow additional properties so we can extend config in vip without updating vip-report-template
|
|
34
|
+
const schemaConfigJsonVipParamsCram: JTDSchemaType<ConfigJsonVipParamsCram> = {
|
|
35
|
+
properties: {
|
|
36
|
+
call_snv: { type: "boolean" },
|
|
37
|
+
call_str: { type: "boolean" },
|
|
38
|
+
call_sv: { type: "boolean" },
|
|
39
|
+
call_cnv: { type: "boolean" },
|
|
40
|
+
},
|
|
41
|
+
additionalProperties: true,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// allow additional properties so we can extend config in vip without updating vip-report-template
|
|
45
|
+
const schemaConfigJsonVipParams: JTDSchemaType<ConfigJsonVipParams> = {
|
|
46
|
+
properties: {
|
|
47
|
+
vcf: schemaConfigJsonVipParamsVcf,
|
|
48
|
+
},
|
|
49
|
+
optionalProperties: {
|
|
50
|
+
cram: schemaConfigJsonVipParamsCram,
|
|
51
|
+
},
|
|
52
|
+
additionalProperties: true,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const schemaConfigJsonVip: JTDSchemaType<ConfigJsonVip> = {
|
|
56
|
+
properties: {
|
|
57
|
+
filter_field: {
|
|
58
|
+
properties: { type: { enum: ["genotype"] }, name: { type: "string" } },
|
|
59
|
+
optionalProperties: { label: { type: "string" }, description: { type: "string" } },
|
|
60
|
+
},
|
|
61
|
+
params: schemaConfigJsonVipParams,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const schemaConfigJsonField: JTDSchemaType<ConfigJsonField> = {
|
|
66
|
+
discriminator: "type",
|
|
67
|
+
mapping: {
|
|
68
|
+
fixed: {
|
|
69
|
+
properties: {
|
|
70
|
+
name: { enum: ["chrom", "pos", "id", "ref", "alt", "qual", "filter"] },
|
|
71
|
+
},
|
|
72
|
+
optionalProperties: {
|
|
73
|
+
label: { type: "string" },
|
|
74
|
+
description: { type: "string" },
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
info: {
|
|
78
|
+
properties: {
|
|
79
|
+
name: { type: "string" },
|
|
80
|
+
},
|
|
81
|
+
optionalProperties: {
|
|
82
|
+
label: { type: "string" },
|
|
83
|
+
description: { type: "string" },
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
format: {
|
|
87
|
+
properties: {
|
|
88
|
+
name: { type: "string" },
|
|
89
|
+
},
|
|
90
|
+
optionalProperties: {
|
|
91
|
+
label: { type: "string" },
|
|
92
|
+
description: { type: "string" },
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
genotype: {
|
|
96
|
+
properties: {
|
|
97
|
+
name: { type: "string" },
|
|
98
|
+
},
|
|
99
|
+
optionalProperties: {
|
|
100
|
+
label: { type: "string" },
|
|
101
|
+
description: { type: "string" },
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
composed: {
|
|
105
|
+
properties: {
|
|
106
|
+
name: {
|
|
107
|
+
enum: [
|
|
108
|
+
"clinVar",
|
|
109
|
+
"gene",
|
|
110
|
+
"genotype",
|
|
111
|
+
"genotype_maternal",
|
|
112
|
+
"genotype_paternal",
|
|
113
|
+
"gnomAdAf",
|
|
114
|
+
"hpo",
|
|
115
|
+
"inheritancePattern",
|
|
116
|
+
"locus",
|
|
117
|
+
"vipC",
|
|
118
|
+
"vipCS",
|
|
119
|
+
"vkgl",
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
optionalProperties: {
|
|
124
|
+
label: { type: "string" },
|
|
125
|
+
description: { type: "string" },
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
group: {
|
|
129
|
+
// TODO deduplicate code, see mappings listed above
|
|
130
|
+
properties: {
|
|
131
|
+
fields: {
|
|
132
|
+
elements: {
|
|
133
|
+
discriminator: "type",
|
|
134
|
+
mapping: {
|
|
135
|
+
fixed: {
|
|
136
|
+
properties: {
|
|
137
|
+
name: { enum: ["chrom", "pos", "id", "ref", "alt", "qual", "filter"] },
|
|
138
|
+
},
|
|
139
|
+
optionalProperties: {
|
|
140
|
+
label: { type: "string" },
|
|
141
|
+
description: { type: "string" },
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
info: {
|
|
145
|
+
properties: {
|
|
146
|
+
name: { type: "string" },
|
|
147
|
+
},
|
|
148
|
+
optionalProperties: {
|
|
149
|
+
label: { type: "string" },
|
|
150
|
+
description: { type: "string" },
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
format: {
|
|
154
|
+
properties: {
|
|
155
|
+
name: { type: "string" },
|
|
156
|
+
},
|
|
157
|
+
optionalProperties: {
|
|
158
|
+
label: { type: "string" },
|
|
159
|
+
description: { type: "string" },
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
genotype: {
|
|
163
|
+
properties: {
|
|
164
|
+
name: { type: "string" },
|
|
165
|
+
},
|
|
166
|
+
optionalProperties: {
|
|
167
|
+
label: { type: "string" },
|
|
168
|
+
description: { type: "string" },
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
composed: {
|
|
172
|
+
properties: {
|
|
173
|
+
name: {
|
|
174
|
+
enum: [
|
|
175
|
+
"clinVar",
|
|
176
|
+
"gene",
|
|
177
|
+
"genotype",
|
|
178
|
+
"gnomAdAf",
|
|
179
|
+
"hpo",
|
|
180
|
+
"inheritancePattern",
|
|
181
|
+
"locus",
|
|
182
|
+
"ref",
|
|
183
|
+
"vipC",
|
|
184
|
+
"vipCS",
|
|
185
|
+
"vkgl",
|
|
186
|
+
],
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
optionalProperties: {
|
|
190
|
+
label: { type: "string" },
|
|
191
|
+
description: { type: "string" },
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const schemaConfigJsonFilter: JTDSchemaType<ConfigJsonFilter> = {
|
|
203
|
+
discriminator: "type",
|
|
204
|
+
mapping: {
|
|
205
|
+
fixed: {
|
|
206
|
+
properties: {
|
|
207
|
+
name: { enum: ["chrom", "pos", "id", "ref", "alt", "qual", "filter"] },
|
|
208
|
+
},
|
|
209
|
+
optionalProperties: {
|
|
210
|
+
label: { type: "string" },
|
|
211
|
+
description: { type: "string" },
|
|
212
|
+
defaultValue: { type: "string" }
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
info: {
|
|
216
|
+
properties: {
|
|
217
|
+
name: { type: "string" },
|
|
218
|
+
},
|
|
219
|
+
optionalProperties: {
|
|
220
|
+
label: { type: "string" },
|
|
221
|
+
description: { type: "string" },
|
|
222
|
+
defaultValue: { type: "string" }
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
format: {
|
|
226
|
+
properties: {
|
|
227
|
+
name: { type: "string" },
|
|
228
|
+
},
|
|
229
|
+
optionalProperties: {
|
|
230
|
+
label: { type: "string" },
|
|
231
|
+
description: { type: "string" },
|
|
232
|
+
defaultValue: { type: "string" }
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
genotype: {
|
|
236
|
+
properties: {
|
|
237
|
+
name: { type: "string" },
|
|
238
|
+
},
|
|
239
|
+
optionalProperties: {
|
|
240
|
+
label: { type: "string" },
|
|
241
|
+
description: { type: "string" },
|
|
242
|
+
defaultValue: { type: "string" }
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
composed: {
|
|
246
|
+
properties: {
|
|
247
|
+
name: {
|
|
248
|
+
enum: ["allelicImbalance", "deNovo", "hpo", "inheritanceMatch", "locus", "vipC", "vipCS"],
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
optionalProperties: {
|
|
252
|
+
label: { type: "string" },
|
|
253
|
+
description: { type: "string" },
|
|
254
|
+
defaultValue: { type: "string" }
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const schemaConfigJsonSortOrder: JTDSchemaType<ConfigJsonSortOrder> = {
|
|
261
|
+
properties: {
|
|
262
|
+
direction: { enum: ["asc", "desc"] },
|
|
263
|
+
field: schemaConfigJsonField,
|
|
264
|
+
},
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
const schemaConfigJsonSort: JTDSchemaType<ConfigJsonSort> = {
|
|
268
|
+
properties: {
|
|
269
|
+
selected: { type: "boolean" },
|
|
270
|
+
orders: {
|
|
271
|
+
elements: schemaConfigJsonSortOrder,
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const schemaConfigJsonRecordsPerPageOption: JTDSchemaType<ConfigJsonRecordsPerPageOption> = {
|
|
277
|
+
properties: {
|
|
278
|
+
number: { type: "uint16" },
|
|
279
|
+
},
|
|
280
|
+
optionalProperties: {
|
|
281
|
+
selected: { type: "boolean" },
|
|
282
|
+
},
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const schemaConfigJsonVariants: JTDSchemaType<ConfigJsonVariants> = {
|
|
286
|
+
properties: {
|
|
287
|
+
cells: {
|
|
288
|
+
optionalProperties: {
|
|
289
|
+
all: { elements: schemaConfigJsonField },
|
|
290
|
+
snv: { elements: schemaConfigJsonField },
|
|
291
|
+
str: { elements: schemaConfigJsonField },
|
|
292
|
+
sv: { elements: schemaConfigJsonField },
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
optionalProperties: {
|
|
297
|
+
filters: {
|
|
298
|
+
optionalProperties: {
|
|
299
|
+
all: { elements: schemaConfigJsonFilter },
|
|
300
|
+
snv: { elements: schemaConfigJsonFilter },
|
|
301
|
+
str: { elements: schemaConfigJsonFilter },
|
|
302
|
+
sv: { elements: schemaConfigJsonFilter },
|
|
303
|
+
},
|
|
304
|
+
},
|
|
305
|
+
sorts: {
|
|
306
|
+
optionalProperties: {
|
|
307
|
+
all: { elements: schemaConfigJsonSort },
|
|
308
|
+
snv: { elements: schemaConfigJsonSort },
|
|
309
|
+
str: { elements: schemaConfigJsonSort },
|
|
310
|
+
sv: { elements: schemaConfigJsonSort },
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
recordsPerPage: {
|
|
314
|
+
optionalProperties: {
|
|
315
|
+
all: { elements: schemaConfigJsonRecordsPerPageOption },
|
|
316
|
+
snv: { elements: schemaConfigJsonRecordsPerPageOption },
|
|
317
|
+
str: { elements: schemaConfigJsonRecordsPerPageOption },
|
|
318
|
+
sv: { elements: schemaConfigJsonRecordsPerPageOption },
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
const schemaConfigJsonVariant: JTDSchemaType<ConfigJsonVariant> = {
|
|
325
|
+
properties: {
|
|
326
|
+
cells: {
|
|
327
|
+
optionalProperties: {
|
|
328
|
+
all: { elements: schemaConfigJsonField },
|
|
329
|
+
snv: { elements: schemaConfigJsonField },
|
|
330
|
+
str: { elements: schemaConfigJsonField },
|
|
331
|
+
sv: { elements: schemaConfigJsonField },
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
},
|
|
335
|
+
optionalProperties: {
|
|
336
|
+
sample_cells: {
|
|
337
|
+
optionalProperties: {
|
|
338
|
+
all: { elements: schemaConfigJsonField },
|
|
339
|
+
snv: { elements: schemaConfigJsonField },
|
|
340
|
+
str: { elements: schemaConfigJsonField },
|
|
341
|
+
sv: { elements: schemaConfigJsonField },
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
},
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
const schemaConfigJsonVariantConsequence: JTDSchemaType<ConfigJsonVariantConsequence> = {
|
|
348
|
+
optionalProperties: {
|
|
349
|
+
sample_cells: {
|
|
350
|
+
optionalProperties: {
|
|
351
|
+
all: { elements: schemaConfigJsonField },
|
|
352
|
+
snv: { elements: schemaConfigJsonField },
|
|
353
|
+
str: { elements: schemaConfigJsonField },
|
|
354
|
+
sv: { elements: schemaConfigJsonField },
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
},
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
export const schema: JTDSchemaType<ConfigJson> = {
|
|
361
|
+
properties: {
|
|
362
|
+
vip: schemaConfigJsonVip,
|
|
363
|
+
sample_variants: schemaConfigJsonVariants,
|
|
364
|
+
variants: schemaConfigJsonVariants,
|
|
365
|
+
sample_variant: schemaConfigJsonVariant,
|
|
366
|
+
variant: schemaConfigJsonVariant,
|
|
367
|
+
sample_variant_consequence: schemaConfigJsonVariantConsequence,
|
|
368
|
+
variant_consequence: schemaConfigJsonVariantConsequence,
|
|
369
|
+
},
|
|
370
|
+
};
|
package/src/App.tsx
CHANGED
|
@@ -4,11 +4,12 @@ import { DatasetDropdown } from "./components/DatasetDropdown";
|
|
|
4
4
|
import { fetchSampleProbandIds, isDatasetSupport } from "./utils/api.ts";
|
|
5
5
|
import { href } from "./utils/utils.ts";
|
|
6
6
|
import { getMetadata } from "./views/data/data.tsx";
|
|
7
|
+
import { HtsFileMetadata } from "@molgenis/vip-report-api";
|
|
7
8
|
|
|
8
9
|
// export for development purposes
|
|
9
10
|
export function init(navigate: Navigator, location?: Location) {
|
|
10
11
|
(async () => {
|
|
11
|
-
document.title = `VCF Report (${(await getMetadata()).htsFile.uri})`;
|
|
12
|
+
document.title = `VCF Report (${((await getMetadata()).app.htsFile as HtsFileMetadata).uri})`;
|
|
12
13
|
const sampleIds = await fetchSampleProbandIds();
|
|
13
14
|
if (location === undefined || location.pathname === "/") {
|
|
14
15
|
let components: (string | number)[];
|
|
@@ -8,7 +8,7 @@ export const DatasetDropdown: Component = () => {
|
|
|
8
8
|
const navigate = useNavigate();
|
|
9
9
|
const [, actions] = useStore();
|
|
10
10
|
|
|
11
|
-
const [selectedDataset, setSelectedDataset] = createSignal("
|
|
11
|
+
const [selectedDataset, setSelectedDataset] = createSignal("GRCh38 Family");
|
|
12
12
|
|
|
13
13
|
function switchIt(datasetName: string) {
|
|
14
14
|
actions.reset();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Component, onCleanup, onMount } from "solid-js";
|
|
2
2
|
import igv, { Browser } from "igv";
|
|
3
3
|
import { fromByteArray } from "base64-js";
|
|
4
|
-
import { VcfRecord, writeVcf } from "@molgenis/vip-report-vcf";
|
|
4
|
+
import { VariantRecords, VcfRecord, writeVcf } from "@molgenis/vip-report-vcf";
|
|
5
5
|
import { ComposedQuery, Cram, Item, Sample } from "@molgenis/vip-report-api";
|
|
6
6
|
import { fetchCram, fetchFastaGz, fetchGenesGz, fetchRecords, MetadataContainer } from "../utils/api.ts";
|
|
7
7
|
|
|
@@ -24,9 +24,19 @@ async function fetchVcf(
|
|
|
24
24
|
},
|
|
25
25
|
],
|
|
26
26
|
};
|
|
27
|
-
const records = await fetchRecords({
|
|
27
|
+
const records = await fetchRecords({
|
|
28
|
+
query,
|
|
29
|
+
size: Number.MAX_SAFE_INTEGER,
|
|
30
|
+
sampleIds: samples.map((sample) => sample.id),
|
|
31
|
+
});
|
|
28
32
|
const vcf = writeVcf(
|
|
29
|
-
{
|
|
33
|
+
{
|
|
34
|
+
metadata: metadata.records,
|
|
35
|
+
data: records.items.reduce((acc, item) => {
|
|
36
|
+
acc[item.id] = item.data;
|
|
37
|
+
return acc;
|
|
38
|
+
}, {} as VariantRecords),
|
|
39
|
+
},
|
|
30
40
|
{ samples: samples.map((sample) => sample.data.person.individualId) },
|
|
31
41
|
);
|
|
32
42
|
return toBytes(vcf);
|
|
@@ -75,7 +85,7 @@ const createBrowserConfig = async (
|
|
|
75
85
|
|
|
76
86
|
return {
|
|
77
87
|
reference: {
|
|
78
|
-
id: metadata.htsFile
|
|
88
|
+
id: metadata.app.htsFile?.genomeAssembly,
|
|
79
89
|
name: "Reference",
|
|
80
90
|
fastaURL: "data:application/gzip;base64," + fromByteArray(fastaGz),
|
|
81
91
|
tracks: tracks,
|
|
@@ -11,10 +11,15 @@ export const RecordsTable: Component<{
|
|
|
11
11
|
fieldConfigs: ConfigCells;
|
|
12
12
|
records: Item<VcfRecord>[];
|
|
13
13
|
verticalHeaders?: boolean;
|
|
14
|
+
showParentHeader?: boolean;
|
|
14
15
|
}> = (props) => {
|
|
15
16
|
return (
|
|
16
17
|
<Table>
|
|
17
|
-
<RecordsTableHeader
|
|
18
|
+
<RecordsTableHeader
|
|
19
|
+
fieldConfigs={props.fieldConfigs}
|
|
20
|
+
verticalHeaders={props.verticalHeaders}
|
|
21
|
+
showParentHeader={props.showParentHeader !== undefined ? props.showParentHeader : false}
|
|
22
|
+
/>
|
|
18
23
|
<RecordsTableBody fieldConfigs={props.fieldConfigs} records={props.records} />
|
|
19
24
|
</Table>
|
|
20
25
|
);
|
|
@@ -23,24 +28,32 @@ export const RecordsTable: Component<{
|
|
|
23
28
|
const RecordsTableHeader: Component<{
|
|
24
29
|
fieldConfigs: ConfigCells;
|
|
25
30
|
verticalHeaders?: boolean;
|
|
31
|
+
showParentHeader: boolean;
|
|
26
32
|
}> = (props) => {
|
|
27
33
|
return (
|
|
28
34
|
<thead>
|
|
29
35
|
<tr style={props.verticalHeaders ? { "writing-mode": "vertical-rl" } : undefined}>
|
|
30
|
-
<RecordsTableHeaderCells fieldConfigs={props.fieldConfigs} />
|
|
36
|
+
<RecordsTableHeaderCells fieldConfigs={props.fieldConfigs} showParentHeader={props.showParentHeader} />
|
|
31
37
|
</tr>
|
|
32
38
|
</thead>
|
|
33
39
|
);
|
|
34
40
|
};
|
|
35
41
|
|
|
36
|
-
export const RecordsTableHeaderCells: Component<{ fieldConfigs: ConfigCells }> = (props) => {
|
|
42
|
+
export const RecordsTableHeaderCells: Component<{ fieldConfigs: ConfigCells; showParentHeader: boolean }> = (props) => {
|
|
43
|
+
const showParentHeader = () => props.showParentHeader;
|
|
37
44
|
return (
|
|
38
45
|
<For each={props.fieldConfigs}>
|
|
39
46
|
{(fieldConfig) => (
|
|
40
|
-
<Switch
|
|
47
|
+
<Switch
|
|
48
|
+
fallback={
|
|
49
|
+
<RecordsTableHeaderCell fieldConfig={fieldConfig as ConfigCellItem} showParentHeader={showParentHeader()} />
|
|
50
|
+
}
|
|
51
|
+
>
|
|
41
52
|
<Match when={fieldConfig.type === "group"}>
|
|
42
53
|
<For each={(fieldConfig as ConfigCellGroup).fieldConfigs}>
|
|
43
|
-
{(childConfigField) =>
|
|
54
|
+
{(childConfigField) => (
|
|
55
|
+
<RecordsTableHeaderCell fieldConfig={childConfigField} showParentHeader={showParentHeader()} />
|
|
56
|
+
)}
|
|
44
57
|
</For>
|
|
45
58
|
</Match>
|
|
46
59
|
</Switch>
|
|
@@ -51,8 +64,12 @@ export const RecordsTableHeaderCells: Component<{ fieldConfigs: ConfigCells }> =
|
|
|
51
64
|
|
|
52
65
|
export const RecordsTableHeaderCell: Component<{
|
|
53
66
|
fieldConfig: ConfigCellItem;
|
|
67
|
+
showParentHeader: boolean;
|
|
54
68
|
}> = (props) => {
|
|
55
|
-
const label = () =>
|
|
69
|
+
const label = () =>
|
|
70
|
+
props.fieldConfig.parentLabel !== undefined && props.fieldConfig.parentLabel() !== "" && props.showParentHeader
|
|
71
|
+
? `${props.fieldConfig.parentLabel()}/${props.fieldConfig.label()}`
|
|
72
|
+
: props.fieldConfig.label();
|
|
56
73
|
const description = () => props.fieldConfig.description();
|
|
57
74
|
|
|
58
75
|
return (
|
|
@@ -27,8 +27,15 @@ export const VariantConsequenceContainer: Component<{
|
|
|
27
27
|
|
|
28
28
|
const samples = (): Item<Sample>[] => (props.sample ? getPedigreeSamples(props.sample) : []);
|
|
29
29
|
const hasDecisionTreePathMeta = () =>
|
|
30
|
-
(props.metadata.records.info.CSQ?.nested?.items ||
|
|
30
|
+
Object.values(props.metadata.records.info.CSQ?.nested?.items || {}).some((csq) => csq.id === "VIPP");
|
|
31
31
|
const hasSampleTreePathMeta = () => props.metadata.records.format.VIPP_S != null;
|
|
32
|
+
const showSampleTree = () => {
|
|
33
|
+
if (props.sample) {
|
|
34
|
+
const treePath = getSampleTreePath(props.metadata.records, props.sample, props.record, props.consequenceId);
|
|
35
|
+
return treePath !== undefined && treePath.length > 0;
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
};
|
|
32
39
|
|
|
33
40
|
return (
|
|
34
41
|
<>
|
|
@@ -77,7 +84,7 @@ export const VariantConsequenceContainer: Component<{
|
|
|
77
84
|
/>
|
|
78
85
|
</div>
|
|
79
86
|
)}
|
|
80
|
-
{props.sampleTree !== null && hasSampleTreePathMeta() && props.sample && (
|
|
87
|
+
{showSampleTree() && props.sampleTree !== null && hasSampleTreePathMeta() && props.sample && (
|
|
81
88
|
<div class="column is-6">
|
|
82
89
|
<h1 class="title is-5">Sample classification tree path</h1>
|
|
83
90
|
<DecisionTreePath
|
|
@@ -31,7 +31,7 @@ export const VariantInfoTable: Component<{
|
|
|
31
31
|
<For each={configCells()}>
|
|
32
32
|
{(fieldConfig) => (
|
|
33
33
|
<tr>
|
|
34
|
-
<RecordsTableHeaderCell fieldConfig={fieldConfig} />
|
|
34
|
+
<RecordsTableHeaderCell fieldConfig={fieldConfig} showParentHeader={true} />
|
|
35
35
|
<RecordsTableCell fieldConfig={fieldConfig} record={props.record} />
|
|
36
36
|
</tr>
|
|
37
37
|
)}
|