@genspectrum/dashboard-components 0.13.7 → 0.14.2

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 (82) hide show
  1. package/custom-elements.json +24 -62
  2. package/dist/{LineageFilterChangedEvent-GedKNGFI.js → LineageFilterChangedEvent-C9dXOxt6.js} +11 -3
  3. package/dist/LineageFilterChangedEvent-C9dXOxt6.js.map +1 -0
  4. package/dist/assets/mutationOverTimeWorker-Dxnxrfe0.js.map +1 -1
  5. package/dist/components.d.ts +40 -50
  6. package/dist/components.js +112 -91
  7. package/dist/components.js.map +1 -1
  8. package/dist/util.d.ts +38 -28
  9. package/dist/util.js +1 -1
  10. package/package.json +2 -2
  11. package/src/lapisApi/lapisApi.ts +1 -1
  12. package/src/operator/FillMissingOperator.spec.ts +1 -1
  13. package/src/operator/GroupByAndSumOperator.spec.ts +1 -1
  14. package/src/operator/GroupByOperator.spec.ts +2 -2
  15. package/src/operator/MapOperator.spec.ts +1 -1
  16. package/src/operator/MockOperator.spec.ts +1 -1
  17. package/src/operator/MockOperator.ts +6 -4
  18. package/src/operator/SortOperator.spec.ts +1 -1
  19. package/src/preact/LapisUrlContext.ts +14 -1
  20. package/src/preact/aggregatedData/aggregate.stories.tsx +4 -4
  21. package/src/preact/aggregatedData/aggregate.tsx +3 -4
  22. package/src/preact/components/csv-download-button.stories.tsx +2 -2
  23. package/src/preact/components/csv-download-button.tsx +1 -1
  24. package/src/preact/components/error-boundary.stories.tsx +5 -5
  25. package/src/preact/components/error-boundary.tsx +14 -3
  26. package/src/preact/components/error-display.stories.tsx +9 -9
  27. package/src/preact/components/fullscreen.tsx +3 -3
  28. package/src/preact/components/info.tsx +1 -1
  29. package/src/preact/components/mutation-type-selector.stories.tsx +1 -1
  30. package/src/preact/components/table.stories.tsx +3 -3
  31. package/src/preact/components/table.tsx +1 -1
  32. package/src/preact/dateRangeSelector/computeInitialValues.spec.ts +34 -20
  33. package/src/preact/dateRangeSelector/computeInitialValues.ts +25 -21
  34. package/src/preact/dateRangeSelector/date-range-selector.stories.tsx +107 -46
  35. package/src/preact/dateRangeSelector/date-range-selector.tsx +31 -22
  36. package/src/preact/dateRangeSelector/dateRangeOption.ts +11 -1
  37. package/src/preact/lineageFilter/lineage-filter.stories.tsx +9 -9
  38. package/src/preact/lineageFilter/lineage-filter.tsx +3 -4
  39. package/src/preact/locationFilter/fetchAutocompletionList.ts +1 -1
  40. package/src/preact/locationFilter/location-filter.stories.tsx +9 -9
  41. package/src/preact/locationFilter/location-filter.tsx +4 -4
  42. package/src/preact/map/sequences-by-location.stories.tsx +4 -4
  43. package/src/preact/map/sequences-by-location.tsx +3 -4
  44. package/src/preact/mutationComparison/mutation-comparison.stories.tsx +3 -3
  45. package/src/preact/mutationComparison/mutation-comparison.tsx +4 -4
  46. package/src/preact/mutationFilter/mutation-filter-info.tsx +3 -3
  47. package/src/preact/mutationFilter/mutation-filter.stories.tsx +7 -7
  48. package/src/preact/mutations/getMutationsGridData.ts +1 -1
  49. package/src/preact/mutations/mutations.stories.tsx +3 -3
  50. package/src/preact/mutations/mutations.tsx +4 -4
  51. package/src/preact/mutationsOverTime/mutations-over-time-grid.tsx +3 -3
  52. package/src/preact/mutationsOverTime/mutations-over-time.stories.tsx +4 -4
  53. package/src/preact/mutationsOverTime/mutations-over-time.tsx +5 -4
  54. package/src/preact/numberSequencesOverTime/number-sequences-over-time.stories.tsx +4 -4
  55. package/src/preact/numberSequencesOverTime/number-sequences-over-time.tsx +4 -4
  56. package/src/preact/prevalenceOverTime/prevalence-over-time-bubble-chart.tsx +4 -4
  57. package/src/preact/prevalenceOverTime/prevalence-over-time.stories.tsx +4 -4
  58. package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +4 -4
  59. package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.stories.tsx +4 -4
  60. package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.tsx +4 -4
  61. package/src/preact/shared/floating-ui/hooks.ts +1 -1
  62. package/src/preact/statistic/statistics.stories.tsx +3 -3
  63. package/src/preact/statistic/statistics.tsx +2 -3
  64. package/src/preact/textInput/text-input.stories.tsx +7 -7
  65. package/src/preact/textInput/text-input.tsx +3 -4
  66. package/src/preact/wastewater/mutationsOverTime/wastewater-mutations-over-time.stories.tsx +3 -3
  67. package/src/preact/wastewater/mutationsOverTime/wastewater-mutations-over-time.tsx +4 -4
  68. package/src/utils/map2d.ts +1 -0
  69. package/src/web-components/PreactLitAdapter.tsx +3 -3
  70. package/src/web-components/gs-app.stories.ts +7 -7
  71. package/src/web-components/gs-app.ts +3 -1
  72. package/src/web-components/input/gs-date-range-selector.stories.ts +10 -17
  73. package/src/web-components/input/gs-date-range-selector.tsx +15 -38
  74. package/src/web-components/input/gs-lineage-filter.stories.ts +1 -1
  75. package/src/web-components/input/gs-location-filter.stories.ts +1 -1
  76. package/src/web-components/input/gs-mutation-filter.stories.ts +7 -7
  77. package/src/web-components/input/gs-text-input.stories.ts +3 -3
  78. package/src/web-components/visualization/gs-aggregate.tsx +2 -2
  79. package/standalone-bundle/assets/mutationOverTimeWorker-CmSrq4SZ.js.map +1 -1
  80. package/standalone-bundle/dashboard-components.js +6068 -6055
  81. package/standalone-bundle/dashboard-components.js.map +1 -1
  82. package/dist/LineageFilterChangedEvent-GedKNGFI.js.map +0 -1
@@ -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,14 +78,14 @@ 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);
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
  });
@@ -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 }),
@@ -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))
@@ -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,14 +77,14 @@ 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);
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
  },
@@ -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' },
@@ -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)',
@@ -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: {
@@ -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', async () => {
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);
@@ -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
 
@@ -1,5 +1,5 @@
1
1
  import { type FunctionComponent } from 'preact';
2
- import { type Dispatch, type StateUpdater, useContext, useState } from 'preact/hooks';
2
+ import { type Dispatch, type StateUpdater, useState } from 'preact/hooks';
3
3
  import z from 'zod';
4
4
 
5
5
  import { getInsertionsTableData } from './getInsertionsTableData';
@@ -15,7 +15,7 @@ import {
15
15
  type SubstitutionOrDeletionEntry,
16
16
  views,
17
17
  } from '../../types';
18
- import { LapisUrlContext } from '../LapisUrlContext';
18
+ import { useLapisUrl } from '../LapisUrlContext';
19
19
  import { CsvDownloadButton } from '../components/csv-download-button';
20
20
  import { ErrorBoundary } from '../components/error-boundary';
21
21
  import { Fullscreen } from '../components/fullscreen';
@@ -59,7 +59,7 @@ export const Mutations: FunctionComponent<MutationsProps> = (componentProps) =>
59
59
  };
60
60
 
61
61
  export const MutationsInner: FunctionComponent<MutationsProps> = (componentProps) => {
62
- const lapis = useContext(LapisUrlContext);
62
+ const lapis = useLapisUrl();
63
63
  const { lapisFilter, baselineLapisFilter, sequenceType } = componentProps;
64
64
 
65
65
  const { data, error, isLoading } = useQuery(async () => {
@@ -237,7 +237,7 @@ type MutationsInfoProps = {
237
237
  };
238
238
 
239
239
  const MutationsInfo: FunctionComponent<MutationsInfoProps> = ({ originalComponentProps }) => {
240
- const lapis = useContext(LapisUrlContext);
240
+ const lapis = useLapisUrl();
241
241
 
242
242
  return (
243
243
  <Info>
@@ -62,9 +62,9 @@ const MutationsOverTimeGrid: FunctionComponent<MutationsOverTimeGridProps> = ({
62
62
  ))}
63
63
  {shownMutations.map((mutation, rowIndex) => {
64
64
  return (
65
- <Fragment key={`fragment-${mutation.toString()}`}>
65
+ <Fragment key={`fragment-${mutation.code}`}>
66
66
  <div
67
- key={`mutation-${mutation.toString()}`}
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.toString()}-${date.toString()}`}
83
+ key={`${mutation.code}-${date.dateString}`}
84
84
  >
85
85
  <ProportionCell
86
86
  value={value}
@@ -4,7 +4,7 @@ import { expect, userEvent, waitFor } from '@storybook/test';
4
4
  import { MutationsOverTime, type MutationsOverTimeProps } from './mutations-over-time';
5
5
  import { LAPIS_URL } from '../../constants';
6
6
  import referenceGenome from '../../lapisApi/__mockData__/referenceGenome.json';
7
- import { LapisUrlContext } from '../LapisUrlContext';
7
+ import { LapisUrlContextProvider } from '../LapisUrlContext';
8
8
  import { ReferenceGenomeContext } from '../ReferenceGenomeContext';
9
9
  import { expectInvalidAttributesErrorMessage } from '../shared/stories/expectErrorMessage';
10
10
 
@@ -38,7 +38,7 @@ export default meta;
38
38
 
39
39
  const Template = {
40
40
  render: (args: MutationsOverTimeProps) => (
41
- <LapisUrlContext.Provider value={LAPIS_URL}>
41
+ <LapisUrlContextProvider value={LAPIS_URL}>
42
42
  <ReferenceGenomeContext.Provider value={referenceGenome}>
43
43
  <MutationsOverTime
44
44
  lapisFilter={args.lapisFilter}
@@ -50,7 +50,7 @@ const Template = {
50
50
  lapisDateField={args.lapisDateField}
51
51
  />
52
52
  </ReferenceGenomeContext.Provider>
53
- </LapisUrlContext.Provider>
53
+ </LapisUrlContextProvider>
54
54
  ),
55
55
  };
56
56
 
@@ -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
  },
@@ -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
  // @ts-expect-error -- uses subpath imports and vite worker import
@@ -18,7 +18,7 @@ import {
18
18
  } from '../../types';
19
19
  import { type Deletion, type Substitution } from '../../utils/mutations';
20
20
  import { toTemporalClass } from '../../utils/temporalClass';
21
- import { LapisUrlContext } from '../LapisUrlContext';
21
+ import { useLapisUrl } from '../LapisUrlContext';
22
22
  import { type ColorScale } from '../components/color-scale-selector';
23
23
  import { ColorScaleSelectorDropdown } from '../components/color-scale-selector-dropdown';
24
24
  import { CsvDownloadButton } from '../components/csv-download-button';
@@ -63,7 +63,7 @@ export const MutationsOverTime: FunctionComponent<MutationsOverTimeProps> = (com
63
63
  };
64
64
 
65
65
  export const MutationsOverTimeInner: FunctionComponent<MutationsOverTimeProps> = (componentProps) => {
66
- const lapis = useContext(LapisUrlContext);
66
+ const lapis = useLapisUrl();
67
67
  const { lapisFilter, sequenceType, granularity, lapisDateField } = componentProps;
68
68
 
69
69
  const messageToWorker = useMemo(() => {
@@ -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
 
@@ -230,7 +231,7 @@ type MutationsOverTimeInfoProps = {
230
231
  };
231
232
 
232
233
  const MutationsOverTimeInfo: FunctionComponent<MutationsOverTimeInfoProps> = ({ originalComponentProps }) => {
233
- const lapis = useContext(LapisUrlContext);
234
+ const lapis = useLapisUrl();
234
235
  return (
235
236
  <Info>
236
237
  <InfoHeadline1>Mutations over time</InfoHeadline1>
@@ -5,7 +5,7 @@ import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
5
5
  import oneVariantEG from '../../preact/numberSequencesOverTime/__mockData__/oneVariantEG.json';
6
6
  import twoVariantsEG from '../../preact/numberSequencesOverTime/__mockData__/twoVariantsEG.json';
7
7
  import twoVariantsJN1 from '../../preact/numberSequencesOverTime/__mockData__/twoVariantsJN1.json';
8
- import { LapisUrlContext } from '../LapisUrlContext';
8
+ import { LapisUrlContextProvider } from '../LapisUrlContext';
9
9
  import { expectInvalidAttributesErrorMessage } from '../shared/stories/expectErrorMessage';
10
10
 
11
11
  export default {
@@ -29,9 +29,9 @@ export default {
29
29
 
30
30
  const Template: StoryObj<NumberSequencesOverTimeProps> = {
31
31
  render: (args) => (
32
- <LapisUrlContext.Provider value={LAPIS_URL}>
32
+ <LapisUrlContextProvider value={LAPIS_URL}>
33
33
  <NumberSequencesOverTime {...args} />
34
- </LapisUrlContext.Provider>
34
+ </LapisUrlContextProvider>
35
35
  ),
36
36
  args: {
37
37
  views: ['bar', 'line', 'table'],
@@ -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
  },
@@ -1,5 +1,5 @@
1
1
  import { type FunctionComponent } from 'preact';
2
- import { useContext, useState } from 'preact/hooks';
2
+ import { useState } from 'preact/hooks';
3
3
  import z from 'zod';
4
4
 
5
5
  import { getNumberOfSequencesOverTimeTableData } from './getNumberOfSequencesOverTimeTableData';
@@ -11,7 +11,7 @@ import {
11
11
  queryNumberOfSequencesOverTime,
12
12
  } from '../../query/queryNumberOfSequencesOverTime';
13
13
  import { namedLapisFilterSchema, temporalGranularitySchema, views } from '../../types';
14
- import { LapisUrlContext } from '../LapisUrlContext';
14
+ import { useLapisUrl } from '../LapisUrlContext';
15
15
  import { CsvDownloadButton } from '../components/csv-download-button';
16
16
  import { ErrorBoundary } from '../components/error-boundary';
17
17
  import { Fullscreen } from '../components/fullscreen';
@@ -59,7 +59,7 @@ export const NumberSequencesOverTime = (componentProps: NumberSequencesOverTimeP
59
59
 
60
60
  const NumberSequencesOverTimeInner = (componentProps: NumberSequencesOverTimeProps) => {
61
61
  const { lapisFilters, lapisDateField, granularity, smoothingWindow } = componentProps;
62
- const lapis = useContext(LapisUrlContext);
62
+ const lapis = useLapisUrl();
63
63
 
64
64
  const { data, error, isLoading } = useQuery(
65
65
  () => queryNumberOfSequencesOverTime(lapis, lapisFilters, lapisDateField, granularity, smoothingWindow),
@@ -169,7 +169,7 @@ type NumberSequencesOverTimeInfoProps = {
169
169
  const NumberSequencesOverTimeInfo: FunctionComponent<NumberSequencesOverTimeInfoProps> = ({
170
170
  originalComponentProps,
171
171
  }) => {
172
- const lapis = useContext(LapisUrlContext);
172
+ const lapis = useLapisUrl();
173
173
 
174
174
  return (
175
175
  <Info>
@@ -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);