@genspectrum/dashboard-components 0.14.1 → 0.15.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/custom-elements.json +90 -58
- package/dist/{LineageFilterChangedEvent-C9dXOxt6.js → LineageFilterChangedEvent-COWV-Y0k.js} +6 -6
- package/dist/LineageFilterChangedEvent-COWV-Y0k.js.map +1 -0
- package/dist/assets/mutationOverTimeWorker-BL50C-yi.js.map +1 -0
- package/dist/components.d.ts +52 -56
- package/dist/components.js +79 -58
- package/dist/components.js.map +1 -1
- package/dist/util.d.ts +49 -49
- package/dist/util.js +2 -2
- package/package.json +2 -2
- package/src/lapisApi/lapisApi.ts +1 -1
- package/src/operator/FillMissingOperator.spec.ts +1 -1
- package/src/operator/GroupByAndSumOperator.spec.ts +1 -1
- package/src/operator/GroupByOperator.spec.ts +2 -2
- package/src/operator/MapOperator.spec.ts +1 -1
- package/src/operator/MockOperator.spec.ts +1 -1
- package/src/operator/MockOperator.ts +6 -4
- package/src/operator/SortOperator.spec.ts +1 -1
- package/src/preact/aggregatedData/aggregate.stories.tsx +1 -1
- package/src/preact/components/csv-download-button.stories.tsx +2 -2
- package/src/preact/components/csv-download-button.tsx +1 -1
- package/src/preact/components/error-boundary.stories.tsx +5 -5
- package/src/preact/components/error-boundary.tsx +14 -3
- package/src/preact/components/error-display.stories.tsx +9 -9
- package/src/preact/components/fullscreen.tsx +3 -3
- package/src/preact/components/info.tsx +1 -1
- package/src/preact/components/mutation-type-selector.stories.tsx +1 -1
- package/src/preact/components/table.stories.tsx +3 -3
- package/src/preact/components/table.tsx +1 -1
- package/src/preact/{dateRangeSelector/date-range-selector.stories.tsx → dateRangeFilter/date-range-filter.stories.tsx} +18 -21
- package/src/preact/{dateRangeSelector/date-range-selector.tsx → dateRangeFilter/date-range-filter.tsx} +11 -11
- package/src/preact/{dateRangeSelector → dateRangeFilter}/dateRangeOption.ts +2 -2
- package/src/preact/lineageFilter/lineage-filter.stories.tsx +6 -6
- package/src/preact/locationFilter/fetchAutocompletionList.ts +1 -1
- package/src/preact/locationFilter/location-filter.stories.tsx +6 -6
- package/src/preact/map/sequences-by-location.stories.tsx +1 -1
- package/src/preact/mutationFilter/mutation-filter.stories.tsx +2 -2
- package/src/preact/mutations/getMutationsGridData.ts +1 -1
- package/src/preact/mutationsOverTime/mutations-over-time-grid.tsx +3 -3
- package/src/preact/mutationsOverTime/mutations-over-time.stories.tsx +1 -1
- package/src/preact/mutationsOverTime/mutations-over-time.tsx +1 -0
- package/src/preact/numberSequencesOverTime/number-sequences-over-time.stories.tsx +1 -1
- package/src/preact/prevalenceOverTime/prevalence-over-time-bubble-chart.tsx +4 -4
- package/src/preact/prevalenceOverTime/prevalence-over-time.stories.tsx +1 -1
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.stories.tsx +1 -1
- package/src/preact/shared/floating-ui/hooks.ts +1 -1
- package/src/preact/{textInput/TextInputChangedEvent.ts → textFilter/TextFilterChangedEvent.ts} +2 -2
- package/src/preact/{textInput/text-input.stories.tsx → textFilter/text-filter.stories.tsx} +14 -14
- package/src/preact/{textInput/text-input.tsx → textFilter/text-filter.tsx} +10 -10
- package/src/utilEntrypoint.ts +2 -2
- package/src/utils/map2d.ts +1 -0
- package/src/web-components/gs-app.stories.ts +7 -7
- package/src/web-components/input/{gs-date-range-selector.stories.ts → gs-date-range-filter.stories.ts} +65 -20
- package/src/web-components/input/{gs-date-range-selector.tsx → gs-date-range-filter.tsx} +28 -13
- package/src/web-components/input/gs-lineage-filter.stories.ts +1 -1
- package/src/web-components/input/gs-location-filter.stories.ts +1 -1
- package/src/web-components/input/gs-mutation-filter.stories.ts +7 -7
- package/src/web-components/input/{gs-text-input.stories.ts → gs-text-filter.stories.ts} +18 -18
- package/src/web-components/input/{gs-text-input.tsx → gs-text-filter.tsx} +16 -16
- package/src/web-components/input/index.ts +2 -2
- package/src/web-components/visualization/gs-aggregate.tsx +2 -2
- package/standalone-bundle/assets/mutationOverTimeWorker-CFB5-Mdk.js.map +1 -0
- package/standalone-bundle/dashboard-components.js +2233 -2220
- package/standalone-bundle/dashboard-components.js.map +1 -1
- package/dist/LineageFilterChangedEvent-C9dXOxt6.js.map +0 -1
- package/dist/assets/mutationOverTimeWorker-Dxnxrfe0.js.map +0 -1
- package/standalone-bundle/assets/mutationOverTimeWorker-CmSrq4SZ.js.map +0 -1
- /package/src/preact/{dateRangeSelector → dateRangeFilter}/computeInitialValues.spec.ts +0 -0
- /package/src/preact/{dateRangeSelector → dateRangeFilter}/computeInitialValues.ts +0 -0
- /package/src/preact/{dateRangeSelector → dateRangeFilter}/dateConversion.ts +0 -0
- /package/src/preact/{dateRangeSelector → dateRangeFilter}/selectableOptions.ts +0 -0
- /package/src/preact/{textInput → textFilter}/__mockData__/aggregated_hosts.json +0 -0
- /package/src/preact/{textInput → textFilter}/fetchStringAutocompleteList.spec.ts +0 -0
- /package/src/preact/{textInput → textFilter}/fetchStringAutocompleteList.ts +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type Meta, type StoryObj } from '@storybook/preact';
|
|
2
2
|
import { expect, userEvent, waitFor, within } from '@storybook/test';
|
|
3
3
|
|
|
4
|
-
import { Table } from './table';
|
|
4
|
+
import { Table, type TableProps } from './table';
|
|
5
5
|
|
|
6
6
|
const meta: Meta = {
|
|
7
7
|
title: 'Component/Table',
|
|
@@ -16,7 +16,7 @@ const meta: Meta = {
|
|
|
16
16
|
|
|
17
17
|
export default meta;
|
|
18
18
|
|
|
19
|
-
export const TableStory: StoryObj = {
|
|
19
|
+
export const TableStory: StoryObj<TableProps> = {
|
|
20
20
|
render: (args) => {
|
|
21
21
|
return <Table data={args.data} columns={args.columns} pageSize={args.pageSize} />;
|
|
22
22
|
},
|
|
@@ -49,7 +49,7 @@ export const TableStory: StoryObj = {
|
|
|
49
49
|
},
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
-
export const TableStoryNoPagination: StoryObj = {
|
|
52
|
+
export const TableStoryNoPagination: StoryObj<TableProps> = {
|
|
53
53
|
render: (args) => {
|
|
54
54
|
return <Table data={args.data} columns={args.columns} pageSize={args.pageSize} />;
|
|
55
55
|
},
|
|
@@ -4,7 +4,7 @@ import type { StepFunction } from '@storybook/types';
|
|
|
4
4
|
import dayjs from 'dayjs/esm';
|
|
5
5
|
import { useEffect, useRef, useState } from 'preact/hooks';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { DateRangeFilter, type DateRangeFilterProps } from './date-range-filter';
|
|
8
8
|
import { previewHandles } from '../../../.storybook/preview';
|
|
9
9
|
import { LAPIS_URL } from '../../constants';
|
|
10
10
|
import { LapisUrlContextProvider } from '../LapisUrlContext';
|
|
@@ -19,9 +19,9 @@ const customDateRange = {
|
|
|
19
19
|
dateTo: '2021-12-31',
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
-
const meta: Meta<
|
|
23
|
-
title: 'Input/
|
|
24
|
-
component:
|
|
22
|
+
const meta: Meta<DateRangeFilterProps> = {
|
|
23
|
+
title: 'Input/DateRangeFilter',
|
|
24
|
+
component: DateRangeFilter,
|
|
25
25
|
parameters: {
|
|
26
26
|
actions: {
|
|
27
27
|
handles: ['gs-date-range-filter-changed', 'gs-date-range-option-changed', ...previewHandles],
|
|
@@ -61,15 +61,15 @@ const meta: Meta<DateRangeSelectorProps> = {
|
|
|
61
61
|
|
|
62
62
|
export default meta;
|
|
63
63
|
|
|
64
|
-
const Primary: StoryObj<
|
|
64
|
+
const Primary: StoryObj<DateRangeFilterProps> = {
|
|
65
65
|
render: (args) => (
|
|
66
66
|
<LapisUrlContextProvider value={LAPIS_URL}>
|
|
67
|
-
<
|
|
67
|
+
<DateRangeFilter {...args} />
|
|
68
68
|
</LapisUrlContextProvider>
|
|
69
69
|
),
|
|
70
70
|
};
|
|
71
71
|
|
|
72
|
-
export const SetCorrectInitialValues: StoryObj<
|
|
72
|
+
export const SetCorrectInitialValues: StoryObj<DateRangeFilterProps> = {
|
|
73
73
|
...Primary,
|
|
74
74
|
args: {
|
|
75
75
|
...Primary.args,
|
|
@@ -88,7 +88,7 @@ export const SetCorrectInitialValues: StoryObj<DateRangeSelectorProps> = {
|
|
|
88
88
|
|
|
89
89
|
const initialDateFrom = '2000-01-01';
|
|
90
90
|
|
|
91
|
-
export const SetCorrectInitialDateFrom: StoryObj<
|
|
91
|
+
export const SetCorrectInitialDateFrom: StoryObj<DateRangeFilterProps> = {
|
|
92
92
|
...Primary,
|
|
93
93
|
args: {
|
|
94
94
|
...Primary.args,
|
|
@@ -107,7 +107,7 @@ export const SetCorrectInitialDateFrom: StoryObj<DateRangeSelectorProps> = {
|
|
|
107
107
|
|
|
108
108
|
const initialDateTo = '2000-01-01';
|
|
109
109
|
|
|
110
|
-
export const SetCorrectInitialDateTo: StoryObj<
|
|
110
|
+
export const SetCorrectInitialDateTo: StoryObj<DateRangeFilterProps> = {
|
|
111
111
|
...Primary,
|
|
112
112
|
args: {
|
|
113
113
|
...Primary.args,
|
|
@@ -124,7 +124,7 @@ export const SetCorrectInitialDateTo: StoryObj<DateRangeSelectorProps> = {
|
|
|
124
124
|
},
|
|
125
125
|
};
|
|
126
126
|
|
|
127
|
-
export const ChangingDateSetsOptionToCustom: StoryObj<
|
|
127
|
+
export const ChangingDateSetsOptionToCustom: StoryObj<DateRangeFilterProps> = {
|
|
128
128
|
...Primary,
|
|
129
129
|
args: {
|
|
130
130
|
...Primary.args,
|
|
@@ -167,7 +167,7 @@ export const ChangingDateSetsOptionToCustom: StoryObj<DateRangeSelectorProps> =
|
|
|
167
167
|
},
|
|
168
168
|
};
|
|
169
169
|
|
|
170
|
-
export const ChangingTheValueProgrammatically: StoryObj<
|
|
170
|
+
export const ChangingTheValueProgrammatically: StoryObj<DateRangeFilterProps> = {
|
|
171
171
|
...Primary,
|
|
172
172
|
render: (args) => {
|
|
173
173
|
const StatefulWrapper = () => {
|
|
@@ -183,7 +183,7 @@ export const ChangingTheValueProgrammatically: StoryObj<DateRangeSelectorProps>
|
|
|
183
183
|
return (
|
|
184
184
|
<div ref={ref}>
|
|
185
185
|
<LapisUrlContextProvider value={LAPIS_URL}>
|
|
186
|
-
<
|
|
186
|
+
<DateRangeFilter {...args} value={value} />
|
|
187
187
|
</LapisUrlContextProvider>
|
|
188
188
|
<button className='btn' onClick={() => setValue(customDateRange.label)}>
|
|
189
189
|
Set to Custom
|
|
@@ -230,7 +230,7 @@ export const ChangingTheValueProgrammatically: StoryObj<DateRangeSelectorProps>
|
|
|
230
230
|
},
|
|
231
231
|
};
|
|
232
232
|
|
|
233
|
-
export const ChangingDateOption: StoryObj<
|
|
233
|
+
export const ChangingDateOption: StoryObj<DateRangeFilterProps> = {
|
|
234
234
|
...Primary,
|
|
235
235
|
play: async ({ canvasElement, step }) => {
|
|
236
236
|
const { canvas, filterChangedListenerMock, optionChangedListenerMock } = await prepare(canvasElement, step);
|
|
@@ -263,7 +263,7 @@ export const ChangingDateOption: StoryObj<DateRangeSelectorProps> = {
|
|
|
263
263
|
},
|
|
264
264
|
};
|
|
265
265
|
|
|
266
|
-
export const HandlesInvalidInitialDateFrom: StoryObj<
|
|
266
|
+
export const HandlesInvalidInitialDateFrom: StoryObj<DateRangeFilterProps> = {
|
|
267
267
|
...Primary,
|
|
268
268
|
args: {
|
|
269
269
|
...Primary.args,
|
|
@@ -278,14 +278,14 @@ export const HandlesInvalidInitialDateFrom: StoryObj<DateRangeSelectorProps> = {
|
|
|
278
278
|
},
|
|
279
279
|
};
|
|
280
280
|
|
|
281
|
-
export const WithNoDateColumn: StoryObj<
|
|
281
|
+
export const WithNoDateColumn: StoryObj<DateRangeFilterProps> = {
|
|
282
282
|
...Primary,
|
|
283
283
|
args: {
|
|
284
284
|
...Primary.args,
|
|
285
285
|
lapisDateField: '',
|
|
286
286
|
},
|
|
287
287
|
play: async ({ canvasElement, step }) => {
|
|
288
|
-
step('expect error message', async () => {
|
|
288
|
+
await step('expect error message', async () => {
|
|
289
289
|
await expectInvalidAttributesErrorMessage(canvasElement, 'String must contain at least 1 character(s)');
|
|
290
290
|
});
|
|
291
291
|
},
|
|
@@ -295,12 +295,9 @@ async function prepare(canvasElement: HTMLElement, step: StepFunction<PreactRend
|
|
|
295
295
|
const canvas = within(canvasElement);
|
|
296
296
|
|
|
297
297
|
const filterChangedListenerMock = fn();
|
|
298
|
-
await step('Setup event listener mock', async () => {
|
|
299
|
-
canvasElement.addEventListener('gs-date-range-filter-changed', filterChangedListenerMock);
|
|
300
|
-
});
|
|
301
|
-
|
|
302
298
|
const optionChangedListenerMock = fn();
|
|
303
|
-
await step('Setup event listener mock',
|
|
299
|
+
await step('Setup event listener mock', () => {
|
|
300
|
+
canvasElement.addEventListener('gs-date-range-filter-changed', filterChangedListenerMock);
|
|
304
301
|
canvasElement.addEventListener('gs-date-range-option-changed', optionChangedListenerMock);
|
|
305
302
|
});
|
|
306
303
|
|
|
@@ -18,39 +18,39 @@ import type { ScaleType } from '../shared/charts/getYAxisScale';
|
|
|
18
18
|
|
|
19
19
|
const customOption = 'Custom';
|
|
20
20
|
|
|
21
|
-
const
|
|
21
|
+
const dateRangeFilterInnerPropsSchema = z.object({
|
|
22
22
|
dateRangeOptions: z.array(dateRangeOptionSchema),
|
|
23
23
|
earliestDate: z.string().date(),
|
|
24
24
|
value: dateRangeValueSchema.optional(),
|
|
25
25
|
lapisDateField: z.string().min(1),
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
const
|
|
28
|
+
const dateRangeFilterPropsSchema = dateRangeFilterInnerPropsSchema.extend({
|
|
29
29
|
width: z.string(),
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
export type
|
|
33
|
-
export type
|
|
32
|
+
export type DateRangeFilterProps = z.infer<typeof dateRangeFilterPropsSchema>;
|
|
33
|
+
export type DateRangeFilterInnerProps = z.infer<typeof dateRangeFilterInnerPropsSchema>;
|
|
34
34
|
|
|
35
|
-
export const
|
|
35
|
+
export const DateRangeFilter = (props: DateRangeFilterProps) => {
|
|
36
36
|
const { width, ...innerProps } = props;
|
|
37
37
|
const size = { width, height: '3rem' };
|
|
38
38
|
|
|
39
39
|
return (
|
|
40
|
-
<ErrorBoundary size={size} layout='horizontal' componentProps={props} schema={
|
|
40
|
+
<ErrorBoundary size={size} layout='horizontal' componentProps={props} schema={dateRangeFilterPropsSchema}>
|
|
41
41
|
<div style={{ width }}>
|
|
42
|
-
<
|
|
42
|
+
<DateRangeFilterInner {...innerProps} />
|
|
43
43
|
</div>
|
|
44
44
|
</ErrorBoundary>
|
|
45
45
|
);
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
-
export const
|
|
48
|
+
export const DateRangeFilterInner = ({
|
|
49
49
|
dateRangeOptions,
|
|
50
50
|
earliestDate = '1900-01-01',
|
|
51
51
|
value,
|
|
52
52
|
lapisDateField,
|
|
53
|
-
}:
|
|
53
|
+
}: DateRangeFilterInnerProps) => {
|
|
54
54
|
const initialValues = useMemo(
|
|
55
55
|
() => computeInitialValues(value, earliestDate, dateRangeOptions),
|
|
56
56
|
[value, earliestDate, dateRangeOptions],
|
|
@@ -148,7 +148,7 @@ export const DateRangeSelectorInner = ({
|
|
|
148
148
|
fireFilterChangedEvent();
|
|
149
149
|
fireOptionChangedEvent({
|
|
150
150
|
dateFrom: dateFrom !== undefined ? toYYYYMMDD(dateFrom) : earliestDate,
|
|
151
|
-
dateTo: toYYYYMMDD(dateTo || new Date())
|
|
151
|
+
dateTo: toYYYYMMDD(dateTo || new Date()),
|
|
152
152
|
});
|
|
153
153
|
};
|
|
154
154
|
|
|
@@ -167,7 +167,7 @@ export const DateRangeSelectorInner = ({
|
|
|
167
167
|
fireFilterChangedEvent();
|
|
168
168
|
fireOptionChangedEvent({
|
|
169
169
|
dateFrom: dateFrom !== undefined ? toYYYYMMDD(dateFrom) : earliestDate,
|
|
170
|
-
dateTo: toYYYYMMDD(dateTo || new Date())
|
|
170
|
+
dateTo: toYYYYMMDD(dateTo || new Date()),
|
|
171
171
|
});
|
|
172
172
|
};
|
|
173
173
|
|
|
@@ -3,7 +3,7 @@ import z from 'zod';
|
|
|
3
3
|
import { toYYYYMMDD } from './dateConversion';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* A date range option that can be used in the `gs-date-range-
|
|
6
|
+
* A date range option that can be used in the `gs-date-range-filter` component.
|
|
7
7
|
*/
|
|
8
8
|
export const dateRangeOptionSchema = z.object({
|
|
9
9
|
/** The label of the date range option that will be shown to the user */
|
|
@@ -65,7 +65,7 @@ const lastYear = new Date(today);
|
|
|
65
65
|
lastYear.setFullYear(today.getFullYear() - 1);
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
|
-
* Presets for the `gs-date-range-
|
|
68
|
+
* Presets for the `gs-date-range-filter` component that can be used as `dateRangeOptions`.
|
|
69
69
|
*/
|
|
70
70
|
export const dateRangeOptionPresets = {
|
|
71
71
|
last2Weeks: {
|
|
@@ -85,7 +85,7 @@ export const Default: StoryObj<LineageFilterProps> = {
|
|
|
85
85
|
play: async ({ canvasElement, step }) => {
|
|
86
86
|
const { canvas, lineageChangedListenerMock } = await prepare(canvasElement, step);
|
|
87
87
|
|
|
88
|
-
step('change lineage filter value fires event', async () => {
|
|
88
|
+
await step('change lineage filter value fires event', async () => {
|
|
89
89
|
const input = await inputField(canvas);
|
|
90
90
|
await userEvent.clear(input);
|
|
91
91
|
await userEvent.type(input, 'B.1');
|
|
@@ -105,7 +105,7 @@ export const ClearSelection: StoryObj<LineageFilterProps> = {
|
|
|
105
105
|
play: async ({ canvasElement, step }) => {
|
|
106
106
|
const { canvas, lineageChangedListenerMock } = await prepare(canvasElement, step);
|
|
107
107
|
|
|
108
|
-
step('clear selection fires event with empty filter', async () => {
|
|
108
|
+
await step('clear selection fires event with empty filter', async () => {
|
|
109
109
|
const clearSelectionButton = await canvas.findByLabelText('clear selection');
|
|
110
110
|
await userEvent.click(clearSelectionButton);
|
|
111
111
|
|
|
@@ -123,7 +123,7 @@ export const OnBlurInput: StoryObj<LineageFilterProps> = {
|
|
|
123
123
|
play: async ({ canvasElement, step }) => {
|
|
124
124
|
const { canvas, lineageChangedListenerMock } = await prepare(canvasElement, step);
|
|
125
125
|
|
|
126
|
-
step('after cleared selection by hand and then blur fires event with empty filter', async () => {
|
|
126
|
+
await step('after cleared selection by hand and then blur fires event with empty filter', async () => {
|
|
127
127
|
const input = await inputField(canvas);
|
|
128
128
|
await userEvent.clear(input);
|
|
129
129
|
await userEvent.click(canvas.getByLabelText('toggle menu'));
|
|
@@ -144,7 +144,7 @@ export const WithNoLapisField: StoryObj<LineageFilterProps> = {
|
|
|
144
144
|
lapisField: '',
|
|
145
145
|
},
|
|
146
146
|
play: async ({ canvasElement, step }) => {
|
|
147
|
-
step('expect error message', async () => {
|
|
147
|
+
await step('expect error message', async () => {
|
|
148
148
|
await expectInvalidAttributesErrorMessage(canvasElement, 'String must contain at least 1 character(s)');
|
|
149
149
|
});
|
|
150
150
|
},
|
|
@@ -154,11 +154,11 @@ async function prepare(canvasElement: HTMLElement, step: StepFunction<PreactRend
|
|
|
154
154
|
const canvas = within(canvasElement);
|
|
155
155
|
|
|
156
156
|
const lineageChangedListenerMock = fn();
|
|
157
|
-
step('Setup event listener mock', () => {
|
|
157
|
+
await step('Setup event listener mock', () => {
|
|
158
158
|
canvasElement.addEventListener('gs-lineage-filter-changed', lineageChangedListenerMock);
|
|
159
159
|
});
|
|
160
160
|
|
|
161
|
-
step('location filter is rendered with value', async () => {
|
|
161
|
+
await step('location filter is rendered with value', async () => {
|
|
162
162
|
await waitFor(async () => {
|
|
163
163
|
return expect(await inputField(canvas)).toHaveValue('A.1');
|
|
164
164
|
});
|
|
@@ -43,7 +43,7 @@ export async function fetchAutocompletionList({
|
|
|
43
43
|
|
|
44
44
|
return [...locationValues]
|
|
45
45
|
.map<EntryWithNullValues>(([json, count]) => ({
|
|
46
|
-
value: JSON.parse(json),
|
|
46
|
+
value: JSON.parse(json) as Record<string, string | null>,
|
|
47
47
|
count,
|
|
48
48
|
}))
|
|
49
49
|
.sort(compareLocationEntries(fields))
|
|
@@ -84,7 +84,7 @@ export const Primary: StoryObj<LocationFilterProps> = {
|
|
|
84
84
|
play: async ({ canvasElement, step }) => {
|
|
85
85
|
const { canvas, locationChangedListenerMock } = await prepare(canvasElement, step);
|
|
86
86
|
|
|
87
|
-
step('change location filter value fires event', async () => {
|
|
87
|
+
await step('change location filter value fires event', async () => {
|
|
88
88
|
const input = await inputField(canvas);
|
|
89
89
|
await userEvent.clear(input);
|
|
90
90
|
await userEvent.type(input, 'Germany');
|
|
@@ -107,7 +107,7 @@ export const ClearSelection: StoryObj<LocationFilterProps> = {
|
|
|
107
107
|
play: async ({ canvasElement, step }) => {
|
|
108
108
|
const { canvas, locationChangedListenerMock } = await prepare(canvasElement, step);
|
|
109
109
|
|
|
110
|
-
step('clear selection fires event with empty filter', async () => {
|
|
110
|
+
await step('clear selection fires event with empty filter', async () => {
|
|
111
111
|
const clearSelectionButton = await canvas.findByLabelText('clear selection');
|
|
112
112
|
await userEvent.click(clearSelectionButton);
|
|
113
113
|
|
|
@@ -128,7 +128,7 @@ export const OnBlurInput: StoryObj<LocationFilterProps> = {
|
|
|
128
128
|
play: async ({ canvasElement, step }) => {
|
|
129
129
|
const { canvas, locationChangedListenerMock } = await prepare(canvasElement, step);
|
|
130
130
|
|
|
131
|
-
step('after cleared selection by hand and then blur fires event with empty filter', async () => {
|
|
131
|
+
await step('after cleared selection by hand and then blur fires event with empty filter', async () => {
|
|
132
132
|
const input = await inputField(canvas);
|
|
133
133
|
await userEvent.clear(input);
|
|
134
134
|
await userEvent.click(canvas.getByLabelText('toggle menu'));
|
|
@@ -151,11 +151,11 @@ async function prepare(canvasElement: HTMLElement, step: StepFunction<PreactRend
|
|
|
151
151
|
const canvas = within(canvasElement);
|
|
152
152
|
|
|
153
153
|
const locationChangedListenerMock = fn();
|
|
154
|
-
step('Setup event listener mock', () => {
|
|
154
|
+
await step('Setup event listener mock', () => {
|
|
155
155
|
canvasElement.addEventListener('gs-location-changed', locationChangedListenerMock);
|
|
156
156
|
});
|
|
157
157
|
|
|
158
|
-
step('location filter is rendered with value', async () => {
|
|
158
|
+
await step('location filter is rendered with value', async () => {
|
|
159
159
|
await waitFor(async () => {
|
|
160
160
|
return expect(await inputField(canvas)).toHaveValue('Europe');
|
|
161
161
|
});
|
|
@@ -171,7 +171,7 @@ export const WithNoFields: StoryObj<LocationFilterProps> = {
|
|
|
171
171
|
fields: [],
|
|
172
172
|
},
|
|
173
173
|
play: async ({ canvasElement, step }) => {
|
|
174
|
-
step('expect error message', async () => {
|
|
174
|
+
await step('expect error message', async () => {
|
|
175
175
|
await expectInvalidAttributesErrorMessage(canvasElement, 'Array must contain at least 1 element(s)');
|
|
176
176
|
});
|
|
177
177
|
},
|
|
@@ -134,7 +134,7 @@ export const InvalidProps: StoryObj<SequencesByLocationProps> = {
|
|
|
134
134
|
lapisLocationField: '',
|
|
135
135
|
},
|
|
136
136
|
play: async ({ canvasElement, step }) => {
|
|
137
|
-
step('expect error message', async () => {
|
|
137
|
+
await step('expect error message', async () => {
|
|
138
138
|
await expectInvalidAttributesErrorMessage(
|
|
139
139
|
canvasElement,
|
|
140
140
|
'"lapisLocationField": String must contain at least 1 character(s)',
|
|
@@ -223,7 +223,7 @@ async function prepare(canvasElement: HTMLElement, step: StepFunction<PreactRend
|
|
|
223
223
|
const canvas = within(canvasElement);
|
|
224
224
|
|
|
225
225
|
const changedListenerMock = fn();
|
|
226
|
-
await step('Setup event listener mock',
|
|
226
|
+
await step('Setup event listener mock', () => {
|
|
227
227
|
canvasElement.addEventListener('gs-mutation-filter-changed', changedListenerMock);
|
|
228
228
|
});
|
|
229
229
|
|
|
@@ -265,5 +265,5 @@ const testNoOptionsExist = async (canvas: ReturnType<typeof within>, mutation: s
|
|
|
265
265
|
await expect(options).toHaveLength(0);
|
|
266
266
|
};
|
|
267
267
|
|
|
268
|
-
const inputField = (canvas: ReturnType<typeof within>) =>
|
|
268
|
+
const inputField = (canvas: ReturnType<typeof within>): HTMLElement =>
|
|
269
269
|
canvas.getByPlaceholderText('Enter a mutation', { exact: false });
|
|
@@ -25,7 +25,7 @@ const accumulateByPosition = (data: SubstitutionOrDeletionEntry[], sequenceType:
|
|
|
25
25
|
|
|
26
26
|
const initiallyFillPositionsToProportionAtBase = () => {
|
|
27
27
|
if (!positionsToProportionAtBase.has(position)) {
|
|
28
|
-
const empty = new Map();
|
|
28
|
+
const empty = new Map<string | undefined, number>();
|
|
29
29
|
basesOfView.forEach((base) => empty.set(base, 0));
|
|
30
30
|
empty.set(mutationEntry.mutation.valueAtReference, 1);
|
|
31
31
|
positionsToProportionAtBase.set(position, empty);
|
|
@@ -62,9 +62,9 @@ const MutationsOverTimeGrid: FunctionComponent<MutationsOverTimeGridProps> = ({
|
|
|
62
62
|
))}
|
|
63
63
|
{shownMutations.map((mutation, rowIndex) => {
|
|
64
64
|
return (
|
|
65
|
-
<Fragment key={`fragment-${mutation.
|
|
65
|
+
<Fragment key={`fragment-${mutation.code}`}>
|
|
66
66
|
<div
|
|
67
|
-
key={`mutation-${mutation.
|
|
67
|
+
key={`mutation-${mutation.code}`}
|
|
68
68
|
style={{ gridRowStart: rowIndex + 2, gridColumnStart: 1 }}
|
|
69
69
|
>
|
|
70
70
|
<MutationCell mutation={mutation} />
|
|
@@ -80,7 +80,7 @@ const MutationsOverTimeGrid: FunctionComponent<MutationsOverTimeGridProps> = ({
|
|
|
80
80
|
return (
|
|
81
81
|
<div
|
|
82
82
|
style={{ gridRowStart: rowIndex + 2, gridColumnStart: columnIndex + 2 }}
|
|
83
|
-
key={`${mutation.
|
|
83
|
+
key={`${mutation.code}-${date.dateString}`}
|
|
84
84
|
>
|
|
85
85
|
<ProportionCell
|
|
86
86
|
value={value}
|
|
@@ -164,7 +164,7 @@ export const WithNoLapisDateFieldField: StoryObj<MutationsOverTimeProps> = {
|
|
|
164
164
|
lapisDateField: '',
|
|
165
165
|
},
|
|
166
166
|
play: async ({ canvasElement, step }) => {
|
|
167
|
-
step('expect error message', async () => {
|
|
167
|
+
await step('expect error message', async () => {
|
|
168
168
|
await expectInvalidAttributesErrorMessage(canvasElement, 'String must contain at least 1 character(s)');
|
|
169
169
|
});
|
|
170
170
|
},
|
|
@@ -78,6 +78,7 @@ export const MutationsOverTimeInner: FunctionComponent<MutationsOverTimeProps> =
|
|
|
78
78
|
|
|
79
79
|
const { data, error, isLoading } = useWebWorker<MutationOverTimeQuery, MutationOverTimeWorkerResponse>(
|
|
80
80
|
messageToWorker,
|
|
81
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
81
82
|
MutationOverTimeWorker,
|
|
82
83
|
);
|
|
83
84
|
|
|
@@ -129,7 +129,7 @@ export const WithNoLapisDateField: StoryObj<NumberSequencesOverTimeProps> = {
|
|
|
129
129
|
lapisDateField: '',
|
|
130
130
|
},
|
|
131
131
|
play: async ({ canvasElement, step }) => {
|
|
132
|
-
step('expect error message', async () => {
|
|
132
|
+
await step('expect error message', async () => {
|
|
133
133
|
await expectInvalidAttributesErrorMessage(canvasElement, 'String must contain at least 1 character(s)');
|
|
134
134
|
});
|
|
135
135
|
},
|
|
@@ -87,13 +87,13 @@ const PrevalenceOverTimeBubbleChart = ({
|
|
|
87
87
|
intersect: false,
|
|
88
88
|
callbacks: {
|
|
89
89
|
title: (context) => {
|
|
90
|
-
const dataset = nonNullDateRangeData[context[0].datasetIndex
|
|
91
|
-
const dataPoint = dataset.content[context[0].dataIndex
|
|
90
|
+
const dataset = nonNullDateRangeData[context[0].datasetIndex];
|
|
91
|
+
const dataPoint = dataset.content[context[0].dataIndex];
|
|
92
92
|
return dataPoint.dateRange?.toString();
|
|
93
93
|
},
|
|
94
94
|
label: (context) => {
|
|
95
|
-
const dataset = nonNullDateRangeData[context.datasetIndex
|
|
96
|
-
const dataPoint = dataset.content[context.dataIndex
|
|
95
|
+
const dataset = nonNullDateRangeData[context.datasetIndex];
|
|
96
|
+
const dataPoint = dataset.content[context.dataIndex];
|
|
97
97
|
|
|
98
98
|
const percentage = (dataPoint.prevalence * 100).toFixed(2);
|
|
99
99
|
const count = dataPoint.count.toFixed(0);
|
|
@@ -254,7 +254,7 @@ export const WithNoLapisDateField: StoryObj<PrevalenceOverTimeProps> = {
|
|
|
254
254
|
lapisDateField: '',
|
|
255
255
|
},
|
|
256
256
|
play: async ({ canvasElement, step }) => {
|
|
257
|
-
step('expect error message', async () => {
|
|
257
|
+
await step('expect error message', async () => {
|
|
258
258
|
await expectInvalidAttributesErrorMessage(canvasElement, 'String must contain at least 1 character(s)');
|
|
259
259
|
});
|
|
260
260
|
},
|
|
@@ -188,7 +188,7 @@ export const WithNoLapisDateField: StoryObj<RelativeGrowthAdvantageProps> = {
|
|
|
188
188
|
lapisDateField: '',
|
|
189
189
|
},
|
|
190
190
|
play: async ({ canvasElement, step }) => {
|
|
191
|
-
step('expect error message', async () => {
|
|
191
|
+
await step('expect error message', async () => {
|
|
192
192
|
await expectInvalidAttributesErrorMessage(canvasElement, 'String must contain at least 1 character(s)');
|
|
193
193
|
});
|
|
194
194
|
},
|
package/src/preact/{textInput/TextInputChangedEvent.ts → textFilter/TextFilterChangedEvent.ts}
RENAMED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
type LapisTextFilter = Record<string, string | undefined>;
|
|
2
2
|
|
|
3
|
-
export class
|
|
3
|
+
export class TextFilterChangedEvent extends CustomEvent<LapisTextFilter> {
|
|
4
4
|
constructor(detail: LapisTextFilter) {
|
|
5
|
-
super('gs-text-
|
|
5
|
+
super('gs-text-filter-changed', {
|
|
6
6
|
detail,
|
|
7
7
|
bubbles: true,
|
|
8
8
|
composed: true,
|
|
@@ -2,18 +2,18 @@ import { type Meta, type StoryObj } from '@storybook/preact';
|
|
|
2
2
|
import { expect, fireEvent, fn, waitFor, within } from '@storybook/test';
|
|
3
3
|
|
|
4
4
|
import data from './__mockData__/aggregated_hosts.json';
|
|
5
|
-
import {
|
|
5
|
+
import { TextFilter, type TextFilterProps } from './text-filter';
|
|
6
6
|
import { previewHandles } from '../../../.storybook/preview';
|
|
7
7
|
import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
|
|
8
8
|
import { LapisUrlContextProvider } from '../LapisUrlContext';
|
|
9
9
|
import { expectInvalidAttributesErrorMessage } from '../shared/stories/expectErrorMessage';
|
|
10
10
|
|
|
11
|
-
const meta: Meta<
|
|
12
|
-
title: 'Input/
|
|
13
|
-
component:
|
|
11
|
+
const meta: Meta<TextFilterProps> = {
|
|
12
|
+
title: 'Input/TextFilter',
|
|
13
|
+
component: TextFilter,
|
|
14
14
|
parameters: {
|
|
15
15
|
actions: {
|
|
16
|
-
handles: ['gs-text-
|
|
16
|
+
handles: ['gs-text-filter-changed', ...previewHandles],
|
|
17
17
|
},
|
|
18
18
|
fetchMock: {
|
|
19
19
|
mocks: [
|
|
@@ -65,10 +65,10 @@ const meta: Meta<TextInputProps> = {
|
|
|
65
65
|
|
|
66
66
|
export default meta;
|
|
67
67
|
|
|
68
|
-
export const Default: StoryObj<
|
|
68
|
+
export const Default: StoryObj<TextFilterProps> = {
|
|
69
69
|
render: (args) => (
|
|
70
70
|
<LapisUrlContextProvider value={LAPIS_URL}>
|
|
71
|
-
<
|
|
71
|
+
<TextFilter {...args} />
|
|
72
72
|
</LapisUrlContextProvider>
|
|
73
73
|
),
|
|
74
74
|
args: {
|
|
@@ -82,7 +82,7 @@ export const Default: StoryObj<TextInputProps> = {
|
|
|
82
82
|
},
|
|
83
83
|
};
|
|
84
84
|
|
|
85
|
-
export const RemoveInitialValue: StoryObj<
|
|
85
|
+
export const RemoveInitialValue: StoryObj<TextFilterProps> = {
|
|
86
86
|
...Default,
|
|
87
87
|
args: {
|
|
88
88
|
...Default.args,
|
|
@@ -92,13 +92,13 @@ export const RemoveInitialValue: StoryObj<TextInputProps> = {
|
|
|
92
92
|
const canvas = within(canvasElement);
|
|
93
93
|
|
|
94
94
|
const changedListenerMock = fn();
|
|
95
|
-
await step('Setup event listener mock',
|
|
96
|
-
canvasElement.addEventListener('gs-text-
|
|
95
|
+
await step('Setup event listener mock', () => {
|
|
96
|
+
canvasElement.addEventListener('gs-text-filter-changed', changedListenerMock);
|
|
97
97
|
});
|
|
98
98
|
|
|
99
|
-
await waitFor(() => {
|
|
99
|
+
await waitFor(async () => {
|
|
100
100
|
const input = canvas.getByPlaceholderText('Enter a host name', { exact: false });
|
|
101
|
-
expect(input).toHaveValue('Homo sapiens');
|
|
101
|
+
await expect(input).toHaveValue('Homo sapiens');
|
|
102
102
|
});
|
|
103
103
|
|
|
104
104
|
await step('Remove initial value', async () => {
|
|
@@ -115,14 +115,14 @@ export const RemoveInitialValue: StoryObj<TextInputProps> = {
|
|
|
115
115
|
},
|
|
116
116
|
};
|
|
117
117
|
|
|
118
|
-
export const WithNoLapisField: StoryObj<
|
|
118
|
+
export const WithNoLapisField: StoryObj<TextFilterProps> = {
|
|
119
119
|
...Default,
|
|
120
120
|
args: {
|
|
121
121
|
...Default.args,
|
|
122
122
|
lapisField: '',
|
|
123
123
|
},
|
|
124
124
|
play: async ({ canvasElement, step }) => {
|
|
125
|
-
step('expect error message', async () => {
|
|
125
|
+
await step('expect error message', async () => {
|
|
126
126
|
await expectInvalidAttributesErrorMessage(canvasElement, 'String must contain at least 1 character(s)');
|
|
127
127
|
});
|
|
128
128
|
},
|