@genspectrum/dashboard-components 0.6.18 → 0.7.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 +5 -12
- package/custom-elements.json +22 -22
- package/dist/assets/mutationOverTimeWorker-BOCXtKzd.js.map +1 -0
- package/dist/dashboard-components.js +301 -302
- package/dist/dashboard-components.js.map +1 -1
- package/dist/genspectrum-components.d.ts +60 -10
- package/dist/style.css +3 -2
- package/package.json +13 -4
- package/src/index.ts +1 -0
- package/src/operator/FetchInsertionsOperator.ts +2 -2
- package/src/operator/FetchSubstitutionsOrDeletionsOperator.ts +3 -3
- package/src/preact/dateRangeSelector/computeInitialValues.spec.ts +53 -38
- package/src/preact/dateRangeSelector/computeInitialValues.ts +17 -23
- package/src/preact/dateRangeSelector/date-range-selector.stories.tsx +46 -32
- package/src/preact/dateRangeSelector/date-range-selector.tsx +24 -26
- package/src/preact/dateRangeSelector/dateRangeOption.ts +65 -0
- package/src/preact/dateRangeSelector/selectableOptions.ts +17 -66
- package/src/preact/mutationComparison/fetchMutationData.spec.ts +3 -3
- package/src/preact/mutationComparison/getMutationComparisonTableData.spec.ts +11 -11
- package/src/preact/mutationComparison/getMutationComparisonTableData.ts +4 -4
- package/src/preact/mutationComparison/mutation-comparison-table.tsx +2 -2
- package/src/preact/mutationFilter/mutation-filter.tsx +27 -18
- package/src/preact/mutationFilter/parseAndValidateMutation.ts +4 -4
- package/src/preact/mutationFilter/parseMutation.spec.ts +17 -17
- package/src/preact/mutations/getInsertionsTableData.spec.ts +3 -3
- package/src/preact/mutations/getMutationsGridData.spec.ts +9 -9
- package/src/preact/mutations/getMutationsTableData.spec.ts +7 -7
- package/src/preact/mutations/mutations-insertions-table.tsx +3 -3
- package/src/preact/mutations/mutations-table.tsx +3 -3
- package/src/preact/mutationsOverTime/MutationOverTimeData.ts +20 -0
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutationsByDay.ts +45686 -0
- package/src/preact/mutationsOverTime/__mockData__/byWeek.ts +58989 -0
- package/src/preact/mutationsOverTime/__mockData__/defaultMockData.ts +103991 -0
- package/src/preact/mutationsOverTime/__mockData__/mockConversion.ts +54 -0
- package/src/preact/mutationsOverTime/__mockData__/showsMessageWhenTooManyMutations.ts +63690 -0
- package/src/preact/mutationsOverTime/getFilteredMutationsOverTime.spec.ts +177 -161
- package/src/preact/mutationsOverTime/getFilteredMutationsOverTimeData.ts +17 -59
- package/src/preact/mutationsOverTime/mutationOverTimeWorker.mock.ts +27 -0
- package/src/preact/mutationsOverTime/mutationOverTimeWorker.ts +29 -0
- package/src/preact/mutationsOverTime/mutations-over-time-grid.tsx +13 -14
- package/src/preact/mutationsOverTime/mutations-over-time.stories.tsx +9 -334
- package/src/preact/mutationsOverTime/mutations-over-time.tsx +59 -54
- package/src/preact/numberSequencesOverTime/getNumberOfSequencesOverTimeTableData.ts +3 -3
- package/src/preact/prevalenceOverTime/getPrevalenceOverTimeTableData.spec.ts +5 -5
- package/src/preact/prevalenceOverTime/prevalence-over-time-bubble-chart.tsx +1 -1
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage-chart.tsx +2 -2
- package/src/preact/shared/sort/sortInsertions.spec.ts +11 -11
- package/src/preact/shared/sort/sortInsertions.ts +2 -2
- package/src/preact/shared/sort/sortSubstitutionsAndDeletions.spec.ts +13 -13
- package/src/preact/shared/sort/sortSubstitutionsAndDeletions.ts +7 -4
- package/src/preact/webWorkers/useWebWorker.ts +51 -0
- package/src/preact/webWorkers/workerFunction.ts +14 -0
- package/src/query/queryAggregatedDataOverTime.ts +3 -3
- package/src/query/queryMutationsOverTime.spec.ts +272 -51
- package/src/query/queryMutationsOverTime.ts +114 -47
- package/src/query/queryPrevalenceOverTime.ts +2 -2
- package/src/query/queryRelativeGrowthAdvantage.ts +3 -3
- package/src/types.ts +25 -5
- package/src/utils/map2d.spec.ts +79 -12
- package/src/utils/map2d.ts +25 -5
- package/src/utils/mutations.spec.ts +20 -20
- package/src/utils/mutations.ts +80 -17
- package/src/utils/sort.ts +5 -2
- package/src/utils/temporal.spec.ts +27 -24
- package/src/utils/{temporal.ts → temporalClass.ts} +170 -72
- package/src/utils/temporalTestHelpers.ts +3 -3
- package/src/web-components/input/gs-date-range-selector.stories.ts +16 -28
- package/src/web-components/input/gs-date-range-selector.tsx +17 -32
- package/src/web-components/introduction.mdx +46 -0
- package/src/web-components/visualization/gs-mutations-over-time.stories.ts +6 -699
- package/src/web-components/visualization/gs-mutations-over-time.tsx +2 -2
- package/standalone-bundle/dashboard-components.js +12011 -12778
- package/standalone-bundle/dashboard-components.js.map +1 -1
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_01.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_02.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_03.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_04.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_05.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_06.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_07.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_20_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_21_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_22_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_23_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_24_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_25_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_26_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_byDay.json +0 -38
- package/src/preact/mutationsOverTime/__mockData__/aggregated_byWeek.json +0 -122
- package/src/preact/mutationsOverTime/__mockData__/aggregated_date.json +0 -642
- package/src/preact/mutationsOverTime/__mockData__/aggregated_tooManyMutations.json +0 -1470
- package/src/preact/mutationsOverTime/__mockData__/aggregated_tooManyMutations_total.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_week3_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_week4_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_week5_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_week6_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_20_01_2024.json +0 -6778
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_21_01_2024.json +0 -7129
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_22_01_2024.json +0 -4681
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_23_01_2024.json +0 -10738
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_24_01_2024.json +0 -11710
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_25_01_2024.json +0 -11557
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_26_01_2024.json +0 -8596
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_byDayOverall.json +0 -4726
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_01.json +0 -1747
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_02.json +0 -1774
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_03.json +0 -1819
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_04.json +0 -1864
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_05.json +0 -1927
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_06.json +0 -1864
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_07.json +0 -9
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_byMonthOverall.json +0 -11143
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_byWeekOverall.json +0 -9154
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_tooManyMutations.json +0 -16453
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week3_2024.json +0 -8812
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week4_2024.json +0 -9730
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week5_2024.json +0 -9865
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week6_2024.json +0 -11314
|
@@ -4,33 +4,28 @@ import { useEffect, useRef, useState } from 'preact/hooks';
|
|
|
4
4
|
|
|
5
5
|
import { computeInitialValues } from './computeInitialValues';
|
|
6
6
|
import { toYYYYMMDD } from './dateConversion';
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
getDatesForSelectorValue,
|
|
10
|
-
getSelectableOptions,
|
|
11
|
-
type PresetOptionValues,
|
|
12
|
-
} from './selectableOptions';
|
|
7
|
+
import { type DateRangeOption } from './dateRangeOption';
|
|
8
|
+
import { getDatesForSelectorValue, getSelectableOptions } from './selectableOptions';
|
|
13
9
|
import { ErrorBoundary } from '../components/error-boundary';
|
|
14
10
|
import { Select } from '../components/select';
|
|
15
11
|
import type { ScaleType } from '../shared/charts/getYAxisScale';
|
|
16
12
|
|
|
17
|
-
|
|
13
|
+
const customOption = 'Custom';
|
|
14
|
+
|
|
15
|
+
export interface DateRangeSelectorProps extends DateRangeSelectorPropsInner {
|
|
18
16
|
width: string;
|
|
19
17
|
}
|
|
20
18
|
|
|
21
|
-
export interface DateRangeSelectorPropsInner
|
|
22
|
-
|
|
19
|
+
export interface DateRangeSelectorPropsInner {
|
|
20
|
+
dateRangeOptions: DateRangeOption[];
|
|
23
21
|
earliestDate: string;
|
|
24
|
-
initialValue:
|
|
22
|
+
initialValue: string | undefined;
|
|
25
23
|
initialDateFrom: string;
|
|
26
24
|
initialDateTo: string;
|
|
27
25
|
dateColumn: string;
|
|
28
26
|
}
|
|
29
27
|
|
|
30
|
-
export const DateRangeSelector =
|
|
31
|
-
width,
|
|
32
|
-
...innerProps
|
|
33
|
-
}: DateRangeSelectorProps<CustomLabel>) => {
|
|
28
|
+
export const DateRangeSelector = ({ width, ...innerProps }: DateRangeSelectorProps) => {
|
|
34
29
|
const size = { width, height: '3rem' };
|
|
35
30
|
|
|
36
31
|
return (
|
|
@@ -42,20 +37,20 @@ export const DateRangeSelector = <CustomLabel extends string>({
|
|
|
42
37
|
);
|
|
43
38
|
};
|
|
44
39
|
|
|
45
|
-
export const DateRangeSelectorInner =
|
|
46
|
-
|
|
40
|
+
export const DateRangeSelectorInner = ({
|
|
41
|
+
dateRangeOptions,
|
|
47
42
|
earliestDate = '1900-01-01',
|
|
48
43
|
initialValue,
|
|
49
44
|
dateColumn,
|
|
50
45
|
initialDateFrom,
|
|
51
46
|
initialDateTo,
|
|
52
|
-
}: DateRangeSelectorPropsInner
|
|
47
|
+
}: DateRangeSelectorPropsInner) => {
|
|
53
48
|
const initialValues = computeInitialValues(
|
|
54
49
|
initialValue,
|
|
55
50
|
initialDateFrom,
|
|
56
51
|
initialDateTo,
|
|
57
52
|
earliestDate,
|
|
58
|
-
|
|
53
|
+
dateRangeOptions,
|
|
59
54
|
);
|
|
60
55
|
|
|
61
56
|
const fromDatePickerRef = useRef<HTMLInputElement>(null);
|
|
@@ -64,7 +59,7 @@ export const DateRangeSelectorInner = <CustomLabel extends string>({
|
|
|
64
59
|
const [dateFromPicker, setDateFromPicker] = useState<flatpickr.Instance | null>(null);
|
|
65
60
|
const [dateToPicker, setDateToPicker] = useState<flatpickr.Instance | null>(null);
|
|
66
61
|
|
|
67
|
-
const [selectedDateRange, setSelectedDateRange] = useState<
|
|
62
|
+
const [selectedDateRange, setSelectedDateRange] = useState<string | undefined>(
|
|
68
63
|
initialValues.initialSelectedDateRange,
|
|
69
64
|
);
|
|
70
65
|
|
|
@@ -104,10 +99,10 @@ export const DateRangeSelectorInner = <CustomLabel extends string>({
|
|
|
104
99
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
105
100
|
}, [fromDatePickerRef, toDatePickerRef]);
|
|
106
101
|
|
|
107
|
-
const onSelectChange = (value:
|
|
102
|
+
const onSelectChange = (value: string) => {
|
|
108
103
|
setSelectedDateRange(value);
|
|
109
104
|
|
|
110
|
-
const dateRange = getDatesForSelectorValue(value,
|
|
105
|
+
const dateRange = getDatesForSelectorValue(value, dateRangeOptions, earliestDate);
|
|
111
106
|
|
|
112
107
|
dateToPicker?.set('minDate', dateRange.dateFrom);
|
|
113
108
|
dateFromPicker?.set('maxDate', dateRange.dateTo);
|
|
@@ -130,7 +125,7 @@ export const DateRangeSelectorInner = <CustomLabel extends string>({
|
|
|
130
125
|
|
|
131
126
|
selectedDates.dateFrom = dateFromPicker?.selectedDates[0] || new Date();
|
|
132
127
|
dateToPicker?.set('minDate', dateFromPicker?.selectedDates[0]);
|
|
133
|
-
setSelectedDateRange(
|
|
128
|
+
setSelectedDateRange(customOption);
|
|
134
129
|
|
|
135
130
|
submit();
|
|
136
131
|
};
|
|
@@ -142,7 +137,7 @@ export const DateRangeSelectorInner = <CustomLabel extends string>({
|
|
|
142
137
|
|
|
143
138
|
selectedDates.dateTo = dateToPicker?.selectedDates[0] || new Date();
|
|
144
139
|
dateFromPicker?.set('maxDate', dateToPicker?.selectedDates[0]);
|
|
145
|
-
setSelectedDateRange(
|
|
140
|
+
setSelectedDateRange(customOption);
|
|
146
141
|
|
|
147
142
|
submit();
|
|
148
143
|
};
|
|
@@ -168,14 +163,17 @@ export const DateRangeSelectorInner = <CustomLabel extends string>({
|
|
|
168
163
|
return (
|
|
169
164
|
<div class='flex flex-wrap' ref={divRef}>
|
|
170
165
|
<Select
|
|
171
|
-
items={
|
|
172
|
-
|
|
166
|
+
items={[
|
|
167
|
+
...getSelectableOptions(dateRangeOptions),
|
|
168
|
+
{ label: customOption, value: customOption, disabled: true },
|
|
169
|
+
]}
|
|
170
|
+
selected={selectedDateRange ?? customOption}
|
|
173
171
|
selectStyle='select-bordered rounded-none flex-grow min-w-[7.5rem]'
|
|
174
172
|
onChange={(event: Event) => {
|
|
175
173
|
event.preventDefault();
|
|
176
174
|
const select = event.target as HTMLSelectElement;
|
|
177
175
|
const value = select.value as ScaleType;
|
|
178
|
-
onSelectChange(value
|
|
176
|
+
onSelectChange(value);
|
|
179
177
|
}}
|
|
180
178
|
/>
|
|
181
179
|
<div className={'flex flex-wrap flex-grow'}>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { toYYYYMMDD } from './dateConversion';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A date range option that can be used in the `gs-date-range-selector` component.
|
|
5
|
+
*/
|
|
6
|
+
export type DateRangeOption = {
|
|
7
|
+
/** The label of the date range option that will be shown to the user */
|
|
8
|
+
label: string;
|
|
9
|
+
/**
|
|
10
|
+
* The start date of the date range in the format `YYYY-MM-DD`.
|
|
11
|
+
* If not set, the date range selector will default to the `earliestDate` property.
|
|
12
|
+
*/
|
|
13
|
+
dateFrom?: string;
|
|
14
|
+
/**
|
|
15
|
+
* The end date of the date range in the format `YYYY-MM-DD`.
|
|
16
|
+
* If not set, the date range selector will default to the current date.
|
|
17
|
+
*/
|
|
18
|
+
dateTo?: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const today = new Date();
|
|
22
|
+
|
|
23
|
+
const twoWeeksAgo = new Date();
|
|
24
|
+
twoWeeksAgo.setDate(today.getDate() - 14);
|
|
25
|
+
|
|
26
|
+
const lastMonth = new Date(today);
|
|
27
|
+
lastMonth.setMonth(today.getMonth() - 1);
|
|
28
|
+
|
|
29
|
+
const last2Months = new Date(today);
|
|
30
|
+
last2Months.setMonth(today.getMonth() - 2);
|
|
31
|
+
|
|
32
|
+
const last3Months = new Date(today);
|
|
33
|
+
last3Months.setMonth(today.getMonth() - 3);
|
|
34
|
+
|
|
35
|
+
const last6Months = new Date(today);
|
|
36
|
+
last6Months.setMonth(today.getMonth() - 6);
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Presets for the `gs-date-range-selector` component that can be used as `dateRangeOptions`.
|
|
40
|
+
*/
|
|
41
|
+
export const dateRangeOptionPresets = {
|
|
42
|
+
last2Weeks: {
|
|
43
|
+
label: 'Last 2 weeks',
|
|
44
|
+
dateFrom: toYYYYMMDD(twoWeeksAgo),
|
|
45
|
+
},
|
|
46
|
+
lastMonth: {
|
|
47
|
+
label: 'Last month',
|
|
48
|
+
dateFrom: toYYYYMMDD(lastMonth),
|
|
49
|
+
},
|
|
50
|
+
last2Months: {
|
|
51
|
+
label: 'Last 2 months',
|
|
52
|
+
dateFrom: toYYYYMMDD(last2Months),
|
|
53
|
+
},
|
|
54
|
+
last3Months: {
|
|
55
|
+
label: 'Last 3 months',
|
|
56
|
+
dateFrom: toYYYYMMDD(last3Months),
|
|
57
|
+
},
|
|
58
|
+
last6Months: {
|
|
59
|
+
label: 'Last 6 months',
|
|
60
|
+
dateFrom: toYYYYMMDD(last6Months),
|
|
61
|
+
},
|
|
62
|
+
allTimes: {
|
|
63
|
+
label: 'All times',
|
|
64
|
+
},
|
|
65
|
+
} satisfies Record<string, DateRangeOption>;
|
|
@@ -1,79 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
export const PRESET_VALUE_ALL_TIMES = 'allTimes';
|
|
3
|
-
export const PRESET_VALUE_LAST_2_WEEKS = 'last2Weeks';
|
|
4
|
-
export const PRESET_VALUE_LAST_MONTH = 'lastMonth';
|
|
5
|
-
export const PRESET_VALUE_LAST_2_MONTHS = 'last2Months';
|
|
6
|
-
export const PRESET_VALUE_LAST_3_MONTHS = 'last3Months';
|
|
7
|
-
export const PRESET_VALUE_LAST_6_MONTHS = 'last6Months';
|
|
1
|
+
import { type DateRangeOption } from './dateRangeOption';
|
|
8
2
|
|
|
9
|
-
export const
|
|
10
|
-
|
|
11
|
-
[PRESET_VALUE_ALL_TIMES]: { label: 'All times' },
|
|
12
|
-
[PRESET_VALUE_LAST_2_WEEKS]: { label: 'Last 2 weeks' },
|
|
13
|
-
[PRESET_VALUE_LAST_MONTH]: { label: 'Last month' },
|
|
14
|
-
[PRESET_VALUE_LAST_2_MONTHS]: { label: 'Last 2 months' },
|
|
15
|
-
[PRESET_VALUE_LAST_3_MONTHS]: { label: 'Last 3 months' },
|
|
16
|
-
[PRESET_VALUE_LAST_6_MONTHS]: { label: 'Last 6 months' },
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export type PresetOptionValues = keyof typeof presets;
|
|
20
|
-
|
|
21
|
-
export type CustomSelectOption<CustomLabel extends string> = { label: CustomLabel; dateFrom: string; dateTo: string };
|
|
22
|
-
|
|
23
|
-
export const getSelectableOptions = <Label extends string>(customSelectOptions: CustomSelectOption<Label>[]) => {
|
|
24
|
-
const presetOptions = Object.entries(presets).map(([key, value]) => {
|
|
25
|
-
return { label: value.label, value: key };
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
const customOptions = customSelectOptions.map((customSelectOption) => {
|
|
3
|
+
export const getSelectableOptions = (dateRangeOptions: DateRangeOption[]) => {
|
|
4
|
+
return dateRangeOptions.map((customSelectOption) => {
|
|
29
5
|
return { label: customSelectOption.label, value: customSelectOption.label };
|
|
30
6
|
});
|
|
31
|
-
|
|
32
|
-
return [...presetOptions, ...customOptions];
|
|
33
7
|
};
|
|
34
8
|
|
|
35
|
-
export const getDatesForSelectorValue =
|
|
36
|
-
|
|
37
|
-
|
|
9
|
+
export const getDatesForSelectorValue = (
|
|
10
|
+
initialSelectedDateRange: string | undefined,
|
|
11
|
+
dateRangeOptions: DateRangeOption[],
|
|
38
12
|
earliestDate: string,
|
|
39
13
|
) => {
|
|
40
14
|
const today = new Date();
|
|
15
|
+
const defaultDates = { dateFrom: new Date(earliestDate), dateTo: today };
|
|
41
16
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return { dateFrom: new Date(customSelectOption.dateFrom), dateTo: new Date(customSelectOption.dateTo) };
|
|
17
|
+
if (initialSelectedDateRange === undefined) {
|
|
18
|
+
return defaultDates;
|
|
45
19
|
}
|
|
46
20
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
case PRESET_VALUE_LAST_MONTH: {
|
|
54
|
-
const lastMonth = new Date(today);
|
|
55
|
-
lastMonth.setMonth(today.getMonth() - 1);
|
|
56
|
-
return { dateFrom: lastMonth, dateTo: today };
|
|
57
|
-
}
|
|
58
|
-
case PRESET_VALUE_LAST_2_MONTHS: {
|
|
59
|
-
const twoMonthsAgo = new Date(today);
|
|
60
|
-
twoMonthsAgo.setMonth(today.getMonth() - 2);
|
|
61
|
-
return { dateFrom: twoMonthsAgo, dateTo: today };
|
|
62
|
-
}
|
|
63
|
-
case PRESET_VALUE_LAST_3_MONTHS: {
|
|
64
|
-
const threeMonthsAgo = new Date(today);
|
|
65
|
-
threeMonthsAgo.setMonth(today.getMonth() - 3);
|
|
66
|
-
return { dateFrom: threeMonthsAgo, dateTo: today };
|
|
67
|
-
}
|
|
68
|
-
case PRESET_VALUE_LAST_6_MONTHS: {
|
|
69
|
-
const sixMonthsAgo = new Date(today);
|
|
70
|
-
sixMonthsAgo.setMonth(today.getMonth() - 6);
|
|
71
|
-
return { dateFrom: sixMonthsAgo, dateTo: today };
|
|
72
|
-
}
|
|
73
|
-
case PRESET_VALUE_ALL_TIMES: {
|
|
74
|
-
return { dateFrom: new Date(earliestDate), dateTo: today };
|
|
75
|
-
}
|
|
76
|
-
default:
|
|
77
|
-
return { dateFrom: today, dateTo: today };
|
|
21
|
+
const dateRangeOption = dateRangeOptions.find((option) => option.label === initialSelectedDateRange);
|
|
22
|
+
if (dateRangeOption) {
|
|
23
|
+
return {
|
|
24
|
+
dateFrom: new Date(dateRangeOption.dateFrom ?? earliestDate),
|
|
25
|
+
dateTo: new Date(dateRangeOption.dateTo ?? today),
|
|
26
|
+
};
|
|
78
27
|
}
|
|
28
|
+
|
|
29
|
+
return defaultDates;
|
|
79
30
|
};
|
|
@@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest';
|
|
|
2
2
|
|
|
3
3
|
import { filterMutationData } from './queryMutationData';
|
|
4
4
|
import { type SubstitutionOrDeletion, type SubstitutionOrDeletionEntry } from '../../types';
|
|
5
|
-
import {
|
|
5
|
+
import { DeletionClass, SubstitutionClass } from '../../utils/mutations';
|
|
6
6
|
|
|
7
7
|
const segment = 'testSegment';
|
|
8
8
|
const displayedSegment = { segment, label: 'label', checked: true };
|
|
@@ -19,14 +19,14 @@ describe('filterMutationData', () => {
|
|
|
19
19
|
case 'substitution':
|
|
20
20
|
return {
|
|
21
21
|
type: 'substitution',
|
|
22
|
-
mutation: new
|
|
22
|
+
mutation: new SubstitutionClass(segment, 'A', 'B', 0),
|
|
23
23
|
count: 0,
|
|
24
24
|
proportion: 0,
|
|
25
25
|
};
|
|
26
26
|
case 'deletion':
|
|
27
27
|
return {
|
|
28
28
|
type: 'deletion',
|
|
29
|
-
mutation: new
|
|
29
|
+
mutation: new DeletionClass(segment, 'A', 0),
|
|
30
30
|
count: 0,
|
|
31
31
|
proportion: 0,
|
|
32
32
|
};
|
|
@@ -4,7 +4,7 @@ import { getMutationComparisonTableData } from './getMutationComparisonTableData
|
|
|
4
4
|
import { type MutationData } from './queryMutationData';
|
|
5
5
|
import { type Dataset } from '../../operator/Dataset';
|
|
6
6
|
import { type SubstitutionEntry } from '../../types';
|
|
7
|
-
import {
|
|
7
|
+
import { SubstitutionClass } from '../../utils/mutations';
|
|
8
8
|
|
|
9
9
|
describe('getPrevalenceOverTimeTableData', () => {
|
|
10
10
|
it('should flatten the data to CSV format', () => {
|
|
@@ -15,13 +15,13 @@ describe('getPrevalenceOverTimeTableData', () => {
|
|
|
15
15
|
data: [
|
|
16
16
|
{
|
|
17
17
|
type: 'substitution',
|
|
18
|
-
mutation: new
|
|
18
|
+
mutation: new SubstitutionClass(undefined, 'A', 'T', 123),
|
|
19
19
|
count: 1,
|
|
20
20
|
proportion: 0.123,
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
type: 'substitution',
|
|
24
|
-
mutation: new
|
|
24
|
+
mutation: new SubstitutionClass(undefined, 'G', 'A', 234),
|
|
25
25
|
count: 2,
|
|
26
26
|
proportion: 0.567,
|
|
27
27
|
},
|
|
@@ -32,13 +32,13 @@ describe('getPrevalenceOverTimeTableData', () => {
|
|
|
32
32
|
data: [
|
|
33
33
|
{
|
|
34
34
|
type: 'substitution',
|
|
35
|
-
mutation: new
|
|
35
|
+
mutation: new SubstitutionClass(undefined, 'A', 'T', 123),
|
|
36
36
|
count: 3,
|
|
37
37
|
proportion: 0.345,
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
40
|
type: 'substitution',
|
|
41
|
-
mutation: new
|
|
41
|
+
mutation: new SubstitutionClass(undefined, 'G', 'A', 234),
|
|
42
42
|
count: 4,
|
|
43
43
|
proportion: 0.789,
|
|
44
44
|
},
|
|
@@ -51,12 +51,12 @@ describe('getPrevalenceOverTimeTableData', () => {
|
|
|
51
51
|
|
|
52
52
|
expect(result).toEqual([
|
|
53
53
|
{
|
|
54
|
-
mutation: new
|
|
54
|
+
mutation: new SubstitutionClass(undefined, 'A', 'T', 123),
|
|
55
55
|
'Test 1 prevalence': 0.123,
|
|
56
56
|
'Test 2 prevalence': 0.345,
|
|
57
57
|
},
|
|
58
58
|
{
|
|
59
|
-
mutation: new
|
|
59
|
+
mutation: new SubstitutionClass(undefined, 'G', 'A', 234),
|
|
60
60
|
'Test 1 prevalence': 0.567,
|
|
61
61
|
'Test 2 prevalence': 0.789,
|
|
62
62
|
},
|
|
@@ -67,7 +67,7 @@ describe('getPrevalenceOverTimeTableData', () => {
|
|
|
67
67
|
function makeSubstitutionWithProportionAtPosition(proportion: number, position: number): SubstitutionEntry {
|
|
68
68
|
return {
|
|
69
69
|
type: 'substitution',
|
|
70
|
-
mutation: new
|
|
70
|
+
mutation: new SubstitutionClass(undefined, 'A', 'T', position),
|
|
71
71
|
count: 1,
|
|
72
72
|
proportion,
|
|
73
73
|
};
|
|
@@ -106,17 +106,17 @@ describe('getPrevalenceOverTimeTableData', () => {
|
|
|
106
106
|
|
|
107
107
|
expect(result).toEqual([
|
|
108
108
|
{
|
|
109
|
-
mutation: new
|
|
109
|
+
mutation: new SubstitutionClass(undefined, 'A', 'T', 200),
|
|
110
110
|
'Test 1 prevalence': inRange,
|
|
111
111
|
'Test 2 prevalence': belowRange,
|
|
112
112
|
},
|
|
113
113
|
{
|
|
114
|
-
mutation: new
|
|
114
|
+
mutation: new SubstitutionClass(undefined, 'A', 'T', 300),
|
|
115
115
|
'Test 1 prevalence': inRange,
|
|
116
116
|
'Test 2 prevalence': inRange,
|
|
117
117
|
},
|
|
118
118
|
{
|
|
119
|
-
mutation: new
|
|
119
|
+
mutation: new SubstitutionClass(undefined, 'A', 'T', 400),
|
|
120
120
|
'Test 1 prevalence': inRange,
|
|
121
121
|
'Test 2 prevalence': aboveRange,
|
|
122
122
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type MutationData } from './queryMutationData';
|
|
2
2
|
import { type Dataset } from '../../operator/Dataset';
|
|
3
|
-
import { type
|
|
3
|
+
import { type DeletionClass, type SubstitutionClass } from '../../utils/mutations';
|
|
4
4
|
import { type ProportionInterval } from '../components/proportion-selector';
|
|
5
5
|
|
|
6
6
|
type Proportions = {
|
|
@@ -8,7 +8,7 @@ type Proportions = {
|
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
type MutationComparisonRow = {
|
|
11
|
-
mutation:
|
|
11
|
+
mutation: SubstitutionClass | DeletionClass;
|
|
12
12
|
proportions: Proportions;
|
|
13
13
|
};
|
|
14
14
|
|
|
@@ -47,7 +47,7 @@ export function getMutationComparisonTableData(data: Dataset<MutationData>, prop
|
|
|
47
47
|
};
|
|
48
48
|
})
|
|
49
49
|
.reduce((acc, val) => ({ ...acc, ...val }), {}),
|
|
50
|
-
} as { mutation:
|
|
50
|
+
} as { mutation: SubstitutionClass | DeletionClass } & Proportions;
|
|
51
51
|
})
|
|
52
52
|
.filter((row) =>
|
|
53
53
|
Object.values(row).some(
|
|
@@ -58,7 +58,7 @@ export function getMutationComparisonTableData(data: Dataset<MutationData>, prop
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
function initializeMutationRow(
|
|
61
|
-
mutation:
|
|
61
|
+
mutation: SubstitutionClass | DeletionClass,
|
|
62
62
|
displayName: string,
|
|
63
63
|
proportion: number,
|
|
64
64
|
): MutationComparisonRow {
|
|
@@ -3,7 +3,7 @@ import { type FunctionComponent } from 'preact';
|
|
|
3
3
|
import { getMutationComparisonTableData } from './getMutationComparisonTableData';
|
|
4
4
|
import { type MutationData } from './queryMutationData';
|
|
5
5
|
import { type Dataset } from '../../operator/Dataset';
|
|
6
|
-
import { type
|
|
6
|
+
import { type DeletionClass, type SubstitutionClass } from '../../utils/mutations';
|
|
7
7
|
import { type ProportionInterval } from '../components/proportion-selector';
|
|
8
8
|
import { Table } from '../components/table';
|
|
9
9
|
import { sortSubstitutionsAndDeletions } from '../shared/sort/sortSubstitutionsAndDeletions';
|
|
@@ -26,7 +26,7 @@ export const MutationComparisonTable: FunctionComponent<MutationsTableProps> = (
|
|
|
26
26
|
sort: {
|
|
27
27
|
compare: sortSubstitutionsAndDeletions,
|
|
28
28
|
},
|
|
29
|
-
formatter: (cell:
|
|
29
|
+
formatter: (cell: SubstitutionClass | DeletionClass) => cell.toString(),
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
32
|
name: 'Prevalence',
|
|
@@ -4,7 +4,12 @@ import { useContext, useRef, useState } from 'preact/hooks';
|
|
|
4
4
|
import { MutationFilterInfo } from './mutation-filter-info';
|
|
5
5
|
import { parseAndValidateMutation } from './parseAndValidateMutation';
|
|
6
6
|
import { type ReferenceGenome } from '../../lapisApi/ReferenceGenome';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
type DeletionClass,
|
|
9
|
+
type InsertionClass,
|
|
10
|
+
type MutationClass,
|
|
11
|
+
type SubstitutionClass,
|
|
12
|
+
} from '../../utils/mutations';
|
|
8
13
|
import { ReferenceGenomeContext } from '../ReferenceGenomeContext';
|
|
9
14
|
import { ErrorBoundary } from '../components/error-boundary';
|
|
10
15
|
import { singleGraphColorRGBByName } from '../shared/charts/colors';
|
|
@@ -18,10 +23,10 @@ export interface MutationFilterProps extends MutationFilterInnerProps {
|
|
|
18
23
|
}
|
|
19
24
|
|
|
20
25
|
export type SelectedFilters = {
|
|
21
|
-
nucleotideMutations: (
|
|
22
|
-
aminoAcidMutations: (
|
|
23
|
-
nucleotideInsertions:
|
|
24
|
-
aminoAcidInsertions:
|
|
26
|
+
nucleotideMutations: (SubstitutionClass | DeletionClass)[];
|
|
27
|
+
aminoAcidMutations: (SubstitutionClass | DeletionClass)[];
|
|
28
|
+
nucleotideInsertions: InsertionClass[];
|
|
29
|
+
aminoAcidInsertions: InsertionClass[];
|
|
25
30
|
};
|
|
26
31
|
|
|
27
32
|
export type SelectedMutationFilterStrings = {
|
|
@@ -199,14 +204,18 @@ const SelectedMutationDisplay: FunctionComponent<{
|
|
|
199
204
|
<SelectedNucleotideMutation
|
|
200
205
|
key={mutation.toString()}
|
|
201
206
|
mutation={mutation}
|
|
202
|
-
onDelete={(mutation:
|
|
207
|
+
onDelete={(mutation: SubstitutionClass | DeletionClass) =>
|
|
208
|
+
onSelectedRemoved(mutation, 'nucleotideMutations')
|
|
209
|
+
}
|
|
203
210
|
/>
|
|
204
211
|
))}
|
|
205
212
|
{selectedFilters.aminoAcidMutations.map((mutation) => (
|
|
206
213
|
<SelectedAminoAcidMutation
|
|
207
214
|
key={mutation.toString()}
|
|
208
215
|
mutation={mutation}
|
|
209
|
-
onDelete={(mutation:
|
|
216
|
+
onDelete={(mutation: SubstitutionClass | DeletionClass) =>
|
|
217
|
+
onSelectedRemoved(mutation, 'aminoAcidMutations')
|
|
218
|
+
}
|
|
210
219
|
/>
|
|
211
220
|
))}
|
|
212
221
|
{selectedFilters.nucleotideInsertions.map((insertion) => (
|
|
@@ -220,7 +229,7 @@ const SelectedMutationDisplay: FunctionComponent<{
|
|
|
220
229
|
<SelectedAminoAcidInsertion
|
|
221
230
|
key={insertion.toString()}
|
|
222
231
|
insertion={insertion}
|
|
223
|
-
onDelete={(insertion:
|
|
232
|
+
onDelete={(insertion: InsertionClass) => onSelectedRemoved(insertion, 'aminoAcidInsertions')}
|
|
224
233
|
/>
|
|
225
234
|
))}
|
|
226
235
|
</>
|
|
@@ -228,8 +237,8 @@ const SelectedMutationDisplay: FunctionComponent<{
|
|
|
228
237
|
};
|
|
229
238
|
|
|
230
239
|
const SelectedAminoAcidInsertion: FunctionComponent<{
|
|
231
|
-
insertion:
|
|
232
|
-
onDelete: (insertion:
|
|
240
|
+
insertion: InsertionClass;
|
|
241
|
+
onDelete: (insertion: InsertionClass) => void;
|
|
233
242
|
}> = ({ insertion, onDelete }) => {
|
|
234
243
|
const backgroundColor = singleGraphColorRGBByName('teal', 0.3);
|
|
235
244
|
const textColor = singleGraphColorRGBByName('teal', 1);
|
|
@@ -244,8 +253,8 @@ const SelectedAminoAcidInsertion: FunctionComponent<{
|
|
|
244
253
|
};
|
|
245
254
|
|
|
246
255
|
const SelectedAminoAcidMutation: FunctionComponent<{
|
|
247
|
-
mutation:
|
|
248
|
-
onDelete: (mutation:
|
|
256
|
+
mutation: SubstitutionClass | DeletionClass;
|
|
257
|
+
onDelete: (mutation: SubstitutionClass | DeletionClass) => void;
|
|
249
258
|
}> = ({ mutation, onDelete }) => {
|
|
250
259
|
const backgroundColor = singleGraphColorRGBByName('rose', 0.3);
|
|
251
260
|
const textColor = singleGraphColorRGBByName('rose', 1);
|
|
@@ -260,8 +269,8 @@ const SelectedAminoAcidMutation: FunctionComponent<{
|
|
|
260
269
|
};
|
|
261
270
|
|
|
262
271
|
const SelectedNucleotideMutation: FunctionComponent<{
|
|
263
|
-
mutation:
|
|
264
|
-
onDelete: (insertion:
|
|
272
|
+
mutation: SubstitutionClass | DeletionClass;
|
|
273
|
+
onDelete: (insertion: SubstitutionClass | DeletionClass) => void;
|
|
265
274
|
}> = ({ mutation, onDelete }) => {
|
|
266
275
|
const backgroundColor = singleGraphColorRGBByName('indigo', 0.3);
|
|
267
276
|
const textColor = singleGraphColorRGBByName('indigo', 1);
|
|
@@ -276,8 +285,8 @@ const SelectedNucleotideMutation: FunctionComponent<{
|
|
|
276
285
|
};
|
|
277
286
|
|
|
278
287
|
const SelectedNucleotideInsertion: FunctionComponent<{
|
|
279
|
-
insertion:
|
|
280
|
-
onDelete: (insertion:
|
|
288
|
+
insertion: InsertionClass;
|
|
289
|
+
onDelete: (insertion: InsertionClass) => void;
|
|
281
290
|
}> = ({ insertion, onDelete }) => {
|
|
282
291
|
const backgroundColor = singleGraphColorRGBByName('green', 0.3);
|
|
283
292
|
const textColor = singleGraphColorRGBByName('green', 1);
|
|
@@ -292,14 +301,14 @@ const SelectedNucleotideInsertion: FunctionComponent<{
|
|
|
292
301
|
);
|
|
293
302
|
};
|
|
294
303
|
|
|
295
|
-
type SelectedFilterProps<MutationType extends
|
|
304
|
+
type SelectedFilterProps<MutationType extends MutationClass> = {
|
|
296
305
|
mutation: MutationType;
|
|
297
306
|
onDelete: (mutation: MutationType) => void;
|
|
298
307
|
backgroundColor: string;
|
|
299
308
|
textColor: string;
|
|
300
309
|
};
|
|
301
310
|
|
|
302
|
-
const SelectedFilter = <MutationType extends
|
|
311
|
+
const SelectedFilter = <MutationType extends MutationClass>({
|
|
303
312
|
mutation,
|
|
304
313
|
onDelete,
|
|
305
314
|
backgroundColor,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type SelectedFilters } from './mutation-filter';
|
|
2
2
|
import { sequenceTypeFromSegment } from './sequenceTypeFromSegment';
|
|
3
3
|
import type { ReferenceGenome } from '../../lapisApi/ReferenceGenome';
|
|
4
|
-
import {
|
|
4
|
+
import { DeletionClass, InsertionClass, SubstitutionClass } from '../../utils/mutations';
|
|
5
5
|
|
|
6
6
|
type ParsedMutationFilter = {
|
|
7
7
|
[MutationType in keyof SelectedFilters]: { type: MutationType; value: SelectedFilters[MutationType][number] };
|
|
@@ -11,7 +11,7 @@ export const parseAndValidateMutation = (
|
|
|
11
11
|
value: string,
|
|
12
12
|
referenceGenome: ReferenceGenome,
|
|
13
13
|
): ParsedMutationFilter | null => {
|
|
14
|
-
const possibleInsertion =
|
|
14
|
+
const possibleInsertion = InsertionClass.parse(value);
|
|
15
15
|
if (possibleInsertion !== null) {
|
|
16
16
|
const sequenceType = sequenceTypeFromSegment(possibleInsertion.segment, referenceGenome);
|
|
17
17
|
switch (sequenceType) {
|
|
@@ -24,7 +24,7 @@ export const parseAndValidateMutation = (
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
const possibleDeletion =
|
|
27
|
+
const possibleDeletion = DeletionClass.parse(value);
|
|
28
28
|
if (possibleDeletion !== null) {
|
|
29
29
|
const sequenceType = sequenceTypeFromSegment(possibleDeletion.segment, referenceGenome);
|
|
30
30
|
switch (sequenceType) {
|
|
@@ -37,7 +37,7 @@ export const parseAndValidateMutation = (
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
const possibleSubstitution =
|
|
40
|
+
const possibleSubstitution = SubstitutionClass.parse(value);
|
|
41
41
|
if (possibleSubstitution !== null) {
|
|
42
42
|
const sequenceType = sequenceTypeFromSegment(possibleSubstitution.segment, referenceGenome);
|
|
43
43
|
switch (sequenceType) {
|