@genspectrum/dashboard-components 0.13.7 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/custom-elements.json +13 -51
  2. package/dist/{LineageFilterChangedEvent-GedKNGFI.js → LineageFilterChangedEvent-C9dXOxt6.js} +11 -3
  3. package/dist/LineageFilterChangedEvent-C9dXOxt6.js.map +1 -0
  4. package/dist/components.d.ts +61 -67
  5. package/dist/components.js +95 -84
  6. package/dist/components.js.map +1 -1
  7. package/dist/util.d.ts +60 -50
  8. package/dist/util.js +1 -1
  9. package/package.json +1 -1
  10. package/src/preact/LapisUrlContext.ts +14 -1
  11. package/src/preact/aggregatedData/aggregate.stories.tsx +3 -3
  12. package/src/preact/aggregatedData/aggregate.tsx +3 -4
  13. package/src/preact/dateRangeSelector/computeInitialValues.spec.ts +34 -20
  14. package/src/preact/dateRangeSelector/computeInitialValues.ts +25 -21
  15. package/src/preact/dateRangeSelector/date-range-selector.stories.tsx +104 -40
  16. package/src/preact/dateRangeSelector/date-range-selector.tsx +29 -20
  17. package/src/preact/dateRangeSelector/dateRangeOption.ts +11 -1
  18. package/src/preact/lineageFilter/lineage-filter.stories.tsx +3 -3
  19. package/src/preact/lineageFilter/lineage-filter.tsx +3 -4
  20. package/src/preact/locationFilter/location-filter.stories.tsx +3 -3
  21. package/src/preact/locationFilter/location-filter.tsx +4 -4
  22. package/src/preact/map/sequences-by-location.stories.tsx +3 -3
  23. package/src/preact/map/sequences-by-location.tsx +3 -4
  24. package/src/preact/mutationComparison/mutation-comparison.stories.tsx +3 -3
  25. package/src/preact/mutationComparison/mutation-comparison.tsx +4 -4
  26. package/src/preact/mutationFilter/mutation-filter-info.tsx +3 -3
  27. package/src/preact/mutationFilter/mutation-filter.stories.tsx +5 -5
  28. package/src/preact/mutations/mutations.stories.tsx +3 -3
  29. package/src/preact/mutations/mutations.tsx +4 -4
  30. package/src/preact/mutationsOverTime/mutations-over-time.stories.tsx +3 -3
  31. package/src/preact/mutationsOverTime/mutations-over-time.tsx +4 -4
  32. package/src/preact/numberSequencesOverTime/number-sequences-over-time.stories.tsx +3 -3
  33. package/src/preact/numberSequencesOverTime/number-sequences-over-time.tsx +4 -4
  34. package/src/preact/prevalenceOverTime/prevalence-over-time.stories.tsx +3 -3
  35. package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +4 -4
  36. package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.stories.tsx +3 -3
  37. package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.tsx +4 -4
  38. package/src/preact/statistic/statistics.stories.tsx +3 -3
  39. package/src/preact/statistic/statistics.tsx +2 -3
  40. package/src/preact/textInput/text-input.stories.tsx +3 -3
  41. package/src/preact/textInput/text-input.tsx +3 -4
  42. package/src/preact/wastewater/mutationsOverTime/wastewater-mutations-over-time.stories.tsx +3 -3
  43. package/src/preact/wastewater/mutationsOverTime/wastewater-mutations-over-time.tsx +4 -4
  44. package/src/web-components/PreactLitAdapter.tsx +3 -3
  45. package/src/web-components/gs-app.ts +3 -1
  46. package/src/web-components/input/gs-date-range-selector.stories.ts +5 -12
  47. package/src/web-components/input/gs-date-range-selector.tsx +15 -38
  48. package/standalone-bundle/dashboard-components.js +6078 -6072
  49. package/standalone-bundle/dashboard-components.js.map +1 -1
  50. package/dist/LineageFilterChangedEvent-GedKNGFI.js.map +0 -1
@@ -2,11 +2,12 @@ import { type Meta, type PreactRenderer, type StoryObj } from '@storybook/preact
2
2
  import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
3
3
  import type { StepFunction } from '@storybook/types';
4
4
  import dayjs from 'dayjs/esm';
5
+ import { useEffect, useRef, useState } from 'preact/hooks';
5
6
 
6
7
  import { DateRangeSelector, type DateRangeSelectorProps } from './date-range-selector';
7
8
  import { previewHandles } from '../../../.storybook/preview';
8
9
  import { LAPIS_URL } from '../../constants';
9
- import { LapisUrlContext } from '../LapisUrlContext';
10
+ import { LapisUrlContextProvider } from '../LapisUrlContext';
10
11
  import { dateRangeOptionPresets } from './dateRangeOption';
11
12
  import { expectInvalidAttributesErrorMessage } from '../shared/stories/expectErrorMessage';
12
13
 
@@ -28,11 +29,10 @@ const meta: Meta<DateRangeSelectorProps> = {
28
29
  fetchMock: {},
29
30
  },
30
31
  argTypes: {
31
- initialValue: {
32
+ value: {
32
33
  control: {
33
- type: 'select',
34
+ type: 'object',
34
35
  },
35
- options: [dateRangeOptionPresets.lastMonth.label, dateRangeOptionPresets.allTimes.label, 'CustomDateRange'],
36
36
  },
37
37
  dateRangeOptions: {
38
38
  control: {
@@ -53,21 +53,19 @@ const meta: Meta<DateRangeSelectorProps> = {
53
53
  args: {
54
54
  dateRangeOptions: [dateRangeOptionPresets.lastMonth, dateRangeOptionPresets.allTimes, customDateRange],
55
55
  earliestDate,
56
- initialValue: dateRangeOptionPresets.lastMonth.label,
56
+ value: undefined,
57
57
  lapisDateField: 'aDateColumn',
58
58
  width: '100%',
59
- initialDateFrom: undefined,
60
- initialDateTo: undefined,
61
59
  },
62
60
  };
63
61
 
64
62
  export default meta;
65
63
 
66
- export const Primary: StoryObj<DateRangeSelectorProps> = {
64
+ const Primary: StoryObj<DateRangeSelectorProps> = {
67
65
  render: (args) => (
68
- <LapisUrlContext.Provider value={LAPIS_URL}>
66
+ <LapisUrlContextProvider value={LAPIS_URL}>
69
67
  <DateRangeSelector {...args} />
70
- </LapisUrlContext.Provider>
68
+ </LapisUrlContextProvider>
71
69
  ),
72
70
  };
73
71
 
@@ -75,15 +73,15 @@ export const SetCorrectInitialValues: StoryObj<DateRangeSelectorProps> = {
75
73
  ...Primary,
76
74
  args: {
77
75
  ...Primary.args,
78
- initialValue: 'CustomDateRange',
76
+ value: 'CustomDateRange',
79
77
  },
80
78
  play: async ({ canvasElement }) => {
81
79
  const canvas = within(canvasElement);
82
80
 
83
- await waitFor(() => {
84
- expect(selectField(canvas)).toHaveValue('CustomDateRange');
85
- expect(dateFromPicker(canvas)).toHaveValue('2021-01-01');
86
- expect(dateToPicker(canvas)).toHaveValue('2021-12-31');
81
+ await waitFor(async () => {
82
+ await expect(selectField(canvas)).toHaveValue('CustomDateRange');
83
+ await expect(dateFromPicker(canvas)).toHaveValue('2021-01-01');
84
+ await expect(dateToPicker(canvas)).toHaveValue('2021-12-31');
87
85
  });
88
86
  },
89
87
  };
@@ -94,15 +92,15 @@ export const SetCorrectInitialDateFrom: StoryObj<DateRangeSelectorProps> = {
94
92
  ...Primary,
95
93
  args: {
96
94
  ...Primary.args,
97
- initialDateFrom,
95
+ value: { dateFrom: initialDateFrom },
98
96
  },
99
97
  play: async ({ canvasElement }) => {
100
98
  const canvas = within(canvasElement);
101
99
 
102
- await waitFor(() => {
103
- expect(selectField(canvas)).toHaveValue('Custom');
104
- expect(dateFromPicker(canvas)).toHaveValue(initialDateFrom);
105
- expect(dateToPicker(canvas)).toHaveValue(dayjs().format('YYYY-MM-DD'));
100
+ await waitFor(async () => {
101
+ await expect(selectField(canvas)).toHaveValue('Custom');
102
+ await expect(dateFromPicker(canvas)).toHaveValue(initialDateFrom);
103
+ await expect(dateToPicker(canvas)).toHaveValue(dayjs().format('YYYY-MM-DD'));
106
104
  });
107
105
  },
108
106
  };
@@ -113,35 +111,39 @@ export const SetCorrectInitialDateTo: StoryObj<DateRangeSelectorProps> = {
113
111
  ...Primary,
114
112
  args: {
115
113
  ...Primary.args,
116
- initialDateTo,
114
+ value: { dateTo: initialDateTo },
117
115
  },
118
116
  play: async ({ canvasElement }) => {
119
117
  const canvas = within(canvasElement);
120
118
 
121
- await waitFor(() => {
122
- expect(selectField(canvas)).toHaveValue('Custom');
123
- expect(dateFromPicker(canvas)).toHaveValue(earliestDate);
124
- expect(dateToPicker(canvas)).toHaveValue(initialDateTo);
119
+ await waitFor(async () => {
120
+ await expect(selectField(canvas)).toHaveValue('Custom');
121
+ await expect(dateFromPicker(canvas)).toHaveValue(earliestDate);
122
+ await expect(dateToPicker(canvas)).toHaveValue(initialDateTo);
125
123
  });
126
124
  },
127
125
  };
128
126
 
129
127
  export const ChangingDateSetsOptionToCustom: StoryObj<DateRangeSelectorProps> = {
130
128
  ...Primary,
129
+ args: {
130
+ ...Primary.args,
131
+ value: dateRangeOptionPresets.lastMonth.label,
132
+ },
131
133
  play: async ({ canvasElement, step }) => {
132
134
  const { canvas, filterChangedListenerMock, optionChangedListenerMock } = await prepare(canvasElement, step);
133
135
 
134
- await waitFor(() => {
135
- expect(selectField(canvas)).toHaveValue('Last month');
136
+ await waitFor(async () => {
137
+ await expect(selectField(canvas)).toHaveValue('Last month');
136
138
  });
137
139
 
138
- step('Change date to custom value', async () => {
140
+ await step('Change date to custom value', async () => {
139
141
  await userEvent.type(dateFromPicker(canvas), '{backspace>12}');
140
142
  await userEvent.type(dateFromPicker(canvas), '2000-01-01');
141
143
  await userEvent.click(dateToPicker(canvas));
142
144
 
143
- await waitFor(() => {
144
- expect(selectField(canvas)).toHaveValue('Custom');
145
+ await waitFor(async () => {
146
+ await expect(selectField(canvas)).toHaveValue('Custom');
145
147
  });
146
148
 
147
149
  await expect(filterChangedListenerMock).toHaveBeenCalledWith(
@@ -165,20 +167,82 @@ export const ChangingDateSetsOptionToCustom: StoryObj<DateRangeSelectorProps> =
165
167
  },
166
168
  };
167
169
 
168
- export const ChangingDateOption: StoryObj<DateRangeSelectorProps> = {
170
+ export const ChangingTheValueProgrammatically: StoryObj<DateRangeSelectorProps> = {
169
171
  ...Primary,
172
+ render: (args) => {
173
+ const StatefulWrapper = () => {
174
+ const [value, setValue] = useState('Last month');
175
+ const ref = useRef<HTMLDivElement>(null);
176
+
177
+ useEffect(() => {
178
+ ref.current?.addEventListener('gs-date-range-option-changed', (event) => {
179
+ setValue((event as CustomEvent).detail);
180
+ });
181
+ }, []);
182
+
183
+ return (
184
+ <div ref={ref}>
185
+ <LapisUrlContextProvider value={LAPIS_URL}>
186
+ <DateRangeSelector {...args} value={value} />
187
+ </LapisUrlContextProvider>
188
+ <button className='btn' onClick={() => setValue(customDateRange.label)}>
189
+ Set to Custom
190
+ </button>
191
+ <button className='btn' onClick={() => setValue(dateRangeOptionPresets.lastMonth.label)}>
192
+ Set to Last month
193
+ </button>
194
+ </div>
195
+ );
196
+ };
197
+
198
+ return <StatefulWrapper />;
199
+ },
170
200
  play: async ({ canvasElement, step }) => {
171
201
  const { canvas, filterChangedListenerMock, optionChangedListenerMock } = await prepare(canvasElement, step);
172
202
 
173
- await waitFor(() => {
174
- expect(selectField(canvas)).toHaveValue('Last month');
203
+ await waitFor(async () => {
204
+ await expect(selectField(canvas)).toHaveValue('Last month');
175
205
  });
176
206
 
177
- step('Change date to custom', async () => {
178
- await userEvent.selectOptions(selectField(canvas), 'CustomDateRange');
207
+ await step('Change the value of the component programmatically', async () => {
208
+ await userEvent.click(canvas.getByRole('button', { name: 'Set to Custom' }));
209
+ await waitFor(async () => {
210
+ await expect(selectField(canvas)).toHaveValue(customDateRange.label);
211
+ });
212
+
213
+ await userEvent.click(canvas.getByRole('button', { name: 'Set to Last month' }));
214
+ await waitFor(async () => {
215
+ await expect(selectField(canvas)).toHaveValue('Last month');
216
+ });
217
+
218
+ await expect(filterChangedListenerMock).toHaveBeenCalledTimes(0);
219
+ await expect(optionChangedListenerMock).toHaveBeenCalledTimes(0);
220
+ });
221
+
222
+ await step('Changing the value from within the component is still possible', async () => {
223
+ await userEvent.selectOptions(selectField(canvas), 'All times');
224
+ await waitFor(async () => {
225
+ await expect(selectField(canvas)).toHaveValue('All times');
226
+ });
227
+ await expect(filterChangedListenerMock).toHaveBeenCalledTimes(1);
228
+ await expect(optionChangedListenerMock).toHaveBeenCalledTimes(1);
229
+ });
230
+ },
231
+ };
232
+
233
+ export const ChangingDateOption: StoryObj<DateRangeSelectorProps> = {
234
+ ...Primary,
235
+ play: async ({ canvasElement, step }) => {
236
+ const { canvas, filterChangedListenerMock, optionChangedListenerMock } = await prepare(canvasElement, step);
237
+
238
+ await waitFor(async () => {
239
+ await expect(selectField(canvas)).toHaveValue('Custom');
240
+ });
179
241
 
180
- await waitFor(() => {
181
- expect(selectField(canvas)).toHaveValue('CustomDateRange');
242
+ await step('Change date to custom', async () => {
243
+ await waitFor(async () => {
244
+ await userEvent.selectOptions(selectField(canvas), 'CustomDateRange');
245
+ await expect(selectField(canvas)).toHaveValue('CustomDateRange');
182
246
  });
183
247
 
184
248
  await expect(filterChangedListenerMock).toHaveBeenCalledWith(
@@ -203,13 +267,13 @@ export const HandlesInvalidInitialDateFrom: StoryObj<DateRangeSelectorProps> = {
203
267
  ...Primary,
204
268
  args: {
205
269
  ...Primary.args,
206
- initialDateFrom: 'not a date',
270
+ value: { dateFrom: 'not a date' },
207
271
  },
208
272
  play: async ({ canvasElement }) => {
209
273
  const canvas = within(canvasElement);
210
274
 
211
- await waitFor(() => {
212
- expect(canvas.getByText('Oops! Something went wrong.')).toBeVisible();
275
+ await waitFor(async () => {
276
+ await expect(canvas.getByText('Oops! Something went wrong.')).toBeVisible();
213
277
  });
214
278
  },
215
279
  };
@@ -1,11 +1,16 @@
1
1
  import flatpickr from 'flatpickr';
2
2
  import 'flatpickr/dist/flatpickr.min.css';
3
- import { useEffect, useRef, useState } from 'preact/hooks';
3
+ import { useEffect, useMemo, useRef, useState } from 'preact/hooks';
4
4
  import z from 'zod';
5
5
 
6
6
  import { computeInitialValues } from './computeInitialValues';
7
7
  import { toYYYYMMDD } from './dateConversion';
8
- import { DateRangeOptionChangedEvent, dateRangeOptionSchema, type DateRangeSelectOption } from './dateRangeOption';
8
+ import {
9
+ DateRangeOptionChangedEvent,
10
+ dateRangeOptionSchema,
11
+ type DateRangeSelectOption,
12
+ dateRangeValueSchema,
13
+ } from './dateRangeOption';
9
14
  import { getDatesForSelectorValue, getSelectableOptions } from './selectableOptions';
10
15
  import { ErrorBoundary } from '../components/error-boundary';
11
16
  import { Select } from '../components/select';
@@ -16,9 +21,7 @@ const customOption = 'Custom';
16
21
  const dateRangeSelectorInnerPropsSchema = z.object({
17
22
  dateRangeOptions: z.array(dateRangeOptionSchema),
18
23
  earliestDate: z.string().date(),
19
- initialValue: z.string().optional(),
20
- initialDateFrom: z.string().date().optional(),
21
- initialDateTo: z.string().date().optional(),
24
+ value: dateRangeValueSchema.optional(),
22
25
  lapisDateField: z.string().min(1),
23
26
  });
24
27
 
@@ -45,17 +48,12 @@ export const DateRangeSelector = (props: DateRangeSelectorProps) => {
45
48
  export const DateRangeSelectorInner = ({
46
49
  dateRangeOptions,
47
50
  earliestDate = '1900-01-01',
48
- initialValue,
51
+ value,
49
52
  lapisDateField,
50
- initialDateFrom,
51
- initialDateTo,
52
53
  }: DateRangeSelectorInnerProps) => {
53
- const initialValues = computeInitialValues(
54
- initialValue,
55
- initialDateFrom,
56
- initialDateTo,
57
- earliestDate,
58
- dateRangeOptions,
54
+ const initialValues = useMemo(
55
+ () => computeInitialValues(value, earliestDate, dateRangeOptions),
56
+ [value, earliestDate, dateRangeOptions],
59
57
  );
60
58
 
61
59
  const fromDatePickerRef = useRef<HTMLInputElement>(null);
@@ -74,6 +72,12 @@ export const DateRangeSelectorInner = ({
74
72
  });
75
73
 
76
74
  useEffect(() => {
75
+ setSelectedDateRange(initialValues.initialSelectedDateRange);
76
+ setSelectedDates({
77
+ dateFrom: initialValues.initialSelectedDateFrom,
78
+ dateTo: initialValues.initialSelectedDateTo,
79
+ });
80
+
77
81
  const commonConfig = {
78
82
  allowInput: true,
79
83
  dateFormat: 'Y-m-d',
@@ -83,7 +87,7 @@ export const DateRangeSelectorInner = ({
83
87
  setDateFromPicker(
84
88
  flatpickr(fromDatePickerRef.current, {
85
89
  ...commonConfig,
86
- defaultDate: selectedDates.dateFrom,
90
+ defaultDate: initialValues.initialSelectedDateFrom,
87
91
  }),
88
92
  );
89
93
  }
@@ -92,17 +96,22 @@ export const DateRangeSelectorInner = ({
92
96
  setDateToPicker(
93
97
  flatpickr(toDatePickerRef.current, {
94
98
  ...commonConfig,
95
- defaultDate: selectedDates.dateTo,
99
+ defaultDate: initialValues.initialSelectedDateTo,
96
100
  }),
97
101
  );
98
102
  }
99
103
 
100
104
  return () => {
101
- dateFromPicker?.destroy();
102
- dateToPicker?.destroy();
105
+ setDateFromPicker((prev) => {
106
+ prev?.destroy();
107
+ return null;
108
+ });
109
+ setDateToPicker((prev) => {
110
+ prev?.destroy();
111
+ return null;
112
+ });
103
113
  };
104
- // eslint-disable-next-line react-hooks/exhaustive-deps
105
- }, [fromDatePickerRef, toDatePickerRef]);
114
+ }, [fromDatePickerRef, toDatePickerRef, initialValues]);
106
115
 
107
116
  const onSelectChange = (value: string) => {
108
117
  setSelectedDateRange(value);
@@ -22,7 +22,17 @@ export const dateRangeOptionSchema = z.object({
22
22
 
23
23
  export type DateRangeOption = z.infer<typeof dateRangeOptionSchema>;
24
24
 
25
- export type DateRangeSelectOption = string | { dateFrom: string; dateTo: string };
25
+ export const dateRangeValueSchema = z.union([
26
+ z.string(),
27
+ z.object({
28
+ dateFrom: z.string().date().optional(),
29
+ dateTo: z.string().date().optional(),
30
+ }),
31
+ ]);
32
+
33
+ export type DateRangeValue = z.infer<typeof dateRangeValueSchema>;
34
+
35
+ export type DateRangeSelectOption = Required<DateRangeValue>;
26
36
 
27
37
  export class DateRangeOptionChangedEvent extends CustomEvent<DateRangeSelectOption> {
28
38
  constructor(detail: DateRangeSelectOption) {
@@ -6,7 +6,7 @@ import { LineageFilter, type LineageFilterProps } from './lineage-filter';
6
6
  import { previewHandles } from '../../../.storybook/preview';
7
7
  import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
8
8
  import aggregatedData from '../../preact/lineageFilter/__mockData__/aggregated.json';
9
- import { LapisUrlContext } from '../LapisUrlContext';
9
+ import { LapisUrlContextProvider } from '../LapisUrlContext';
10
10
  import { expectInvalidAttributesErrorMessage } from '../shared/stories/expectErrorMessage';
11
11
 
12
12
  const meta: Meta = {
@@ -78,9 +78,9 @@ export default meta;
78
78
 
79
79
  export const Default: StoryObj<LineageFilterProps> = {
80
80
  render: (args) => (
81
- <LapisUrlContext.Provider value={LAPIS_URL}>
81
+ <LapisUrlContextProvider value={LAPIS_URL}>
82
82
  <LineageFilter {...args} />
83
- </LapisUrlContext.Provider>
83
+ </LapisUrlContextProvider>
84
84
  ),
85
85
  play: async ({ canvasElement, step }) => {
86
86
  const { canvas, lineageChangedListenerMock } = await prepare(canvasElement, step);
@@ -1,10 +1,9 @@
1
1
  import { type FunctionComponent } from 'preact';
2
- import { useContext } from 'preact/hooks';
3
2
  import z from 'zod';
4
3
 
5
- import { fetchLineageAutocompleteList } from './fetchLineageAutocompleteList';
6
- import { LapisUrlContext } from '../LapisUrlContext';
4
+ import { useLapisUrl } from '../LapisUrlContext';
7
5
  import { LineageFilterChangedEvent } from './LineageFilterChangedEvent';
6
+ import { fetchLineageAutocompleteList } from './fetchLineageAutocompleteList';
8
7
  import { lapisFilterSchema } from '../../types';
9
8
  import { DownshiftCombobox } from '../components/downshift-combobox';
10
9
  import { ErrorBoundary } from '../components/error-boundary';
@@ -47,7 +46,7 @@ const LineageFilterInner: FunctionComponent<LineageFilterInnerProps> = ({
47
46
  value,
48
47
  lapisFilter,
49
48
  }) => {
50
- const lapis = useContext(LapisUrlContext);
49
+ const lapis = useLapisUrl();
51
50
 
52
51
  const { data, error, isLoading } = useQuery(
53
52
  () => fetchLineageAutocompleteList({ lapis, field: lapisField, lapisFilter }),
@@ -6,7 +6,7 @@ import data from './__mockData__/aggregated.json';
6
6
  import { LocationFilter, type LocationFilterProps } from './location-filter';
7
7
  import { previewHandles } from '../../../.storybook/preview';
8
8
  import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
9
- import { LapisUrlContext } from '../LapisUrlContext';
9
+ import { LapisUrlContextProvider } from '../LapisUrlContext';
10
10
  import { expectInvalidAttributesErrorMessage } from '../shared/stories/expectErrorMessage';
11
11
 
12
12
  const meta: Meta<LocationFilterProps> = {
@@ -77,9 +77,9 @@ export default meta;
77
77
 
78
78
  export const Primary: StoryObj<LocationFilterProps> = {
79
79
  render: (args) => (
80
- <LapisUrlContext.Provider value={LAPIS_URL}>
80
+ <LapisUrlContextProvider value={LAPIS_URL}>
81
81
  <LocationFilter {...args} />
82
- </LapisUrlContext.Provider>
82
+ </LapisUrlContextProvider>
83
83
  ),
84
84
  play: async ({ canvasElement, step }) => {
85
85
  const { canvas, locationChangedListenerMock } = await prepare(canvasElement, step);
@@ -1,11 +1,11 @@
1
1
  import { type FunctionComponent } from 'preact';
2
- import { useContext, useMemo } from 'preact/hooks';
2
+ import { useMemo } from 'preact/hooks';
3
3
  import z from 'zod';
4
4
 
5
- import { fetchAutocompletionList, type LocationEntry } from './fetchAutocompletionList';
6
- import { LapisUrlContext } from '../LapisUrlContext';
7
5
  import { LocationChangedEvent } from './LocationChangedEvent';
6
+ import { fetchAutocompletionList, type LocationEntry } from './fetchAutocompletionList';
8
7
  import { lapisFilterSchema, type LapisLocationFilter, lapisLocationFilterSchema } from '../../types';
8
+ import { useLapisUrl } from '../LapisUrlContext';
9
9
  import { DownshiftCombobox } from '../components/downshift-combobox';
10
10
  import { ErrorBoundary } from '../components/error-boundary';
11
11
  import { LoadingDisplay } from '../components/loading-display';
@@ -40,7 +40,7 @@ export const LocationFilter: FunctionComponent<LocationFilterProps> = (props) =>
40
40
  };
41
41
 
42
42
  export const LocationFilterInner = ({ value, fields, placeholderText, lapisFilter }: LocationFilterInnerProps) => {
43
- const lapis = useContext(LapisUrlContext);
43
+ const lapis = useLapisUrl();
44
44
 
45
45
  const { data, error, isLoading } = useQuery(
46
46
  () => fetchAutocompletionList({ fields, lapis, lapisFilter }),
@@ -2,7 +2,7 @@ import { type Meta, type StoryObj } from '@storybook/preact';
2
2
 
3
3
  import worldAtlas from './__mockData__/worldAtlas.json';
4
4
  import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
5
- import { LapisUrlContext } from '../LapisUrlContext';
5
+ import { LapisUrlContextProvider } from '../LapisUrlContext';
6
6
  import aggregatedWorld from './__mockData__/aggregatedWorld.json';
7
7
  import { SequencesByLocation, type SequencesByLocationProps } from './sequences-by-location';
8
8
  import { expectInvalidAttributesErrorMessage, playThatExpectsErrorMessage } from '../shared/stories/expectErrorMessage';
@@ -37,9 +37,9 @@ const aggregatedWorldMatcher = {
37
37
 
38
38
  export const Default: StoryObj<SequencesByLocationProps> = {
39
39
  render: (args) => (
40
- <LapisUrlContext.Provider value={LAPIS_URL}>
40
+ <LapisUrlContextProvider value={LAPIS_URL}>
41
41
  <SequencesByLocation {...args} />
42
- </LapisUrlContext.Provider>
42
+ </LapisUrlContextProvider>
43
43
  ),
44
44
  args: {
45
45
  lapisFilter: { dateFrom: '2022-01-01', dateTo: '2022-04-01' },
@@ -1,7 +1,7 @@
1
1
  import type { FunctionComponent } from 'preact';
2
- import { useContext } from 'preact/hooks';
3
2
  import z from 'zod';
4
3
 
4
+ import { useLapisUrl } from '../LapisUrlContext';
5
5
  import { SequencesByLocationMap } from './sequences-by-location-map';
6
6
  import { SequencesByLocationTable } from './sequences-by-location-table';
7
7
  import {
@@ -11,7 +11,6 @@ import {
11
11
  } from '../../query/computeMapLocationData';
12
12
  import { type AggregateData } from '../../query/queryAggregateData';
13
13
  import { querySequencesByLocationData } from '../../query/querySequencesByLocationData';
14
- import { LapisUrlContext } from '../LapisUrlContext';
15
14
  import { CsvDownloadButton } from '../components/csv-download-button';
16
15
  import { ErrorBoundary } from '../components/error-boundary';
17
16
  import { Fullscreen } from '../components/fullscreen';
@@ -58,7 +57,7 @@ export const SequencesByLocation: FunctionComponent<SequencesByLocationProps> =
58
57
  const SequencesByLocationMapInner: FunctionComponent<SequencesByLocationProps> = (props) => {
59
58
  const { lapisFilter, lapisLocationField, mapSource } = props;
60
59
 
61
- const lapis = useContext(LapisUrlContext);
60
+ const lapis = useLapisUrl();
62
61
  const {
63
62
  data,
64
63
  error,
@@ -158,7 +157,7 @@ type SequencesByLocationMapInfoProps = {
158
157
  };
159
158
 
160
159
  const SequencesByLocationMapInfo: FunctionComponent<SequencesByLocationMapInfoProps> = ({ originalComponentProps }) => {
161
- const lapis = useContext(LapisUrlContext);
160
+ const lapis = useLapisUrl();
162
161
  return (
163
162
  <Info>
164
163
  <InfoHeadline1>Prevalence by location</InfoHeadline1>
@@ -6,7 +6,7 @@ import nucleotideMutationsSomeDataset from './__mockData__/nucleotideMutationsSo
6
6
  import { MutationComparison, type MutationComparisonProps } from './mutation-comparison';
7
7
  import { LAPIS_URL, NUCLEOTIDE_MUTATIONS_ENDPOINT } from '../../constants';
8
8
  import referenceGenome from '../../lapisApi/__mockData__/referenceGenome.json';
9
- import { LapisUrlContext } from '../LapisUrlContext';
9
+ import { LapisUrlContextProvider } from '../LapisUrlContext';
10
10
  import { ReferenceGenomeContext } from '../ReferenceGenomeContext';
11
11
 
12
12
  const dateToSomeDataset = '2022-01-01';
@@ -76,7 +76,7 @@ export default meta;
76
76
 
77
77
  const Template: StoryObj<MutationComparisonProps> = {
78
78
  render: (args) => (
79
- <LapisUrlContext.Provider value={LAPIS_URL}>
79
+ <LapisUrlContextProvider value={LAPIS_URL}>
80
80
  <ReferenceGenomeContext.Provider value={referenceGenome}>
81
81
  <MutationComparison
82
82
  lapisFilters={args.lapisFilters}
@@ -87,7 +87,7 @@ const Template: StoryObj<MutationComparisonProps> = {
87
87
  pageSize={args.pageSize}
88
88
  />
89
89
  </ReferenceGenomeContext.Provider>
90
- </LapisUrlContext.Provider>
90
+ </LapisUrlContextProvider>
91
91
  ),
92
92
  };
93
93
 
@@ -1,5 +1,5 @@
1
1
  import { type FunctionComponent } from 'preact';
2
- import { type Dispatch, type StateUpdater, useContext, useMemo, useState } from 'preact/hooks';
2
+ import { type Dispatch, type StateUpdater, useMemo, useState } from 'preact/hooks';
3
3
  import z from 'zod';
4
4
 
5
5
  import { getMutationComparisonTableData } from './getMutationComparisonTableData';
@@ -7,7 +7,7 @@ import { MutationComparisonTable } from './mutation-comparison-table';
7
7
  import { MutationComparisonVenn } from './mutation-comparison-venn';
8
8
  import { filterMutationData, type MutationData, queryMutationData } from './queryMutationData';
9
9
  import { namedLapisFilterSchema, sequenceTypeSchema, views } from '../../types';
10
- import { LapisUrlContext } from '../LapisUrlContext';
10
+ import { useLapisUrl } from '../LapisUrlContext';
11
11
  import { CsvDownloadButton } from '../components/csv-download-button';
12
12
  import { ErrorBoundary } from '../components/error-boundary';
13
13
  import { Fullscreen } from '../components/fullscreen';
@@ -52,7 +52,7 @@ export const MutationComparison: FunctionComponent<MutationComparisonProps> = (c
52
52
 
53
53
  const MutationComparisonInner: FunctionComponent<MutationComparisonProps> = (componentProps) => {
54
54
  const { lapisFilters, sequenceType } = componentProps;
55
- const lapis = useContext(LapisUrlContext);
55
+ const lapis = useLapisUrl();
56
56
 
57
57
  const { data, error, isLoading } = useQuery(async () => {
58
58
  return queryMutationData(lapisFilters, sequenceType, lapis);
@@ -187,7 +187,7 @@ type MutationComparisonInfoProps = {
187
187
  };
188
188
 
189
189
  const MutationComparisonInfo: FunctionComponent<MutationComparisonInfoProps> = ({ originalComponentProps }) => {
190
- const lapis = useContext(LapisUrlContext);
190
+ const lapis = useLapisUrl();
191
191
  return (
192
192
  <Info>
193
193
  <InfoHeadline1>Info for mutation comparison</InfoHeadline1>
@@ -55,13 +55,13 @@ const QuickStart = () => {
55
55
  )}
56
56
  </ul>
57
57
  </InfoParagraph>
58
-
59
- {referenceGenome.nucleotideSequences.length > 1 ? (
58
+ {referenceGenome.nucleotideSequences.length > 1 && (
60
59
  <InfoParagraph>
61
60
  This organism has the following segments:{' '}
62
61
  {referenceGenome.nucleotideSequences.map((gene) => gene.name).join(', ')}.
63
62
  </InfoParagraph>
64
- ) : (
63
+ )}
64
+ {referenceGenome.nucleotideSequences.length === 0 && (
65
65
  <InfoParagraph>This organism doesn't support nucleotide sequences.</InfoParagraph>
66
66
  )}
67
67
  {referenceGenome.genes.length !== 0 ? (
@@ -6,7 +6,7 @@ import { MutationFilter, type MutationFilterProps } from './mutation-filter';
6
6
  import { previewHandles } from '../../../.storybook/preview';
7
7
  import { LAPIS_URL } from '../../constants';
8
8
  import referenceGenome from '../../lapisApi/__mockData__/referenceGenome.json';
9
- import { LapisUrlContext } from '../LapisUrlContext';
9
+ import { LapisUrlContextProvider } from '../LapisUrlContext';
10
10
  import { ReferenceGenomeContext } from '../ReferenceGenomeContext';
11
11
 
12
12
  const meta: Meta<MutationFilterProps> = {
@@ -32,11 +32,11 @@ export default meta;
32
32
 
33
33
  export const Default: StoryObj<MutationFilterProps> = {
34
34
  render: (args) => (
35
- <LapisUrlContext.Provider value={LAPIS_URL}>
35
+ <LapisUrlContextProvider value={LAPIS_URL}>
36
36
  <ReferenceGenomeContext.Provider value={referenceGenome}>
37
37
  <MutationFilter width={args.width} initialValue={args.initialValue} />
38
38
  </ReferenceGenomeContext.Provider>
39
- </LapisUrlContext.Provider>
39
+ </LapisUrlContextProvider>
40
40
  ),
41
41
  args: {
42
42
  width: '100%',
@@ -184,11 +184,11 @@ export const FiresFilterChangedEvents: StoryObj<MutationFilterProps> = {
184
184
 
185
185
  export const WithInitialValue: StoryObj<MutationFilterProps> = {
186
186
  render: (args) => (
187
- <LapisUrlContext.Provider value={LAPIS_URL}>
187
+ <LapisUrlContextProvider value={LAPIS_URL}>
188
188
  <ReferenceGenomeContext.Provider value={referenceGenome}>
189
189
  <MutationFilter initialValue={args.initialValue} width={args.width} />
190
190
  </ReferenceGenomeContext.Provider>
191
- </LapisUrlContext.Provider>
191
+ </LapisUrlContextProvider>
192
192
  ),
193
193
  args: {
194
194
  initialValue: {
@@ -13,7 +13,7 @@ import {
13
13
  import referenceGenome from '../../lapisApi/__mockData__/referenceGenome.json';
14
14
  import baselineNucleotideMutations from '../../preact/mutations/__mockData__/baselineNucleotideMutations.json';
15
15
  import overallVariantCount from '../../preact/mutations/__mockData__/overallVariantCount.json';
16
- import { LapisUrlContext } from '../LapisUrlContext';
16
+ import { LapisUrlContextProvider } from '../LapisUrlContext';
17
17
  import { ReferenceGenomeContext } from '../ReferenceGenomeContext';
18
18
 
19
19
  const meta: Meta<MutationsProps> = {
@@ -39,11 +39,11 @@ export default meta;
39
39
 
40
40
  const Template = {
41
41
  render: (args: MutationsProps) => (
42
- <LapisUrlContext.Provider value={LAPIS_URL}>
42
+ <LapisUrlContextProvider value={LAPIS_URL}>
43
43
  <ReferenceGenomeContext.Provider value={referenceGenome}>
44
44
  <Mutations {...args} />
45
45
  </ReferenceGenomeContext.Provider>
46
- </LapisUrlContext.Provider>
46
+ </LapisUrlContextProvider>
47
47
  ),
48
48
  };
49
49