@genspectrum/dashboard-components 1.2.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +9 -0
  2. package/custom-elements.json +20 -1
  3. package/dist/assets/mutationOverTimeWorker-CQxrFo53.js.map +1 -0
  4. package/dist/components.d.ts +34 -28
  5. package/dist/components.js +48 -16
  6. package/dist/components.js.map +1 -1
  7. package/dist/util.d.ts +28 -28
  8. package/package.json +1 -1
  9. package/src/lapisApi/lapisApi.ts +29 -0
  10. package/src/lapisApi/lapisTypes.ts +35 -1
  11. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutationsByDay.ts +1 -0
  12. package/src/preact/mutationsOverTime/__mockData__/byWeek.ts +1 -0
  13. package/src/preact/mutationsOverTime/__mockData__/defaultMockData.ts +1 -0
  14. package/src/preact/mutationsOverTime/__mockData__/noDataWhenNoMutationsAreInFilter.ts +1 -0
  15. package/src/preact/mutationsOverTime/__mockData__/noDataWhenThereAreNoDatesInFilter.ts +1 -0
  16. package/src/preact/mutationsOverTime/__mockData__/showsMessageWhenTooManyMutations.ts +1 -0
  17. package/src/preact/mutationsOverTime/__mockData__/withDisplayMutations.ts +352 -0
  18. package/src/preact/mutationsOverTime/getFilteredMutationsOverTime.spec.ts +0 -24
  19. package/src/preact/mutationsOverTime/getFilteredMutationsOverTimeData.ts +0 -8
  20. package/src/preact/mutationsOverTime/mutationOverTimeWorker.mock.ts +2 -0
  21. package/src/preact/mutationsOverTime/mutations-over-time.stories.tsx +2 -0
  22. package/src/preact/mutationsOverTime/mutations-over-time.tsx +11 -6
  23. package/src/query/queryMutationsOverTime.spec.ts +98 -0
  24. package/src/query/queryMutationsOverTime.ts +172 -28
  25. package/src/query/queryMutationsOverTimeNewEndpoint.spec.ts +1057 -0
  26. package/src/web-components/visualization/gs-mutations-over-time.spec-d.ts +3 -0
  27. package/src/web-components/visualization/gs-mutations-over-time.stories.ts +3 -0
  28. package/src/web-components/visualization/gs-mutations-over-time.tsx +9 -0
  29. package/standalone-bundle/assets/mutationOverTimeWorker-CDACUs6w.js.map +1 -0
  30. package/standalone-bundle/dashboard-components.js +3628 -3594
  31. package/standalone-bundle/dashboard-components.js.map +1 -1
  32. package/dist/assets/mutationOverTimeWorker-DpW4YOGl.js.map +0 -1
  33. package/standalone-bundle/assets/mutationOverTimeWorker-CZVvQBze.js.map +0 -1
@@ -0,0 +1,352 @@
1
+ import { type MutationOverTimeMockData } from './mockConversion';
2
+
3
+ export const withDisplayMutations: MutationOverTimeMockData = {
4
+ query: {
5
+ lapisFilter: {
6
+ pangoLineage: 'JN.1*',
7
+ dateFrom: '2024-01-15',
8
+ dateTo: '2024-07-10',
9
+ },
10
+ sequenceType: 'nucleotide',
11
+ granularity: 'month',
12
+ lapisDateField: 'date',
13
+ lapis: 'https://lapis.cov-spectrum.org/open/v2',
14
+ displayMutations: ['A19722G', 'G21641T', 'T21653-'],
15
+ useNewEndpoint: false,
16
+ },
17
+ response: {
18
+ overallMutationData: [
19
+ {
20
+ type: 'substitution',
21
+ mutation: {
22
+ valueAtReference: 'A',
23
+ substitutionValue: 'G',
24
+ position: 19722,
25
+ type: 'substitution',
26
+ code: 'A19722G',
27
+ },
28
+ count: 10234,
29
+ proportion: 0.09900453714363107,
30
+ },
31
+ {
32
+ type: 'substitution',
33
+ mutation: {
34
+ valueAtReference: 'G',
35
+ substitutionValue: 'T',
36
+ position: 21641,
37
+ type: 'substitution',
38
+ code: 'G21641T',
39
+ },
40
+ count: 4485,
41
+ proportion: 0.05001951709139575,
42
+ },
43
+ {
44
+ type: 'deletion',
45
+ mutation: {
46
+ valueAtReference: 'T',
47
+ position: 21653,
48
+ type: 'deletion',
49
+ code: 'T21653-',
50
+ },
51
+ count: 17169,
52
+ proportion: 0.16814713976514833,
53
+ },
54
+ ],
55
+ mutationOverTimeSerializedAsArray: {
56
+ data: [
57
+ [
58
+ 'A19722G',
59
+ [
60
+ [
61
+ '2024-01',
62
+ {
63
+ type: 'belowThreshold',
64
+ totalCount: 26387,
65
+ },
66
+ ],
67
+ [
68
+ '2024-02',
69
+ {
70
+ type: 'belowThreshold',
71
+ totalCount: 17340,
72
+ },
73
+ ],
74
+ [
75
+ '2024-03',
76
+ {
77
+ type: 'value',
78
+ count: 36,
79
+ proportion: 0.0043859649122807015,
80
+ totalCount: 8236,
81
+ },
82
+ ],
83
+ [
84
+ '2024-04',
85
+ {
86
+ type: 'value',
87
+ count: 194,
88
+ proportion: 0.030082183284230114,
89
+ totalCount: 6488,
90
+ },
91
+ ],
92
+ [
93
+ '2024-05',
94
+ {
95
+ type: 'value',
96
+ count: 759,
97
+ proportion: 0.08675277174534232,
98
+ totalCount: 8799,
99
+ },
100
+ ],
101
+ [
102
+ '2024-06',
103
+ {
104
+ type: 'value',
105
+ count: 2921,
106
+ proportion: 0.19071559153826065,
107
+ totalCount: 15400,
108
+ },
109
+ ],
110
+ [
111
+ '2024-07',
112
+ {
113
+ type: 'value',
114
+ count: 6318,
115
+ proportion: 0.2995448511283899,
116
+ totalCount: 21234,
117
+ },
118
+ ],
119
+ ],
120
+ ],
121
+ [
122
+ 'G21641T',
123
+ [
124
+ [
125
+ '2024-01',
126
+ {
127
+ type: 'value',
128
+ count: 1625,
129
+ proportion: 0.07085858806087297,
130
+ totalCount: 26387,
131
+ },
132
+ ],
133
+ [
134
+ '2024-02',
135
+ {
136
+ type: 'value',
137
+ count: 419,
138
+ proportion: 0.027931471235250985,
139
+ totalCount: 17340,
140
+ },
141
+ ],
142
+ [
143
+ '2024-03',
144
+ {
145
+ type: 'value',
146
+ count: 228,
147
+ proportion: 0.03451930355791068,
148
+ totalCount: 8236,
149
+ },
150
+ ],
151
+ [
152
+ '2024-04',
153
+ {
154
+ type: 'value',
155
+ count: 545,
156
+ proportion: 0.10551790900290416,
157
+ totalCount: 6488,
158
+ },
159
+ ],
160
+ [
161
+ '2024-05',
162
+ {
163
+ type: 'value',
164
+ count: 666,
165
+ proportion: 0.09498003422703936,
166
+ totalCount: 8799,
167
+ },
168
+ ],
169
+ [
170
+ '2024-06',
171
+ {
172
+ type: 'value',
173
+ count: 732,
174
+ proportion: 0.05598470363288719,
175
+ totalCount: 15400,
176
+ },
177
+ ],
178
+ [
179
+ '2024-07',
180
+ {
181
+ type: 'value',
182
+ count: 270,
183
+ proportion: 0.013585589212035825,
184
+ totalCount: 21234,
185
+ },
186
+ ],
187
+ ],
188
+ ],
189
+ [
190
+ 'T21653-',
191
+ [
192
+ [
193
+ '2024-01',
194
+ {
195
+ type: 'belowThreshold',
196
+ totalCount: 26387,
197
+ },
198
+ ],
199
+ [
200
+ '2024-02',
201
+ {
202
+ type: 'belowThreshold',
203
+ totalCount: 17340,
204
+ },
205
+ ],
206
+ [
207
+ '2024-03',
208
+ {
209
+ type: 'value',
210
+ count: 40,
211
+ proportion: 0.004921259842519685,
212
+ totalCount: 8236,
213
+ },
214
+ ],
215
+ [
216
+ '2024-04',
217
+ {
218
+ type: 'value',
219
+ count: 228,
220
+ proportion: 0.03576470588235294,
221
+ totalCount: 6488,
222
+ },
223
+ ],
224
+ [
225
+ '2024-05',
226
+ {
227
+ type: 'value',
228
+ count: 1304,
229
+ proportion: 0.151504589287789,
230
+ totalCount: 8799,
231
+ },
232
+ ],
233
+ [
234
+ '2024-06',
235
+ {
236
+ type: 'value',
237
+ count: 4744,
238
+ proportion: 0.31656212464967304,
239
+ totalCount: 15400,
240
+ },
241
+ ],
242
+ [
243
+ '2024-07',
244
+ {
245
+ type: 'value',
246
+ count: 10815,
247
+ proportion: 0.5221610660486674,
248
+ totalCount: 21234,
249
+ },
250
+ ],
251
+ ],
252
+ ],
253
+ ],
254
+ keysFirstAxis: [
255
+ [
256
+ 'A19722G',
257
+ {
258
+ type: 'substitution',
259
+ code: 'A19722G',
260
+ position: 19722,
261
+ valueAtReference: 'A',
262
+ substitutionValue: 'G',
263
+ },
264
+ ],
265
+ [
266
+ 'G21641T',
267
+ {
268
+ type: 'substitution',
269
+ code: 'G21641T',
270
+ position: 21641,
271
+ valueAtReference: 'G',
272
+ substitutionValue: 'T',
273
+ },
274
+ ],
275
+ [
276
+ 'T21653-',
277
+ {
278
+ type: 'deletion',
279
+ code: 'T21653-',
280
+ position: 21653,
281
+ valueAtReference: 'T',
282
+ },
283
+ ],
284
+ ],
285
+ keysSecondAxis: [
286
+ [
287
+ '2024-01',
288
+ {
289
+ type: 'YearMonth',
290
+ yearNumber: 2024,
291
+ monthNumber: 1,
292
+ dateString: '2024-01',
293
+ },
294
+ ],
295
+ [
296
+ '2024-02',
297
+ {
298
+ type: 'YearMonth',
299
+ yearNumber: 2024,
300
+ monthNumber: 2,
301
+ dateString: '2024-02',
302
+ },
303
+ ],
304
+ [
305
+ '2024-03',
306
+ {
307
+ type: 'YearMonth',
308
+ yearNumber: 2024,
309
+ monthNumber: 3,
310
+ dateString: '2024-03',
311
+ },
312
+ ],
313
+ [
314
+ '2024-04',
315
+ {
316
+ type: 'YearMonth',
317
+ yearNumber: 2024,
318
+ monthNumber: 4,
319
+ dateString: '2024-04',
320
+ },
321
+ ],
322
+ [
323
+ '2024-05',
324
+ {
325
+ type: 'YearMonth',
326
+ yearNumber: 2024,
327
+ monthNumber: 5,
328
+ dateString: '2024-05',
329
+ },
330
+ ],
331
+ [
332
+ '2024-06',
333
+ {
334
+ type: 'YearMonth',
335
+ yearNumber: 2024,
336
+ monthNumber: 6,
337
+ dateString: '2024-06',
338
+ },
339
+ ],
340
+ [
341
+ '2024-07',
342
+ {
343
+ type: 'YearMonth',
344
+ yearNumber: 2024,
345
+ monthNumber: 7,
346
+ dateString: '2024-07',
347
+ },
348
+ ],
349
+ ],
350
+ },
351
+ },
352
+ };
@@ -211,30 +211,6 @@ describe('getFilteredMutationOverTimeData', () => {
211
211
  expect(result.getFirstAxisKeys()).to.deep.equal([someSubstitution, anotherSubstitution, someDeletion]);
212
212
  });
213
213
 
214
- it('should filter by displayMutations', () => {
215
- const { data, overallMutationData } = prepareMutationOverTimeData([
216
- someSubstitutionEntry,
217
- anotherSubstitutionEntry,
218
- someDeletionEntry,
219
- ]);
220
-
221
- const result = getFilteredMutationOverTimeData({
222
- data,
223
- overallMutationData,
224
- displayedSegments: [],
225
- displayedMutationTypes: [],
226
- proportionInterval,
227
- displayMutations: [anotherSubstitution.code, someDeletion.code],
228
- mutationFilterValue: { textFilter: '', annotationNameFilter: new Set() },
229
- sequenceType: 'nucleotide',
230
- annotationProvider: () => {
231
- return [];
232
- },
233
- });
234
-
235
- expect(result.getFirstAxisKeys()).to.deep.equal([anotherSubstitution, someDeletion]);
236
- });
237
-
238
214
  it('should filter by mutation filter text value', () => {
239
215
  const { data, overallMutationData } = prepareMutationOverTimeData([
240
216
  someSubstitutionEntry,
@@ -34,16 +34,12 @@ export function getFilteredMutationOverTimeData({
34
34
  displayedSegments,
35
35
  displayedMutationTypes,
36
36
  proportionInterval,
37
- displayMutations,
38
37
  mutationFilterValue,
39
38
  sequenceType,
40
39
  annotationProvider,
41
40
  }: GetFilteredMutationOverTimeDataArgs) {
42
41
  const filteredData = new Map2dView(data);
43
42
 
44
- const displayMutationsSet =
45
- displayMutations === undefined ? null : new Set(displayMutations.map((it) => it.toUpperCase()));
46
-
47
43
  const mutationsToFilterOut = overallMutationData.filter((entry) => {
48
44
  if (entry.proportion < proportionInterval.min || entry.proportion > proportionInterval.max) {
49
45
  return true;
@@ -52,10 +48,6 @@ export function getFilteredMutationOverTimeData({
52
48
  return true;
53
49
  }
54
50
 
55
- if (displayMutationsSet !== null && !displayMutationsSet.has(entry.mutation.code.toUpperCase())) {
56
- return true;
57
- }
58
-
59
51
  if (
60
52
  mutationOrAnnotationDoNotMatchFilter(entry.mutation, sequenceType, mutationFilterValue, annotationProvider)
61
53
  ) {
@@ -7,11 +7,13 @@ import { defaultMockData } from './__mockData__/defaultMockData';
7
7
  import { getMutationOverTimeMock } from './__mockData__/mockConversion';
8
8
  import { noDataWhenNoMutationsAreInFilter } from './__mockData__/noDataWhenNoMutationsAreInFilter';
9
9
  import { showsMessageWhenTooManyMutations } from './__mockData__/showsMessageWhenTooManyMutations';
10
+ import { withDisplayMutations } from './__mockData__/withDisplayMutations';
10
11
 
11
12
  const mockQueries: { query: MutationOverTimeQuery; response: MutationOverTimeWorkerResponse }[] = [
12
13
  getMutationOverTimeMock(defaultMockData),
13
14
  getMutationOverTimeMock(showsMessageWhenTooManyMutations),
14
15
  getMutationOverTimeMock(byWeek),
16
+ getMutationOverTimeMock(withDisplayMutations),
15
17
  getMutationOverTimeMock(aminoAcidMutationsByDay),
16
18
  getMutationOverTimeMock(noDataWhenNoMutationsAreInFilter),
17
19
  ];
@@ -36,6 +36,7 @@ const meta: Meta<MutationsOverTimeProps> = {
36
36
  displayMutations: { control: 'object' },
37
37
  initialMeanProportionInterval: { control: 'object' },
38
38
  pageSizes: { control: 'object' },
39
+ useNewEndpoint: { control: 'boolean' },
39
40
  },
40
41
  parameters: {
41
42
  fetchMock: {},
@@ -80,6 +81,7 @@ export const Default: StoryObj<MutationsOverTimeProps> = {
80
81
  granularity: 'month',
81
82
  lapisDateField: 'date',
82
83
  initialMeanProportionInterval: { min: 0.05, max: 0.9 },
84
+ useNewEndpoint: false,
83
85
  pageSizes: [10, 20, 30, 40, 50],
84
86
  },
85
87
  };
@@ -12,6 +12,7 @@ import {
12
12
  } from './getFilteredMutationsOverTimeData';
13
13
  import { type MutationOverTimeWorkerResponse } from './mutationOverTimeWorker';
14
14
  import MutationsOverTimeGrid from './mutations-over-time-grid';
15
+ import { type MutationOverTimeQuery } from '../../query/queryMutationsOverTime';
15
16
  import {
16
17
  lapisFilterSchema,
17
18
  sequenceTypeSchema,
@@ -52,6 +53,7 @@ const mutationOverTimeSchema = z.object({
52
53
  views: z.array(mutationsOverTimeViewSchema),
53
54
  granularity: temporalGranularitySchema,
54
55
  lapisDateField: z.string().min(1),
56
+ useNewEndpoint: z.boolean().optional(),
55
57
  displayMutations: displayMutationsSchema.optional(),
56
58
  initialMeanProportionInterval: z.object({
57
59
  min: z.number().min(0).max(1),
@@ -76,19 +78,24 @@ export const MutationsOverTime: FunctionComponent<MutationsOverTimeProps> = (com
76
78
  );
77
79
  };
78
80
 
79
- export const MutationsOverTimeInner: FunctionComponent<MutationsOverTimeProps> = (componentProps) => {
81
+ export const MutationsOverTimeInner: FunctionComponent<MutationsOverTimeProps> = ({
82
+ useNewEndpoint = false,
83
+ ...componentProps
84
+ }) => {
80
85
  const lapis = useLapisUrl();
81
- const { lapisFilter, sequenceType, granularity, lapisDateField } = componentProps;
86
+ const { lapisFilter, sequenceType, granularity, lapisDateField, displayMutations } = componentProps;
82
87
 
83
- const messageToWorker = useMemo(() => {
88
+ const messageToWorker: MutationOverTimeQuery = useMemo(() => {
84
89
  return {
85
90
  lapisFilter,
86
91
  sequenceType,
87
92
  granularity,
88
93
  lapisDateField,
89
94
  lapis,
95
+ displayMutations,
96
+ useNewEndpoint,
90
97
  };
91
- }, [granularity, lapis, lapisDateField, lapisFilter, sequenceType]);
98
+ }, [granularity, lapis, lapisDateField, lapisFilter, sequenceType, displayMutations, useNewEndpoint]);
92
99
 
93
100
  const { data, error, isLoading } = useWebWorker<MutationOverTimeWorkerResponse>(
94
101
  messageToWorker,
@@ -154,7 +161,6 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
154
161
  displayedSegments,
155
162
  displayedMutationTypes,
156
163
  proportionInterval,
157
- displayMutations: originalComponentProps.displayMutations,
158
164
  mutationFilterValue,
159
165
  sequenceType: originalComponentProps.sequenceType,
160
166
  annotationProvider,
@@ -165,7 +171,6 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
165
171
  displayedSegments,
166
172
  displayedMutationTypes,
167
173
  proportionInterval,
168
- originalComponentProps.displayMutations,
169
174
  originalComponentProps.sequenceType,
170
175
  mutationFilterValue,
171
176
  annotationProvider,
@@ -876,6 +876,104 @@ describe('queryMutationsOverTime', () => {
876
876
  expect(mutationOverTimeData.getAsArray()).to.deep.equal([[null]]);
877
877
  });
878
878
 
879
+ it('should respect the includeMutations parameter', async () => {
880
+ const lapisFilter = { field1: 'value1', field2: 'value2' };
881
+ const dateField = 'dateField';
882
+
883
+ lapisRequestMocks.multipleAggregated([
884
+ {
885
+ body: { ...lapisFilter, fields: [dateField] },
886
+ response: {
887
+ data: [
888
+ { count: 1, [dateField]: '2023-01-05' },
889
+ { count: 2, [dateField]: '2023-02-15' },
890
+ ],
891
+ },
892
+ },
893
+ {
894
+ body: {
895
+ ...lapisFilter,
896
+ dateFieldFrom: '2023-01-01',
897
+ dateFieldTo: '2023-01-31',
898
+ fields: [],
899
+ },
900
+ response: { data: [{ count: 11 }] },
901
+ },
902
+ {
903
+ body: {
904
+ ...lapisFilter,
905
+ dateFieldFrom: '2023-02-01',
906
+ dateFieldTo: '2023-02-28',
907
+ fields: [],
908
+ },
909
+ response: { data: [{ count: 12 }] },
910
+ },
911
+ ]);
912
+
913
+ lapisRequestMocks.multipleMutations(
914
+ [
915
+ {
916
+ body: {
917
+ ...lapisFilter,
918
+ dateFieldFrom: '2023-01-01',
919
+ dateFieldTo: '2023-01-31',
920
+ minProportion: 0.001,
921
+ },
922
+ response: { data: [getSomeTestMutation(0.1, 1), getSomeOtherTestMutation(0.4, 4)] },
923
+ },
924
+ {
925
+ body: {
926
+ ...lapisFilter,
927
+ dateFieldFrom: '2023-02-01',
928
+ dateFieldTo: '2023-02-28',
929
+ minProportion: 0.001,
930
+ },
931
+ response: { data: [getSomeTestMutation(0.2, 2)] },
932
+ },
933
+ {
934
+ body: {
935
+ ...lapisFilter,
936
+ dateFieldFrom: '2023-01-01',
937
+ dateFieldTo: '2023-02-28',
938
+ minProportion: 0.001,
939
+ },
940
+ response: {
941
+ data: [getSomeTestMutation(0.21, 6), getSomeOtherTestMutation(0.22, 4)],
942
+ },
943
+ },
944
+ ],
945
+ 'nucleotide',
946
+ );
947
+
948
+ const { mutationOverTimeData } = await queryMutationsOverTimeData({
949
+ lapisFilter,
950
+ sequenceType: 'nucleotide',
951
+ lapis: DUMMY_LAPIS_URL,
952
+ lapisDateField: dateField,
953
+ granularity: 'month',
954
+ displayMutations: ['otherSequenceName:G234C', 'A44T'],
955
+ });
956
+
957
+ expect(mutationOverTimeData.getAsArray()).to.deep.equal([
958
+ [
959
+ { type: 'belowThreshold', totalCount: 11 },
960
+ { type: 'belowThreshold', totalCount: 12 },
961
+ ],
962
+ [
963
+ { type: 'value', proportion: 0.4, count: 4, totalCount: 11 },
964
+ { type: 'belowThreshold', totalCount: 12 },
965
+ ],
966
+ ]);
967
+
968
+ const sequences = mutationOverTimeData.getFirstAxisKeys();
969
+ expect(sequences[0].code).toBe('A44T');
970
+ expect(sequences[1].code).toBe('otherSequenceName:G234C');
971
+
972
+ const dates = mutationOverTimeData.getSecondAxisKeys();
973
+ expect(dates[0].dateString).toBe('2023-01');
974
+ expect(dates[1].dateString).toBe('2023-02');
975
+ });
976
+
879
977
  function getSomeTestMutation(proportion: number, count: number) {
880
978
  return {
881
979
  mutation: 'sequenceName:A123T',