@molgenis/vip-report-template 6.1.1 → 7.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.
Files changed (285) hide show
  1. package/.nvmrc +1 -1
  2. package/.travis.yml +9 -11
  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 +35 -29
  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 +8 -5
  12. package/src/components/DatasetDropdown.tsx +10 -23
  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 +143 -0
  119. package/src/mocks/GRCh37/static.ts +63 -133
  120. package/src/mocks/GRCh37/vcf/family.vcf.blob +37 -31
  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 +341 -328
  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 -114
  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 -183
  237. package/src/components/VariantsTable.tsx +0 -124
  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 -259
  281. package/src/utils/csqUtils.ts +0 -27
  282. package/src/utils/decisionTreeUtils.ts +0 -14
  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,129 @@
1
+ import { FieldMetadata, InfoMetadata, RecordSampleType, VcfRecord } from "@molgenis/vip-report-vcf";
2
+ import { Item } from "@molgenis/vip-report-api";
3
+ import { CellValueCustom } from "./configCellComposed";
4
+ import { FieldValue } from "../utils/vcf.ts";
5
+
6
+ export type CellId = string;
7
+ export type CellType =
8
+ | "chrom"
9
+ | "pos"
10
+ | "id"
11
+ | "ref"
12
+ | "alt"
13
+ | "qual"
14
+ | "filter"
15
+ | "info"
16
+ | "format"
17
+ | "genotype"
18
+ | "composed";
19
+
20
+ interface ConfigCellBase<T extends CellValue> {
21
+ type: CellType;
22
+ label: () => string;
23
+ description: () => string | null;
24
+ value: (record: Item<VcfRecord>, valueIndex: number) => T;
25
+ valueCount: (record: Item<VcfRecord>) => number;
26
+ }
27
+
28
+ export type CellValueChrom = string;
29
+
30
+ export interface ConfigCellChrom extends ConfigCellBase<CellValueChrom> {
31
+ type: "chrom";
32
+ }
33
+
34
+ export type CellValuePos = number;
35
+
36
+ export interface ConfigCellPos extends ConfigCellBase<CellValuePos> {
37
+ type: "pos";
38
+ }
39
+
40
+ export type CellValueId = string[];
41
+
42
+ export interface ConfigCellId extends ConfigCellBase<CellValueId> {
43
+ type: "id";
44
+ }
45
+
46
+ export type CellValueRef = string;
47
+
48
+ export interface ConfigCellRef extends ConfigCellBase<CellValueRef> {
49
+ type: "ref";
50
+ }
51
+
52
+ export type CellValueAlt = (string | null)[];
53
+
54
+ export interface ConfigCellAlt extends ConfigCellBase<CellValueAlt> {
55
+ type: "alt";
56
+ }
57
+
58
+ export type CellValueQual = number | null;
59
+
60
+ export interface ConfigCellQual extends ConfigCellBase<CellValueQual> {
61
+ type: "qual";
62
+ }
63
+
64
+ export type CellValueFilter = string[];
65
+
66
+ export interface ConfigCellFilter extends ConfigCellBase<string[]> {
67
+ type: "filter";
68
+ }
69
+
70
+ export type ConfigCellFixed =
71
+ | ConfigCellChrom
72
+ | ConfigCellPos
73
+ | ConfigCellId
74
+ | ConfigCellRef
75
+ | ConfigCellAlt
76
+ | ConfigCellQual
77
+ | ConfigCellFilter;
78
+
79
+ export type CellValueInfo = FieldValue | undefined;
80
+
81
+ export interface ConfigCellInfo extends ConfigCellBase<CellValueInfo> {
82
+ type: "info";
83
+ field: InfoMetadata;
84
+ }
85
+
86
+ export type CellValueFormat = string[];
87
+
88
+ export interface ConfigCellFormat extends ConfigCellBase<CellValueFormat> {
89
+ type: "format";
90
+ }
91
+
92
+ export type CellValueGenotype = RecordSampleType | undefined;
93
+
94
+ export interface ConfigCellGenotype extends ConfigCellBase<CellValueGenotype> {
95
+ type: "genotype";
96
+ field: FieldMetadata;
97
+ }
98
+
99
+ interface ConfigCellCustom<T extends CellValueCustom> extends ConfigCellBase<T> {
100
+ type: "composed";
101
+ id: CellId;
102
+ }
103
+
104
+ export type ConfigCellItem =
105
+ | ConfigCellFixed
106
+ | ConfigCellFormat
107
+ | ConfigCellInfo
108
+ | ConfigCellGenotype
109
+ | ConfigCellCustom<CellValueCustom>;
110
+
111
+ export interface ConfigCellGroup {
112
+ type: "group";
113
+ fieldConfigs: ConfigCellItem[];
114
+ }
115
+
116
+ export type ConfigCell = ConfigCellItem | ConfigCellGroup;
117
+
118
+ export type CellValueFixed =
119
+ | CellValueChrom
120
+ | CellValuePos
121
+ | CellValueId
122
+ | CellValueRef
123
+ | CellValueAlt
124
+ | CellValueQual
125
+ | CellValueFilter;
126
+
127
+ export type CellValue = CellValueFixed | CellValueFormat | CellValueInfo | CellValueGenotype | CellValueCustom;
128
+
129
+ // note: add composed field to configCellComposed.d.ts
@@ -0,0 +1,80 @@
1
+ import { ConfigFilterComposed, FilterValueComposed } from "./configFilterComposed";
2
+ import { SampleContainer } from "../utils/api.ts";
3
+ import { FieldMetadataWrapper } from "../utils/vcf.ts";
4
+
5
+ export type FilterId = string;
6
+ export type FilterType = "fixed" | "info" | "genotype" | "composed";
7
+ export type FilterCategoryId = string;
8
+ export type FilterCategory = {
9
+ id: FilterCategoryId;
10
+ label: string;
11
+ count?: number;
12
+ };
13
+
14
+ export type FilterValueCategorical = FilterCategoryId[];
15
+ export type FilterValueString = string[];
16
+ export type ValueNumber = number | undefined;
17
+ export type FilterValueFlag = FilterValueCategorical;
18
+ export type FilterValueInterval = { left: ValueNumber; right: ValueNumber };
19
+
20
+ export type FilterValueChrom = FilterValueString;
21
+ export type FilterValuePos = FilterValueInterval;
22
+ export type FilterValueId = FilterValueString;
23
+ export type FilterValueRef = FilterValueString;
24
+ export type FilterValueAlt = FilterValueString;
25
+ export type FilterValueQual = FilterValueInterval;
26
+ export type FilterValueFilter = FilterValueString;
27
+
28
+ export type FilterValueFixed =
29
+ | FilterValueChrom
30
+ | FilterValuePos
31
+ | FilterValueId
32
+ | FilterValueRef
33
+ | FilterValueAlt
34
+ | FilterValueQual
35
+ | FilterValueFilter;
36
+
37
+ export type FilterValueField = FilterValueCategorical | FilterValueString | FilterValueInterval;
38
+
39
+ export type FilterValue = FilterValueFixed | FilterValueField | FilterValueComposed;
40
+ export type FilterValueMap = { [key: FilterId]: FilterValue };
41
+
42
+ export type ConfigFilterFixed =
43
+ | ConfigFilterChrom
44
+ | ConfigFilterPos
45
+ | ConfigFilterId
46
+ | ConfigFilterRef
47
+ | ConfigFilterAlt
48
+ | ConfigFilterQual
49
+ | ConfigFilterFilter;
50
+
51
+ export type ConfigFilter =
52
+ | ConfigFilterFixed
53
+ | ConfigFilterComposed
54
+ | ConfigFilterField // TODO rename to ConfigFilterInfo?
55
+ | ConfigFilterFormat; // TODO rename to ConfigFilterGenotype
56
+
57
+ export interface ConfigFilterBase {
58
+ type: FilterType;
59
+ id: FilterId;
60
+ label: () => string;
61
+ description: () => string | null;
62
+ }
63
+
64
+ export type ConfigFilterChrom = ConfigFilterBase;
65
+ export type ConfigFilterPos = ConfigFilterBase;
66
+ export type ConfigFilterId = ConfigFilterBase;
67
+ export type ConfigFilterRef = ConfigFilterBase;
68
+ export type ConfigFilterAlt = ConfigFilterBase;
69
+ export type ConfigFilterQual = ConfigFilterBase;
70
+ export type ConfigFilterFilter = ConfigFilterBase;
71
+
72
+ export interface ConfigFilterField extends ConfigFilterBase {
73
+ field: FieldMetadataWrapper;
74
+ }
75
+
76
+ export interface ConfigFilterFormat extends ConfigFilterField {
77
+ sample: SampleContainer;
78
+ }
79
+
80
+ // note: add composed filters to configFilterComposed.d.ts
@@ -0,0 +1,60 @@
1
+ import {
2
+ ConfigFilterBase,
3
+ ConfigFilterField,
4
+ ConfigFilterFormat,
5
+ FilterValueCategorical,
6
+ FilterValueFlag,
7
+ } from "./configFilter";
8
+ import { SampleContainer } from "../utils/api.ts";
9
+ import { FieldMetadataWrapper } from "../utils/vcf.ts";
10
+
11
+ export type ChromosomeId = string;
12
+ export type FilterValueHpo = FilterValueCategorical;
13
+ export type FilterValueLocus = { chromosome: ChromosomeId; start?: number; end?: number };
14
+ export type FilterValueVipC = FilterValueCategorical;
15
+ export type FilterValueVipCS = FilterValueCategorical;
16
+ export type FilterValueAllelicImbalance = FilterValueFlag;
17
+ export type FilterValueInheritanceMatch = FilterValueFlag;
18
+ export type FilterValueDeNovo = FilterValueFlag;
19
+
20
+ export type ConfigFilterComposed =
21
+ | ConfigFilterHpo
22
+ | ConfigFilterLocus
23
+ | ConfigFilterAllelicImbalance
24
+ | ConfigFilterInheritanceMatch
25
+ | ConfigFilterDeNovo
26
+ | ConfigFilterVipC
27
+ | ConfigFilterVipCS;
28
+
29
+ export type ConfigFilterHpo = ConfigFilterField;
30
+
31
+ export interface ConfigFilterAllelicImbalance extends ConfigFilterBase {
32
+ sample: SampleContainer;
33
+ viabField: FieldMetadataWrapper;
34
+ genotypeField: FieldMetadataWrapper;
35
+ }
36
+
37
+ export interface ConfigFilterInheritanceMatch extends ConfigFilterBase {
38
+ sample: SampleContainer;
39
+ vimField: FieldMetadataWrapper;
40
+ }
41
+
42
+ export interface ConfigFilterDeNovo extends ConfigFilterBase {
43
+ sample: SampleContainer;
44
+ vidField: FieldMetadataWrapper;
45
+ }
46
+
47
+ export type ConfigFilterVipC = ConfigFilterField;
48
+ export type ConfigFilterVipCS = ConfigFilterFormat;
49
+
50
+ export interface ConfigFilterLocus extends ConfigFilterBase {
51
+ chromosomes: ChromosomeId[];
52
+ }
53
+
54
+ export type FilterValueComposed =
55
+ | FilterValueHpo
56
+ | FilterValueLocus
57
+ | FilterValueAllelicImbalance
58
+ | FilterValueInheritanceMatch
59
+ | FilterValueVipC
60
+ | FilterValueVipCS;
@@ -0,0 +1,13 @@
1
+ import { FieldMetadata } from "@molgenis/vip-report-vcf";
2
+
3
+ export interface ConfigSort {
4
+ selected: boolean | undefined;
5
+ orders: ConfigSortOrder[];
6
+ }
7
+
8
+ export interface ConfigSortOrder {
9
+ direction: "desc" | "asc";
10
+ field: FieldMetadata;
11
+ }
12
+
13
+ export type ConfigSorts = ConfigSort[];
@@ -0,0 +1,17 @@
1
+ import { FilterId, FilterValue } from "./configFilter";
2
+
3
+ export type FilterValueMap = { [key: FilterId]: FilterValue };
4
+
5
+ export interface FilterValueChangeEvent<FilterValueType> {
6
+ value: FilterValueType;
7
+ }
8
+
9
+ export interface FilterChangeEvent extends FilterValueChangeEvent<FilterValue> {
10
+ id: FilterId;
11
+ }
12
+
13
+ export type FilterChangeCallback = (event: FilterChangeEvent) => void;
14
+ export type FilterClearEvent = {
15
+ id: FilterId;
16
+ };
17
+ export type FilterClearCallback = (event: FilterClearEvent) => void;
@@ -0,0 +1,34 @@
1
+ import { SetStoreFunction } from "solid-js/store";
2
+ import { VariantTypeId } from "../utils/variantType.ts";
3
+ import { SortOrder } from "@molgenis/vip-report-api";
4
+ import { FilterValueMap } from "./filter";
5
+
6
+ export type Page = { number: number; size?: number };
7
+ export type Sort = SortOrder | SortOrder[];
8
+ export type AppStateVariantType = {
9
+ filterValues?: FilterValueMap;
10
+ page?: Page;
11
+ /**
12
+ * null: do not sort, the caller of this function should not fall back to a default sort
13
+ * undefined: sort behavior is undefined, the caller of this function could fall back to a default sort
14
+ */
15
+ sort?: Sort | null;
16
+ };
17
+ export type AppStateVariantTypes = Partial<Record<VariantTypeId, AppStateVariantType>>;
18
+ type AppStateSamples = {
19
+ page?: number;
20
+ searchQuery?: string;
21
+ probandFilterValue?: boolean;
22
+ };
23
+ export type AppState = {
24
+ variants: AppStateVariantTypes;
25
+ sampleVariants: Record<string, AppStateVariantTypes>;
26
+ samples: AppStateSamples;
27
+ };
28
+ export type AppActions = {
29
+ reset(): void;
30
+ setSamplePage(page: number): void;
31
+ setSampleSearchQuery(searchQuery: string): void;
32
+ setSampleProbandFilterValue(probandFilterValue: boolean): void;
33
+ };
34
+ export type AppStore = [state: AppState, actions: AppActions, setState: SetStoreFunction<AppState>];
@@ -0,0 +1,281 @@
1
+ import {
2
+ AppMetadata,
3
+ Cram,
4
+ DecisionTree,
5
+ HtsFileMetadata,
6
+ Item,
7
+ Json,
8
+ PagedItems,
9
+ Params,
10
+ PhenotypicFeature,
11
+ Query,
12
+ Sample,
13
+ WindowApiClient,
14
+ } from "@molgenis/vip-report-api";
15
+ import { isSampleFather, isSampleMother } from "./sample.ts";
16
+ import { NestedFieldMetadata, Value, VcfMetadata, VcfRecord } from "@molgenis/vip-report-vcf";
17
+ import { createRecordSort } from "./query/sort.ts";
18
+ import { createFieldMap, FieldMap, isNumerical } from "./vcf.ts";
19
+ import { compareCsq, compareCsqDefault } from "./csq.ts";
20
+ import { VariantTypeId } from "./variantType.ts";
21
+ import { MockApiClient } from "../mocks/MockApiClient.ts";
22
+ import { ConfigJson } from "../types/config";
23
+ import { RuntimeError } from "./error.ts";
24
+ import { validateConfig } from "./config/configValidator.ts";
25
+
26
+ export type VcfMetadataContainer = VcfMetadata & {
27
+ fieldMap: FieldMap;
28
+ };
29
+ /**
30
+ * Expose aggregate metadata container for convenience
31
+ */
32
+ export type MetadataContainer = {
33
+ app: AppMetadata;
34
+ htsFile: HtsFileMetadata;
35
+ records: VcfMetadataContainer;
36
+ variantTypeIds: Set<VariantTypeId>;
37
+ };
38
+
39
+ /**
40
+ * Expose aggregate sample container for convenience
41
+ */
42
+ export type SampleContainer = {
43
+ item: Item<Sample>;
44
+ paternalSample: Item<Sample> | null;
45
+ maternalSample: Item<Sample> | null;
46
+ phenotypes: PhenotypicFeature[];
47
+ otherPedigreeSamples: Item<Sample>[];
48
+ variantTypeIds: Set<VariantTypeId>;
49
+ };
50
+
51
+ // lazy import MockApiClient to ensure that it is excluded from the build artifact
52
+ const api = import.meta.env.PROD
53
+ ? new WindowApiClient()
54
+ : await (async () => {
55
+ const module = await import("../mocks/MockApiClient.ts");
56
+ return new module.MockApiClient();
57
+ })();
58
+
59
+ export async function fetchConfig(): Promise<ConfigJson> {
60
+ console.log("Api.fetchConfig");
61
+ const config: Json = await api.getConfig();
62
+ if (config === null) throw new RuntimeError("no config provided");
63
+ return validateConfig(config);
64
+ }
65
+
66
+ export async function fetchDecisionTree(): Promise<DecisionTree | null> {
67
+ console.log("Api.fetchDecisionTree");
68
+ return await api.getDecisionTree();
69
+ }
70
+
71
+ export async function fetchSampleTree(): Promise<DecisionTree | null> {
72
+ console.log("Api.fetchSampleTree");
73
+ return await api.getSampleTree();
74
+ }
75
+
76
+ export async function fetchSamples(params: Params): Promise<PagedItems<SampleContainer>> {
77
+ console.log("Api.fetchSamples", JSON.stringify(params));
78
+ const samplePagedItems = await api.getSamples(params);
79
+ const samples = await Promise.all(samplePagedItems.items.map((sample) => fetchSampleContainer(sample)));
80
+ return {
81
+ page: samplePagedItems.page,
82
+ total: samplePagedItems.total,
83
+ items: samples.map((sample) => ({ id: sample.item.id, data: sample })),
84
+ };
85
+ }
86
+
87
+ /**
88
+ * Fetch metadata composed of app metadata, high throughput sequencing file metadata and records metadata
89
+ */
90
+ export async function fetchMetadata(): Promise<MetadataContainer> {
91
+ console.log("Api.fetchMetadata");
92
+ const [appMetadata, htsFileMetadata, recordsMetadata, variantTypeIds] = await Promise.all([
93
+ api.getAppMetadata(),
94
+ api.getHtsFileMetadata(),
95
+ api.getRecordsMeta(),
96
+ fetchVariantTypeIdsQuery(),
97
+ ]);
98
+
99
+ // precompute field map
100
+ const fieldMap = createFieldMap(recordsMetadata);
101
+
102
+ return { app: appMetadata, htsFile: htsFileMetadata, records: { ...recordsMetadata, fieldMap }, variantTypeIds };
103
+ }
104
+
105
+ /**
106
+ * Fetch sample composed of sample, pedigree samples and phenotypic features
107
+ */
108
+ export async function fetchSampleById(sampleId: number): Promise<SampleContainer> {
109
+ console.log("Api.fetchSampleById", sampleId);
110
+ const sample = await api.getSampleById(sampleId);
111
+
112
+ const [pedigreeSamples, phenotypicFeatures, variantTypeIds] = await Promise.all([
113
+ fetchPedigreeSamples(sample),
114
+ fetchPhenotypicFeatures(sample),
115
+ fetchVariantTypeIdsQuery(),
116
+ ]);
117
+
118
+ return composeSample(sample, phenotypicFeatures, pedigreeSamples, variantTypeIds);
119
+ }
120
+
121
+ export async function fetchRecordById(id: number): Promise<Item<VcfRecord>> {
122
+ console.log("Api.fetchRecordById", id);
123
+ return api.getRecordById(id);
124
+ }
125
+
126
+ export async function fetchRecords(params: Params): Promise<PagedItems<VcfRecord>> {
127
+ console.log("Api.fetchRecords", JSON.stringify(params));
128
+ const [recordsMeta, records] = await Promise.all([api.getRecordsMeta(), api.getRecords(params)]);
129
+ if (recordsMeta.info.CSQ === undefined) {
130
+ return records;
131
+ }
132
+
133
+ const orders = createRecordSort(recordsMeta, params.sort).orders.filter(
134
+ (order) =>
135
+ order.field.parent?.id === "CSQ" &&
136
+ isNumerical(order.field) &&
137
+ order.field.number.type === "NUMBER" &&
138
+ order.field.number.count === 1,
139
+ );
140
+
141
+ const fieldMetas = (recordsMeta.info.CSQ.nested as NestedFieldMetadata).items;
142
+ const consequenceIndex = fieldMetas.findIndex((item) => item.id === "Consequence");
143
+ const pickIndex = fieldMetas.findIndex((item) => item.id === "PICK");
144
+
145
+ for (const record of records.items) {
146
+ const csqArray = record.data.n.CSQ as Value[][] | undefined;
147
+ if (csqArray) {
148
+ csqArray.sort((aValue, bValue) => {
149
+ for (const order of orders) {
150
+ const compareValue = compareCsq(aValue, bValue, order.field, order.direction);
151
+ if (compareValue !== 0) return compareValue;
152
+ }
153
+ return compareCsqDefault(aValue, bValue, pickIndex, consequenceIndex);
154
+ });
155
+ }
156
+ }
157
+ return records;
158
+ }
159
+
160
+ export async function fetchSampleProbandIds(): Promise<number[]> {
161
+ console.log("Api.fetchSampleProbandIds");
162
+ const query: Query = { selector: ["proband"], operator: "==", args: true };
163
+ const samplePagedItems = await api.getSamples({ query, page: 0, size: Number.MAX_SAFE_INTEGER });
164
+ return samplePagedItems.items.map((sampleItem) => sampleItem.id);
165
+ }
166
+
167
+ export async function fetchFastaGz(contig: string, pos: number): Promise<Uint8Array | null> {
168
+ console.log("Api.fetchFastaGz", contig, pos);
169
+ return api.getFastaGz(contig, pos);
170
+ }
171
+
172
+ export async function fetchGenesGz(): Promise<Uint8Array | null> {
173
+ console.log("Api.fetchGenesGz");
174
+ return api.getGenesGz();
175
+ }
176
+
177
+ export async function fetchCram(sampleId: string): Promise<Cram | null> {
178
+ console.log("Api.fetchCram", sampleId);
179
+ return api.getCram(sampleId);
180
+ }
181
+
182
+ async function fetchSampleContainer(sample: Item<Sample>): Promise<SampleContainer> {
183
+ const [pedigreeSamples, phenotypicFeatures, variantTypeIds] = await Promise.all([
184
+ fetchPedigreeSamples(sample),
185
+ fetchPhenotypicFeatures(sample),
186
+ fetchVariantTypeIdsQuery(),
187
+ ]);
188
+
189
+ return composeSample(sample, phenotypicFeatures, pedigreeSamples, variantTypeIds);
190
+ }
191
+
192
+ /**
193
+ * Compose sample from API sample, API sample phenotypes and API pedigree samples data
194
+ *
195
+ * @param sample API sample
196
+ * @param samplePhenotypes API sample phenotypes
197
+ * @param pedigreeSamples API samples from same pedigree
198
+ * @param variantTypeIds variant types available for this sample
199
+ */
200
+ export function composeSample(
201
+ sample: Item<Sample>,
202
+ samplePhenotypes?: PhenotypicFeature[],
203
+ pedigreeSamples?: PagedItems<Sample>,
204
+ variantTypeIds?: Set<VariantTypeId>,
205
+ ): SampleContainer {
206
+ let paternalSample: Item<Sample> | null = null;
207
+ let maternalSample: Item<Sample> | null = null;
208
+ const otherPedigreeSamples: Item<Sample>[] = [];
209
+
210
+ pedigreeSamples?.items.forEach((pedigreeSample) => {
211
+ if (isSampleFather(sample.data, pedigreeSample.data)) {
212
+ paternalSample = pedigreeSample;
213
+ } else if (isSampleMother(sample.data, pedigreeSample.data)) {
214
+ maternalSample = pedigreeSample;
215
+ } else {
216
+ otherPedigreeSamples.push(pedigreeSample);
217
+ }
218
+ });
219
+
220
+ return {
221
+ item: sample,
222
+ paternalSample,
223
+ maternalSample,
224
+ phenotypes: samplePhenotypes || [],
225
+ otherPedigreeSamples,
226
+ variantTypeIds: variantTypeIds || new Set<VariantTypeId>(),
227
+ };
228
+ }
229
+
230
+ async function fetchPedigreeSamples(sample: Item<Sample>): Promise<PagedItems<Sample>> {
231
+ return await api.getSamples({
232
+ query: {
233
+ operator: "and",
234
+ args: [
235
+ { selector: ["person", "individualId"], operator: "!=", args: sample.data.person.individualId },
236
+ { selector: ["person", "familyId"], operator: "==", args: sample.data.person.familyId },
237
+ ],
238
+ },
239
+ size: Number.MAX_SAFE_INTEGER,
240
+ });
241
+ }
242
+
243
+ async function fetchPhenotypicFeatures(sample: Item<Sample>): Promise<PhenotypicFeature[]> {
244
+ const phenotypes = await api.getPhenotypes({
245
+ query: { selector: ["subject", "id"], operator: "==", args: sample.data.person.individualId },
246
+ size: Number.MAX_SAFE_INTEGER,
247
+ });
248
+ return phenotypes.items.map((item) => item.data).flatMap((phenotype) => phenotype.phenotypicFeaturesList);
249
+ }
250
+
251
+ async function fetchVariantTypeIdsQuery(): Promise<Set<VariantTypeId>> {
252
+ const config: ConfigJson = await fetchConfig();
253
+
254
+ const variantTypeIds = new Set<VariantTypeId>();
255
+ const params = config.vip.params.cram;
256
+ if (params) {
257
+ if (params.call_snv) variantTypeIds.add("snv");
258
+ if (params.call_str) variantTypeIds.add("str");
259
+ if (params.call_sv || params.call_cnv) variantTypeIds.add("sv");
260
+ } else {
261
+ variantTypeIds.add("snv");
262
+ variantTypeIds.add("str");
263
+ variantTypeIds.add("sv");
264
+ }
265
+ return variantTypeIds;
266
+ }
267
+
268
+ // development
269
+ export function isDatasetSupport(): boolean {
270
+ return !import.meta.env.PROD;
271
+ }
272
+
273
+ export function getDatasetIds(): string[] {
274
+ if (import.meta.env.PROD) throw new Error("unsupported");
275
+ return (api as MockApiClient).getDatasetIds();
276
+ }
277
+
278
+ export function selectDataset(id: string): void {
279
+ if (import.meta.env.PROD) throw new Error(`unknown id ${id}`);
280
+ (api as MockApiClient).selectDataset(id);
281
+ }