@molgenis/vip-report-template 7.1.3 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -1,13 +1,13 @@
1
1
  import { VariantFilters } from "./VariantFilters";
2
- import { Params } from "@molgenis/vip-report-api";
2
+ import { HtsFileMetadata, RecordParams } from "@molgenis/vip-report-api";
3
3
  import { Component, createResource, Show } from "solid-js";
4
4
  import { VariantType } from "../utils/variantType.ts";
5
5
  import { useNavigate } from "@solidjs/router";
6
6
  import { initConfig } from "../utils/config/config.ts";
7
7
  import { createQuery } from "../utils/query/query.ts";
8
8
  import { PageChangeEvent } from "./Pager";
9
- import { writeVcf } from "@molgenis/vip-report-vcf";
10
- import { fetchRecords, MetadataContainer, SampleContainer } from "../utils/api.ts";
9
+ import { InfoOrder, VariantRecords, writeVcf } from "@molgenis/vip-report-vcf";
10
+ import { fetchInfoOrder, fetchRecords, MetadataContainer, SampleContainer } from "../utils/api.ts";
11
11
  import { createVcfDownloadFilename } from "../utils/download.ts";
12
12
  import { RecordsPerPageChangeEvent } from "./RecordsPerPage";
13
13
  import { SortChangeEvent } from "./Sort";
@@ -33,7 +33,8 @@ export const VariantsContainer: Component<{
33
33
 
34
34
  const config = () => initConfig(props.config, props.variantType, props.metadata, props.sample);
35
35
  const variantTypeIds = () => (props.sample !== null ? props.sample.variantTypeIds : props.metadata.variantTypeIds);
36
- const query = () => createQuery(config(), props.variantType, props.sample, props.store.getFilterValues());
36
+ const query = () =>
37
+ createQuery(config(), props.metadata, props.variantType, props.sample, props.store.getFilterValues());
37
38
 
38
39
  const defaultSort = () => config().variants.sorts.find((configSort) => configSort.selected);
39
40
  const sort = () => createSort(props.store.getSort(), defaultSort()) || undefined;
@@ -41,12 +42,31 @@ export const VariantsContainer: Component<{
41
42
  const recordsPerPage = () =>
42
43
  props.store.getPageSize() !== null ? props.store.getPageSize()! : defaultRecordsPerPage();
43
44
 
45
+ const sampleIds = () => {
46
+ let sampleIds: number[] | undefined;
47
+ if (props.sample !== null) {
48
+ sampleIds = [props.sample.item.id];
49
+ if (props.sample.maternalSample !== null && props.sample.maternalSample !== undefined) {
50
+ sampleIds.push(props.sample.maternalSample.id);
51
+ }
52
+ if (props.sample.paternalSample !== null && props.sample.paternalSample !== undefined) {
53
+ sampleIds.push(props.sample.paternalSample.id);
54
+ }
55
+ }
56
+ return sampleIds;
57
+ };
58
+
59
+ const hasSvTypeField = () => {
60
+ return Object.hasOwn(props.metadata.records.info, "SVTYPE");
61
+ };
62
+
44
63
  const [records] = createResource(
45
- (): Params => ({
64
+ (): RecordParams => ({
46
65
  query: query() || undefined,
47
66
  page: props.store.getPageNumber() || 0,
48
67
  size: recordsPerPage(),
49
68
  sort: sort(),
69
+ sampleIds: sampleIds(),
50
70
  }),
51
71
  fetchRecords,
52
72
  );
@@ -64,15 +84,33 @@ export const VariantsContainer: Component<{
64
84
  const onRecordsDownload = async () => {
65
85
  const samples = props.sample ? getPedigreeSamples(props.sample) : [];
66
86
  const filter = samples ? { samples: samples.map((sample) => sample.data.person.individualId) } : undefined;
87
+ const sampleIds = samples ? samples.map((sample) => sample.id) : ([] as number[]);
67
88
 
68
89
  // create vcf using all records that match filters, use default sort to ensure valid vcf ordering
69
- const records = await fetchRecords({ query: query() || undefined, page: 0, size: Number.MAX_SAFE_INTEGER });
70
- const vcf = writeVcf({ metadata: props.metadata.records, data: records.items.map((item) => item.data) }, filter);
90
+ const records = await fetchRecords({
91
+ query: query() || undefined,
92
+ page: 0,
93
+ size: Number.MAX_SAFE_INTEGER,
94
+ sampleIds: sampleIds,
95
+ });
96
+
97
+ const infoOrder: InfoOrder = await fetchInfoOrder();
98
+ const vcf = writeVcf(
99
+ {
100
+ metadata: props.metadata.records,
101
+ data: records.items.reduce((acc, item) => {
102
+ acc[item.id] = item.data;
103
+ return acc;
104
+ }, {} as VariantRecords),
105
+ infoOrder: infoOrder,
106
+ },
107
+ filter,
108
+ );
71
109
 
72
110
  const url = window.URL.createObjectURL(new Blob([vcf]));
73
111
  const link = document.createElement("a");
74
112
  link.href = url;
75
- link.setAttribute("download", createVcfDownloadFilename(props.metadata.htsFile));
113
+ link.setAttribute("download", createVcfDownloadFilename(props.metadata.app.htsFile as HtsFileMetadata));
76
114
  document.body.appendChild(link);
77
115
  link.click();
78
116
  document.body.removeChild(link);
@@ -101,7 +139,7 @@ export const VariantsContainer: Component<{
101
139
  </div>
102
140
  <div class="columns is-1">
103
141
  <div class="column is-2-fullhd is-3">
104
- <Show when={variantTypeIds().size > 1}>
142
+ <Show when={variantTypeIds().size > 1 && hasSvTypeField()}>
105
143
  <div class="columns">
106
144
  <div class="column">
107
145
  <VariantTypeSelect
@@ -32,9 +32,8 @@ export const VariantsContainerHeader: Component<{
32
32
  if (props.sample) {
33
33
  const sampleFather = props.sample.paternalSample;
34
34
  const sampleMother = props.sample.maternalSample;
35
- const sampleOtherFamilyMembers = props.sample.otherPedigreeSamples;
36
35
 
37
- if (!(sampleFather === null && sampleMother === null && sampleOtherFamilyMembers.length === 0)) {
36
+ if (sampleFather !== null || sampleMother !== null) {
38
37
  const tokens: string[] = [];
39
38
  if (sampleMother !== null) {
40
39
  tokens.push(`mother (${getTitleAffectedStatusLabel(sampleMother)})`);
@@ -43,12 +42,6 @@ export const VariantsContainerHeader: Component<{
43
42
  tokens.push(`father (${getTitleAffectedStatusLabel(sampleFather)})`);
44
43
  }
45
44
 
46
- for (const familyMember of sampleOtherFamilyMembers) {
47
- tokens.push(
48
- `${getSampleLabel(familyMember)} (${getTitleSampleSexLabel(familyMember)} ${getTitleAffectedStatusLabel(familyMember)})`,
49
- );
50
- }
51
-
52
45
  let str = tokens.pop() as string;
53
46
  if (tokens.length > 0) str = `${tokens.join(", ")} and ${str}`;
54
47
  subtitle = `Includes genotypes for ${str}`;
@@ -12,7 +12,7 @@ export const FieldGenotype: Component<{
12
12
  const value = props.value.svType;
13
13
 
14
14
  let variantType: VariantTypeId;
15
- if (value === null) {
15
+ if (value === null || value === undefined) {
16
16
  variantType = "snv";
17
17
  } else if (value === "STR") {
18
18
  variantType = "str";
@@ -6,20 +6,17 @@ import { FieldGenotypeSnvSv } from "./FieldGenotypeSnvSv.tsx";
6
6
  export const FieldGenotypeStr: Component<{
7
7
  value: CellValueGenotype;
8
8
  }> = (props) => {
9
- const showGenotype = () =>
10
- props.value.displayRepeatUnit !== undefined &&
11
- props.value.repeatUnitValue !== undefined &&
12
- props.value.repeatCount !== undefined &&
13
- props.value.repeatUnitMatch !== undefined;
9
+ const showGenotype = () => props.value.repeatUnitValue != null && props.value.repeatCount != null;
14
10
 
15
11
  return (
16
12
  <Show when={showGenotype()} fallback={<FieldGenotypeSnvSv value={props.value} />}>
17
- <abbr title={`display repeat unit familiar to clinician: ${props.value.displayRepeatUnit!}`}>
18
- <Allele value={props.value.repeatUnitValue!} isAbbreviate={false} />
19
- <sub>n</sub>
20
- </abbr>
13
+ <Show when={props.value.displayRepeatUnit != null} fallback={<AlleleStr value={props.value.repeatUnitValue!} />}>
14
+ <abbr title={`display repeat unit familiar to clinician: ${props.value.displayRepeatUnit!}`}>
15
+ <AlleleStr value={props.value.repeatUnitValue!} />
16
+ </abbr>
17
+ </Show>
21
18
  <span class="ml-1">{`(n=${props.value.repeatCount!})`}</span>
22
- <Show when={!props.value.repeatUnitMatch!}>
19
+ <Show when={props.value.repeatUnitMatch === false}>
23
20
  <abbr
24
21
  title={"the called repeat unit does not match the repeat unit in the loci bed file"}
25
22
  class="ml-1 is-clickable"
@@ -30,3 +27,14 @@ export const FieldGenotypeStr: Component<{
30
27
  </Show>
31
28
  );
32
29
  };
30
+
31
+ const AlleleStr: Component<{
32
+ value: string;
33
+ }> = (props) => {
34
+ return (
35
+ <>
36
+ <Allele value={props.value} isAbbreviate={false} />
37
+ <sub>n</sub>
38
+ </>
39
+ );
40
+ };
@@ -26,7 +26,7 @@ export const FieldGnomAd: Component<{
26
26
 
27
27
  const lowCoverage = () => {
28
28
  const cov = gnomAdCov();
29
- return cov !== undefined && cov !== null && cov < 0.5;
29
+ return cov != null && cov < 0.5;
30
30
  };
31
31
 
32
32
  return (
@@ -11,10 +11,7 @@ export const FieldInheritanceModes: Component<{ value: CellValueInheritanceModes
11
11
  (inheritanceModesGene() !== undefined && inheritanceModesGene().length === 0) ||
12
12
  inheritanceModesGene().findIndex((category) => category?.value === "AR") !== -1
13
13
  ) {
14
- isArInheritance =
15
- props.value.isPossibleCompound !== undefined &&
16
- props.value.isPossibleCompound !== null &&
17
- props.value.isPossibleCompound;
14
+ isArInheritance = props.value.isPossibleCompound != null && props.value.isPossibleCompound;
18
15
  }
19
16
  return isArInheritance;
20
17
  };
@@ -20,7 +20,7 @@ export const FieldVkgl: Component<{ value: CellValueVkgl }> = (props) => {
20
20
  };
21
21
 
22
22
  const descriptions = Object.entries(labValues)
23
- .filter(([, value]) => value !== null && value !== undefined)
23
+ .filter(([, value]) => value != null)
24
24
  .map(([key, value]) => `${key}:${value?.label}`);
25
25
 
26
26
  return descriptions.length > 0 ? descriptions.join(", ") : null;
@@ -8,7 +8,7 @@ export const FieldCategorical: Component<{
8
8
  metadata: FieldMetadata;
9
9
  }> = (props) => {
10
10
  return (
11
- <Show when={props.value !== null && props.value !== undefined}>
11
+ <Show when={props.value != null}>
12
12
  <Show when={props.value!.description} fallback={<span>{props.value!.label}</span>}>
13
13
  {(description) => <Abbr title={description()} value={props.value!.label} />}
14
14
  </Show>
@@ -5,7 +5,7 @@ export const FieldCharacter: Component<{
5
5
  value: ValueString | undefined;
6
6
  }> = (props) => {
7
7
  return (
8
- <Show when={props.value !== null && props.value !== undefined}>
8
+ <Show when={props.value != null}>
9
9
  <span>{props.value as string}</span>
10
10
  </Show>
11
11
  );
@@ -5,7 +5,7 @@ export const FieldFlag: Component<{
5
5
  value: ValueFlag | undefined;
6
6
  }> = (props) => {
7
7
  return (
8
- <Show when={props.value !== null && props.value !== undefined}>
8
+ <Show when={props.value != null}>
9
9
  <span>{(props.value as boolean).toString()}</span>
10
10
  </Show>
11
11
  );
@@ -6,7 +6,7 @@ export const FieldFloat: Component<{
6
6
  value: ValueFloat | undefined;
7
7
  }> = (props) => {
8
8
  return (
9
- <Show when={props.value !== null && props.value !== undefined}>
9
+ <Show when={props.value != null}>
10
10
  <Show
11
11
  when={(props.value as number).toString().length > 6}
12
12
  fallback={<span>{(props.value as number).toString()}</span>}
@@ -5,7 +5,7 @@ export const FieldInteger: Component<{
5
5
  value: ValueInteger | undefined;
6
6
  }> = (props) => {
7
7
  return (
8
- <Show when={props.value !== null && props.value !== undefined}>
8
+ <Show when={props.value != null}>
9
9
  <span>{props.value as number}</span>
10
10
  </Show>
11
11
  );
@@ -6,7 +6,7 @@ export const FieldString: Component<{
6
6
  value: ValueString | undefined;
7
7
  }> = (props) => {
8
8
  return (
9
- <Show when={props.value !== null && props.value !== undefined}>
9
+ <Show when={props.value != null}>
10
10
  <Show when={(props.value as string).length > 20} fallback={<span>{props.value as string}</span>}>
11
11
  <Abbr title={props.value as string} value={(props.value as string).substring(0, 20)} />
12
12
  </Show>
@@ -24,6 +24,7 @@ export type FilterValueClearCallback = () => void;
24
24
  export interface FilterProps<C extends ConfigFilterBase, FilterValueType> {
25
25
  config: C;
26
26
  value?: FilterValueType;
27
+ defaultValue?: string;
27
28
  onValueChange: FilterValueChangeCallback<FilterValueType>;
28
29
  onValueClear: FilterValueClearCallback;
29
30
  }
@@ -19,6 +19,7 @@ export const FilterAllelicImbalance: Component<
19
19
  <FilterCategorical
20
20
  config={config()}
21
21
  value={props.value as FilterValueCategorical}
22
+ defaultValue={props.defaultValue}
22
23
  onValueChange={props.onValueChange}
23
24
  onValueClear={props.onValueClear}
24
25
  />
@@ -35,6 +35,7 @@ export const FilterComposed: Component<FilterProps<ConfigFilterComposed, FilterV
35
35
  <FilterHpo
36
36
  config={props.config as ConfigFilterHpo}
37
37
  value={props.value as FilterValueHpo | undefined}
38
+ defaultValue={props.defaultValue}
38
39
  onValueChange={props.onValueChange}
39
40
  onValueClear={props.onValueClear}
40
41
  />
@@ -43,6 +44,7 @@ export const FilterComposed: Component<FilterProps<ConfigFilterComposed, FilterV
43
44
  <FilterLocus
44
45
  config={props.config as ConfigFilterLocus}
45
46
  value={props.value as FilterValueLocus | undefined}
47
+ defaultValue={props.defaultValue}
46
48
  onValueChange={props.onValueChange}
47
49
  onValueClear={props.onValueClear}
48
50
  />
@@ -51,6 +53,7 @@ export const FilterComposed: Component<FilterProps<ConfigFilterComposed, FilterV
51
53
  <FilterAllelicImbalance
52
54
  config={props.config as ConfigFilterAllelicImbalance}
53
55
  value={props.value as FilterValueAllelicImbalance | undefined}
56
+ defaultValue={props.defaultValue}
54
57
  onValueChange={props.onValueChange}
55
58
  onValueClear={props.onValueClear}
56
59
  />
@@ -59,6 +62,7 @@ export const FilterComposed: Component<FilterProps<ConfigFilterComposed, FilterV
59
62
  <FilterInheritance
60
63
  config={props.config as ConfigFilterInheritanceMatch}
61
64
  value={props.value as FilterValueInheritanceMatch | undefined}
65
+ defaultValue={props.defaultValue}
62
66
  onValueChange={props.onValueChange}
63
67
  onValueClear={props.onValueClear}
64
68
  />
@@ -67,6 +71,7 @@ export const FilterComposed: Component<FilterProps<ConfigFilterComposed, FilterV
67
71
  <FilterDeNovo
68
72
  config={props.config as ConfigFilterDeNovo}
69
73
  value={props.value as FilterValueDeNovo | undefined}
74
+ defaultValue={props.defaultValue}
70
75
  onValueChange={props.onValueChange}
71
76
  onValueClear={props.onValueClear}
72
77
  />
@@ -75,6 +80,7 @@ export const FilterComposed: Component<FilterProps<ConfigFilterComposed, FilterV
75
80
  <FilterVipC
76
81
  config={props.config as ConfigFilterVipC}
77
82
  value={props.value as FilterValueVipC | undefined}
83
+ defaultValue={props.defaultValue}
78
84
  onValueChange={props.onValueChange}
79
85
  onValueClear={props.onValueClear}
80
86
  />
@@ -83,6 +89,7 @@ export const FilterComposed: Component<FilterProps<ConfigFilterComposed, FilterV
83
89
  <FilterVipCS
84
90
  config={props.config as ConfigFilterVipCS}
85
91
  value={props.value as FilterValueVipCS | undefined}
92
+ defaultValue={props.defaultValue}
86
93
  onValueChange={props.onValueChange}
87
94
  onValueClear={props.onValueClear}
88
95
  />
@@ -28,6 +28,7 @@ export const FilterDeNovo: Component<FilterProps<ConfigFilterDeNovo, FilterValue
28
28
  <FilterCategorical
29
29
  config={config()}
30
30
  value={props.value as FilterValueCategorical}
31
+ defaultValue={props.defaultValue}
31
32
  onValueChange={props.onValueChange}
32
33
  onValueClear={props.onValueClear}
33
34
  />
@@ -9,6 +9,7 @@ export const FilterHpo: Component<FilterProps<ConfigFilterHpo, FilterValueHpo>>
9
9
  <FilterTyped
10
10
  config={props.config as ConfigFilterField}
11
11
  value={props.value as FilterValueCategorical}
12
+ defaultValue={props.defaultValue}
12
13
  onValueChange={props.onValueChange as FilterValueChangeCallback<FilterValueField>}
13
14
  onValueClear={props.onValueClear}
14
15
  />
@@ -35,6 +35,7 @@ export const FilterInheritance: Component<FilterProps<ConfigFilterInheritanceMat
35
35
  <FilterCategorical
36
36
  config={config()}
37
37
  value={props.value as FilterValueCategorical}
38
+ defaultValue={props.defaultValue}
38
39
  onValueChange={props.onValueChange}
39
40
  onValueClear={props.onValueClear}
40
41
  />
@@ -1,4 +1,4 @@
1
- import { Component, createEffect, createSignal } from "solid-js";
1
+ import { Component, createEffect, createSignal, onMount } from "solid-js";
2
2
  import { FilterWrapper } from "../FilterWrapper";
3
3
  import { ButtonApply } from "../../form/ButtonApply";
4
4
  import { ButtonReset } from "../../form/ButtonReset";
@@ -23,6 +23,21 @@ export const FilterLocus: Component<FilterProps<ConfigFilterLocus, FilterValueLo
23
23
  }
24
24
  });
25
25
 
26
+ onMount(() => {
27
+ const pattern = /^(\w+):(\w+)-(\w+)$/;
28
+ if (props.config.defaultValue !== undefined) {
29
+ const match = (props.config.defaultValue as string).match(pattern);
30
+ if (!match) {
31
+ throw new Error(`Invalid region format: ${props.config.defaultValue}`);
32
+ }
33
+ const [, chrom, start, end] = match;
34
+ setChromosome(chrom);
35
+ setStartPosition(start);
36
+ setEndPosition(end);
37
+ onApply();
38
+ }
39
+ });
40
+
26
41
  const onApply = () => {
27
42
  const chr = chromosome();
28
43
  if (chr === undefined) return;
@@ -47,7 +62,6 @@ export const FilterLocus: Component<FilterProps<ConfigFilterLocus, FilterValueLo
47
62
 
48
63
  props.onValueClear();
49
64
  };
50
-
51
65
  return (
52
66
  <FilterWrapper config={props.config} error={error()}>
53
67
  <div class="field is-grouped">
@@ -66,7 +80,7 @@ export const FilterLocus: Component<FilterProps<ConfigFilterLocus, FilterValueLo
66
80
  <Input placeholder="End" value={endPosition()} onValueChange={(e) => setEndPosition(e.value)} />
67
81
  </div>
68
82
  <div class="control">
69
- <ButtonApply onClick={onApply} />
83
+ <ButtonApply onClick={onApply} isEnabled={() => chromosome() !== undefined && chromosome() !== ""} />
70
84
  </div>
71
85
  </div>
72
86
  <ButtonReset onClick={() => onReset()} />
@@ -0,0 +1,30 @@
1
+ import { Component } from "solid-js";
2
+ import { ConfigFilterPick, FilterValuePick } from "../../../types/configFilterComposed";
3
+ import { FilterProps } from "../Filter.tsx";
4
+ import { ConfigFilterField, FilterValueCategorical } from "../../../types/configFilter";
5
+ import { FilterCategorical } from "../typed/FilterCategorical";
6
+
7
+ export const FilterPick: Component<FilterProps<ConfigFilterPick, FilterValuePick>> = (props) => {
8
+ const config = (): ConfigFilterField => ({
9
+ ...props.config,
10
+ field: {
11
+ ...props.config.field,
12
+ categories: {
13
+ true: {
14
+ label: "True",
15
+ description: "VEP Picked transcript.",
16
+ },
17
+ },
18
+ },
19
+ });
20
+
21
+ return (
22
+ <FilterCategorical
23
+ config={config()}
24
+ value={props.value as FilterValueCategorical}
25
+ defaultValue={props.defaultValue}
26
+ onValueChange={props.onValueChange}
27
+ onValueClear={props.onValueClear}
28
+ />
29
+ );
30
+ };
@@ -9,6 +9,7 @@ export const FilterVipC: Component<FilterProps<ConfigFilterVipC, FilterValueVipC
9
9
  <FilterTyped
10
10
  config={props.config as ConfigFilterField}
11
11
  value={props.value as FilterValueCategorical}
12
+ defaultValue={props.defaultValue}
12
13
  onValueChange={props.onValueChange as FilterValueChangeCallback<FilterValueField>}
13
14
  onValueClear={props.onValueClear}
14
15
  />
@@ -9,6 +9,7 @@ export const FilterVipCS: Component<FilterProps<ConfigFilterVipCS, FilterValueVi
9
9
  <FilterTyped
10
10
  config={props.config as ConfigFilterField}
11
11
  value={props.value as FilterValueCategorical}
12
+ defaultValue={props.defaultValue}
12
13
  onValueChange={props.onValueChange as FilterValueChangeCallback<FilterValueField>}
13
14
  onValueClear={props.onValueClear}
14
15
  />
@@ -39,6 +39,7 @@ export const FilterFixed: Component<FilterProps<ConfigFilterFixed, FilterValue>>
39
39
  <FilterChrom
40
40
  config={props.config as ConfigFilterChrom}
41
41
  value={props.value as FilterValueChrom}
42
+ defaultValue={props.defaultValue}
42
43
  onValueChange={props.onValueChange}
43
44
  onValueClear={props.onValueClear}
44
45
  />
@@ -47,6 +48,7 @@ export const FilterFixed: Component<FilterProps<ConfigFilterFixed, FilterValue>>
47
48
  <FilterPos
48
49
  config={props.config as ConfigFilterPos}
49
50
  value={props.value as FilterValuePos}
51
+ defaultValue={props.defaultValue}
50
52
  onValueChange={props.onValueChange}
51
53
  onValueClear={props.onValueClear}
52
54
  />
@@ -55,6 +57,7 @@ export const FilterFixed: Component<FilterProps<ConfigFilterFixed, FilterValue>>
55
57
  <FilterId
56
58
  config={props.config as ConfigFilterId}
57
59
  value={props.value as FilterValueId}
60
+ defaultValue={props.defaultValue}
58
61
  onValueChange={props.onValueChange}
59
62
  onValueClear={props.onValueClear}
60
63
  />
@@ -63,6 +66,7 @@ export const FilterFixed: Component<FilterProps<ConfigFilterFixed, FilterValue>>
63
66
  <FilterRef
64
67
  config={props.config as ConfigFilterRef}
65
68
  value={props.value as FilterValueRef}
69
+ defaultValue={props.defaultValue}
66
70
  onValueChange={props.onValueChange}
67
71
  onValueClear={props.onValueClear}
68
72
  />
@@ -71,6 +75,7 @@ export const FilterFixed: Component<FilterProps<ConfigFilterFixed, FilterValue>>
71
75
  <FilterAlt
72
76
  config={props.config as ConfigFilterAlt}
73
77
  value={props.value as FilterValueAlt}
78
+ defaultValue={props.defaultValue}
74
79
  onValueChange={props.onValueChange}
75
80
  onValueClear={props.onValueClear}
76
81
  />
@@ -79,6 +84,7 @@ export const FilterFixed: Component<FilterProps<ConfigFilterFixed, FilterValue>>
79
84
  <FilterQual
80
85
  config={props.config as ConfigFilterQual}
81
86
  value={props.value as FilterValueQual}
87
+ defaultValue={props.defaultValue}
82
88
  onValueChange={props.onValueChange}
83
89
  onValueClear={props.onValueClear}
84
90
  />
@@ -87,6 +93,7 @@ export const FilterFixed: Component<FilterProps<ConfigFilterFixed, FilterValue>>
87
93
  <FilterFilter
88
94
  config={props.config as ConfigFilterFilter}
89
95
  value={props.value as FilterValueFilter}
96
+ defaultValue={props.defaultValue}
90
97
  onValueChange={props.onValueChange}
91
98
  onValueClear={props.onValueClear}
92
99
  />
@@ -1,4 +1,4 @@
1
- import { Component, createEffect, createSignal, For, JSX, Show } from "solid-js";
1
+ import { Component, createEffect, createSignal, For, JSX, onMount, Show } from "solid-js";
2
2
  import { FilterWrapper } from "../FilterWrapper";
3
3
  import {
4
4
  ConfigFilterField,
@@ -88,6 +88,23 @@ export const FilterCategorical: Component<FilterProps<ConfigFilterField, FilterV
88
88
  }
89
89
  };
90
90
 
91
+ function validateValues(values: string[], filterCategories: FilterCategory[]) {
92
+ const invalidValues = values.filter((v) => !filterCategories.map((fc) => fc.id).includes(v));
93
+ if (invalidValues.length > 0) {
94
+ throw new Error(
95
+ `Invalid default values ('${invalidValues.join(", ")}') found for filter '${props.config.field.id}'.`,
96
+ );
97
+ }
98
+ }
99
+
100
+ onMount(() => {
101
+ if (props.config.defaultValue !== undefined) {
102
+ const values = props.config.defaultValue.split(",");
103
+ validateValues(values, categories());
104
+ props.onValueChange({ value: values as FilterValueCategorical });
105
+ }
106
+ });
107
+
91
108
  return (
92
109
  <FilterWrapper config={props.config} tooltipContentElement={tooltipContentElement()}>
93
110
  <div class="field">
@@ -9,6 +9,7 @@ export const FilterFlag: Component<FilterProps<ConfigFilterField, FilterValueFla
9
9
  field: {
10
10
  ...props.config.field,
11
11
  categories: { true: { label: "True" }, false: { label: "False" } },
12
+ required: true, //Missing == false for flags
12
13
  },
13
14
  });
14
15
 
@@ -16,6 +17,7 @@ export const FilterFlag: Component<FilterProps<ConfigFilterField, FilterValueFla
16
17
  <FilterCategorical
17
18
  config={config()}
18
19
  value={props.value as FilterValueCategorical}
20
+ defaultValue={props.defaultValue}
19
21
  onValueChange={props.onValueChange}
20
22
  onValueClear={props.onValueClear}
21
23
  />
@@ -1,4 +1,4 @@
1
- import { Component, createEffect, createSignal } from "solid-js";
1
+ import { Component, createEffect, createSignal, onMount } from "solid-js";
2
2
  import { FilterWrapper } from "../FilterWrapper";
3
3
  import { ConfigFilterField, FilterValueInterval } from "../../../types/configFilter";
4
4
  import { Input } from "../../form/Input";
@@ -24,6 +24,34 @@ export const FilterInterval: Component<FilterProps<ConfigFilterField, FilterValu
24
24
  }
25
25
  });
26
26
 
27
+ onMount(() => {
28
+ if (props.config.defaultValue !== undefined) {
29
+ const split = props.config.defaultValue.split(",");
30
+ if (split.length >= 1) {
31
+ if (split[0] !== undefined && split[0] !== "") {
32
+ if (Number.isNaN(Number(split[0]))) {
33
+ throw new TypeError(
34
+ `'${props.config.defaultValue}' is not a valid default value for field '${props.config.field.id}'.`,
35
+ );
36
+ }
37
+ setLeftInputValue(split[0]);
38
+ }
39
+ }
40
+ if (split.length === 2) {
41
+ if (split[1] !== undefined && split[1] !== "") {
42
+ if (Number.isNaN(Number(split[1]))) {
43
+ throw new TypeError(
44
+ `'${props.config.defaultValue}' is not a valid default value for field '${props.config.field.id}'.`,
45
+ );
46
+ }
47
+ console.log("7");
48
+ setRightInputValue(split[1]);
49
+ }
50
+ onApply();
51
+ }
52
+ }
53
+ });
54
+
27
55
  const onApply = () => {
28
56
  const validationResult = validateIntervalInput(props.config.id, leftInputValue(), rightInputValue());
29
57
  if (validationResult !== undefined) {
@@ -1,4 +1,4 @@
1
- import { Component, createEffect, createSignal } from "solid-js";
1
+ import { Component, createEffect, createSignal, onMount } from "solid-js";
2
2
  import { FilterWrapper } from "../FilterWrapper";
3
3
  import { ConfigFilterField, FilterValueString } from "../../../types/configFilter";
4
4
  import { Input } from "../../form/Input";
@@ -23,6 +23,13 @@ export const FilterString: Component<FilterProps<ConfigFilterField, FilterValueS
23
23
  }
24
24
  };
25
25
 
26
+ onMount(() => {
27
+ if (props.config.defaultValue !== undefined) {
28
+ setInputValue(props.config.defaultValue);
29
+ onApply();
30
+ }
31
+ });
32
+
26
33
  return (
27
34
  <FilterWrapper config={props.config}>
28
35
  <div class="field is-grouped">
@@ -31,6 +31,7 @@ export const FilterTyped: Component<FilterProps<ConfigFilterField, FilterValueFi
31
31
  <FilterString
32
32
  config={props.config}
33
33
  value={props.value as FilterValueString}
34
+ defaultValue={props.defaultValue}
34
35
  onValueChange={props.onValueChange}
35
36
  onValueClear={props.onValueClear}
36
37
  />