@molgenis/vip-report-template 7.1.3 → 8.0.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.
Files changed (155) hide show
  1. package/.gitattributes +3 -1
  2. package/README.md +13 -0
  3. package/eslint.config.mjs +6 -1
  4. package/package.json +6 -5
  5. package/scripts/validateConfig/README.txt +5 -0
  6. package/scripts/validateConfig/compileValidator.ts +17 -0
  7. package/scripts/validateConfig/createSchema.ts +6 -0
  8. package/scripts/validateConfig/schema.ts +370 -0
  9. package/src/App.tsx +2 -1
  10. package/src/components/DatasetDropdown.tsx +1 -1
  11. package/src/components/GenomeBrowser.tsx +14 -4
  12. package/src/components/RecordsTable.tsx +23 -6
  13. package/src/components/VariantConsequenceContainer.tsx +9 -2
  14. package/src/components/VariantInfoTable.tsx +1 -1
  15. package/src/components/VariantsContainer.tsx +47 -9
  16. package/src/components/VariantsContainerHeader.tsx +1 -8
  17. package/src/components/field/composed/FieldGenotype.tsx +1 -1
  18. package/src/components/field/composed/FieldGenotypeStr.tsx +18 -10
  19. package/src/components/field/composed/FieldGnomAd.tsx +1 -1
  20. package/src/components/field/composed/FieldInheritanceModes.tsx +1 -4
  21. package/src/components/field/composed/FieldVkgl.tsx +1 -1
  22. package/src/components/field/typed/FieldCategorical.tsx +1 -1
  23. package/src/components/field/typed/FieldCharacter.tsx +1 -1
  24. package/src/components/field/typed/FieldFlag.tsx +1 -1
  25. package/src/components/field/typed/FieldFloat.tsx +1 -1
  26. package/src/components/field/typed/FieldInteger.tsx +1 -1
  27. package/src/components/field/typed/FieldString.tsx +1 -1
  28. package/src/components/filter/Filter.tsx +1 -0
  29. package/src/components/filter/composed/FilterAllelicImbalance.tsx +1 -0
  30. package/src/components/filter/composed/FilterComposed.tsx +7 -0
  31. package/src/components/filter/composed/FilterDeNovo.tsx +1 -0
  32. package/src/components/filter/composed/FilterHpo.tsx +1 -0
  33. package/src/components/filter/composed/FilterInheritance.tsx +1 -0
  34. package/src/components/filter/composed/FilterLocus.tsx +17 -3
  35. package/src/components/filter/composed/FilterPick.tsx +30 -0
  36. package/src/components/filter/composed/FilterVipC.tsx +1 -0
  37. package/src/components/filter/composed/FilterVipCS.tsx +1 -0
  38. package/src/components/filter/fixed/FilterFixed.tsx +7 -0
  39. package/src/components/filter/typed/FilterCategorical.tsx +18 -1
  40. package/src/components/filter/typed/FilterFlag.tsx +2 -0
  41. package/src/components/filter/typed/FilterInterval.tsx +29 -1
  42. package/src/components/filter/typed/FilterString.tsx +8 -1
  43. package/src/components/filter/typed/FilterTyped.tsx +1 -0
  44. package/src/components/form/ButtonApply.tsx +6 -2
  45. package/src/mocks/GRCh38/README.txt +15 -0
  46. package/src/mocks/GRCh38/decisionTree.json +201 -0
  47. package/src/mocks/GRCh38/family.ped +6 -0
  48. package/src/mocks/GRCh38/field_metadata.json +36 -11
  49. package/src/mocks/GRCh38/sample1.ped +1 -0
  50. package/src/mocks/GRCh38/static.ts +36 -148
  51. package/src/mocks/GRCh38/str.ped +1 -0
  52. package/src/mocks/GRCh38/vcf/family.db.blob +0 -0
  53. package/src/mocks/GRCh38/vcf/family.vcf +312 -0
  54. package/src/mocks/GRCh38/vcf/fixPaths.sql +7 -0
  55. package/src/mocks/GRCh38/vcf/no_vep.db.blob +0 -0
  56. package/src/mocks/GRCh38/vcf/{no_vep.vcf.blob → no_vep.vcf} +1 -1
  57. package/src/mocks/GRCh38/vcf/samples_0.db.blob +0 -0
  58. package/src/mocks/GRCh38/vcf/samples_1.db.blob +0 -0
  59. package/src/mocks/GRCh38/vcf/samples_100.db.blob +0 -0
  60. package/src/mocks/GRCh38/vcf/{samples_100.vcf.blob → samples_100.vcf} +6 -6
  61. package/src/mocks/GRCh38/vcf/str.db.blob +0 -0
  62. package/src/mocks/GRCh38/vcf/{str.vcf.blob → str.vcf} +17 -17
  63. package/src/mocks/MockApiClient.ts +60 -226
  64. package/src/mocks/config_cram.json +4 -0
  65. package/src/mocks/config_default_values.json +722 -0
  66. package/src/mocks/config_vcf.json +15 -1
  67. package/src/mocks/sql-wasm.wasm.blob +0 -0
  68. package/src/types/config.d.ts +9 -5
  69. package/src/types/configCells.d.ts +1 -0
  70. package/src/types/configFilter.d.ts +1 -0
  71. package/src/types/configFilterComposed.d.ts +3 -0
  72. package/src/utils/api.ts +21 -49
  73. package/src/utils/config/configCellsComposed.ts +1 -1
  74. package/src/utils/config/configCellsField.ts +2 -0
  75. package/src/utils/config/configFiltersComposed.ts +7 -0
  76. package/src/utils/config/configFiltersField.ts +3 -2
  77. package/src/utils/config/configFiltersFixed.ts +7 -0
  78. package/src/utils/config/configValidator.precompiled.ts +83402 -0
  79. package/src/utils/config/configValidator.ts +3 -368
  80. package/src/utils/csq.ts +5 -10
  81. package/src/utils/decisionTree.ts +8 -9
  82. package/src/utils/query/query.ts +3 -2
  83. package/src/utils/query/queryFilter.ts +2 -3
  84. package/src/utils/query/queryFilterComposed.ts +12 -12
  85. package/src/utils/query/queryFilterField.ts +14 -7
  86. package/src/utils/query/queryFilterFixed.ts +5 -5
  87. package/src/utils/query/querySample.ts +15 -4
  88. package/src/utils/query/selector.ts +5 -20
  89. package/src/utils/query/sort.ts +4 -4
  90. package/src/utils/vcf.ts +20 -11
  91. package/src/views/Help.tsx +2 -2
  92. package/src/views/SampleVariant.tsx +4 -1
  93. package/src/views/Samples.tsx +10 -3
  94. package/src/views/data/data.tsx +2 -2
  95. package/tests/utils/config/configFiltersComposed.test.ts +2 -0
  96. package/tests/utils/config/configFiltersField.test.ts +4 -2
  97. package/tests/utils/config/configFiltersFixed.test.ts +23 -6
  98. package/tests/utils/query/query.test.ts +34 -6
  99. package/tests/utils/query/queryFilter.test.ts +4 -31
  100. package/tests/utils/query/queryFilterComposed.test.ts +13 -13
  101. package/tests/utils/query/queryFilterField.test.ts +5 -5
  102. package/tests/utils/query/queryFilterFixed.test.ts +5 -5
  103. package/tests/utils/query/querySample.test.ts +50 -10
  104. package/tests/utils/query/sort.test.ts +1 -1
  105. package/tests/utils/vcf.test.ts +1 -0
  106. package/vite.config.mts +2 -1
  107. package/src/mocks/GRCh37/alignment.cram.blob +0 -0
  108. package/src/mocks/GRCh37/alignment.cram.crai.blob +0 -0
  109. package/src/mocks/GRCh37/decisionTree.json +0 -355
  110. package/src/mocks/GRCh37/fasta/1-10042288-10042788.fasta.gz.blob +0 -0
  111. package/src/mocks/GRCh37/fasta/1-152520538-152521038.fasta.gz.blob +0 -0
  112. package/src/mocks/GRCh37/fasta/1-16375333-16375833.fasta.gz.blob +0 -0
  113. package/src/mocks/GRCh37/fasta/1-16376162-16376662.fasta.gz.blob +0 -0
  114. package/src/mocks/GRCh37/fasta/1-17348965-17349469.fasta.gz.blob +0 -0
  115. package/src/mocks/GRCh37/fasta/1-17348969-17349469.fasta.gz.blob +0 -0
  116. package/src/mocks/GRCh37/fasta/1-17354844-17355344.fasta.gz.blob +0 -0
  117. package/src/mocks/GRCh37/fasta/10-126091249-126091749.fasta.gz.blob +0 -0
  118. package/src/mocks/GRCh37/fasta/11-134013975-134014475.fasta.gz.blob +0 -0
  119. package/src/mocks/GRCh37/fasta/13-77569878-77570378.fasta.gz.blob +0 -0
  120. package/src/mocks/GRCh37/fasta/14-105167610-105168110.fasta.gz.blob +0 -0
  121. package/src/mocks/GRCh37/fasta/14-89307588-89308088.fasta.gz.blob +0 -0
  122. package/src/mocks/GRCh37/fasta/14-89309945-89310445.fasta.gz.blob +0 -0
  123. package/src/mocks/GRCh37/fasta/14-89336157-89336657.fasta.gz.blob +0 -0
  124. package/src/mocks/GRCh37/fasta/17-29555814-29556314.fasta.gz.blob +0 -0
  125. package/src/mocks/GRCh37/fasta/17-29585172-29585672.fasta.gz.blob +0 -0
  126. package/src/mocks/GRCh37/fasta/17-29663629-29664129.fasta.gz.blob +0 -0
  127. package/src/mocks/GRCh37/fasta/17-29675976-29676476.fasta.gz.blob +0 -0
  128. package/src/mocks/GRCh37/fasta/17-29683733-29684233.fasta.gz.blob +0 -0
  129. package/src/mocks/GRCh37/fasta/19-11215896-11216396.fasta.gz.blob +0 -0
  130. package/src/mocks/GRCh37/fasta/19-11223801-11224301.fasta.gz.blob +0 -0
  131. package/src/mocks/GRCh37/fasta/19-17449149-17449649.fasta.gz.blob +0 -0
  132. package/src/mocks/GRCh37/fasta/19-17451747-17452247.fasta.gz.blob +0 -0
  133. package/src/mocks/GRCh37/fasta/2-47635417-47635917.fasta.gz.blob +0 -0
  134. package/src/mocks/GRCh37/fasta/20-62326742-62327242.fasta.gz.blob +0 -0
  135. package/src/mocks/GRCh37/fasta/22-50627343-50627843.fasta.gz.blob +0 -0
  136. package/src/mocks/GRCh37/fasta/22-50721296-50721796.fasta.gz.blob +0 -0
  137. package/src/mocks/GRCh37/fasta/4-106320044-106320544.fasta.gz.blob +0 -0
  138. package/src/mocks/GRCh37/fasta/7-42017061-42017561.fasta.gz.blob +0 -0
  139. package/src/mocks/GRCh37/fasta/7-42064707-42065207.fasta.gz.blob +0 -0
  140. package/src/mocks/GRCh37/fasta/8-145140250-145140750.fasta.gz.blob +0 -0
  141. package/src/mocks/GRCh37/fasta/8-61764893-61765393.fasta.gz.blob +0 -0
  142. package/src/mocks/GRCh37/fasta/9-107546383-107546883.fasta.gz.blob +0 -0
  143. package/src/mocks/GRCh37/fasta/9-107584614-107585114.fasta.gz.blob +0 -0
  144. package/src/mocks/GRCh37/fasta/MT-15076-15576.fasta.gz.blob +0 -0
  145. package/src/mocks/GRCh37/fasta/X-48932771-48933271.fasta.gz.blob +0 -0
  146. package/src/mocks/GRCh37/fasta/Y-2655391-2655891.fasta.gz.blob +0 -0
  147. package/src/mocks/GRCh37/field_metadata.json +0 -794
  148. package/src/mocks/GRCh37/genes.gff.gz.blob +0 -0
  149. package/src/mocks/GRCh37/sampleTree.json +0 -143
  150. package/src/mocks/GRCh37/static.ts +0 -189
  151. package/src/mocks/GRCh37/vcf/family.vcf.blob +0 -134
  152. package/src/mocks/GRCh38/vcf/family.vcf.blob +0 -272
  153. package/src/mocks/static.ts +0 -1636
  154. /package/src/mocks/GRCh38/vcf/{samples_0.vcf.blob → samples_0.vcf} +0 -0
  155. /package/src/mocks/GRCh38/vcf/{samples_1.vcf.blob → samples_1.vcf} +0 -0
package/.gitattributes CHANGED
@@ -1,4 +1,6 @@
1
1
  *.* text eol=lf
2
2
  *.cram.blob binary
3
3
  *.cram.crai.blob binary
4
- *.gz.blob binary
4
+ *.gz.blob binary
5
+ *.wasm.blob binary
6
+ *.db.blob binary
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": "7.1.3",
3
+ "version": "8.0.1",
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.0",
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": "^6.2.3",
30
- "@molgenis/vip-report-vcf": "^3.1.1",
29
+ "@molgenis/vip-report-api": "^7.0.2",
30
+ "@molgenis/vip-report-vcf": "^4.0.3",
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,6 @@
1
+ import { writeFileSync } from "fs";
2
+ import { schema } from "./schema"; // adjust the path if needed
3
+
4
+ // Write the JSON schema to file
5
+ writeFileSync("schemaConfigJson.jtd.json", JSON.stringify(schema, null, 2));
6
+ console.log("Wrote schemaConfigJson.jtd.json");
@@ -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("GRCh37 Family");
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({ query, size: Number.MAX_SAFE_INTEGER });
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
- { metadata: metadata.records, data: records.items.map((item) => item.data) },
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.genomeAssembly,
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 fieldConfigs={props.fieldConfigs} verticalHeaders={props.verticalHeaders} />
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 fallback={<RecordsTableHeaderCell fieldConfig={fieldConfig as ConfigCellItem} />}>
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) => <RecordsTableHeaderCell fieldConfig={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 = () => props.fieldConfig.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 || []).findIndex((csq) => csq.id === "VIPP") !== -1;
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
  )}