@molgenis/vip-report-template 6.2.0 → 7.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 (285) hide show
  1. package/.nvmrc +1 -1
  2. package/.travis.yml +9 -9
  3. package/README.md +411 -1
  4. package/eslint.config.mjs +11 -0
  5. package/package.json +40 -35
  6. package/scripts/deploy_npm_registry.sh +5 -0
  7. package/src/App.tsx +30 -24
  8. package/src/assets/sass/main.scss +12 -4
  9. package/src/components/Allele.tsx +95 -0
  10. package/src/components/Anchor.tsx +1 -1
  11. package/src/components/Breadcrumb.tsx +6 -4
  12. package/src/components/DatasetDropdown.tsx +12 -25
  13. package/src/components/ErrorNotification.tsx +9 -0
  14. package/src/components/GenomeBrowser.tsx +40 -23
  15. package/src/components/HpoTerm.tsx +1 -1
  16. package/src/components/{record/Pager.tsx → Pager.tsx} +21 -14
  17. package/src/components/RecordsPerPage.tsx +9 -7
  18. package/src/components/RecordsTable.tsx +130 -0
  19. package/src/components/SampleTable.tsx +70 -98
  20. package/src/components/SearchBox.tsx +8 -2
  21. package/src/components/Sort.tsx +28 -25
  22. package/src/components/Table.tsx +16 -0
  23. package/src/components/Tooltip.tsx +20 -0
  24. package/src/components/VariantBreadcrumb.tsx +54 -0
  25. package/src/components/VariantConsequenceContainer.tsx +100 -0
  26. package/src/components/VariantConsequenceTable.tsx +58 -0
  27. package/src/components/VariantContainer.tsx +71 -0
  28. package/src/components/VariantFilters.tsx +27 -0
  29. package/src/components/VariantGenotypeTable.tsx +44 -0
  30. package/src/components/VariantInfoTable.tsx +24 -33
  31. package/src/components/VariantResults.tsx +103 -0
  32. package/src/components/VariantTable.tsx +62 -66
  33. package/src/components/VariantTypeSelect.tsx +34 -0
  34. package/src/components/VariantsContainer.tsx +150 -0
  35. package/src/components/VariantsContainerHeader.tsx +70 -0
  36. package/src/components/field/Field.tsx +80 -0
  37. package/src/components/field/FieldAlt.tsx +19 -0
  38. package/src/components/field/FieldChrom.tsx +6 -0
  39. package/src/components/{record/Id.tsx → field/FieldFilter.tsx} +2 -1
  40. package/src/components/field/FieldFormat.tsx +10 -0
  41. package/src/components/{record/Filter.tsx → field/FieldId.tsx} +1 -1
  42. package/src/components/field/FieldPos.tsx +6 -0
  43. package/src/components/field/FieldQual.tsx +6 -0
  44. package/src/components/field/FieldRef.tsx +8 -0
  45. package/src/components/field/composed/FieldClinVar.tsx +72 -0
  46. package/src/components/field/composed/FieldComposed.tsx +68 -0
  47. package/src/components/field/composed/FieldGene.tsx +39 -0
  48. package/src/components/field/composed/FieldGenotype.tsx +35 -0
  49. package/src/components/{record/format/GenotypeField.tsx → field/composed/FieldGenotypeSnvSv.tsx} +20 -16
  50. package/src/components/field/composed/FieldGenotypeStr.tsx +31 -0
  51. package/src/components/field/composed/FieldGnomAd.tsx +58 -0
  52. package/src/components/field/composed/FieldHpo.tsx +50 -0
  53. package/src/components/field/composed/FieldInheritanceModes.tsx +32 -0
  54. package/src/components/field/composed/FieldLocus.tsx +18 -0
  55. package/src/components/field/composed/FieldVipC.tsx +25 -0
  56. package/src/components/field/composed/FieldVipCS.tsx +15 -0
  57. package/src/components/field/composed/FieldVkgl.tsx +37 -0
  58. package/src/components/field/genotype/FieldGenotype.tsx +19 -0
  59. package/src/components/field/genotype/FieldGenotypeType.tsx +9 -0
  60. package/src/components/field/info/FieldConsequence.tsx +15 -0
  61. package/src/components/{record/info/Hgvs.tsx → field/info/FieldHgvs.tsx} +4 -6
  62. package/src/components/field/info/FieldInfo.tsx +27 -0
  63. package/src/components/{record/info/PubMed.tsx → field/info/FieldPubMed.tsx} +4 -7
  64. package/src/components/field/typed/FieldCategorical.tsx +17 -0
  65. package/src/components/{record/field/FieldValueCharacter.tsx → field/typed/FieldCharacter.tsx} +3 -2
  66. package/src/components/{record/field/FieldValueFlag.tsx → field/typed/FieldFlag.tsx} +3 -2
  67. package/src/components/{record/field/FieldValueFloat.tsx → field/typed/FieldFloat.tsx} +3 -2
  68. package/src/components/{record/field/FieldValueInteger.tsx → field/typed/FieldInteger.tsx} +3 -2
  69. package/src/components/{record/field/FieldValueString.tsx → field/typed/FieldString.tsx} +3 -2
  70. package/src/components/field/typed/FieldTyped.tsx +20 -0
  71. package/src/components/field/typed/FieldTypedItem.tsx +49 -0
  72. package/src/components/field/typed/FieldTypedMultiple.tsx +21 -0
  73. package/src/components/filter/Filter.tsx +56 -48
  74. package/src/components/filter/FilterWrapper.scss +23 -0
  75. package/src/components/filter/FilterWrapper.tsx +63 -0
  76. package/src/components/filter/composed/FilterAllelicImbalance.tsx +26 -0
  77. package/src/components/filter/composed/FilterComposed.tsx +92 -0
  78. package/src/components/filter/composed/FilterDeNovo.tsx +35 -0
  79. package/src/components/filter/composed/FilterHpo.tsx +16 -0
  80. package/src/components/filter/composed/FilterInheritance.tsx +42 -0
  81. package/src/components/filter/composed/FilterLocus.tsx +75 -0
  82. package/src/components/filter/composed/FilterVipC.tsx +16 -0
  83. package/src/components/filter/composed/FilterVipCS.tsx +16 -0
  84. package/src/components/filter/fixed/FilterAlt.tsx +20 -0
  85. package/src/components/filter/fixed/FilterChrom.tsx +22 -0
  86. package/src/components/filter/fixed/FilterFilter.tsx +20 -0
  87. package/src/components/filter/fixed/FilterFixed.tsx +96 -0
  88. package/src/components/filter/fixed/FilterId.tsx +20 -0
  89. package/src/components/filter/fixed/FilterPos.tsx +22 -0
  90. package/src/components/filter/fixed/FilterQual.tsx +21 -0
  91. package/src/components/filter/fixed/FilterRef.tsx +22 -0
  92. package/src/components/filter/typed/FilterCategorical.tsx +119 -0
  93. package/src/components/filter/typed/FilterFlag.tsx +23 -0
  94. package/src/components/filter/typed/FilterInterval.tsx +72 -0
  95. package/src/components/filter/typed/FilterString.tsx +43 -0
  96. package/src/components/filter/typed/FilterTyped.tsx +56 -0
  97. package/src/components/form/ButtonApply.tsx +11 -0
  98. package/src/components/form/ButtonDownload.tsx +11 -0
  99. package/src/components/form/ButtonReset.tsx +9 -0
  100. package/src/components/{Checkbox.tsx → form/Checkbox.tsx} +4 -9
  101. package/src/components/form/Input.tsx +19 -0
  102. package/src/components/form/Select.scss +7 -0
  103. package/src/components/form/Select.tsx +34 -0
  104. package/src/components/tree/DecisionTreeBoolMultiQuery.tsx +1 -1
  105. package/src/components/tree/DecisionTreeBoolQuery.tsx +1 -1
  106. package/src/components/tree/DecisionTreeNode.tsx +41 -39
  107. package/src/components/tree/DecisionTreeNodeBool.tsx +1 -1
  108. package/src/components/tree/DecisionTreeNodeBoolMulti.tsx +1 -1
  109. package/src/components/tree/DecisionTreeNodeCategorical.tsx +1 -1
  110. package/src/components/tree/DecisionTreeNodeExists.tsx +1 -1
  111. package/src/components/tree/DecisionTreeNodeLeaf.tsx +1 -1
  112. package/src/components/tree/DecisionTreeOutcomeNode.tsx +1 -1
  113. package/src/components/tree/DecisionTreePath.tsx +1 -1
  114. package/src/igv.d.ts +2 -1
  115. package/src/index.tsx +48 -19
  116. package/src/mocks/GRCh37/decisionTree.json +23 -22
  117. package/src/mocks/GRCh37/field_metadata.json +435 -95
  118. package/src/mocks/GRCh37/sampleTree.json +21 -1
  119. package/src/mocks/GRCh37/static.ts +62 -134
  120. package/src/mocks/GRCh37/vcf/family.vcf.blob +9 -3
  121. package/src/mocks/GRCh38/decisionTree.json +52 -33
  122. package/src/mocks/GRCh38/decisionTreeStr.json +572 -0
  123. package/src/mocks/GRCh38/fasta/chr1_149380406-149403321.fasta.gz.blob +0 -0
  124. package/src/mocks/GRCh38/field_metadata.json +435 -95
  125. package/src/mocks/GRCh38/sampleTree.json +175 -0
  126. package/src/mocks/GRCh38/static.ts +101 -42
  127. package/src/mocks/GRCh38/str.cram.blob +0 -0
  128. package/src/mocks/GRCh38/str.cram.crai.blob +0 -0
  129. package/src/mocks/GRCh38/vcf/family.vcf.blob +25 -24
  130. package/src/mocks/GRCh38/vcf/no_vep.vcf.blob +29 -28
  131. package/src/mocks/GRCh38/vcf/samples_0.vcf.blob +28 -27
  132. package/src/mocks/GRCh38/vcf/samples_1.vcf.blob +29 -28
  133. package/src/mocks/GRCh38/vcf/samples_100.vcf.blob +28 -27
  134. package/src/mocks/GRCh38/vcf/str.vcf.blob +321 -0
  135. package/src/mocks/MockApiClient.ts +339 -332
  136. package/src/mocks/config_cram.json +701 -0
  137. package/src/mocks/config_vcf.json +699 -0
  138. package/src/store/app.ts +30 -0
  139. package/src/store/index.tsx +3 -168
  140. package/src/store/variants.ts +182 -0
  141. package/src/types/config.d.ts +190 -0
  142. package/src/types/configCellComposed.d.ts +86 -0
  143. package/src/types/configCells.d.ts +129 -0
  144. package/src/types/configFilter.d.ts +80 -0
  145. package/src/types/configFilterComposed.d.ts +60 -0
  146. package/src/types/configSort.d.ts +13 -0
  147. package/src/types/filter.d.ts +17 -0
  148. package/src/types/store.d.ts +34 -0
  149. package/src/utils/api.ts +281 -0
  150. package/src/utils/config/config.ts +182 -0
  151. package/src/utils/config/configCells.ts +74 -0
  152. package/src/utils/config/configCellsComposed.ts +508 -0
  153. package/src/utils/config/configCellsField.ts +61 -0
  154. package/src/utils/config/configCellsFixed.ts +126 -0
  155. package/src/utils/config/configFilters.ts +46 -0
  156. package/src/utils/config/configFiltersComposed.ts +208 -0
  157. package/src/utils/config/configFiltersField.ts +49 -0
  158. package/src/utils/config/configFiltersFixed.ts +106 -0
  159. package/src/utils/config/configSorts.ts +44 -0
  160. package/src/utils/config/configValidator.ts +380 -0
  161. package/src/utils/config/configVip.ts +25 -0
  162. package/src/utils/csq.ts +115 -0
  163. package/src/utils/decisionTree.ts +45 -0
  164. package/src/utils/download.ts +30 -0
  165. package/src/utils/error.ts +69 -0
  166. package/src/utils/query/query.ts +55 -0
  167. package/src/utils/query/queryFilter.ts +132 -0
  168. package/src/utils/query/queryFilterComposed.ts +247 -0
  169. package/src/utils/query/queryFilterField.ts +75 -0
  170. package/src/utils/query/queryFilterFixed.ts +44 -0
  171. package/src/utils/query/querySample.ts +18 -0
  172. package/src/utils/query/queryVariantType.ts +76 -0
  173. package/src/utils/query/selector.ts +41 -0
  174. package/src/utils/{sortUtils.ts → query/sort.ts} +32 -11
  175. package/src/utils/sample.ts +19 -35
  176. package/src/utils/utils.ts +66 -2
  177. package/src/utils/variantType.ts +43 -0
  178. package/src/utils/vcf.ts +352 -0
  179. package/src/views/Help.tsx +109 -114
  180. package/src/views/Home.tsx +3 -2
  181. package/src/views/Sample.tsx +12 -7
  182. package/src/views/SampleVariant.tsx +23 -112
  183. package/src/views/SampleVariantConsequence.tsx +54 -144
  184. package/src/views/SampleVariants.tsx +33 -445
  185. package/src/views/SampleVariantsRedirect.tsx +20 -0
  186. package/src/views/Samples.tsx +7 -10
  187. package/src/views/Variant.tsx +31 -61
  188. package/src/views/VariantConsequence.tsx +42 -72
  189. package/src/views/Variants.tsx +29 -138
  190. package/src/views/VariantsRedirect.tsx +25 -0
  191. package/src/views/data/data.tsx +32 -6
  192. package/tests/store/variants.test.ts +122 -0
  193. package/tests/utils/config/config.test.ts +167 -0
  194. package/tests/utils/config/configCells.test.ts +86 -0
  195. package/tests/utils/config/configCellsComposed.test.ts +1163 -0
  196. package/tests/utils/config/configCellsField.test.ts +164 -0
  197. package/tests/utils/config/configCellsFixed.test.ts +99 -0
  198. package/tests/utils/config/configFilters.test.ts +80 -0
  199. package/tests/utils/config/configFiltersComposed.test.ts +504 -0
  200. package/tests/utils/config/configFiltersField.test.ts +140 -0
  201. package/tests/utils/config/configFiltersFixed.test.ts +81 -0
  202. package/tests/utils/config/configSorts.test.ts +55 -0
  203. package/tests/utils/config/configValidator.test.ts +56 -0
  204. package/tests/utils/config/configVip.test.ts +53 -0
  205. package/tests/utils/decisionTree.test.ts +71 -0
  206. package/tests/utils/download.test.ts +20 -0
  207. package/tests/utils/query/query.test.ts +84 -0
  208. package/tests/utils/query/queryFilter.test.ts +243 -0
  209. package/tests/utils/query/queryFilterComposed.test.ts +301 -0
  210. package/tests/utils/query/queryFilterField.test.ts +75 -0
  211. package/tests/utils/query/queryFilterFixed.test.ts +86 -0
  212. package/tests/utils/query/querySample.test.ts +45 -0
  213. package/tests/utils/query/queryVariantType.test.ts +56 -0
  214. package/{src/__tests__/sortUtils.test.ts → tests/utils/query/sort.test.ts} +3 -4
  215. package/tests/utils/sample.test.ts +259 -0
  216. package/tests/utils/utils.test.ts +120 -0
  217. package/tests/utils/variantType.test.ts +48 -0
  218. package/tests/utils/vcf.test.ts +649 -0
  219. package/tsconfig.json +6 -2
  220. package/vite.config.mts +20 -3
  221. package/.eslintignore +0 -4
  222. package/.eslintrc.js +0 -23
  223. package/src/Api.ts +0 -12
  224. package/src/__tests__/decisionTreeUtils.test.ts +0 -75
  225. package/src/__tests__/field.test.ts +0 -107
  226. package/src/__tests__/query.test.ts +0 -188
  227. package/src/__tests__/sample.test.ts +0 -184
  228. package/src/__tests__/utils.test.ts +0 -24
  229. package/src/__tests__/viewUtils.test.ts +0 -125
  230. package/src/components/ConsequenceTable.tsx +0 -45
  231. package/src/components/Error.tsx +0 -9
  232. package/src/components/FieldHeader.tsx +0 -26
  233. package/src/components/InfoCollapsablePane.tsx +0 -90
  234. package/src/components/VariantInfoNestedTable.tsx +0 -127
  235. package/src/components/VariantSampleTable.tsx +0 -58
  236. package/src/components/VariantsSampleTable.tsx +0 -184
  237. package/src/components/VariantsTable.tsx +0 -125
  238. package/src/components/filter/FilterAllelicBalance.tsx +0 -81
  239. package/src/components/filter/FilterCategorical.tsx +0 -81
  240. package/src/components/filter/FilterClinVar.tsx +0 -21
  241. package/src/components/filter/FilterGene.tsx +0 -34
  242. package/src/components/filter/FilterHpo.tsx +0 -161
  243. package/src/components/filter/FilterInheritance.tsx +0 -162
  244. package/src/components/filter/FilterIntegerGq.tsx +0 -47
  245. package/src/components/filter/FilterVI.tsx +0 -68
  246. package/src/components/filter/FilterVariantType.tsx +0 -146
  247. package/src/components/filter/Filters.tsx +0 -29
  248. package/src/components/filter/InfoFilter.tsx +0 -39
  249. package/src/components/filter/InfoFilters.tsx +0 -35
  250. package/src/components/filter/SampleFilters.tsx +0 -93
  251. package/src/components/filter/SamplesFilters.tsx +0 -33
  252. package/src/components/record/Allele.tsx +0 -38
  253. package/src/components/record/AlleleBreakend.tsx +0 -5
  254. package/src/components/record/AlleleMissing.tsx +0 -5
  255. package/src/components/record/AlleleNucs.tsx +0 -49
  256. package/src/components/record/AlleleSymbolic.tsx +0 -5
  257. package/src/components/record/Alt.tsx +0 -17
  258. package/src/components/record/Chrom.tsx +0 -5
  259. package/src/components/record/Format.tsx +0 -40
  260. package/src/components/record/Info.tsx +0 -55
  261. package/src/components/record/Pos.tsx +0 -5
  262. package/src/components/record/Qual.tsx +0 -5
  263. package/src/components/record/RecordDownload.tsx +0 -66
  264. package/src/components/record/Ref.tsx +0 -6
  265. package/src/components/record/field/Field.tsx +0 -36
  266. package/src/components/record/field/FieldMultipleValue.tsx +0 -22
  267. package/src/components/record/field/FieldSingleValue.tsx +0 -35
  268. package/src/components/record/info/ClinVar.tsx +0 -81
  269. package/src/components/record/info/Consequence.tsx +0 -18
  270. package/src/components/record/info/Gene.tsx +0 -56
  271. package/src/components/record/info/GnomAD.tsx +0 -54
  272. package/src/components/record/info/Hpo.tsx +0 -52
  273. package/src/components/record/info/InheritanceModes.tsx +0 -22
  274. package/src/components/record/info/VipC.tsx +0 -23
  275. package/src/components/record/info/Vkgl.tsx +0 -42
  276. package/src/mocks/GRCh37/vcf/no_vep.vcf.blob +0 -61
  277. package/src/mocks/GRCh37/vcf/samples_0.vcf.blob +0 -93
  278. package/src/mocks/GRCh37/vcf/samples_1.vcf.blob +0 -93
  279. package/src/mocks/GRCh37/vcf/samples_100.vcf.blob +0 -93
  280. package/src/utils/ApiUtils.ts +0 -263
  281. package/src/utils/csqUtils.ts +0 -27
  282. package/src/utils/decisionTreeUtils.ts +0 -31
  283. package/src/utils/field.ts +0 -49
  284. package/src/utils/query.ts +0 -154
  285. package/src/utils/viewUtils.ts +0 -32
@@ -0,0 +1,70 @@
1
+ import { Component, Show } from "solid-js";
2
+ import { getSampleAffectedStatusLabel, getSampleLabel, getSampleSexLabel } from "../utils/sample";
3
+ import { SampleContainer } from "../utils/api.ts";
4
+ import { Item, Sample } from "@molgenis/vip-report-api";
5
+
6
+ export const VariantsContainerHeader: Component<{
7
+ sample: SampleContainer | null;
8
+ }> = (props) => {
9
+ function getTitleSampleSexLabel(sample: Item<Sample>): string {
10
+ const label = getSampleSexLabel(sample);
11
+ return label !== "?" ? label : "sex:?";
12
+ }
13
+
14
+ function getTitleAffectedStatusLabel(sample: Item<Sample>): string {
15
+ const label = getSampleAffectedStatusLabel(sample);
16
+ return label !== "?" ? label : "affected status:?";
17
+ }
18
+
19
+ const title = (): string => {
20
+ let title: string;
21
+ if (props.sample) {
22
+ const sample = props.sample.item;
23
+ title = `Reported variants for ${getSampleLabel(sample)} (${getTitleSampleSexLabel(sample)} ${getTitleAffectedStatusLabel(sample)})`;
24
+ } else {
25
+ title = "Reported variants";
26
+ }
27
+ return title;
28
+ };
29
+
30
+ const subtitle = (): string | null => {
31
+ let subtitle: string | null;
32
+ if (props.sample) {
33
+ const sampleFather = props.sample.paternalSample;
34
+ const sampleMother = props.sample.maternalSample;
35
+ const sampleOtherFamilyMembers = props.sample.otherPedigreeSamples;
36
+
37
+ if (!(sampleFather === undefined && sampleMother === undefined && sampleOtherFamilyMembers.length === 0)) {
38
+ const tokens: string[] = [];
39
+ if (sampleMother !== null) {
40
+ tokens.push(`mother (${getTitleAffectedStatusLabel(sampleMother)})`);
41
+ }
42
+ if (sampleFather !== null) {
43
+ tokens.push(`father (${getTitleAffectedStatusLabel(sampleFather)})`);
44
+ }
45
+
46
+ for (const familyMember of sampleOtherFamilyMembers) {
47
+ tokens.push(
48
+ `${getSampleLabel(familyMember)} (${getTitleSampleSexLabel(familyMember)} ${getTitleAffectedStatusLabel(familyMember)})`,
49
+ );
50
+ }
51
+
52
+ let str = tokens.pop() as string;
53
+ if (tokens.length > 0) str = `${tokens.join(", ")} and ${str}`;
54
+ subtitle = `Includes genotypes for ${str}`;
55
+ } else {
56
+ subtitle = null;
57
+ }
58
+ } else {
59
+ subtitle = "Includes all reported variants without genotypes";
60
+ }
61
+ return subtitle;
62
+ };
63
+
64
+ return (
65
+ <>
66
+ <p class="title is-3">{title()}</p>
67
+ <Show when={subtitle()}>{(subtitle) => <p class="subtitle is-5">{subtitle()}</p>}</Show>
68
+ </>
69
+ );
70
+ };
@@ -0,0 +1,80 @@
1
+ import { Component, Match, Switch } from "solid-js";
2
+ import {
3
+ CellValue,
4
+ CellValueAlt,
5
+ CellValueChrom,
6
+ CellValueFilter,
7
+ CellValueFormat,
8
+ CellValueGenotype,
9
+ CellValueId,
10
+ CellValueInfo,
11
+ CellValuePos,
12
+ CellValueQual,
13
+ CellValueRef,
14
+ ConfigCellCustom,
15
+ ConfigCellGenotype,
16
+ ConfigCellInfo,
17
+ ConfigCellItem,
18
+ } from "../../types/configCells";
19
+ import { ErrorNotification } from "../ErrorNotification";
20
+ import { FieldComposed } from "./composed/FieldComposed";
21
+ import { CellValueCustom } from "../../types/configCellComposed";
22
+ import { FieldGenotype } from "./genotype/FieldGenotype";
23
+ import { FieldInfo } from "./info/FieldInfo";
24
+ import { FieldChrom } from "./FieldChrom";
25
+ import { FieldPos } from "./FieldPos";
26
+ import { FieldId } from "./FieldId";
27
+ import { FieldRef } from "./FieldRef";
28
+ import { FieldAlt } from "./FieldAlt";
29
+ import { FieldQual } from "./FieldQual";
30
+ import { FieldFilter } from "./FieldFilter";
31
+ import { FieldFormat } from "./FieldFormat";
32
+
33
+ export const Field: Component<{
34
+ config: ConfigCellItem;
35
+ value: CellValue;
36
+ }> = (props) => {
37
+ const type = () => props.config.type;
38
+
39
+ return (
40
+ <Switch fallback={<ErrorNotification error={`unexpected field type ${type()}`} />}>
41
+ <Match when={type() === "chrom"}>
42
+ <FieldChrom value={props.value as CellValueChrom} />
43
+ </Match>
44
+ <Match when={type() === "pos"}>
45
+ <FieldPos value={props.value as CellValuePos} />
46
+ </Match>
47
+ <Match when={type() === "id"}>
48
+ <FieldId value={props.value as CellValueId} />
49
+ </Match>
50
+ <Match when={type() === "ref"}>
51
+ <FieldRef value={props.value as CellValueRef} />
52
+ </Match>
53
+ <Match when={type() === "alt"}>
54
+ <FieldAlt value={props.value as CellValueAlt} />
55
+ </Match>
56
+ <Match when={type() === "qual"}>
57
+ <FieldQual value={props.value as CellValueQual} />
58
+ </Match>
59
+ <Match when={type() === "filter"}>
60
+ <FieldFilter value={props.value as CellValueFilter} />
61
+ </Match>
62
+ <Match when={type() === "info"}>
63
+ <FieldInfo metadata={(props.config as ConfigCellInfo).field} value={props.value as CellValueInfo} />
64
+ </Match>
65
+ <Match when={type() === "format"}>
66
+ <FieldFormat value={props.value as CellValueFormat} />
67
+ </Match>
68
+ <Match when={type() === "genotype"}>
69
+ <FieldGenotype metadata={(props.config as ConfigCellGenotype).field} value={props.value as CellValueGenotype} />
70
+ <></>
71
+ </Match>
72
+ <Match when={type() === "composed"}>
73
+ <FieldComposed
74
+ config={props.config as ConfigCellCustom<CellValueCustom>}
75
+ value={props.value as CellValueCustom}
76
+ />
77
+ </Match>
78
+ </Switch>
79
+ );
80
+ };
@@ -0,0 +1,19 @@
1
+ import { Component, For } from "solid-js";
2
+ import { Allele } from "../Allele";
3
+ import { CellValueAlt } from "../../types/configCells";
4
+
5
+ export const FieldAlt: Component<{ value: CellValueAlt; isAbbreviate?: boolean }> = (props) => {
6
+ const abbreviate = () => (props.isAbbreviate !== undefined ? props.isAbbreviate : true);
7
+ return (
8
+ <>
9
+ <For each={props.value}>
10
+ {(alt, i) => (
11
+ <>
12
+ {i() !== 0 && <span>, </span>}
13
+ <Allele value={alt} isAbbreviate={abbreviate()} />
14
+ </>
15
+ )}
16
+ </For>
17
+ </>
18
+ );
19
+ };
@@ -0,0 +1,6 @@
1
+ import { Component } from "solid-js";
2
+ import { CellValueChrom } from "../../types/configCells";
3
+
4
+ export const FieldChrom: Component<{ value: CellValueChrom }> = (props) => {
5
+ return <span>{props.value}</span>;
6
+ };
@@ -1,6 +1,7 @@
1
1
  import { Component, For } from "solid-js";
2
+ import { CellValueFilter } from "../../types/configCells";
2
3
 
3
- export const Id: Component<{ value: string[] | null }> = (props) => {
4
+ export const FieldFilter: Component<{ value: CellValueFilter }> = (props) => {
4
5
  return (
5
6
  <>
6
7
  <For each={props.value}>{(id) => <span>{id}</span>}</For>
@@ -0,0 +1,10 @@
1
+ import { Component, For } from "solid-js";
2
+ import { CellValueFormat } from "../../types/configCells";
3
+
4
+ export const FieldFormat: Component<{ value: CellValueFormat }> = (props) => {
5
+ return (
6
+ <>
7
+ <For each={props.value}>{(formatKey) => <span>{formatKey}</span>}</For>
8
+ </>
9
+ );
10
+ };
@@ -1,6 +1,6 @@
1
1
  import { Component, For } from "solid-js";
2
2
 
3
- export const Filter: Component<{ value: string[] | null }> = (props) => {
3
+ export const FieldId: Component<{ value: string[] | null }> = (props) => {
4
4
  return (
5
5
  <>
6
6
  <For each={props.value}>{(id) => <span>{id}</span>}</For>
@@ -0,0 +1,6 @@
1
+ import { Component } from "solid-js";
2
+ import { CellValuePos } from "../../types/configCells";
3
+
4
+ export const FieldPos: Component<{ value: CellValuePos }> = (props) => {
5
+ return <span>{props.value}</span>;
6
+ };
@@ -0,0 +1,6 @@
1
+ import { Component } from "solid-js";
2
+ import { CellValueQual } from "../../types/configCells";
3
+
4
+ export const FieldQual: Component<{ value: CellValueQual }> = (props) => {
5
+ return <>{props.value && <span>{props.value}</span>}</>;
6
+ };
@@ -0,0 +1,8 @@
1
+ import { Component } from "solid-js";
2
+ import { Allele } from "../Allele";
3
+ import { CellValueRef } from "../../types/configCells";
4
+
5
+ export const FieldRef: Component<{ value: CellValueRef; isAbbreviate?: boolean }> = (props) => {
6
+ const abbreviate = () => (props.isAbbreviate !== undefined ? props.isAbbreviate : true);
7
+ return <Allele value={props.value} isAbbreviate={abbreviate()} />;
8
+ };
@@ -0,0 +1,72 @@
1
+ import { Component, Show } from "solid-js";
2
+ import { Anchor } from "../../Anchor";
3
+ import { Abbr } from "../../Abbr";
4
+ import { CellValueClinVar } from "../../../types/configCellComposed";
5
+
6
+ export const FieldClinVar: Component<{
7
+ value: CellValueClinVar;
8
+ }> = (props) => {
9
+ const label = () =>
10
+ props.value.clnSigs
11
+ .filter((category) => category !== null)
12
+ .map((category) => category.label)
13
+ .join(", ");
14
+
15
+ const href = () => {
16
+ const ids = props.value.clnIds;
17
+ return ids && ids.length === 1 ? `https://www.ncbi.nlm.nih.gov/clinvar/variation/${ids[0]}/` : undefined;
18
+ };
19
+
20
+ const description = () => {
21
+ const status = props.value.clnRevStats || [];
22
+ if (status.length === 0) return;
23
+
24
+ const statusValues = status.filter((category) => category !== null).map((category) => category.value);
25
+ const descriptionText = status
26
+ .filter((category) => category !== null)
27
+ .map((category) => category.label)
28
+ .join(", ");
29
+
30
+ let description;
31
+ if (status.length === 1 && statusValues.includes("practice_guideline")) {
32
+ description = "\u2605\u2605\u2605\u2605";
33
+ } else if (status.length === 1 && statusValues.includes("reviewed_by_expert_panel")) {
34
+ description = "\u2605\u2605\u2605\u2606";
35
+ } else if (
36
+ status.length === 3 &&
37
+ statusValues.includes("criteria_provided") &&
38
+ statusValues.includes("_multiple_submitters") &&
39
+ statusValues.includes("_no_conflicts")
40
+ ) {
41
+ description = "\u2605\u2605\u2606\u2606";
42
+ } else if (
43
+ status.length === 2 &&
44
+ statusValues.includes("criteria_provided") &&
45
+ statusValues.includes("_conflicting_interpretations")
46
+ ) {
47
+ description = "\u2605\u2606\u2606\u2606";
48
+ } else if (
49
+ status.length === 2 &&
50
+ statusValues.includes("criteria_provided") &&
51
+ statusValues.includes("_single_submitter")
52
+ ) {
53
+ description = "\u2605\u2606\u2606\u2606";
54
+ } else {
55
+ description = "\u2606\u2606\u2606\u2606";
56
+ }
57
+ description += " (" + descriptionText + ")";
58
+ return description;
59
+ };
60
+
61
+ return (
62
+ <Show when={label()}>
63
+ {(label) => (
64
+ <Anchor href={href()}>
65
+ <Show when={description()} fallback={<span>{label()}</span>}>
66
+ {(description) => <Abbr title={description()} value={label()} />}
67
+ </Show>
68
+ </Anchor>
69
+ )}
70
+ </Show>
71
+ );
72
+ };
@@ -0,0 +1,68 @@
1
+ import { Component, Match, Switch } from "solid-js";
2
+ import { FieldLocus } from "./FieldLocus";
3
+ import { FieldVipC } from "./FieldVipC";
4
+ import { FieldGenotype } from "./FieldGenotype";
5
+ import { FieldGene } from "./FieldGene";
6
+ import { ErrorNotification } from "../../ErrorNotification";
7
+ import { FieldClinVar } from "./FieldClinVar";
8
+ import { FieldGnomAd } from "./FieldGnomAd";
9
+ import { FieldHpo } from "./FieldHpo";
10
+ import { ConfigCellCustom } from "../../../types/configCells";
11
+ import {
12
+ CellValueClinVar,
13
+ CellValueCustom,
14
+ CellValueGene,
15
+ CellValueGenotype,
16
+ CellValueGnomAd,
17
+ CellValueHpo,
18
+ CellValueInheritanceModes,
19
+ CellValueLocus,
20
+ CellValueVipC,
21
+ CellValueVipCS,
22
+ CellValueVkgl,
23
+ } from "../../../types/configCellComposed";
24
+ import { FieldVkgl } from "./FieldVkgl";
25
+ import { FieldInheritanceModes } from "./FieldInheritanceModes";
26
+ import { FieldVipCS } from "./FieldVipCS.tsx";
27
+
28
+ export const FieldComposed: Component<{
29
+ config: ConfigCellCustom<CellValueCustom>;
30
+ value: CellValueCustom;
31
+ }> = (props) => {
32
+ const id = () => props.config.id;
33
+
34
+ return (
35
+ <Switch fallback={<ErrorNotification error={`unknown composed cell identifier ${id()}`} />}>
36
+ <Match when={id() === "clinVar"}>
37
+ <FieldClinVar value={props.value as CellValueClinVar} />
38
+ </Match>
39
+ <Match when={id() === "gene"}>
40
+ <FieldGene value={props.value as CellValueGene} />
41
+ </Match>
42
+ <Match when={id() === "genotype" || id() === "genotype_maternal" || id() === "genotype_paternal"}>
43
+ <FieldGenotype value={props.value as CellValueGenotype} />
44
+ </Match>
45
+ <Match when={id() === "gnomAdAf"}>
46
+ <FieldGnomAd value={props.value as CellValueGnomAd} />
47
+ </Match>
48
+ <Match when={id() === "hpo"}>
49
+ <FieldHpo value={props.value as CellValueHpo} />
50
+ </Match>
51
+ <Match when={id() === "inheritancePattern"}>
52
+ <FieldInheritanceModes value={props.value as CellValueInheritanceModes} />
53
+ </Match>
54
+ <Match when={id() === "locus"}>
55
+ <FieldLocus value={props.value as CellValueLocus} />
56
+ </Match>
57
+ <Match when={id() === "vipC"}>
58
+ <FieldVipC value={props.value as CellValueVipC} />
59
+ </Match>
60
+ <Match when={id() === "vipCS"}>
61
+ <FieldVipCS value={props.value as CellValueVipCS} />
62
+ </Match>
63
+ <Match when={id() === "vkgl"}>
64
+ <FieldVkgl value={props.value as CellValueVkgl} />
65
+ </Match>
66
+ </Switch>
67
+ );
68
+ };
@@ -0,0 +1,39 @@
1
+ import { Component, Show } from "solid-js";
2
+ import { Anchor } from "../../Anchor";
3
+ import { Abbr } from "../../Abbr";
4
+ import { CellValueGene } from "../../../types/configCellComposed";
5
+
6
+ export const FieldGene: Component<{
7
+ value: CellValueGene;
8
+ }> = (props) => {
9
+ const href = (): string | null => {
10
+ const symbol = props.value.symbol;
11
+ if (symbol === null) return null;
12
+
13
+ const geneIdentifier = props.value.geneIdentifier;
14
+ const queryString =
15
+ props.value.symbolSource === "EntrezGene" && geneIdentifier
16
+ ? `query=ncbi_gene_id:${geneIdentifier}`
17
+ : `query=${encodeURIComponent(symbol)}&filter=document_type:%22gene%22`;
18
+ return `https://www.genenames.org/tools/search/#!/?${queryString}`;
19
+ };
20
+
21
+ return (
22
+ <Show when={props.value.symbol} keyed>
23
+ {(symbol) => (
24
+ <>
25
+ <Anchor href={href()}>
26
+ <span>{symbol}</span>
27
+ </Anchor>
28
+ {props.value.incompletePenetrance && props.value.incompletePenetrance.value === "1" && (
29
+ <span class="ml-1">
30
+ <Show when={props.value.incompletePenetrance.description} fallback={"IP"}>
31
+ {(description) => <Abbr title={description()} value="IP" />}
32
+ </Show>
33
+ </span>
34
+ )}
35
+ </>
36
+ )}
37
+ </Show>
38
+ );
39
+ };
@@ -0,0 +1,35 @@
1
+ import { Component, Match, Switch } from "solid-js";
2
+ import { VariantTypeId } from "../../../utils/variantType.ts";
3
+ import { CellValueGenotype } from "../../../types/configCellComposed";
4
+ import { FieldGenotypeSnvSv } from "./FieldGenotypeSnvSv";
5
+ import { FieldGenotypeStr } from "./FieldGenotypeStr";
6
+ import { ErrorNotification } from "../../ErrorNotification";
7
+
8
+ export const FieldGenotype: Component<{
9
+ value: CellValueGenotype;
10
+ }> = (props) => {
11
+ const variantTypeId = (): VariantTypeId => {
12
+ const value = props.value.svType;
13
+
14
+ let variantType: VariantTypeId;
15
+ if (value === null) {
16
+ variantType = "snv";
17
+ } else if (value === "STR") {
18
+ variantType = "str";
19
+ } else {
20
+ variantType = "sv";
21
+ }
22
+ return variantType;
23
+ };
24
+
25
+ return (
26
+ <Switch fallback={<ErrorNotification error={`unexpected variant type ${variantTypeId()}`} />}>
27
+ <Match when={variantTypeId() === "all" || variantTypeId() === "snv" || variantTypeId() === "sv"}>
28
+ <FieldGenotypeSnvSv value={props.value} />
29
+ </Match>
30
+ <Match when={variantTypeId() === "str"}>
31
+ <FieldGenotypeStr value={props.value} />
32
+ </Match>
33
+ </Switch>
34
+ );
35
+ };
@@ -1,6 +1,7 @@
1
1
  import { Component, For, Show } from "solid-js";
2
- import { Genotype } from "@molgenis/vip-report-vcf/src/SampleDataParser";
3
- import { Allele } from "../Allele";
2
+ import { Genotype } from "@molgenis/vip-report-vcf";
3
+ import { Allele } from "../../Allele";
4
+ import { CellValueGenotype } from "../../../types/configCellComposed";
4
5
 
5
6
  function isAllelicImbalance(genotype: Genotype, allelicBalance: number | undefined | null) {
6
7
  if (genotype.t === "het" && allelicBalance !== undefined && allelicBalance !== null) {
@@ -19,32 +20,35 @@ function getTitle(allelicImbalance: boolean) {
19
20
  return allelicImbalance ? `Allelic imbalance` : ``;
20
21
  }
21
22
 
22
- export const GenotypeField: Component<{
23
- genotype: Genotype;
24
- refAllele: string;
25
- altAlleles: (string | null)[];
26
- isAbbreviate: boolean;
27
- allelicBalance: number | undefined | null;
28
- readDepth: number | undefined | null;
23
+ export const FieldGenotypeSnvSv: Component<{
24
+ value: CellValueGenotype;
29
25
  }> = (props) => {
30
- const allelicImbalance: boolean = isAllelicImbalance(props.genotype, props.allelicBalance);
26
+ const refAllele = () => props.value.refAllele;
27
+ const altAlleles = () => props.value.altAlleles;
28
+ const genotype = () => props.value.genotype;
29
+ const allelicImbalance = () => isAllelicImbalance(genotype(), props.value.viab);
30
+
31
31
  return (
32
32
  <>
33
- <For each={props.genotype.a}>
33
+ <For each={genotype().a}>
34
34
  {(alleleIndex, i) => (
35
35
  <>
36
- {i() !== 0 && <span class="phase">{props.genotype.p ? "|" : "/"}</span>}
36
+ {i() !== 0 && <span class="phase">{genotype().p ? "|" : "/"}</span>}
37
37
  <Allele
38
38
  value={
39
- alleleIndex !== null ? (alleleIndex === 0 ? props.refAllele : props.altAlleles[alleleIndex - 1]) : null
39
+ alleleIndex !== null
40
+ ? alleleIndex === 0
41
+ ? refAllele()
42
+ : (altAlleles()[alleleIndex - 1] as string | null)
43
+ : null
40
44
  }
41
- isAbbreviate={props.isAbbreviate}
45
+ isAbbreviate={true}
42
46
  />
43
47
  </>
44
48
  )}
45
49
  </For>
46
- <Show when={allelicImbalance}>
47
- <abbr title={getTitle(allelicImbalance)} class="ml-1 is-clickable">
50
+ <Show when={allelicImbalance()}>
51
+ <abbr title={getTitle(allelicImbalance())} class="ml-1 is-clickable">
48
52
  <i class="fas fa-circle-exclamation has-text-danger" />
49
53
  </abbr>
50
54
  </Show>
@@ -0,0 +1,31 @@
1
+ import { Component, Show } from "solid-js";
2
+ import { Allele } from "../../Allele";
3
+ import { CellValueGenotype } from "../../../types/configCellComposed";
4
+
5
+ export const FieldGenotypeStr: Component<{
6
+ value: CellValueGenotype;
7
+ }> = (props) => {
8
+ const showGenotype = () =>
9
+ props.value.displayRepeatUnit !== undefined &&
10
+ props.value.repeatUnitValue !== undefined &&
11
+ props.value.repeatCount !== undefined &&
12
+ props.value.repeatUnitMatch !== undefined;
13
+
14
+ return (
15
+ <Show when={showGenotype()}>
16
+ <abbr title={`display repeat unit familiar to clinician: ${props.value.displayRepeatUnit!}`}>
17
+ <Allele value={props.value.repeatUnitValue!} isAbbreviate={false} />
18
+ <sub>n</sub>
19
+ </abbr>
20
+ <span class="ml-1">{`(n=${props.value.repeatCount!})`}</span>
21
+ <Show when={!props.value.repeatUnitMatch!}>
22
+ <abbr
23
+ title={"the called repeat unit does not match the repeat unit in the loci bed file"}
24
+ class="ml-1 is-clickable"
25
+ >
26
+ <i class="fas fa-circle-exclamation has-text-danger" />
27
+ </abbr>
28
+ </Show>
29
+ </Show>
30
+ );
31
+ };
@@ -0,0 +1,58 @@
1
+ import { Component, Show } from "solid-js";
2
+ import { FieldFloat } from "../typed/FieldFloat";
3
+ import { Anchor } from "../../Anchor";
4
+ import { CellValueGnomAd } from "../../../types/configCellComposed";
5
+
6
+ export const FieldGnomAd: Component<{
7
+ value: CellValueGnomAd;
8
+ }> = (props) => {
9
+ const alleleNum = () => props.value.alleleNum;
10
+ const gnomAdAf = () => props.value.gnomAdAf;
11
+ const gnomAdCov = () => props.value.gnomAdCov;
12
+ const gnomAdQc = () => props.value.gnomAdQcs || [];
13
+
14
+ const href = (): string | undefined => {
15
+ let href;
16
+ if (gnomAdAf() !== null && alleleNum() !== undefined) {
17
+ const alt = props.value.a[alleleNum()! - 1];
18
+ if (alt) {
19
+ const variantId = [props.value.c, props.value.p, props.value.r, alt].join("-");
20
+ const dataset = "gnomad_r4";
21
+ href = `https://gnomad.broadinstitute.org/variant/${encodeURIComponent(variantId)}?dataset=${dataset}`;
22
+ }
23
+ }
24
+ return href;
25
+ };
26
+
27
+ const lowCoverage = () => {
28
+ const cov = gnomAdCov();
29
+ return cov !== undefined && cov !== null && cov < 0.5;
30
+ };
31
+
32
+ return (
33
+ <Show when={gnomAdAf() !== null}>
34
+ <Show when={href()} fallback={<FieldFloat value={gnomAdAf()} />} keyed>
35
+ {(href) => (
36
+ <>
37
+ <Anchor href={href}>
38
+ <FieldFloat value={gnomAdAf()} />
39
+ </Anchor>
40
+ <Show when={gnomAdQc().length > 0}>
41
+ <abbr title={"Failed quality control filters: " + gnomAdQc().join(", ")} class="ml-1 is-clickable">
42
+ <i class="fas fa-circle-exclamation has-text-warning" />
43
+ </abbr>
44
+ </Show>
45
+ <Show when={lowCoverage()}>
46
+ <abbr
47
+ title="This variant is covered in fewer than 50% of individuals in gnomAD. This may indicate a low-quality site."
48
+ class="ml-1 is-clickable"
49
+ >
50
+ <i class="fas fa-circle-exclamation has-text-warning" />
51
+ </abbr>
52
+ </Show>
53
+ </>
54
+ )}
55
+ </Show>
56
+ </Show>
57
+ );
58
+ };
@@ -0,0 +1,50 @@
1
+ import { Component, For, Match, Show, Switch } from "solid-js";
2
+ import { Anchor } from "../../Anchor";
3
+ import { FieldString } from "../typed/FieldString";
4
+ import { CellValueHpo } from "../../../types/configCellComposed";
5
+
6
+ type HpoTerm = {
7
+ id: string;
8
+ href: string;
9
+ };
10
+
11
+ export const FieldHpo: Component<{
12
+ value: CellValueHpo;
13
+ }> = (props) => {
14
+ const hpoTerms = (): HpoTerm[] =>
15
+ props.value.hpos.map((category) => ({
16
+ id: category!.value!,
17
+ href: `https://hpo.jax.org/app/browse/term/${encodeURI(category!.value!)}`,
18
+ }));
19
+
20
+ const gadoPd = () => props.value.gadoPd || null;
21
+
22
+ return (
23
+ <>
24
+ <For each={hpoTerms()}>
25
+ {(hpoTerm, i) => (
26
+ <>
27
+ {i() !== 0 && <span>, </span>}
28
+ <Anchor href={hpoTerm.href}>
29
+ <FieldString value={hpoTerm.id} />
30
+ </Anchor>
31
+ </>
32
+ )}
33
+ </For>
34
+ <Show when={gadoPd()}>
35
+ {(gadoPd) => (
36
+ <abbr title={gadoPd().description} class="ml-1 is-clickable">
37
+ <Switch>
38
+ <Match when={gadoPd().value === "LC"}>
39
+ <i class="fas fa-question-circle has-text-info" />
40
+ </Match>
41
+ <Match when={gadoPd().value === "HC"}>
42
+ <i class="fas fa-info-circle has-text-info" />
43
+ </Match>
44
+ </Switch>
45
+ </abbr>
46
+ )}
47
+ </Show>
48
+ </>
49
+ );
50
+ };