@genspectrum/dashboard-components 1.15.0 → 1.17.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 (60) hide show
  1. package/custom-elements.json +5 -5
  2. package/dist/components.d.ts +66 -67
  3. package/dist/components.js +457 -256
  4. package/dist/components.js.map +1 -1
  5. package/dist/util.d.ts +69 -66
  6. package/package.json +2 -9
  7. package/src/preact/MutationAnnotationsContext.tsx +1 -1
  8. package/src/preact/components/csv-download-button.tsx +22 -14
  9. package/src/preact/components/features-over-time-grid.tsx +189 -43
  10. package/src/preact/components/mutations-over-time-mutations-filter.stories.tsx +1 -1
  11. package/src/preact/components/mutations-over-time-mutations-filter.tsx +1 -1
  12. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutationsByDay/aminoAcidMutationsOverTimePage1.json +52 -0
  13. package/src/preact/mutationsOverTime/__mockData__/byWeek/mutationsOverTimePage1.json +76 -0
  14. package/src/preact/mutationsOverTime/__mockData__/defaultMockData/mockDefaultMutationsOverTimeWithFilter.json +43 -0
  15. package/src/preact/mutationsOverTime/__mockData__/defaultMockData/mutationsOverTimePage1.json +126 -0
  16. package/src/preact/mutationsOverTime/__mockData__/defaultMockData/mutationsOverTimePage2.json +116 -0
  17. package/src/preact/mutationsOverTime/__mockData__/defaultMockData/mutationsOverTimePageSize20.json +216 -0
  18. package/src/preact/mutationsOverTime/getFilteredMutationCodes.spec.ts +236 -0
  19. package/src/preact/mutationsOverTime/{getFilteredMutationsOverTimeData.ts → getFilteredMutationCodes.ts} +32 -45
  20. package/src/preact/mutationsOverTime/mutations-over-time.stories.tsx +128 -23
  21. package/src/preact/mutationsOverTime/mutations-over-time.tsx +139 -74
  22. package/src/preact/mutationsOverTime/useMutationsOverTimePageData.ts +111 -0
  23. package/src/preact/queriesOverTime/queries-over-time-row-label-tooltip.stories.tsx +8 -10
  24. package/src/preact/queriesOverTime/queries-over-time-row-label-tooltip.tsx +7 -17
  25. package/src/preact/queriesOverTime/queries-over-time.tsx +1 -1
  26. package/src/preact/shared/tanstackTable/pagination-context.tsx +5 -2
  27. package/src/preact/shared/tanstackTable/pagination.tsx +11 -9
  28. package/src/preact/shared/tanstackTable/tanstackTable.tsx +7 -4
  29. package/src/preact/wastewater/mutationsOverTime/wastewater-mutations-over-time.tsx +1 -1
  30. package/src/query/queryMutationsOverTime.spec.ts +187 -662
  31. package/src/query/queryMutationsOverTime.ts +46 -33
  32. package/src/utilEntrypoint.ts +1 -1
  33. package/src/utils/useControlledState.ts +15 -0
  34. package/src/web-components/gs-app.ts +2 -3
  35. package/src/web-components/input/gs-date-range-filter.tsx +2 -3
  36. package/src/web-components/input/gs-lineage-filter.tsx +2 -3
  37. package/src/web-components/input/gs-location-filter.tsx +2 -3
  38. package/src/web-components/input/gs-mutation-filter.tsx +3 -4
  39. package/src/web-components/input/gs-number-range-filter.tsx +2 -3
  40. package/src/web-components/input/gs-text-filter.tsx +2 -3
  41. package/src/web-components/mutation-annotations-context.ts +3 -1
  42. package/src/web-components/visualization/gs-aggregate.tsx +2 -3
  43. package/src/web-components/visualization/gs-genome-data-viewer.tsx +2 -3
  44. package/src/web-components/visualization/gs-mutation-comparison.tsx +2 -3
  45. package/src/web-components/visualization/gs-mutations-over-time.stories.ts +78 -22
  46. package/src/web-components/visualization/gs-mutations-over-time.tsx +2 -3
  47. package/src/web-components/visualization/gs-mutations.tsx +7 -8
  48. package/src/web-components/visualization/gs-number-sequences-over-time.tsx +2 -3
  49. package/src/web-components/visualization/gs-prevalence-over-time.tsx +2 -3
  50. package/src/web-components/visualization/gs-queries-over-time.tsx +2 -3
  51. package/src/web-components/visualization/gs-relative-growth-advantage.tsx +2 -3
  52. package/src/web-components/visualization/gs-sequences-by-location.tsx +2 -3
  53. package/src/web-components/visualization/gs-statistics.tsx +2 -3
  54. package/src/web-components/wastewaterVisualization/gs-wastewater-mutations-over-time.tsx +2 -3
  55. package/standalone-bundle/dashboard-components.js +6877 -6697
  56. package/standalone-bundle/dashboard-components.js.map +1 -1
  57. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutationsByDay/aminoAcidMutationsOverTime.json +0 -5496
  58. package/src/preact/mutationsOverTime/__mockData__/byWeek/mutationsOverTime.json +0 -7100
  59. package/src/preact/mutationsOverTime/__mockData__/defaultMockData/mutationsOverTime.json +0 -12646
  60. package/src/preact/mutationsOverTime/getFilteredMutationsOverTime.spec.ts +0 -417
@@ -0,0 +1,116 @@
1
+ {
2
+ "data": {
3
+ "mutations": [
4
+ "C21654-",
5
+ "T21655-",
6
+ "G22111T",
7
+ "G22599C",
8
+ "T22928C",
9
+ "T23011-",
10
+ "C23039G",
11
+ "C23277T",
12
+ "G24872T"
13
+ ],
14
+ "dateRanges": [
15
+ { "dateFrom": "2024-01-01", "dateTo": "2024-01-31" },
16
+ { "dateFrom": "2024-02-01", "dateTo": "2024-02-29" },
17
+ { "dateFrom": "2024-03-01", "dateTo": "2024-03-31" },
18
+ { "dateFrom": "2024-04-01", "dateTo": "2024-04-30" },
19
+ { "dateFrom": "2024-05-01", "dateTo": "2024-05-31" },
20
+ { "dateFrom": "2024-06-01", "dateTo": "2024-06-30" },
21
+ { "dateFrom": "2024-07-01", "dateTo": "2024-07-31" }
22
+ ],
23
+ "data": [
24
+ [
25
+ { "count": 12, "coverage": 13942 },
26
+ { "count": 14, "coverage": 17357 },
27
+ { "count": 41, "coverage": 8317 },
28
+ { "count": 234, "coverage": 6565 },
29
+ { "count": 1368, "coverage": 9053 },
30
+ { "count": 5079, "coverage": 16078 },
31
+ { "count": 3245, "coverage": 7312 }
32
+ ],
33
+ [
34
+ { "count": 12, "coverage": 13941 },
35
+ { "count": 14, "coverage": 17360 },
36
+ { "count": 41, "coverage": 8327 },
37
+ { "count": 235, "coverage": 6596 },
38
+ { "count": 1376, "coverage": 9143 },
39
+ { "count": 5089, "coverage": 16368 },
40
+ { "count": 3256, "coverage": 7477 }
41
+ ],
42
+ [
43
+ { "count": 233, "coverage": 13964 },
44
+ { "count": 283, "coverage": 17438 },
45
+ { "count": 203, "coverage": 8317 },
46
+ { "count": 300, "coverage": 6600 },
47
+ { "count": 706, "coverage": 9120 },
48
+ { "count": 1920, "coverage": 16355 },
49
+ { "count": 1003, "coverage": 7453 }
50
+ ],
51
+ [
52
+ { "count": 410, "coverage": 13781 },
53
+ { "count": 1049, "coverage": 17284 },
54
+ { "count": 1440, "coverage": 8281 },
55
+ { "count": 2548, "coverage": 6510 },
56
+ { "count": 5236, "coverage": 9027 },
57
+ { "count": 9013, "coverage": 16267 },
58
+ { "count": 3814, "coverage": 7396 }
59
+ ],
60
+ [
61
+ { "count": 98, "coverage": 13705 },
62
+ { "count": 385, "coverage": 16878 },
63
+ { "count": 948, "coverage": 8052 },
64
+ { "count": 2803, "coverage": 6478 },
65
+ { "count": 6969, "coverage": 8920 },
66
+ { "count": 15034, "coverage": 16124 },
67
+ { "count": 7056, "coverage": 7294 }
68
+ ],
69
+ [
70
+ { "count": 12413, "coverage": 13785 },
71
+ { "count": 15423, "coverage": 17010 },
72
+ { "count": 7059, "coverage": 8159 },
73
+ { "count": 5463, "coverage": 6524 },
74
+ { "count": 7900, "coverage": 9038 },
75
+ { "count": 14926, "coverage": 16295 },
76
+ { "count": 6758, "coverage": 7330 }
77
+ ],
78
+ [
79
+ { "count": 2, "coverage": 13859 },
80
+ { "count": 7, "coverage": 17116 },
81
+ { "count": 40, "coverage": 8220 },
82
+ { "count": 361, "coverage": 6565 },
83
+ { "count": 1709, "coverage": 9116 },
84
+ { "count": 6158, "coverage": 16313 },
85
+ { "count": 3340, "coverage": 7373 }
86
+ ],
87
+ [
88
+ { "count": 1061, "coverage": 14046 },
89
+ { "count": 2717, "coverage": 17559 },
90
+ { "count": 2232, "coverage": 8409 },
91
+ { "count": 1865, "coverage": 6653 },
92
+ { "count": 1369, "coverage": 9240 },
93
+ { "count": 1048, "coverage": 16493 },
94
+ { "count": 365, "coverage": 7503 }
95
+ ],
96
+ [
97
+ { "count": 42, "coverage": 13767 },
98
+ { "count": 203, "coverage": 17280 },
99
+ { "count": 563, "coverage": 8256 },
100
+ { "count": 1666, "coverage": 6528 },
101
+ { "count": 4632, "coverage": 9026 },
102
+ { "count": 11162, "coverage": 16187 },
103
+ { "count": 5451, "coverage": 7393 }
104
+ ]
105
+ ],
106
+ "totalCountsByDateRange": [14065, 17583, 8432, 6680, 9252, 16512, 7508]
107
+ },
108
+ "info": {
109
+ "dataVersion": "1774200829",
110
+ "requestId": "8df92719-e99e-4477-a60b-ed73d4690b8c",
111
+ "requestInfo": "sars_cov-2_nextstrain_open on lapis.cov-spectrum.org at 2026-03-24T09:27:56.668988862",
112
+ "reportTo": "Please report to https://github.com/GenSpectrum/LAPIS/issues in case you encounter any unexpected issues. Please include the request ID and the requestInfo in your report.",
113
+ "lapisVersion": "0.7.0",
114
+ "siloVersion": "0.10.0"
115
+ }
116
+ }
@@ -0,0 +1,216 @@
1
+ {
2
+ "data": {
3
+ "mutations": [
4
+ "C44T",
5
+ "C774T",
6
+ "C7113T",
7
+ "C12616T",
8
+ "A13121T",
9
+ "G15372T",
10
+ "G17334T",
11
+ "T18453C",
12
+ "A19722G",
13
+ "T21653-",
14
+ "C21654-",
15
+ "T21655-",
16
+ "G22111T",
17
+ "G22599C",
18
+ "T22928C",
19
+ "T23011-",
20
+ "C23039G",
21
+ "C23277T",
22
+ "G24872T"
23
+ ],
24
+ "dateRanges": [
25
+ { "dateFrom": "2024-01-01", "dateTo": "2024-01-31" },
26
+ { "dateFrom": "2024-02-01", "dateTo": "2024-02-29" },
27
+ { "dateFrom": "2024-03-01", "dateTo": "2024-03-31" },
28
+ { "dateFrom": "2024-04-01", "dateTo": "2024-04-30" },
29
+ { "dateFrom": "2024-05-01", "dateTo": "2024-05-31" },
30
+ { "dateFrom": "2024-06-01", "dateTo": "2024-06-30" },
31
+ { "dateFrom": "2024-07-01", "dateTo": "2024-07-31" }
32
+ ],
33
+ "data": [
34
+ [
35
+ { "count": 1447, "coverage": 2444 },
36
+ { "count": 1917, "coverage": 3372 },
37
+ { "count": 1028, "coverage": 1810 },
38
+ { "count": 1005, "coverage": 1373 },
39
+ { "count": 1863, "coverage": 2315 },
40
+ { "count": 4282, "coverage": 4958 },
41
+ { "count": 1775, "coverage": 2237 }
42
+ ],
43
+ [
44
+ { "count": 3596, "coverage": 13661 },
45
+ { "count": 4644, "coverage": 17266 },
46
+ { "count": 1957, "coverage": 8250 },
47
+ { "count": 860, "coverage": 6549 },
48
+ { "count": 379, "coverage": 9171 },
49
+ { "count": 178, "coverage": 16412 },
50
+ { "count": 41, "coverage": 7462 }
51
+ ],
52
+ [
53
+ { "count": 41, "coverage": 13981 },
54
+ { "count": 202, "coverage": 17441 },
55
+ { "count": 568, "coverage": 8356 },
56
+ { "count": 1740, "coverage": 6589 },
57
+ { "count": 4746, "coverage": 9111 },
58
+ { "count": 11247, "coverage": 16298 },
59
+ { "count": 5484, "coverage": 7443 }
60
+ ],
61
+ [
62
+ { "count": 25, "coverage": 13988 },
63
+ { "count": 26, "coverage": 17508 },
64
+ { "count": 3, "coverage": 8376 },
65
+ { "count": 3, "coverage": 6645 },
66
+ { "count": 58, "coverage": 9199 },
67
+ { "count": 950, "coverage": 16346 },
68
+ { "count": 1144, "coverage": 7459 }
69
+ ],
70
+ [
71
+ { "count": 1, "coverage": 14032 },
72
+ { "count": 1, "coverage": 17551 },
73
+ { "count": 1, "coverage": 8418 },
74
+ { "count": 0, "coverage": 6672 },
75
+ { "count": 44, "coverage": 9238 },
76
+ { "count": 922, "coverage": 16465 },
77
+ { "count": 1119, "coverage": 7468 }
78
+ ],
79
+ [
80
+ { "count": 8, "coverage": 13900 },
81
+ { "count": 11, "coverage": 17458 },
82
+ { "count": 44, "coverage": 8358 },
83
+ { "count": 200, "coverage": 6577 },
84
+ { "count": 769, "coverage": 9065 },
85
+ { "count": 3065, "coverage": 16446 },
86
+ { "count": 1930, "coverage": 7464 }
87
+ ],
88
+ [
89
+ { "count": 65, "coverage": 14003 },
90
+ { "count": 200, "coverage": 17511 },
91
+ { "count": 565, "coverage": 8397 },
92
+ { "count": 1702, "coverage": 6603 },
93
+ { "count": 4598, "coverage": 9035 },
94
+ { "count": 11288, "coverage": 16416 },
95
+ { "count": 5451, "coverage": 7457 }
96
+ ],
97
+ [
98
+ { "count": 2949, "coverage": 13937 },
99
+ { "count": 3625, "coverage": 17486 },
100
+ { "count": 1511, "coverage": 8380 },
101
+ { "count": 585, "coverage": 6635 },
102
+ { "count": 239, "coverage": 9210 },
103
+ { "count": 76, "coverage": 16400 },
104
+ { "count": 19, "coverage": 7481 }
105
+ ],
106
+ [
107
+ { "count": 1, "coverage": 14014 },
108
+ { "count": 7, "coverage": 17517 },
109
+ { "count": 36, "coverage": 8404 },
110
+ { "count": 196, "coverage": 6641 },
111
+ { "count": 789, "coverage": 9202 },
112
+ { "count": 3041, "coverage": 16418 },
113
+ { "count": 1925, "coverage": 7470 }
114
+ ],
115
+ [
116
+ { "count": 13, "coverage": 13948 },
117
+ { "count": 15, "coverage": 17359 },
118
+ { "count": 41, "coverage": 8319 },
119
+ { "count": 237, "coverage": 6564 },
120
+ { "count": 1370, "coverage": 9054 },
121
+ { "count": 5079, "coverage": 16077 },
122
+ { "count": 3245, "coverage": 7342 }
123
+ ],
124
+ [
125
+ { "count": 12, "coverage": 13942 },
126
+ { "count": 14, "coverage": 17357 },
127
+ { "count": 41, "coverage": 8317 },
128
+ { "count": 234, "coverage": 6565 },
129
+ { "count": 1368, "coverage": 9053 },
130
+ { "count": 5079, "coverage": 16078 },
131
+ { "count": 3245, "coverage": 7312 }
132
+ ],
133
+ [
134
+ { "count": 12, "coverage": 13941 },
135
+ { "count": 14, "coverage": 17360 },
136
+ { "count": 41, "coverage": 8327 },
137
+ { "count": 235, "coverage": 6596 },
138
+ { "count": 1376, "coverage": 9143 },
139
+ { "count": 5089, "coverage": 16368 },
140
+ { "count": 3256, "coverage": 7477 }
141
+ ],
142
+ [
143
+ { "count": 233, "coverage": 13964 },
144
+ { "count": 283, "coverage": 17438 },
145
+ { "count": 203, "coverage": 8317 },
146
+ { "count": 300, "coverage": 6600 },
147
+ { "count": 706, "coverage": 9120 },
148
+ { "count": 1920, "coverage": 16355 },
149
+ { "count": 1003, "coverage": 7453 }
150
+ ],
151
+ [
152
+ { "count": 410, "coverage": 13781 },
153
+ { "count": 1049, "coverage": 17284 },
154
+ { "count": 1440, "coverage": 8281 },
155
+ { "count": 2548, "coverage": 6510 },
156
+ { "count": 5236, "coverage": 9027 },
157
+ { "count": 9013, "coverage": 16267 },
158
+ { "count": 3814, "coverage": 7396 }
159
+ ],
160
+ [
161
+ { "count": 98, "coverage": 13705 },
162
+ { "count": 385, "coverage": 16878 },
163
+ { "count": 948, "coverage": 8052 },
164
+ { "count": 2803, "coverage": 6478 },
165
+ { "count": 6969, "coverage": 8920 },
166
+ { "count": 15034, "coverage": 16124 },
167
+ { "count": 7056, "coverage": 7294 }
168
+ ],
169
+ [
170
+ { "count": 12413, "coverage": 13785 },
171
+ { "count": 15423, "coverage": 17010 },
172
+ { "count": 7059, "coverage": 8159 },
173
+ { "count": 5463, "coverage": 6524 },
174
+ { "count": 7900, "coverage": 9038 },
175
+ { "count": 14926, "coverage": 16295 },
176
+ { "count": 6758, "coverage": 7330 }
177
+ ],
178
+ [
179
+ { "count": 2, "coverage": 13859 },
180
+ { "count": 7, "coverage": 17116 },
181
+ { "count": 40, "coverage": 8220 },
182
+ { "count": 361, "coverage": 6565 },
183
+ { "count": 1709, "coverage": 9116 },
184
+ { "count": 6158, "coverage": 16313 },
185
+ { "count": 3340, "coverage": 7373 }
186
+ ],
187
+ [
188
+ { "count": 1061, "coverage": 14046 },
189
+ { "count": 2717, "coverage": 17559 },
190
+ { "count": 2232, "coverage": 8409 },
191
+ { "count": 1865, "coverage": 6653 },
192
+ { "count": 1369, "coverage": 9240 },
193
+ { "count": 1048, "coverage": 16493 },
194
+ { "count": 365, "coverage": 7503 }
195
+ ],
196
+ [
197
+ { "count": 42, "coverage": 13767 },
198
+ { "count": 203, "coverage": 17280 },
199
+ { "count": 563, "coverage": 8256 },
200
+ { "count": 1666, "coverage": 6528 },
201
+ { "count": 4632, "coverage": 9026 },
202
+ { "count": 11162, "coverage": 16187 },
203
+ { "count": 5451, "coverage": 7393 }
204
+ ]
205
+ ],
206
+ "totalCountsByDateRange": [14065, 17583, 8432, 6680, 9252, 16512, 7508]
207
+ },
208
+ "info": {
209
+ "dataVersion": "1774200829",
210
+ "requestId": "a42fb76f-423d-4436-b8e6-a7bfcf1cc6d8",
211
+ "requestInfo": "sars_cov-2_nextstrain_open on lapis.cov-spectrum.org at 2026-03-24T09:11:40.921431027",
212
+ "reportTo": "Please report to https://github.com/GenSpectrum/LAPIS/issues in case you encounter any unexpected issues. Please include the request ID and the requestInfo in your report.",
213
+ "lapisVersion": "0.7.0",
214
+ "siloVersion": "0.10.0"
215
+ }
216
+ }
@@ -0,0 +1,236 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { getFilteredMutationCodes, type MutationFilter } from './getFilteredMutationCodes';
4
+ import { type DeletionEntry, type SubstitutionEntry } from '../../types';
5
+ import { type Deletion, type Substitution } from '../../utils/mutations';
6
+ import { type MutationAnnotations } from '../../web-components/mutation-annotations-context';
7
+ import { getMutationAnnotationsContext, getMutationAnnotationsProvider } from '../MutationAnnotationsContext';
8
+
9
+ describe('getFilteredMutationCodes', () => {
10
+ it('should filter by displayed segments', () => {
11
+ const result = getFilteredMutationCodes({
12
+ overallMutationData: [someSubstitutionEntry, anotherSubstitutionEntry, someDeletionEntry],
13
+ displayedSegments: [
14
+ { segment: 'someSegment', checked: false, label: 'Some Segment' },
15
+ { segment: 'someOtherSegment', checked: true, label: 'Some Other Segment' },
16
+ ],
17
+ displayedMutationTypes: [],
18
+ proportionInterval,
19
+ mutationFilterValue: { textFilter: '', annotationNameFilter: new Set() },
20
+ sequenceType: 'nucleotide',
21
+ annotationProvider: () => [],
22
+ });
23
+
24
+ expect(result).to.deep.equal([anotherSubstitution.code]);
25
+ });
26
+
27
+ it('should filter by mutation types', () => {
28
+ const result = getFilteredMutationCodes({
29
+ overallMutationData: [someSubstitutionEntry, anotherSubstitutionEntry, someDeletionEntry],
30
+ displayedSegments: [],
31
+ displayedMutationTypes: [
32
+ { type: 'substitution', checked: false, label: 'Substitution' },
33
+ { type: 'deletion', checked: true, label: 'Deletion' },
34
+ ],
35
+ proportionInterval,
36
+ mutationFilterValue: { textFilter: '', annotationNameFilter: new Set() },
37
+ sequenceType: 'nucleotide',
38
+ annotationProvider: () => [],
39
+ });
40
+
41
+ expect(result).to.deep.equal([someDeletion.code]);
42
+ });
43
+
44
+ it('should remove mutations where overall proportion is below filter', () => {
45
+ const result = getFilteredMutationCodes({
46
+ overallMutationData: [
47
+ { ...someSubstitutionEntry, proportion: belowFilter },
48
+ { ...anotherSubstitutionEntry, proportion: inFilter },
49
+ { ...someDeletionEntry, proportion: inFilter },
50
+ ],
51
+ displayedSegments: [],
52
+ displayedMutationTypes: [],
53
+ proportionInterval,
54
+ mutationFilterValue: { textFilter: '', annotationNameFilter: new Set() },
55
+ sequenceType: 'nucleotide',
56
+ annotationProvider: () => [],
57
+ });
58
+
59
+ expect(result).to.deep.equal([anotherSubstitution.code, someDeletion.code]);
60
+ });
61
+
62
+ it('should remove mutations where overall proportion is above filter', () => {
63
+ const result = getFilteredMutationCodes({
64
+ overallMutationData: [
65
+ { ...someSubstitutionEntry, proportion: aboveFilter },
66
+ { ...anotherSubstitutionEntry, proportion: inFilter },
67
+ { ...someDeletionEntry, proportion: inFilter },
68
+ ],
69
+ displayedSegments: [],
70
+ displayedMutationTypes: [],
71
+ proportionInterval,
72
+ mutationFilterValue: { textFilter: '', annotationNameFilter: new Set() },
73
+ sequenceType: 'nucleotide',
74
+ annotationProvider: () => [],
75
+ });
76
+
77
+ expect(result).to.deep.equal([anotherSubstitution.code, someDeletion.code]);
78
+ });
79
+
80
+ it('should not remove mutations where overall proportion is at lower bound of filter', () => {
81
+ const result = getFilteredMutationCodes({
82
+ overallMutationData: [
83
+ { ...someSubstitutionEntry, proportion: atFilterMin },
84
+ { ...anotherSubstitutionEntry, proportion: inFilter },
85
+ { ...someDeletionEntry, proportion: inFilter },
86
+ ],
87
+ displayedSegments: [],
88
+ displayedMutationTypes: [],
89
+ proportionInterval,
90
+ mutationFilterValue: { textFilter: '', annotationNameFilter: new Set() },
91
+ sequenceType: 'nucleotide',
92
+ annotationProvider: () => [],
93
+ });
94
+
95
+ expect(result).to.deep.equal([someSubstitution.code, anotherSubstitution.code, someDeletion.code]);
96
+ });
97
+
98
+ it('should not remove mutations where overall proportion is at upper bound of filter', () => {
99
+ const result = getFilteredMutationCodes({
100
+ overallMutationData: [
101
+ { ...someSubstitutionEntry, proportion: atFilterMax },
102
+ { ...anotherSubstitutionEntry, proportion: inFilter },
103
+ { ...someDeletionEntry, proportion: inFilter },
104
+ ],
105
+ displayedSegments: [],
106
+ displayedMutationTypes: [],
107
+ proportionInterval,
108
+ mutationFilterValue: { textFilter: '', annotationNameFilter: new Set() },
109
+ sequenceType: 'nucleotide',
110
+ annotationProvider: () => [],
111
+ });
112
+
113
+ expect(result).to.deep.equal([someSubstitution.code, anotherSubstitution.code, someDeletion.code]);
114
+ });
115
+
116
+ it('should filter by mutation filter text value', () => {
117
+ const result = getFilteredMutationCodes({
118
+ overallMutationData: [someSubstitutionEntry, anotherSubstitutionEntry, someDeletionEntry],
119
+ displayedSegments: [],
120
+ displayedMutationTypes: [],
121
+ proportionInterval,
122
+ mutationFilterValue: { textFilter: '23T', annotationNameFilter: new Set() },
123
+ sequenceType: 'nucleotide',
124
+ annotationProvider: () => [],
125
+ });
126
+
127
+ expect(result).to.deep.equal([someSubstitution.code]);
128
+ });
129
+
130
+ describe('should filter by annotation', () => {
131
+ const expectFilteredValue = (filterValue: MutationFilter, annotations: MutationAnnotations) => {
132
+ const annotationProvider = getMutationAnnotationsProvider(getMutationAnnotationsContext(annotations));
133
+
134
+ const result = getFilteredMutationCodes({
135
+ overallMutationData: [someSubstitutionEntry, anotherSubstitutionEntry, someDeletionEntry],
136
+ displayedSegments: [],
137
+ displayedMutationTypes: [],
138
+ proportionInterval,
139
+ mutationFilterValue: filterValue,
140
+ sequenceType: 'nucleotide',
141
+ annotationProvider,
142
+ });
143
+
144
+ expect(result).to.deep.equal([someSubstitution.code]);
145
+ };
146
+
147
+ it('with filter value in symbol', () => {
148
+ expectFilteredValue({ textFilter: '#', annotationNameFilter: new Set() }, [
149
+ { name: 'Annotation 1', description: 'Description 1', symbol: '#', nucleotideMutations: ['A123T'] },
150
+ ]);
151
+ });
152
+
153
+ it('with filter value in name', () => {
154
+ expectFilteredValue({ textFilter: 'Annota', annotationNameFilter: new Set() }, [
155
+ { name: 'Annotation 1 #', description: 'Description 1', symbol: '+', nucleotideMutations: ['A123T'] },
156
+ ]);
157
+ });
158
+
159
+ it('with filter value in description', () => {
160
+ expectFilteredValue({ textFilter: 'Descr', annotationNameFilter: new Set() }, [
161
+ { name: 'Annotation 1', description: 'Description 1', symbol: '#', nucleotideMutations: ['A123T'] },
162
+ ]);
163
+ });
164
+
165
+ it('with annotation name filter', () => {
166
+ expectFilteredValue({ textFilter: '', annotationNameFilter: new Set(['Annotation 1']) }, [
167
+ { name: 'Annotation 1', description: 'Description 1', symbol: '#', nucleotideMutations: ['A123T'] },
168
+ ]);
169
+ });
170
+ });
171
+
172
+ it('should not filter by individual time-series proportions below the overall filter', () => {
173
+ const result = getFilteredMutationCodes({
174
+ overallMutationData: [someSubstitutionEntry, anotherSubstitutionEntry, someDeletionEntry],
175
+ displayedSegments: [],
176
+ displayedMutationTypes: [],
177
+ proportionInterval,
178
+ mutationFilterValue: { textFilter: '', annotationNameFilter: new Set() },
179
+ sequenceType: 'nucleotide',
180
+ annotationProvider: () => [],
181
+ });
182
+
183
+ expect(result).to.deep.equal([someSubstitution.code, anotherSubstitution.code, someDeletion.code]);
184
+ });
185
+
186
+ const belowFilter = 0.1;
187
+ const atFilterMin = 0.2;
188
+ const inFilter = 0.5;
189
+ const atFilterMax = 0.9;
190
+ const aboveFilter = 0.99;
191
+ const proportionInterval = { min: atFilterMin, max: atFilterMax };
192
+
193
+ const someSubstitution: Substitution = {
194
+ type: 'substitution',
195
+ valueAtReference: 'A',
196
+ substitutionValue: 'T',
197
+ code: 'A123T',
198
+ segment: 'someSegment',
199
+ position: 123,
200
+ };
201
+ const someSubstitutionEntry: SubstitutionEntry<Substitution> = {
202
+ type: 'substitution',
203
+ mutation: someSubstitution,
204
+ count: 234,
205
+ proportion: inFilter,
206
+ };
207
+
208
+ const anotherSubstitution: Substitution = {
209
+ type: 'substitution',
210
+ valueAtReference: 'G',
211
+ substitutionValue: 'C',
212
+ code: 'G345C',
213
+ segment: 'someOtherSegment',
214
+ position: 345,
215
+ };
216
+ const anotherSubstitutionEntry: SubstitutionEntry<Substitution> = {
217
+ type: 'substitution',
218
+ mutation: anotherSubstitution,
219
+ count: 456,
220
+ proportion: inFilter,
221
+ };
222
+
223
+ const someDeletion: Deletion = {
224
+ type: 'deletion',
225
+ valueAtReference: 'A',
226
+ segment: 'someSegment',
227
+ position: 567,
228
+ code: 'A123-',
229
+ };
230
+ const someDeletionEntry: DeletionEntry<Deletion> = {
231
+ type: 'deletion',
232
+ mutation: someDeletion,
233
+ count: 789,
234
+ proportion: inFilter,
235
+ };
236
+ });