@genspectrum/dashboard-components 1.12.0 → 1.13.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.
- package/README.md +0 -7
- package/custom-elements.json +6 -25
- package/dist/components.d.ts +30 -36
- package/dist/components.js +943 -757
- package/dist/components.js.map +1 -1
- package/dist/util.d.ts +46 -30
- package/package.json +1 -5
- package/src/lapisApi/lapisApi.ts +21 -1
- package/src/lapisApi/lapisTypes.ts +36 -0
- package/src/preact/components/annotated-mutation.tsx +2 -2
- package/src/preact/{mutationsOverTime/mutations-over-time-grid.tsx → components/features-over-time-grid.tsx} +45 -52
- package/src/preact/genomeViewer/genome-data-viewer.tsx +2 -2
- package/src/preact/mutationsOverTime/MutationOverTimeData.ts +6 -4
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutationsByDay/aminoAcidMutations.json +5482 -0
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutationsByDay/aminoAcidMutationsOverTime.json +5496 -0
- package/src/preact/mutationsOverTime/__mockData__/byWeek/mutationsOverTime.json +7100 -0
- package/src/preact/mutationsOverTime/__mockData__/byWeek/nucleotideMutations.json +10122 -0
- package/src/preact/mutationsOverTime/__mockData__/defaultMockData/mutationsOverTime.json +12646 -0
- package/src/preact/mutationsOverTime/__mockData__/defaultMockData/nucleotideMutations.json +12632 -0
- package/src/preact/mutationsOverTime/__mockData__/request1800s/mutationsOverTime.json +16 -0
- package/src/preact/mutationsOverTime/__mockData__/request1800s/nucleotideMutations.json +11 -0
- package/src/preact/mutationsOverTime/__mockData__/withDisplayMutations/mutationsOverTime.json +52 -0
- package/src/preact/mutationsOverTime/getFilteredMutationsOverTime.spec.ts +3 -3
- package/src/preact/mutationsOverTime/mutations-over-time-grid-tooltip.tsx +3 -6
- package/src/preact/mutationsOverTime/mutations-over-time.stories.tsx +199 -12
- package/src/preact/mutationsOverTime/mutations-over-time.tsx +30 -35
- package/src/preact/wastewater/mutationsOverTime/wastewater-mutations-over-time.tsx +30 -3
- package/src/query/queryDatesInDataset.ts +89 -0
- package/src/query/queryMutationsOverTime.spec.ts +526 -548
- package/src/query/queryMutationsOverTime.ts +21 -232
- package/src/query/queryQueriesOverTime.spec.ts +432 -0
- package/src/query/queryQueriesOverTime.ts +125 -0
- package/src/utilEntrypoint.ts +3 -1
- package/src/utils/mutations.spec.ts +6 -0
- package/src/utils/mutations.ts +1 -1
- package/src/utils/temporalClass.ts +4 -0
- package/src/web-components/visualization/gs-mutations-over-time.spec-d.ts +0 -3
- package/src/web-components/visualization/gs-mutations-over-time.stories.ts +283 -17
- package/src/web-components/visualization/gs-mutations-over-time.tsx +0 -9
- package/standalone-bundle/dashboard-components.js +8935 -8781
- package/standalone-bundle/dashboard-components.js.map +1 -1
- package/dist/assets/mutationOverTimeWorker-f8Kp0S6V.js.map +0 -1
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutationsByDay.ts +0 -47170
- package/src/preact/mutationsOverTime/__mockData__/byWeek.ts +0 -54026
- package/src/preact/mutationsOverTime/__mockData__/defaultMockData.ts +0 -108385
- package/src/preact/mutationsOverTime/__mockData__/mockConversion.ts +0 -54
- package/src/preact/mutationsOverTime/__mockData__/noDataWhenNoMutationsAreInFilter.ts +0 -23
- package/src/preact/mutationsOverTime/__mockData__/noDataWhenThereAreNoDatesInFilter.ts +0 -23
- package/src/preact/mutationsOverTime/__mockData__/showsMessageWhenTooManyMutations.ts +0 -65527
- package/src/preact/mutationsOverTime/__mockData__/withDisplayMutations.ts +0 -352
- package/src/preact/mutationsOverTime/__mockData__/withGaps.ts +0 -298
- package/src/preact/mutationsOverTime/mutationOverTimeWorker.mock.ts +0 -33
- package/src/preact/mutationsOverTime/mutationOverTimeWorker.ts +0 -29
- package/src/preact/webWorkers/useWebWorker.ts +0 -74
- package/src/preact/webWorkers/workerFunction.ts +0 -30
- package/src/query/queryMutationsOverTimeNewEndpoint.spec.ts +0 -988
- package/standalone-bundle/assets/mutationOverTimeWorker-AhhjjklP.js.map +0 -1
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"data": {
|
|
3
|
+
"mutations": [],
|
|
4
|
+
"dateRanges": [{ "dateFrom": "1800-01-01", "dateTo": "1800-12-31" }],
|
|
5
|
+
"data": [],
|
|
6
|
+
"totalCountsByDateRange": []
|
|
7
|
+
},
|
|
8
|
+
"info": {
|
|
9
|
+
"dataVersion": null,
|
|
10
|
+
"requestId": "dff5f887-1b84-4789-93be-3bca6c8adb1c",
|
|
11
|
+
"requestInfo": "sars_cov-2_nextstrain_open on lapis.cov-spectrum.org at 2025-12-17T16:48:49.532134692",
|
|
12
|
+
"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.",
|
|
13
|
+
"lapisVersion": "12a364c66262f2f56289873faddf0552b550742e",
|
|
14
|
+
"siloVersion": "0.8.0"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"data": [],
|
|
3
|
+
"info": {
|
|
4
|
+
"dataVersion": "1765731908",
|
|
5
|
+
"requestId": "3bb9782f-49fa-459c-98e6-ef13e122238d",
|
|
6
|
+
"requestInfo": "sars_cov-2_nextstrain_open on lapis.cov-spectrum.org at 2025-12-17T16:48:49.434876617",
|
|
7
|
+
"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.",
|
|
8
|
+
"lapisVersion": "12a364c66262f2f56289873faddf0552b550742e",
|
|
9
|
+
"siloVersion": "0.8.0"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"data": {
|
|
3
|
+
"mutations": ["A13121T", "T21653-", "G24872T"],
|
|
4
|
+
"dateRanges": [
|
|
5
|
+
{ "dateFrom": "2024-01-01", "dateTo": "2024-01-31" },
|
|
6
|
+
{ "dateFrom": "2024-02-01", "dateTo": "2024-02-29" },
|
|
7
|
+
{ "dateFrom": "2024-03-01", "dateTo": "2024-03-31" },
|
|
8
|
+
{ "dateFrom": "2024-04-01", "dateTo": "2024-04-30" },
|
|
9
|
+
{ "dateFrom": "2024-05-01", "dateTo": "2024-05-31" },
|
|
10
|
+
{ "dateFrom": "2024-06-01", "dateTo": "2024-06-30" },
|
|
11
|
+
{ "dateFrom": "2024-07-01", "dateTo": "2024-07-31" }
|
|
12
|
+
],
|
|
13
|
+
"data": [
|
|
14
|
+
[
|
|
15
|
+
{ "count": 1, "coverage": 14030 },
|
|
16
|
+
{ "count": 1, "coverage": 17545 },
|
|
17
|
+
{ "count": 1, "coverage": 8418 },
|
|
18
|
+
{ "count": 0, "coverage": 0 },
|
|
19
|
+
{ "count": 43, "coverage": 9236 },
|
|
20
|
+
{ "count": 922, "coverage": 16466 },
|
|
21
|
+
{ "count": 1119, "coverage": 7468 }
|
|
22
|
+
],
|
|
23
|
+
[
|
|
24
|
+
{ "count": 13, "coverage": 13946 },
|
|
25
|
+
{ "count": 15, "coverage": 17353 },
|
|
26
|
+
{ "count": 41, "coverage": 8318 },
|
|
27
|
+
{ "count": 0, "coverage": 0 },
|
|
28
|
+
{ "count": 1369, "coverage": 9052 },
|
|
29
|
+
{ "count": 5080, "coverage": 16078 },
|
|
30
|
+
{ "count": 3245, "coverage": 7342 }
|
|
31
|
+
],
|
|
32
|
+
[
|
|
33
|
+
{ "count": 42, "coverage": 13765 },
|
|
34
|
+
{ "count": 203, "coverage": 17274 },
|
|
35
|
+
{ "count": 563, "coverage": 8256 },
|
|
36
|
+
{ "count": 0, "coverage": 0 },
|
|
37
|
+
{ "count": 4631, "coverage": 9024 },
|
|
38
|
+
{ "count": 11162, "coverage": 16188 },
|
|
39
|
+
{ "count": 5451, "coverage": 7393 }
|
|
40
|
+
]
|
|
41
|
+
],
|
|
42
|
+
"totalCountsByDateRange": [14063, 17577, 8431, 0, 9250, 16513, 7508]
|
|
43
|
+
},
|
|
44
|
+
"info": {
|
|
45
|
+
"dataVersion": "1765731908",
|
|
46
|
+
"requestId": "220cae2b-f73c-42fd-a3ac-1c49e0f239ec",
|
|
47
|
+
"requestInfo": "sars_cov-2_nextstrain_open on lapis.cov-spectrum.org at 2025-12-17T16:59:33.639804323",
|
|
48
|
+
"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.",
|
|
49
|
+
"lapisVersion": "12a364c66262f2f56289873faddf0552b550742e",
|
|
50
|
+
"siloVersion": "0.8.0"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest';
|
|
|
2
2
|
|
|
3
3
|
import { BaseMutationOverTimeDataMap } from './MutationOverTimeData';
|
|
4
4
|
import { getFilteredMutationOverTimeData, type MutationFilter } from './getFilteredMutationsOverTimeData';
|
|
5
|
-
import { type
|
|
5
|
+
import { type ProportionValue } from '../../query/queryMutationsOverTime';
|
|
6
6
|
import { type DeletionEntry, type SubstitutionEntry } from '../../types';
|
|
7
7
|
import { type Deletion, type Substitution } from '../../utils/mutations';
|
|
8
8
|
import { type TemporalClass } from '../../utils/temporalClass';
|
|
@@ -392,13 +392,13 @@ describe('getFilteredMutationOverTimeData', () => {
|
|
|
392
392
|
count: 1,
|
|
393
393
|
proportion: inFilter,
|
|
394
394
|
totalCount: 10,
|
|
395
|
-
} satisfies
|
|
395
|
+
} satisfies ProportionValue;
|
|
396
396
|
const emptyMutationOverTimeValue = {
|
|
397
397
|
type: 'value',
|
|
398
398
|
count: 0,
|
|
399
399
|
proportion: NaN,
|
|
400
400
|
totalCount: 0,
|
|
401
|
-
} satisfies
|
|
401
|
+
} satisfies ProportionValue;
|
|
402
402
|
|
|
403
403
|
function prepareMutationOverTimeData(
|
|
404
404
|
mutationEntries: (SubstitutionEntry<Substitution> | DeletionEntry<Deletion>)[],
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import type { FunctionComponent } from 'preact';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
type MutationOverTimeMutationValue,
|
|
5
|
-
MUTATIONS_OVER_TIME_MIN_PROPORTION,
|
|
6
|
-
} from '../../query/queryMutationsOverTime';
|
|
3
|
+
import { type ProportionValue, MUTATIONS_OVER_TIME_MIN_PROPORTION } from '../../query/queryMutationsOverTime';
|
|
7
4
|
import type { Deletion, Substitution } from '../../utils/mutations';
|
|
8
5
|
import { type Temporal, type TemporalClass, toTemporalClass, YearMonthDayClass } from '../../utils/temporalClass';
|
|
9
6
|
import { formatProportion } from '../shared/table/formatProportion';
|
|
@@ -11,7 +8,7 @@ import { formatProportion } from '../shared/table/formatProportion';
|
|
|
11
8
|
export type MutationsOverTimeGridTooltipProps = {
|
|
12
9
|
mutation: Substitution | Deletion;
|
|
13
10
|
date: Temporal;
|
|
14
|
-
value:
|
|
11
|
+
value: ProportionValue;
|
|
15
12
|
};
|
|
16
13
|
|
|
17
14
|
export const MutationsOverTimeGridTooltip: FunctionComponent<MutationsOverTimeGridTooltipProps> = ({
|
|
@@ -66,7 +63,7 @@ export const MutationsOverTimeGridTooltip: FunctionComponent<MutationsOverTimeGr
|
|
|
66
63
|
};
|
|
67
64
|
|
|
68
65
|
const TooltipValueCountsDescription: FunctionComponent<{
|
|
69
|
-
value: NonNullable<
|
|
66
|
+
value: NonNullable<ProportionValue>;
|
|
70
67
|
mutationCode: string;
|
|
71
68
|
mutationPosition: number;
|
|
72
69
|
}> = ({ value, mutationCode, mutationPosition }) => {
|
|
@@ -4,11 +4,16 @@ import { type Canvas } from '@storybook/types';
|
|
|
4
4
|
|
|
5
5
|
import { MutationsOverTime, type MutationsOverTimeProps } from './mutations-over-time';
|
|
6
6
|
import { LAPIS_URL } from '../../constants';
|
|
7
|
-
import referenceGenome from '../../lapisApi/__mockData__/referenceGenome.json';
|
|
8
7
|
import { type MutationAnnotations } from '../../web-components/mutation-annotations-context';
|
|
9
8
|
import { LapisUrlContextProvider } from '../LapisUrlContext';
|
|
10
9
|
import { MutationAnnotationsContextProvider } from '../MutationAnnotationsContext';
|
|
11
10
|
import { ReferenceGenomeContext } from '../ReferenceGenomeContext';
|
|
11
|
+
import mockDefaultMutationsOverTime from './__mockData__/defaultMockData/mutationsOverTime.json';
|
|
12
|
+
import mockDefaultNucleotideMutations from './__mockData__/defaultMockData/nucleotideMutations.json';
|
|
13
|
+
import mock1800sMutationsOverTime from './__mockData__/request1800s/mutationsOverTime.json';
|
|
14
|
+
import mock1800sNucleotideMutations from './__mockData__/request1800s/nucleotideMutations.json';
|
|
15
|
+
import mockWithDisplayMutationsMutationsOverTime from './__mockData__/withDisplayMutations/mutationsOverTime.json';
|
|
16
|
+
import referenceGenome from '../../lapisApi/__mockData__/referenceGenome.json';
|
|
12
17
|
import { expectInvalidAttributesErrorMessage } from '../shared/stories/expectErrorMessage';
|
|
13
18
|
import { playThatExpectsFinishedLoadingEvent } from '../shared/stories/expectFinishedLoadingEvent';
|
|
14
19
|
import { expectMutationAnnotation } from '../shared/stories/expectMutationAnnotation';
|
|
@@ -37,11 +42,55 @@ const meta: Meta<MutationsOverTimeProps> = {
|
|
|
37
42
|
initialMeanProportionInterval: { control: 'object' },
|
|
38
43
|
hideGaps: { control: 'boolean' },
|
|
39
44
|
pageSizes: { control: 'object' },
|
|
40
|
-
useNewEndpoint: { control: 'boolean' },
|
|
41
45
|
customColumns: { control: 'object' },
|
|
42
46
|
},
|
|
43
47
|
parameters: {
|
|
44
|
-
fetchMock: {
|
|
48
|
+
fetchMock: {
|
|
49
|
+
mocks: [
|
|
50
|
+
{
|
|
51
|
+
matcher: {
|
|
52
|
+
url: `${LAPIS_URL}/sample/nucleotideMutations`,
|
|
53
|
+
body: {
|
|
54
|
+
pangoLineage: 'JN.1*',
|
|
55
|
+
dateFrom: '2024-01-01',
|
|
56
|
+
dateTo: '2024-07-31',
|
|
57
|
+
minProportion: 0.001,
|
|
58
|
+
},
|
|
59
|
+
response: {
|
|
60
|
+
status: 200,
|
|
61
|
+
body: mockDefaultNucleotideMutations,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
matcher: {
|
|
67
|
+
url: `${LAPIS_URL}/component/nucleotideMutationsOverTime`,
|
|
68
|
+
body: {
|
|
69
|
+
filters: {
|
|
70
|
+
pangoLineage: 'JN.1*',
|
|
71
|
+
dateFrom: '2024-01-15',
|
|
72
|
+
dateTo: '2024-07-10',
|
|
73
|
+
},
|
|
74
|
+
dateRanges: [
|
|
75
|
+
{ dateFrom: '2024-01-01', dateTo: '2024-01-31' },
|
|
76
|
+
{ dateFrom: '2024-02-01', dateTo: '2024-02-29' },
|
|
77
|
+
{ dateFrom: '2024-03-01', dateTo: '2024-03-31' },
|
|
78
|
+
{ dateFrom: '2024-04-01', dateTo: '2024-04-30' },
|
|
79
|
+
{ dateFrom: '2024-05-01', dateTo: '2024-05-31' },
|
|
80
|
+
{ dateFrom: '2024-06-01', dateTo: '2024-06-30' },
|
|
81
|
+
{ dateFrom: '2024-07-01', dateTo: '2024-07-31' },
|
|
82
|
+
],
|
|
83
|
+
dateField: 'date',
|
|
84
|
+
},
|
|
85
|
+
matchPartialBody: true, // includeMutations left out
|
|
86
|
+
response: {
|
|
87
|
+
status: 200,
|
|
88
|
+
body: mockDefaultMutationsOverTime,
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
},
|
|
45
94
|
},
|
|
46
95
|
};
|
|
47
96
|
|
|
@@ -84,7 +133,6 @@ export const Default: StoryObj<MutationsOverTimeProps> = {
|
|
|
84
133
|
lapisDateField: 'date',
|
|
85
134
|
initialMeanProportionInterval: { min: 0.05, max: 0.9 },
|
|
86
135
|
hideGaps: false,
|
|
87
|
-
useNewEndpoint: false,
|
|
88
136
|
pageSizes: [10, 20, 30, 40, 50],
|
|
89
137
|
},
|
|
90
138
|
};
|
|
@@ -109,6 +157,38 @@ export const ShowsNoDataWhenNoMutationsAreInFilter: StoryObj<MutationsOverTimePr
|
|
|
109
157
|
height: '700px',
|
|
110
158
|
granularity: 'year',
|
|
111
159
|
},
|
|
160
|
+
parameters: {
|
|
161
|
+
fetchMock: {
|
|
162
|
+
mocks: [
|
|
163
|
+
{
|
|
164
|
+
matcher: {
|
|
165
|
+
url: `${LAPIS_URL}/sample/nucleotideMutations`,
|
|
166
|
+
body: { dateFrom: '1800-01-01', dateTo: '1800-12-31', minProportion: 0.001 },
|
|
167
|
+
response: {
|
|
168
|
+
status: 200,
|
|
169
|
+
body: mock1800sNucleotideMutations,
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
matcher: {
|
|
175
|
+
name: 'mockDefaultMutationsOverTime',
|
|
176
|
+
url: `${LAPIS_URL}/component/nucleotideMutationsOverTime`,
|
|
177
|
+
body: {
|
|
178
|
+
filters: { dateFrom: '1800-01-01', dateTo: '1800-01-02' },
|
|
179
|
+
dateRanges: [{ dateFrom: '1800-01-01', dateTo: '1800-12-31' }],
|
|
180
|
+
includeMutations: [],
|
|
181
|
+
dateField: 'date',
|
|
182
|
+
},
|
|
183
|
+
response: {
|
|
184
|
+
status: 200,
|
|
185
|
+
body: mock1800sMutationsOverTime,
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
],
|
|
190
|
+
},
|
|
191
|
+
},
|
|
112
192
|
play: async ({ canvas }) => {
|
|
113
193
|
await waitFor(() => expect(canvas.getByText('No data available.', { exact: false })).toBeVisible(), {
|
|
114
194
|
timeout: 10000,
|
|
@@ -120,7 +200,51 @@ export const UsesHideGaps: StoryObj<MutationsOverTimeProps> = {
|
|
|
120
200
|
...Default,
|
|
121
201
|
args: {
|
|
122
202
|
...Default.args,
|
|
123
|
-
displayMutations: ['
|
|
203
|
+
displayMutations: ['A13121T', 'G24872T', 'T21653-'],
|
|
204
|
+
},
|
|
205
|
+
parameters: {
|
|
206
|
+
fetchMock: {
|
|
207
|
+
mocks: [
|
|
208
|
+
{
|
|
209
|
+
matcher: {
|
|
210
|
+
url: `${LAPIS_URL}/sample/nucleotideMutations`,
|
|
211
|
+
body: {
|
|
212
|
+
pangoLineage: 'JN.1*',
|
|
213
|
+
dateFrom: '2024-01-01',
|
|
214
|
+
dateTo: '2024-07-31',
|
|
215
|
+
minProportion: 0.001,
|
|
216
|
+
},
|
|
217
|
+
response: {
|
|
218
|
+
status: 200,
|
|
219
|
+
body: mockDefaultNucleotideMutations,
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
matcher: {
|
|
225
|
+
url: `${LAPIS_URL}/component/nucleotideMutationsOverTime`,
|
|
226
|
+
body: {
|
|
227
|
+
filters: { pangoLineage: 'JN.1*', dateFrom: '2024-01-15', dateTo: '2024-07-10' },
|
|
228
|
+
dateRanges: [
|
|
229
|
+
{ dateFrom: '2024-01-01', dateTo: '2024-01-31' },
|
|
230
|
+
{ dateFrom: '2024-02-01', dateTo: '2024-02-29' },
|
|
231
|
+
{ dateFrom: '2024-03-01', dateTo: '2024-03-31' },
|
|
232
|
+
{ dateFrom: '2024-04-01', dateTo: '2024-04-30' },
|
|
233
|
+
{ dateFrom: '2024-05-01', dateTo: '2024-05-31' },
|
|
234
|
+
{ dateFrom: '2024-06-01', dateTo: '2024-06-30' },
|
|
235
|
+
{ dateFrom: '2024-07-01', dateTo: '2024-07-31' },
|
|
236
|
+
],
|
|
237
|
+
includeMutations: ['A13121T', 'T21653-', 'G24872T'],
|
|
238
|
+
dateField: 'date',
|
|
239
|
+
},
|
|
240
|
+
response: {
|
|
241
|
+
status: 200,
|
|
242
|
+
body: mockWithDisplayMutationsMutationsOverTime,
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
],
|
|
247
|
+
},
|
|
124
248
|
},
|
|
125
249
|
play: async ({ canvas, step }) => {
|
|
126
250
|
await expectDateRangeOnPage(canvas, '2024-04');
|
|
@@ -201,17 +325,61 @@ export const WithCustomColumns: StoryObj<MutationsOverTimeProps> = {
|
|
|
201
325
|
...Default,
|
|
202
326
|
args: {
|
|
203
327
|
...Default.args,
|
|
204
|
-
displayMutations: ['
|
|
328
|
+
displayMutations: ['A13121T', 'G24872T', 'T21653-'],
|
|
205
329
|
customColumns: [
|
|
206
330
|
{
|
|
207
331
|
header: 'Jaccard Index',
|
|
208
332
|
values: {
|
|
209
|
-
|
|
210
|
-
|
|
333
|
+
A13121T: 0.75,
|
|
334
|
+
G24872T: 'Foobar',
|
|
211
335
|
},
|
|
212
336
|
},
|
|
213
337
|
],
|
|
214
338
|
},
|
|
339
|
+
parameters: {
|
|
340
|
+
fetchMock: {
|
|
341
|
+
mocks: [
|
|
342
|
+
{
|
|
343
|
+
matcher: {
|
|
344
|
+
url: `${LAPIS_URL}/sample/nucleotideMutations`,
|
|
345
|
+
body: {
|
|
346
|
+
pangoLineage: 'JN.1*',
|
|
347
|
+
dateFrom: '2024-01-01',
|
|
348
|
+
dateTo: '2024-07-31',
|
|
349
|
+
minProportion: 0.001,
|
|
350
|
+
},
|
|
351
|
+
response: {
|
|
352
|
+
status: 200,
|
|
353
|
+
body: mockDefaultNucleotideMutations,
|
|
354
|
+
},
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
matcher: {
|
|
359
|
+
url: `${LAPIS_URL}/component/nucleotideMutationsOverTime`,
|
|
360
|
+
body: {
|
|
361
|
+
filters: { pangoLineage: 'JN.1*', dateFrom: '2024-01-15', dateTo: '2024-07-10' },
|
|
362
|
+
dateRanges: [
|
|
363
|
+
{ dateFrom: '2024-01-01', dateTo: '2024-01-31' },
|
|
364
|
+
{ dateFrom: '2024-02-01', dateTo: '2024-02-29' },
|
|
365
|
+
{ dateFrom: '2024-03-01', dateTo: '2024-03-31' },
|
|
366
|
+
{ dateFrom: '2024-04-01', dateTo: '2024-04-30' },
|
|
367
|
+
{ dateFrom: '2024-05-01', dateTo: '2024-05-31' },
|
|
368
|
+
{ dateFrom: '2024-06-01', dateTo: '2024-06-30' },
|
|
369
|
+
{ dateFrom: '2024-07-01', dateTo: '2024-07-31' },
|
|
370
|
+
],
|
|
371
|
+
includeMutations: ['A13121T', 'T21653-', 'G24872T'],
|
|
372
|
+
dateField: 'date',
|
|
373
|
+
},
|
|
374
|
+
response: {
|
|
375
|
+
status: 200,
|
|
376
|
+
body: mockWithDisplayMutationsMutationsOverTime,
|
|
377
|
+
},
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
],
|
|
381
|
+
},
|
|
382
|
+
},
|
|
215
383
|
play: async ({ canvas }) => {
|
|
216
384
|
await waitFor(() => expect(canvas.getByText('Jaccard Index')).toBeVisible(), {
|
|
217
385
|
timeout: 5000,
|
|
@@ -245,6 +413,29 @@ export const ShowsNoDataMessageWhenThereAreNoDatesInFilter: StoryObj<MutationsOv
|
|
|
245
413
|
height: '700px',
|
|
246
414
|
granularity: 'year',
|
|
247
415
|
},
|
|
416
|
+
parameters: {
|
|
417
|
+
fetchMock: {
|
|
418
|
+
mocks: [
|
|
419
|
+
{
|
|
420
|
+
matcher: {
|
|
421
|
+
url: `${LAPIS_URL}/sample/nucleotideMutations`,
|
|
422
|
+
body: {
|
|
423
|
+
filters: { dateFrom: '2345-01-01', dateTo: '2020-01-02' },
|
|
424
|
+
dateRanges: [],
|
|
425
|
+
includeMutations: [],
|
|
426
|
+
dateField: 'date',
|
|
427
|
+
},
|
|
428
|
+
response: {
|
|
429
|
+
status: 200,
|
|
430
|
+
body: {
|
|
431
|
+
data: { mutations: [], dateRanges: [], data: [], totalCountsByDateRange: [] },
|
|
432
|
+
},
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
],
|
|
437
|
+
},
|
|
438
|
+
},
|
|
248
439
|
play: async ({ canvas }) => {
|
|
249
440
|
await waitFor(() => expect(canvas.getByText('No data available.', { exact: false })).toBeVisible(), {
|
|
250
441
|
timeout: 10000,
|
|
@@ -254,10 +445,6 @@ export const ShowsNoDataMessageWhenThereAreNoDatesInFilter: StoryObj<MutationsOv
|
|
|
254
445
|
|
|
255
446
|
export const ShowsNoDataMessageForStrictFilters: StoryObj<MutationsOverTimeProps> = {
|
|
256
447
|
...Default,
|
|
257
|
-
args: {
|
|
258
|
-
...Default.args,
|
|
259
|
-
lapisFilter: { pangoLineage: 'JN.1*', dateFrom: '2024-01-15', dateTo: '2024-07-10' },
|
|
260
|
-
},
|
|
261
448
|
play: async ({ canvas }) => {
|
|
262
449
|
await waitFor(() => expect(canvas.getByText('Grid')).toBeVisible(), { timeout: 10000 });
|
|
263
450
|
|
|
@@ -2,17 +2,14 @@ import { type FunctionComponent } from 'preact';
|
|
|
2
2
|
import { type Dispatch, type StateUpdater, useMemo, useState, useEffect, useLayoutEffect, useRef } from 'preact/hooks';
|
|
3
3
|
import z from 'zod';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
import MutationOverTimeWorker from '#mutationOverTime?worker&inline';
|
|
7
|
-
import { BaseMutationOverTimeDataMap, type MutationOverTimeDataMap } from './MutationOverTimeData';
|
|
5
|
+
import { type BaseMutationOverTimeDataMap, type MutationOverTimeDataMap } from './MutationOverTimeData';
|
|
8
6
|
import {
|
|
9
7
|
displayMutationsSchema,
|
|
10
8
|
getFilteredMutationOverTimeData,
|
|
11
9
|
type MutationFilter,
|
|
12
10
|
} from './getFilteredMutationsOverTimeData';
|
|
13
|
-
import {
|
|
14
|
-
import
|
|
15
|
-
import { getProportion, type MutationOverTimeQuery } from '../../query/queryMutationsOverTime';
|
|
11
|
+
import { MutationsOverTimeGridTooltip } from './mutations-over-time-grid-tooltip';
|
|
12
|
+
import { type ProportionValue, getProportion, queryMutationsOverTimeData } from '../../query/queryMutationsOverTime';
|
|
16
13
|
import {
|
|
17
14
|
lapisFilterSchema,
|
|
18
15
|
sequenceTypeSchema,
|
|
@@ -21,14 +18,16 @@ import {
|
|
|
21
18
|
views,
|
|
22
19
|
} from '../../types';
|
|
23
20
|
import { type Deletion, type Substitution } from '../../utils/mutations';
|
|
24
|
-
import { toTemporalClass } from '../../utils/temporalClass';
|
|
21
|
+
import { type Temporal, toTemporalClass } from '../../utils/temporalClass';
|
|
25
22
|
import { useDispatchFinishedLoadingEvent } from '../../utils/useDispatchFinishedLoadingEvent';
|
|
26
23
|
import { useLapisUrl } from '../LapisUrlContext';
|
|
27
24
|
import { useMutationAnnotationsProvider } from '../MutationAnnotationsContext';
|
|
25
|
+
import { AnnotatedMutation } from '../components/annotated-mutation';
|
|
28
26
|
import { type ColorScale } from '../components/color-scale-selector';
|
|
29
27
|
import { ColorScaleSelectorDropdown } from '../components/color-scale-selector-dropdown';
|
|
30
28
|
import { CsvDownloadButton } from '../components/csv-download-button';
|
|
31
29
|
import { ErrorBoundary } from '../components/error-boundary';
|
|
30
|
+
import FeaturesOverTimeGrid, { type FeatureRenderer, customColumnSchema } from '../components/features-over-time-grid';
|
|
32
31
|
import { Fullscreen } from '../components/fullscreen';
|
|
33
32
|
import Info, { InfoComponentCode, InfoHeadline1, InfoParagraph } from '../components/info';
|
|
34
33
|
import { LoadingDisplay } from '../components/loading-display';
|
|
@@ -42,7 +41,7 @@ import { type DisplayedSegment, SegmentSelector, useDisplayedSegments } from '..
|
|
|
42
41
|
import Tabs from '../components/tabs';
|
|
43
42
|
import { pageSizesSchema } from '../shared/tanstackTable/pagination';
|
|
44
43
|
import { PageSizeContextProvider } from '../shared/tanstackTable/pagination-context';
|
|
45
|
-
import {
|
|
44
|
+
import { useQuery } from '../useQuery';
|
|
46
45
|
|
|
47
46
|
const mutationsOverTimeViewSchema = z.literal(views.grid);
|
|
48
47
|
export type MutationsOverTimeView = z.infer<typeof mutationsOverTimeViewSchema>;
|
|
@@ -59,7 +58,6 @@ const mutationOverTimeSchema = z.object({
|
|
|
59
58
|
views: z.array(mutationsOverTimeViewSchema),
|
|
60
59
|
granularity: temporalGranularitySchema,
|
|
61
60
|
lapisDateField: z.string().min(1),
|
|
62
|
-
useNewEndpoint: z.boolean().optional(),
|
|
63
61
|
displayMutations: displayMutationsSchema.optional(),
|
|
64
62
|
initialMeanProportionInterval: meanProportionIntervalSchema,
|
|
65
63
|
hideGaps: z.boolean().optional(),
|
|
@@ -83,45 +81,29 @@ export const MutationsOverTime: FunctionComponent<MutationsOverTimeProps> = (com
|
|
|
83
81
|
);
|
|
84
82
|
};
|
|
85
83
|
|
|
86
|
-
export const MutationsOverTimeInner: FunctionComponent<MutationsOverTimeProps> = ({
|
|
87
|
-
useNewEndpoint = false,
|
|
88
|
-
...componentProps
|
|
89
|
-
}) => {
|
|
84
|
+
export const MutationsOverTimeInner: FunctionComponent<MutationsOverTimeProps> = ({ ...componentProps }) => {
|
|
90
85
|
const lapis = useLapisUrl();
|
|
91
86
|
const { lapisFilter, sequenceType, granularity, lapisDateField, displayMutations } = componentProps;
|
|
92
87
|
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
lapisFilter,
|
|
96
|
-
|
|
97
|
-
granularity,
|
|
98
|
-
lapisDateField,
|
|
99
|
-
lapis,
|
|
100
|
-
displayMutations,
|
|
101
|
-
useNewEndpoint,
|
|
102
|
-
};
|
|
103
|
-
}, [granularity, lapis, lapisDateField, lapisFilter, sequenceType, displayMutations, useNewEndpoint]);
|
|
104
|
-
|
|
105
|
-
const { data, error, isLoading } = useWebWorker<MutationOverTimeWorkerResponse>(
|
|
106
|
-
messageToWorker,
|
|
107
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
108
|
-
MutationOverTimeWorker,
|
|
88
|
+
const { data, error, isLoading } = useQuery(
|
|
89
|
+
() =>
|
|
90
|
+
queryMutationsOverTimeData(lapisFilter, sequenceType, lapis, lapisDateField, granularity, displayMutations),
|
|
91
|
+
[granularity, lapis, lapisDateField, lapisFilter, sequenceType, displayMutations],
|
|
109
92
|
);
|
|
110
93
|
|
|
111
94
|
if (isLoading) {
|
|
112
95
|
return <LoadingDisplay />;
|
|
113
96
|
}
|
|
114
97
|
|
|
115
|
-
if (error !==
|
|
98
|
+
if (error !== null) {
|
|
116
99
|
throw error;
|
|
117
100
|
}
|
|
118
101
|
|
|
119
|
-
if (data
|
|
102
|
+
if (data.overallMutationData.length === 0) {
|
|
120
103
|
return <NoDataDisplay />;
|
|
121
104
|
}
|
|
122
105
|
|
|
123
|
-
const { overallMutationData,
|
|
124
|
-
const mutationOverTimeData = new BaseMutationOverTimeDataMap(mutationOverTimeSerialized);
|
|
106
|
+
const { overallMutationData, mutationOverTimeData } = data;
|
|
125
107
|
return (
|
|
126
108
|
<MutationsOverTimeTabs
|
|
127
109
|
overallMutationData={overallMutationData}
|
|
@@ -193,6 +175,18 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
|
|
|
193
175
|
annotationProvider,
|
|
194
176
|
]);
|
|
195
177
|
|
|
178
|
+
const mutationRenderer: FeatureRenderer<Substitution | Deletion> = {
|
|
179
|
+
asString: (value: Substitution | Deletion) => value.code,
|
|
180
|
+
renderRowLabel: (value: Substitution | Deletion) => (
|
|
181
|
+
<div className={'text-center'}>
|
|
182
|
+
<AnnotatedMutation mutation={value} sequenceType={originalComponentProps.sequenceType} />
|
|
183
|
+
</div>
|
|
184
|
+
),
|
|
185
|
+
renderTooltip: (value: Substitution | Deletion, temporal: Temporal, proportionValue: ProportionValue) => (
|
|
186
|
+
<MutationsOverTimeGridTooltip mutation={value} date={temporal} value={proportionValue} />
|
|
187
|
+
),
|
|
188
|
+
};
|
|
189
|
+
|
|
196
190
|
const getTab = (view: MutationsOverTimeView) => {
|
|
197
191
|
switch (view) {
|
|
198
192
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- for extensibility
|
|
@@ -200,12 +194,13 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
|
|
|
200
194
|
return {
|
|
201
195
|
title: 'Grid',
|
|
202
196
|
content: (
|
|
203
|
-
<
|
|
197
|
+
<FeaturesOverTimeGrid
|
|
198
|
+
rowLabelHeader='Mutation'
|
|
204
199
|
data={filteredData}
|
|
205
200
|
colorScale={colorScale}
|
|
206
|
-
sequenceType={originalComponentProps.sequenceType}
|
|
207
201
|
pageSizes={originalComponentProps.pageSizes}
|
|
208
202
|
customColumns={originalComponentProps.customColumns}
|
|
203
|
+
featureRenderer={mutationRenderer}
|
|
209
204
|
tooltipPortalTarget={tooltipPortalTarget}
|
|
210
205
|
/>
|
|
211
206
|
),
|
|
@@ -3,14 +3,19 @@ import { type Dispatch, type StateUpdater, useMemo, useState, useRef } from 'pre
|
|
|
3
3
|
import z from 'zod';
|
|
4
4
|
|
|
5
5
|
import { computeWastewaterMutationsOverTimeDataPerLocation } from './computeWastewaterMutationsOverTimeDataPerLocation';
|
|
6
|
+
import { type ProportionValue } from '../../../query/queryMutationsOverTime';
|
|
6
7
|
import { lapisFilterSchema, type SequenceType, sequenceTypeSchema } from '../../../types';
|
|
7
8
|
import { Map2dView } from '../../../utils/map2d';
|
|
9
|
+
import { type Deletion, type Substitution } from '../../../utils/mutations';
|
|
10
|
+
import { type Temporal } from '../../../utils/temporalClass';
|
|
8
11
|
import { useDispatchFinishedLoadingEvent } from '../../../utils/useDispatchFinishedLoadingEvent';
|
|
9
12
|
import { useLapisUrl } from '../../LapisUrlContext';
|
|
10
13
|
import { useMutationAnnotationsProvider } from '../../MutationAnnotationsContext';
|
|
14
|
+
import { AnnotatedMutation } from '../../components/annotated-mutation';
|
|
11
15
|
import { type ColorScale } from '../../components/color-scale-selector';
|
|
12
16
|
import { ColorScaleSelectorDropdown } from '../../components/color-scale-selector-dropdown';
|
|
13
17
|
import { ErrorBoundary } from '../../components/error-boundary';
|
|
18
|
+
import FeaturesOverTimeGrid from '../../components/features-over-time-grid';
|
|
14
19
|
import { Fullscreen } from '../../components/fullscreen';
|
|
15
20
|
import Info, { InfoComponentCode, InfoHeadline1, InfoParagraph } from '../../components/info';
|
|
16
21
|
import { LoadingDisplay } from '../../components/loading-display';
|
|
@@ -24,7 +29,7 @@ import {
|
|
|
24
29
|
type MutationFilter,
|
|
25
30
|
mutationOrAnnotationDoNotMatchFilter,
|
|
26
31
|
} from '../../mutationsOverTime/getFilteredMutationsOverTimeData';
|
|
27
|
-
import
|
|
32
|
+
import { MutationsOverTimeGridTooltip } from '../../mutationsOverTime/mutations-over-time-grid-tooltip';
|
|
28
33
|
import { pageSizesSchema } from '../../shared/tanstackTable/pagination';
|
|
29
34
|
import { PageSizeContextProvider } from '../../shared/tanstackTable/pagination-context';
|
|
30
35
|
import { useQuery } from '../../useQuery';
|
|
@@ -166,7 +171,8 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
|
|
|
166
171
|
mutationOverTimeDataPerLocation.map(({ location, data }) => ({
|
|
167
172
|
title: location,
|
|
168
173
|
content: (
|
|
169
|
-
<
|
|
174
|
+
<FeaturesOverTimeGrid
|
|
175
|
+
rowLabelHeader='Mutation'
|
|
170
176
|
data={getFilteredMutationOverTimeData({
|
|
171
177
|
data,
|
|
172
178
|
displayedSegments,
|
|
@@ -176,7 +182,28 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
|
|
|
176
182
|
})}
|
|
177
183
|
colorScale={colorScale}
|
|
178
184
|
pageSizes={originalComponentProps.pageSizes}
|
|
179
|
-
|
|
185
|
+
featureRenderer={{
|
|
186
|
+
asString: (value: Substitution | Deletion) => value.code,
|
|
187
|
+
renderRowLabel: (value: Substitution | Deletion) => (
|
|
188
|
+
<div className={'text-center'}>
|
|
189
|
+
<AnnotatedMutation
|
|
190
|
+
mutation={value}
|
|
191
|
+
sequenceType={originalComponentProps.sequenceType}
|
|
192
|
+
/>
|
|
193
|
+
</div>
|
|
194
|
+
),
|
|
195
|
+
renderTooltip: (
|
|
196
|
+
value: Substitution | Deletion,
|
|
197
|
+
temporal: Temporal,
|
|
198
|
+
proportionValue: ProportionValue,
|
|
199
|
+
) => (
|
|
200
|
+
<MutationsOverTimeGridTooltip
|
|
201
|
+
mutation={value}
|
|
202
|
+
date={temporal}
|
|
203
|
+
value={proportionValue}
|
|
204
|
+
/>
|
|
205
|
+
),
|
|
206
|
+
}}
|
|
180
207
|
tooltipPortalTarget={tooltipPortalTargetRef.current}
|
|
181
208
|
/>
|
|
182
209
|
),
|