@genspectrum/dashboard-components 0.6.19 → 0.7.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.
- package/custom-elements.json +18 -18
- package/dist/assets/mutationOverTimeWorker-BOCXtKzd.js.map +1 -0
- package/dist/dashboard-components.js +296 -302
- package/dist/dashboard-components.js.map +1 -1
- package/dist/genspectrum-components.d.ts +98 -48
- package/package.json +1 -3
- package/src/index.ts +1 -0
- package/src/preact/aggregatedData/aggregate.tsx +41 -33
- 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/mutation-comparison.tsx +32 -34
- package/src/preact/mutations/mutations.tsx +63 -56
- package/src/preact/mutationsOverTime/MutationOverTimeData.ts +20 -0
- package/src/preact/mutationsOverTime/getFilteredMutationsOverTime.spec.ts +2 -3
- package/src/preact/mutationsOverTime/getFilteredMutationsOverTimeData.ts +2 -2
- package/src/preact/mutationsOverTime/mutations-over-time-grid.tsx +3 -3
- package/src/preact/mutationsOverTime/mutations-over-time.tsx +40 -43
- package/src/preact/numberSequencesOverTime/number-sequences-over-time.tsx +46 -64
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.tsx +29 -36
- package/src/query/queryMutationsOverTime.ts +3 -5
- package/src/utils/map2d.spec.ts +52 -13
- package/src/utils/map2d.ts +3 -4
- 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/standalone-bundle/dashboard-components.js +14322 -15115
- package/standalone-bundle/dashboard-components.js.map +1 -1
- package/dist/assets/mutationOverTimeWorker-BdzqDqvO.js.map +0 -1
|
@@ -15,7 +15,7 @@ import { CsvDownloadButton } from '../components/csv-download-button';
|
|
|
15
15
|
import { ErrorBoundary } from '../components/error-boundary';
|
|
16
16
|
import { ErrorDisplay } from '../components/error-display';
|
|
17
17
|
import { Fullscreen } from '../components/fullscreen';
|
|
18
|
-
import Info, { InfoHeadline1, InfoParagraph } from '../components/info';
|
|
18
|
+
import Info, { InfoComponentCode, InfoHeadline1, InfoParagraph } from '../components/info';
|
|
19
19
|
import { LoadingDisplay } from '../components/loading-display';
|
|
20
20
|
import { NoDataDisplay } from '../components/no-data-display';
|
|
21
21
|
import { ResizeContainer } from '../components/resize-container';
|
|
@@ -26,12 +26,9 @@ import { useQuery } from '../useQuery';
|
|
|
26
26
|
|
|
27
27
|
type NumberSequencesOverTimeView = 'bar' | 'line' | 'table';
|
|
28
28
|
|
|
29
|
-
export interface NumberSequencesOverTimeProps
|
|
29
|
+
export interface NumberSequencesOverTimeProps {
|
|
30
30
|
width: string;
|
|
31
31
|
height: string;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
interface NumberSequencesOverTimeInnerProps {
|
|
35
32
|
lapisFilter: NamedLapisFilter | NamedLapisFilter[];
|
|
36
33
|
lapisDateField: string;
|
|
37
34
|
views: NumberSequencesOverTimeView[];
|
|
@@ -40,26 +37,21 @@ interface NumberSequencesOverTimeInnerProps {
|
|
|
40
37
|
pageSize: boolean | number;
|
|
41
38
|
}
|
|
42
39
|
|
|
43
|
-
export const NumberSequencesOverTime = (
|
|
40
|
+
export const NumberSequencesOverTime = (componentProps: NumberSequencesOverTimeProps) => {
|
|
41
|
+
const { width, height } = componentProps;
|
|
44
42
|
const size = { height, width };
|
|
45
43
|
|
|
46
44
|
return (
|
|
47
45
|
<ErrorBoundary size={size}>
|
|
48
46
|
<ResizeContainer size={size}>
|
|
49
|
-
<NumberSequencesOverTimeInner {...
|
|
47
|
+
<NumberSequencesOverTimeInner {...componentProps} />
|
|
50
48
|
</ResizeContainer>
|
|
51
49
|
</ErrorBoundary>
|
|
52
50
|
);
|
|
53
51
|
};
|
|
54
52
|
|
|
55
|
-
const NumberSequencesOverTimeInner = ({
|
|
56
|
-
lapisFilter,
|
|
57
|
-
granularity,
|
|
58
|
-
smoothingWindow,
|
|
59
|
-
lapisDateField,
|
|
60
|
-
views,
|
|
61
|
-
pageSize,
|
|
62
|
-
}: NumberSequencesOverTimeInnerProps) => {
|
|
53
|
+
const NumberSequencesOverTimeInner = (componentProps: NumberSequencesOverTimeProps) => {
|
|
54
|
+
const { lapisFilter, lapisDateField, granularity, smoothingWindow } = componentProps;
|
|
63
55
|
const lapis = useContext(LapisUrlContext);
|
|
64
56
|
|
|
65
57
|
const { data, error, isLoading } = useQuery(
|
|
@@ -79,32 +71,15 @@ const NumberSequencesOverTimeInner = ({
|
|
|
79
71
|
return <NoDataDisplay />;
|
|
80
72
|
}
|
|
81
73
|
|
|
82
|
-
return
|
|
83
|
-
<NumberSequencesOverTimeTabs
|
|
84
|
-
views={views}
|
|
85
|
-
data={data}
|
|
86
|
-
granularity={granularity}
|
|
87
|
-
smoothingWindow={smoothingWindow}
|
|
88
|
-
pageSize={pageSize}
|
|
89
|
-
/>
|
|
90
|
-
);
|
|
74
|
+
return <NumberSequencesOverTimeTabs data={data} originalComponentProps={componentProps} />;
|
|
91
75
|
};
|
|
92
76
|
|
|
93
77
|
interface NumberSequencesOverTimeTabsProps {
|
|
94
|
-
views: NumberSequencesOverTimeView[];
|
|
95
78
|
data: NumberOfSequencesDatasets;
|
|
96
|
-
|
|
97
|
-
smoothingWindow: number;
|
|
98
|
-
pageSize: boolean | number;
|
|
79
|
+
originalComponentProps: NumberSequencesOverTimeProps;
|
|
99
80
|
}
|
|
100
81
|
|
|
101
|
-
const NumberSequencesOverTimeTabs = ({
|
|
102
|
-
views,
|
|
103
|
-
data,
|
|
104
|
-
granularity,
|
|
105
|
-
smoothingWindow,
|
|
106
|
-
pageSize,
|
|
107
|
-
}: NumberSequencesOverTimeTabsProps) => {
|
|
82
|
+
const NumberSequencesOverTimeTabs = ({ data, originalComponentProps }: NumberSequencesOverTimeTabsProps) => {
|
|
108
83
|
const [yAxisScaleType, setYAxisScaleType] = useState<ScaleType>('linear');
|
|
109
84
|
|
|
110
85
|
const getTab = (view: NumberSequencesOverTimeView) => {
|
|
@@ -122,7 +97,13 @@ const NumberSequencesOverTimeTabs = ({
|
|
|
122
97
|
case 'table':
|
|
123
98
|
return {
|
|
124
99
|
title: 'Table',
|
|
125
|
-
content:
|
|
100
|
+
content: (
|
|
101
|
+
<NumberSequencesOverTimeTable
|
|
102
|
+
data={data}
|
|
103
|
+
granularity={originalComponentProps.granularity}
|
|
104
|
+
pageSize={originalComponentProps.pageSize}
|
|
105
|
+
/>
|
|
106
|
+
),
|
|
126
107
|
};
|
|
127
108
|
default:
|
|
128
109
|
throw new Error(`Unknown view: ${view}`);
|
|
@@ -131,15 +112,14 @@ const NumberSequencesOverTimeTabs = ({
|
|
|
131
112
|
|
|
132
113
|
return (
|
|
133
114
|
<Tabs
|
|
134
|
-
tabs={views.map((view) => getTab(view))}
|
|
115
|
+
tabs={originalComponentProps.views.map((view) => getTab(view))}
|
|
135
116
|
toolbar={(activeTab) => (
|
|
136
117
|
<Toolbar
|
|
137
118
|
activeTab={activeTab}
|
|
138
119
|
data={data}
|
|
139
|
-
granularity={granularity}
|
|
140
|
-
smoothingWindow={smoothingWindow}
|
|
141
120
|
yAxisScaleType={yAxisScaleType}
|
|
142
121
|
setYAxisScaleType={setYAxisScaleType}
|
|
122
|
+
originalComponentProps={originalComponentProps}
|
|
143
123
|
/>
|
|
144
124
|
)}
|
|
145
125
|
/>
|
|
@@ -149,20 +129,12 @@ const NumberSequencesOverTimeTabs = ({
|
|
|
149
129
|
interface ToolbarProps {
|
|
150
130
|
activeTab: string;
|
|
151
131
|
data: NumberOfSequencesDatasets;
|
|
152
|
-
granularity: TemporalGranularity;
|
|
153
132
|
yAxisScaleType: ScaleType;
|
|
154
133
|
setYAxisScaleType: (scaleType: ScaleType) => void;
|
|
155
|
-
|
|
134
|
+
originalComponentProps: NumberSequencesOverTimeProps;
|
|
156
135
|
}
|
|
157
136
|
|
|
158
|
-
const Toolbar = ({
|
|
159
|
-
activeTab,
|
|
160
|
-
data,
|
|
161
|
-
granularity,
|
|
162
|
-
yAxisScaleType,
|
|
163
|
-
setYAxisScaleType,
|
|
164
|
-
smoothingWindow,
|
|
165
|
-
}: ToolbarProps) => {
|
|
137
|
+
const Toolbar = ({ activeTab, data, yAxisScaleType, setYAxisScaleType, originalComponentProps }: ToolbarProps) => {
|
|
166
138
|
return (
|
|
167
139
|
<>
|
|
168
140
|
{activeTab !== 'Table' && (
|
|
@@ -174,29 +146,39 @@ const Toolbar = ({
|
|
|
174
146
|
)}
|
|
175
147
|
<CsvDownloadButton
|
|
176
148
|
className='mx-1 btn btn-xs'
|
|
177
|
-
getData={() => getNumberOfSequencesOverTimeTableData(data, granularity)}
|
|
149
|
+
getData={() => getNumberOfSequencesOverTimeTableData(data, originalComponentProps.granularity)}
|
|
178
150
|
filename='number_of_sequences_over_time.csv'
|
|
179
151
|
/>
|
|
180
|
-
<NumberSequencesOverTimeInfo
|
|
152
|
+
<NumberSequencesOverTimeInfo originalComponentProps={originalComponentProps} />
|
|
181
153
|
<Fullscreen />
|
|
182
154
|
</>
|
|
183
155
|
);
|
|
184
156
|
};
|
|
185
157
|
|
|
186
158
|
type NumberSequencesOverTimeInfoProps = {
|
|
187
|
-
|
|
188
|
-
smoothingWindow: number;
|
|
159
|
+
originalComponentProps: NumberSequencesOverTimeProps;
|
|
189
160
|
};
|
|
190
161
|
|
|
191
162
|
const NumberSequencesOverTimeInfo: FunctionComponent<NumberSequencesOverTimeInfoProps> = ({
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
<
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
163
|
+
originalComponentProps,
|
|
164
|
+
}) => {
|
|
165
|
+
const lapis = useContext(LapisUrlContext);
|
|
166
|
+
|
|
167
|
+
return (
|
|
168
|
+
<Info>
|
|
169
|
+
<InfoHeadline1>Number of sequences over time</InfoHeadline1>
|
|
170
|
+
<InfoParagraph>
|
|
171
|
+
This presents the number of available sequences of a variant per{' '}
|
|
172
|
+
<b>{originalComponentProps.granularity}</b>
|
|
173
|
+
{originalComponentProps.smoothingWindow > 0 &&
|
|
174
|
+
`, smoothed using a ${originalComponentProps.smoothingWindow}-${originalComponentProps.granularity} sliding window`}
|
|
175
|
+
.
|
|
176
|
+
</InfoParagraph>
|
|
177
|
+
<InfoComponentCode
|
|
178
|
+
componentName='number-sequences-over-time'
|
|
179
|
+
params={originalComponentProps}
|
|
180
|
+
lapisUrl={lapis}
|
|
181
|
+
/>
|
|
182
|
+
</Info>
|
|
183
|
+
);
|
|
184
|
+
};
|
|
@@ -11,7 +11,7 @@ import { LapisUrlContext } from '../LapisUrlContext';
|
|
|
11
11
|
import { ErrorBoundary } from '../components/error-boundary';
|
|
12
12
|
import { ErrorDisplay } from '../components/error-display';
|
|
13
13
|
import { Fullscreen } from '../components/fullscreen';
|
|
14
|
-
import Info, { InfoHeadline1, InfoHeadline2, InfoLink, InfoParagraph } from '../components/info';
|
|
14
|
+
import Info, { InfoComponentCode, InfoHeadline1, InfoHeadline2, InfoLink, InfoParagraph } from '../components/info';
|
|
15
15
|
import { LoadingDisplay } from '../components/loading-display';
|
|
16
16
|
import { NoDataDisplay } from '../components/no-data-display';
|
|
17
17
|
import { ResizeContainer } from '../components/resize-container';
|
|
@@ -23,12 +23,9 @@ import { useQuery } from '../useQuery';
|
|
|
23
23
|
|
|
24
24
|
export type View = 'line';
|
|
25
25
|
|
|
26
|
-
export interface RelativeGrowthAdvantageProps
|
|
26
|
+
export interface RelativeGrowthAdvantageProps {
|
|
27
27
|
width: string;
|
|
28
28
|
height: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface RelativeGrowthAdvantagePropsInner {
|
|
32
29
|
numeratorFilter: LapisFilter;
|
|
33
30
|
denominatorFilter: LapisFilter;
|
|
34
31
|
generationTime: number;
|
|
@@ -37,36 +34,28 @@ export interface RelativeGrowthAdvantagePropsInner {
|
|
|
37
34
|
yAxisMaxConfig: YAxisMaxConfig;
|
|
38
35
|
}
|
|
39
36
|
|
|
40
|
-
export const RelativeGrowthAdvantage: FunctionComponent<RelativeGrowthAdvantageProps> = ({
|
|
41
|
-
width,
|
|
42
|
-
height,
|
|
43
|
-
...innerProps
|
|
44
|
-
}) => {
|
|
37
|
+
export const RelativeGrowthAdvantage: FunctionComponent<RelativeGrowthAdvantageProps> = (componentProps) => {
|
|
38
|
+
const { width, height } = componentProps;
|
|
45
39
|
const size = { height, width };
|
|
46
40
|
|
|
47
41
|
return (
|
|
48
42
|
<ErrorBoundary size={size}>
|
|
49
43
|
<ResizeContainer size={size}>
|
|
50
|
-
<RelativeGrowthAdvantageInner {...
|
|
44
|
+
<RelativeGrowthAdvantageInner {...componentProps} />
|
|
51
45
|
</ResizeContainer>
|
|
52
46
|
</ErrorBoundary>
|
|
53
47
|
);
|
|
54
48
|
};
|
|
55
49
|
|
|
56
|
-
export const RelativeGrowthAdvantageInner: FunctionComponent<
|
|
57
|
-
numeratorFilter,
|
|
58
|
-
denominatorFilter,
|
|
59
|
-
generationTime,
|
|
60
|
-
views,
|
|
61
|
-
lapisDateField,
|
|
62
|
-
yAxisMaxConfig,
|
|
63
|
-
}) => {
|
|
50
|
+
export const RelativeGrowthAdvantageInner: FunctionComponent<RelativeGrowthAdvantageProps> = (componentProps) => {
|
|
64
51
|
const lapis = useContext(LapisUrlContext);
|
|
52
|
+
const { numeratorFilter, denominatorFilter, generationTime, lapisDateField } = componentProps;
|
|
53
|
+
|
|
65
54
|
const [yAxisScaleType, setYAxisScaleType] = useState<ScaleType>('linear');
|
|
66
55
|
|
|
67
56
|
const { data, error, isLoading } = useQuery(
|
|
68
57
|
() => queryRelativeGrowthAdvantage(numeratorFilter, denominatorFilter, generationTime, lapis, lapisDateField),
|
|
69
|
-
[lapis, numeratorFilter, denominatorFilter, generationTime,
|
|
58
|
+
[lapis, numeratorFilter, denominatorFilter, generationTime, lapisDateField],
|
|
70
59
|
);
|
|
71
60
|
|
|
72
61
|
if (isLoading) {
|
|
@@ -86,9 +75,7 @@ export const RelativeGrowthAdvantageInner: FunctionComponent<RelativeGrowthAdvan
|
|
|
86
75
|
data={data}
|
|
87
76
|
yAxisScaleType={yAxisScaleType}
|
|
88
77
|
setYAxisScaleType={setYAxisScaleType}
|
|
89
|
-
|
|
90
|
-
generationTime={generationTime}
|
|
91
|
-
yAxisMaxConfig={yAxisMaxConfig}
|
|
78
|
+
originalComponentProps={componentProps}
|
|
92
79
|
/>
|
|
93
80
|
);
|
|
94
81
|
};
|
|
@@ -97,18 +84,14 @@ type RelativeGrowthAdvantageTabsProps = {
|
|
|
97
84
|
data: NonNullable<RelativeGrowthAdvantageData>;
|
|
98
85
|
yAxisScaleType: ScaleType;
|
|
99
86
|
setYAxisScaleType: (scaleType: ScaleType) => void;
|
|
100
|
-
|
|
101
|
-
generationTime: number;
|
|
102
|
-
yAxisMaxConfig: YAxisMaxConfig;
|
|
87
|
+
originalComponentProps: RelativeGrowthAdvantageProps;
|
|
103
88
|
};
|
|
104
89
|
|
|
105
90
|
const RelativeGrowthAdvantageTabs: FunctionComponent<RelativeGrowthAdvantageTabsProps> = ({
|
|
106
91
|
data,
|
|
107
92
|
yAxisScaleType,
|
|
108
93
|
setYAxisScaleType,
|
|
109
|
-
|
|
110
|
-
generationTime,
|
|
111
|
-
yAxisMaxConfig,
|
|
94
|
+
originalComponentProps,
|
|
112
95
|
}) => {
|
|
113
96
|
const getTab = (view: View) => {
|
|
114
97
|
switch (view) {
|
|
@@ -123,17 +106,17 @@ const RelativeGrowthAdvantageTabs: FunctionComponent<RelativeGrowthAdvantageTabs
|
|
|
123
106
|
params: data.params,
|
|
124
107
|
}}
|
|
125
108
|
yAxisScaleType={yAxisScaleType}
|
|
126
|
-
yAxisMaxConfig={yAxisMaxConfig}
|
|
109
|
+
yAxisMaxConfig={originalComponentProps.yAxisMaxConfig}
|
|
127
110
|
/>
|
|
128
111
|
),
|
|
129
112
|
};
|
|
130
113
|
}
|
|
131
114
|
};
|
|
132
115
|
|
|
133
|
-
const tabs = views.map((view) => getTab(view));
|
|
116
|
+
const tabs = originalComponentProps.views.map((view) => getTab(view));
|
|
134
117
|
const toolbar = () => (
|
|
135
118
|
<RelativeGrowthAdvantageToolbar
|
|
136
|
-
|
|
119
|
+
originalComponentProps={originalComponentProps}
|
|
137
120
|
yAxisScaleType={yAxisScaleType}
|
|
138
121
|
setYAxisScaleType={setYAxisScaleType}
|
|
139
122
|
/>
|
|
@@ -145,24 +128,29 @@ const RelativeGrowthAdvantageTabs: FunctionComponent<RelativeGrowthAdvantageTabs
|
|
|
145
128
|
type RelativeGrowthAdvantageToolbarProps = {
|
|
146
129
|
yAxisScaleType: ScaleType;
|
|
147
130
|
setYAxisScaleType: (scaleType: ScaleType) => void;
|
|
148
|
-
|
|
131
|
+
originalComponentProps: RelativeGrowthAdvantageProps;
|
|
149
132
|
};
|
|
150
133
|
|
|
151
134
|
const RelativeGrowthAdvantageToolbar: FunctionComponent<RelativeGrowthAdvantageToolbarProps> = ({
|
|
152
135
|
yAxisScaleType,
|
|
153
136
|
setYAxisScaleType,
|
|
154
|
-
|
|
137
|
+
originalComponentProps,
|
|
155
138
|
}) => {
|
|
156
139
|
return (
|
|
157
140
|
<>
|
|
158
141
|
<ScalingSelector yAxisScaleType={yAxisScaleType} setYAxisScaleType={setYAxisScaleType} />
|
|
159
|
-
<RelativeGrowthAdvantageInfo
|
|
142
|
+
<RelativeGrowthAdvantageInfo originalComponentProps={originalComponentProps} />
|
|
160
143
|
<Fullscreen />
|
|
161
144
|
</>
|
|
162
145
|
);
|
|
163
146
|
};
|
|
164
147
|
|
|
165
|
-
const RelativeGrowthAdvantageInfo: FunctionComponent<{
|
|
148
|
+
const RelativeGrowthAdvantageInfo: FunctionComponent<{ originalComponentProps: RelativeGrowthAdvantageProps }> = ({
|
|
149
|
+
originalComponentProps,
|
|
150
|
+
}) => {
|
|
151
|
+
const lapis = useContext(LapisUrlContext);
|
|
152
|
+
const generationTime = originalComponentProps.generationTime;
|
|
153
|
+
|
|
166
154
|
return (
|
|
167
155
|
<Info>
|
|
168
156
|
<InfoHeadline1>Relative growth advantage</InfoHeadline1>
|
|
@@ -193,6 +181,11 @@ const RelativeGrowthAdvantageInfo: FunctionComponent<{ generationTime: number }>
|
|
|
193
181
|
10.1016/j.epidem.2021.100480
|
|
194
182
|
</InfoLink>
|
|
195
183
|
</InfoParagraph>
|
|
184
|
+
<InfoComponentCode
|
|
185
|
+
componentName='relative-growth-advantage'
|
|
186
|
+
params={originalComponentProps}
|
|
187
|
+
lapisUrl={lapis}
|
|
188
|
+
/>
|
|
196
189
|
</Info>
|
|
197
190
|
);
|
|
198
191
|
};
|
|
@@ -6,6 +6,7 @@ import { MapOperator } from '../operator/MapOperator';
|
|
|
6
6
|
import { RenameFieldOperator } from '../operator/RenameFieldOperator';
|
|
7
7
|
import { SortOperator } from '../operator/SortOperator';
|
|
8
8
|
import { UserFacingError } from '../preact/components/error-display';
|
|
9
|
+
import { BaseMutationOverTimeDataMap } from '../preact/mutationsOverTime/MutationOverTimeData';
|
|
9
10
|
import { sortSubstitutionsAndDeletions } from '../preact/shared/sort/sortSubstitutionsAndDeletions';
|
|
10
11
|
import {
|
|
11
12
|
type DeletionEntry,
|
|
@@ -15,7 +16,7 @@ import {
|
|
|
15
16
|
type SubstitutionOrDeletionEntry,
|
|
16
17
|
type TemporalGranularity,
|
|
17
18
|
} from '../types';
|
|
18
|
-
import { type Map2d
|
|
19
|
+
import { type Map2d } from '../utils/map2d';
|
|
19
20
|
import {
|
|
20
21
|
type Deletion,
|
|
21
22
|
type DeletionClass,
|
|
@@ -218,10 +219,7 @@ export function groupByMutation(
|
|
|
218
219
|
data: MutationOverTimeData[],
|
|
219
220
|
overallMutationData: (SubstitutionEntry | DeletionEntry)[],
|
|
220
221
|
) {
|
|
221
|
-
const dataArray = new
|
|
222
|
-
serializeSubstitutionOrDeletion,
|
|
223
|
-
serializeTemporal,
|
|
224
|
-
);
|
|
222
|
+
const dataArray = new BaseMutationOverTimeDataMap();
|
|
225
223
|
|
|
226
224
|
const allDates = data.map((mutationData) => mutationData.date);
|
|
227
225
|
|
package/src/utils/map2d.spec.ts
CHANGED
|
@@ -4,20 +4,29 @@ import { Map2dBase, Map2dView } from './map2d';
|
|
|
4
4
|
|
|
5
5
|
describe('Map2dBase', () => {
|
|
6
6
|
it('should add a value and return it', () => {
|
|
7
|
-
const map2d = new Map2dBase<string, string, number>(
|
|
7
|
+
const map2d = new Map2dBase<string, string, number>(
|
|
8
|
+
(value) => value,
|
|
9
|
+
(value) => value,
|
|
10
|
+
);
|
|
8
11
|
map2d.set('a', 'b', 2);
|
|
9
12
|
expect(map2d.get('a', 'b')).toBe(2);
|
|
10
13
|
});
|
|
11
14
|
|
|
12
15
|
it('should update a value', () => {
|
|
13
|
-
const map2d = new Map2dBase<string, string, number>(
|
|
16
|
+
const map2d = new Map2dBase<string, string, number>(
|
|
17
|
+
(value) => value,
|
|
18
|
+
(value) => value,
|
|
19
|
+
);
|
|
14
20
|
map2d.set('a', 'b', 2);
|
|
15
21
|
map2d.set('a', 'b', 3);
|
|
16
22
|
expect(map2d.get('a', 'b')).toBe(3);
|
|
17
23
|
});
|
|
18
24
|
|
|
19
25
|
it('should return the data as an array', () => {
|
|
20
|
-
const map2d = new Map2dBase<string, string, number>(
|
|
26
|
+
const map2d = new Map2dBase<string, string, number>(
|
|
27
|
+
(value) => value,
|
|
28
|
+
(value) => value,
|
|
29
|
+
);
|
|
21
30
|
map2d.set('a', 'b', 1);
|
|
22
31
|
map2d.set('a', 'd', 2);
|
|
23
32
|
map2d.set('c', 'b', 3);
|
|
@@ -30,7 +39,10 @@ describe('Map2dBase', () => {
|
|
|
30
39
|
});
|
|
31
40
|
|
|
32
41
|
it('should fill empty values with the given value', () => {
|
|
33
|
-
const map2d = new Map2dBase<string, string, number>(
|
|
42
|
+
const map2d = new Map2dBase<string, string, number>(
|
|
43
|
+
(value) => value,
|
|
44
|
+
(value) => value,
|
|
45
|
+
);
|
|
34
46
|
map2d.set('a', 'b', 2);
|
|
35
47
|
map2d.set('c', 'd', 4);
|
|
36
48
|
expect(map2d.getAsArray(0)).toEqual([
|
|
@@ -40,7 +52,10 @@ describe('Map2dBase', () => {
|
|
|
40
52
|
});
|
|
41
53
|
|
|
42
54
|
it('should return the keys from the first axis', () => {
|
|
43
|
-
const map2d = new Map2dBase<string, string, number>(
|
|
55
|
+
const map2d = new Map2dBase<string, string, number>(
|
|
56
|
+
(value) => value,
|
|
57
|
+
(value) => value,
|
|
58
|
+
);
|
|
44
59
|
map2d.set('a', 'b', 2);
|
|
45
60
|
map2d.set('c', 'd', 4);
|
|
46
61
|
|
|
@@ -48,7 +63,10 @@ describe('Map2dBase', () => {
|
|
|
48
63
|
});
|
|
49
64
|
|
|
50
65
|
it('should return the keys from the second axis', () => {
|
|
51
|
-
const map2d = new Map2dBase<string, string, number>(
|
|
66
|
+
const map2d = new Map2dBase<string, string, number>(
|
|
67
|
+
(value) => value,
|
|
68
|
+
(value) => value,
|
|
69
|
+
);
|
|
52
70
|
map2d.set('a', 'b', 2);
|
|
53
71
|
map2d.set('c', 'd', 4);
|
|
54
72
|
|
|
@@ -56,7 +74,10 @@ describe('Map2dBase', () => {
|
|
|
56
74
|
});
|
|
57
75
|
|
|
58
76
|
it('should work with objects as keys', () => {
|
|
59
|
-
const map2d = new Map2dBase<{ a: string }, { b: string }, number>(
|
|
77
|
+
const map2d = new Map2dBase<{ a: string }, { b: string }, number>(
|
|
78
|
+
({ a }) => a,
|
|
79
|
+
({ b }) => b,
|
|
80
|
+
);
|
|
60
81
|
map2d.set({ a: 'a' }, { b: 'b' }, 2);
|
|
61
82
|
map2d.set({ a: 'second' }, { b: 'second' }, 3);
|
|
62
83
|
|
|
@@ -65,14 +86,20 @@ describe('Map2dBase', () => {
|
|
|
65
86
|
});
|
|
66
87
|
|
|
67
88
|
it('should update a value with objects as keys', () => {
|
|
68
|
-
const map2d = new Map2dBase<{ a: string }, { b: string }, number>(
|
|
89
|
+
const map2d = new Map2dBase<{ a: string }, { b: string }, number>(
|
|
90
|
+
({ a }) => a,
|
|
91
|
+
({ b }) => b,
|
|
92
|
+
);
|
|
69
93
|
map2d.set({ a: 'a' }, { b: 'b' }, 2);
|
|
70
94
|
map2d.set({ a: 'a' }, { b: 'b' }, 3);
|
|
71
95
|
expect(map2d.get({ a: 'a' }, { b: 'b' })).toBe(3);
|
|
72
96
|
});
|
|
73
97
|
|
|
74
98
|
it('should return a row by key', () => {
|
|
75
|
-
const map2d = new Map2dBase<string, string, number>(
|
|
99
|
+
const map2d = new Map2dBase<string, string, number>(
|
|
100
|
+
(value) => value,
|
|
101
|
+
(value) => value,
|
|
102
|
+
);
|
|
76
103
|
map2d.set('a', 'b', 2);
|
|
77
104
|
map2d.set('c', 'd', 4);
|
|
78
105
|
|
|
@@ -81,14 +108,20 @@ describe('Map2dBase', () => {
|
|
|
81
108
|
});
|
|
82
109
|
|
|
83
110
|
it('should return an empty array when the row does not exist', () => {
|
|
84
|
-
const map2d = new Map2dBase<string, string, number>(
|
|
111
|
+
const map2d = new Map2dBase<string, string, number>(
|
|
112
|
+
(value) => value,
|
|
113
|
+
(value) => value,
|
|
114
|
+
);
|
|
85
115
|
map2d.set('a', 'b', 2);
|
|
86
116
|
|
|
87
117
|
expect(map2d.getRow('c', 0)).toEqual([]);
|
|
88
118
|
});
|
|
89
119
|
|
|
90
120
|
it('should return content as object', () => {
|
|
91
|
-
const map2d = new Map2dBase<string, string, number>(
|
|
121
|
+
const map2d = new Map2dBase<string, string, number>(
|
|
122
|
+
(value) => value,
|
|
123
|
+
(value) => value,
|
|
124
|
+
);
|
|
92
125
|
map2d.set('a', 'b', 2);
|
|
93
126
|
map2d.set('c', 'd', 4);
|
|
94
127
|
|
|
@@ -99,7 +132,10 @@ describe('Map2dBase', () => {
|
|
|
99
132
|
});
|
|
100
133
|
|
|
101
134
|
it('should use initial data', () => {
|
|
102
|
-
const map2d = new Map2dBase<string, string, number>(
|
|
135
|
+
const map2d = new Map2dBase<string, string, number>(
|
|
136
|
+
(value) => value,
|
|
137
|
+
(value) => value,
|
|
138
|
+
);
|
|
103
139
|
map2d.set('a', 'b', 2);
|
|
104
140
|
map2d.set('c', 'd', 4);
|
|
105
141
|
|
|
@@ -174,7 +210,10 @@ describe('Map2dView', () => {
|
|
|
174
210
|
});
|
|
175
211
|
|
|
176
212
|
function createBaseContainer() {
|
|
177
|
-
const container = new Map2dBase<string, string, number>(
|
|
213
|
+
const container = new Map2dBase<string, string, number>(
|
|
214
|
+
(value) => value,
|
|
215
|
+
(value) => value,
|
|
216
|
+
);
|
|
178
217
|
container.set('a', 'b', 1);
|
|
179
218
|
container.set('c', 'b', 3);
|
|
180
219
|
container.set('c', 'd', 4);
|
package/src/utils/map2d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import hash from 'object-hash';
|
|
2
|
-
|
|
3
1
|
export interface Map2d<Key1, Key2, Value> {
|
|
4
2
|
get(keyFirstAxis: Key1, keySecondAxis: Key2): Value | undefined;
|
|
5
3
|
|
|
@@ -16,6 +14,7 @@ export interface Map2d<Key1, Key2, Value> {
|
|
|
16
14
|
getAsArray(fillEmptyWith: Value): Value[][];
|
|
17
15
|
|
|
18
16
|
serializeFirstAxis(key: Key1): string;
|
|
17
|
+
|
|
19
18
|
serializeSecondAxis(key: Key2): string;
|
|
20
19
|
|
|
21
20
|
readonly keysFirstAxis: Map<string, Key1>;
|
|
@@ -36,8 +35,8 @@ export class Map2dBase<Key1 extends object | string, Key2 extends object | strin
|
|
|
36
35
|
readonly keysSecondAxis = new Map<string, Key2>();
|
|
37
36
|
|
|
38
37
|
constructor(
|
|
39
|
-
readonly serializeFirstAxis: (key: Key1) => string
|
|
40
|
-
readonly serializeSecondAxis: (key: Key2) => string
|
|
38
|
+
readonly serializeFirstAxis: (key: Key1) => string,
|
|
39
|
+
readonly serializeSecondAxis: (key: Key2) => string,
|
|
41
40
|
initialContent?: Map2DContents<Key1, Key2, Value>,
|
|
42
41
|
) {
|
|
43
42
|
if (initialContent) {
|
|
@@ -9,29 +9,21 @@ import { type DateRangeSelectorProps } from '../../preact/dateRangeSelector/date
|
|
|
9
9
|
import './gs-date-range-selector';
|
|
10
10
|
import '../app';
|
|
11
11
|
import { toYYYYMMDD } from '../../preact/dateRangeSelector/dateConversion';
|
|
12
|
-
import {
|
|
13
|
-
PRESET_VALUE_ALL_TIMES,
|
|
14
|
-
PRESET_VALUE_CUSTOM,
|
|
15
|
-
PRESET_VALUE_LAST_2_MONTHS,
|
|
16
|
-
PRESET_VALUE_LAST_2_WEEKS,
|
|
17
|
-
PRESET_VALUE_LAST_3_MONTHS,
|
|
18
|
-
PRESET_VALUE_LAST_6_MONTHS,
|
|
19
|
-
PRESET_VALUE_LAST_MONTH,
|
|
20
|
-
} from '../../preact/dateRangeSelector/selectableOptions';
|
|
12
|
+
import { dateRangeOptionPresets } from '../../preact/dateRangeSelector/dateRangeOption';
|
|
21
13
|
import { withinShadowRoot } from '../withinShadowRoot.story';
|
|
22
14
|
|
|
23
15
|
const codeExample = String.raw`
|
|
24
16
|
<gs-date-range-selector
|
|
25
|
-
|
|
17
|
+
dateRangeOptions='[{ "label": "Year 2021", "dateFrom": "2021-01-01", "dateTo": "2021-12-31" }]'
|
|
26
18
|
earliestDate="1970-01-01"
|
|
27
|
-
initialValue="
|
|
19
|
+
initialValue="Year 2021"
|
|
28
20
|
initialDateFrom="2020-01-01"
|
|
29
21
|
initialDateTo="2021-01-01"
|
|
30
22
|
width="100%"
|
|
31
23
|
dateColumn="myDateColumn"
|
|
32
24
|
></gs-date-range-selector>`;
|
|
33
25
|
|
|
34
|
-
const meta: Meta<Required<DateRangeSelectorProps
|
|
26
|
+
const meta: Meta<Required<DateRangeSelectorProps>> = {
|
|
35
27
|
title: 'Input/DateRangeSelector',
|
|
36
28
|
component: 'gs-date-range-selector',
|
|
37
29
|
parameters: withComponentDocs({
|
|
@@ -50,19 +42,10 @@ const meta: Meta<Required<DateRangeSelectorProps<'CustomDateRange'>>> = {
|
|
|
50
42
|
control: {
|
|
51
43
|
type: 'select',
|
|
52
44
|
},
|
|
53
|
-
options: [
|
|
54
|
-
PRESET_VALUE_CUSTOM,
|
|
55
|
-
PRESET_VALUE_ALL_TIMES,
|
|
56
|
-
PRESET_VALUE_LAST_2_WEEKS,
|
|
57
|
-
PRESET_VALUE_LAST_MONTH,
|
|
58
|
-
PRESET_VALUE_LAST_2_MONTHS,
|
|
59
|
-
PRESET_VALUE_LAST_3_MONTHS,
|
|
60
|
-
PRESET_VALUE_LAST_6_MONTHS,
|
|
61
|
-
'CustomDateRange',
|
|
62
|
-
],
|
|
45
|
+
options: [dateRangeOptionPresets.lastMonth.label, dateRangeOptionPresets.allTimes.label, 'CustomDateRange'],
|
|
63
46
|
},
|
|
64
47
|
dateColumn: { control: { type: 'text' } },
|
|
65
|
-
|
|
48
|
+
dateRangeOptions: {
|
|
66
49
|
control: {
|
|
67
50
|
type: 'object',
|
|
68
51
|
},
|
|
@@ -79,9 +62,14 @@ const meta: Meta<Required<DateRangeSelectorProps<'CustomDateRange'>>> = {
|
|
|
79
62
|
},
|
|
80
63
|
},
|
|
81
64
|
args: {
|
|
82
|
-
|
|
65
|
+
dateRangeOptions: [
|
|
66
|
+
dateRangeOptionPresets.lastMonth,
|
|
67
|
+
dateRangeOptionPresets.last3Months,
|
|
68
|
+
dateRangeOptionPresets.allTimes,
|
|
69
|
+
{ label: 'CustomDateRange', dateFrom: '2021-01-01', dateTo: '2021-12-31' },
|
|
70
|
+
],
|
|
83
71
|
earliestDate: '1970-01-01',
|
|
84
|
-
initialValue:
|
|
72
|
+
initialValue: dateRangeOptionPresets.lastMonth.label,
|
|
85
73
|
dateColumn: 'aDateColumn',
|
|
86
74
|
width: '100%',
|
|
87
75
|
initialDateFrom: '',
|
|
@@ -92,12 +80,12 @@ const meta: Meta<Required<DateRangeSelectorProps<'CustomDateRange'>>> = {
|
|
|
92
80
|
|
|
93
81
|
export default meta;
|
|
94
82
|
|
|
95
|
-
export const DateRangeSelectorStory: StoryObj<Required<DateRangeSelectorProps
|
|
83
|
+
export const DateRangeSelectorStory: StoryObj<Required<DateRangeSelectorProps>> = {
|
|
96
84
|
render: (args) =>
|
|
97
85
|
html` <gs-app lapis="${LAPIS_URL}">
|
|
98
86
|
<div class="max-w-screen-lg">
|
|
99
87
|
<gs-date-range-selector
|
|
100
|
-
.
|
|
88
|
+
.dateRangeOptions=${args.dateRangeOptions}
|
|
101
89
|
.earliestDate=${args.earliestDate}
|
|
102
90
|
.initialValue=${args.initialValue}
|
|
103
91
|
.initialDateFrom=${args.initialDateFrom}
|
|
@@ -112,7 +100,7 @@ export const DateRangeSelectorStory: StoryObj<Required<DateRangeSelectorProps<'C
|
|
|
112
100
|
const dateTo = () => canvas.getByPlaceholderText('Date to');
|
|
113
101
|
|
|
114
102
|
await step('Expect last 6 months to be selected', async () => {
|
|
115
|
-
await expect(canvas.getByRole('combobox')).toHaveValue('
|
|
103
|
+
await expect(canvas.getByRole('combobox')).toHaveValue('Last month');
|
|
116
104
|
await waitFor(() => {
|
|
117
105
|
expect(dateTo()).toHaveValue(toYYYYMMDD(new Date()));
|
|
118
106
|
});
|