@genspectrum/dashboard-components 0.6.14 → 0.6.15

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 (32) hide show
  1. package/custom-elements.json +12 -6
  2. package/dist/dashboard-components.js +97 -53
  3. package/dist/dashboard-components.js.map +1 -1
  4. package/dist/genspectrum-components.d.ts +27 -9
  5. package/dist/style.css +2 -2
  6. package/package.json +3 -3
  7. package/src/index.ts +8 -0
  8. package/src/lapisApi/lapisApi.ts +15 -7
  9. package/src/preact/components/color-scale-selector-dropdown.stories.tsx +1 -1
  10. package/src/preact/components/error-boundary.stories.tsx +21 -4
  11. package/src/preact/components/error-display.stories.tsx +20 -2
  12. package/src/preact/components/error-display.tsx +64 -10
  13. package/src/preact/components/info.stories.tsx +5 -5
  14. package/src/preact/components/info.tsx +1 -3
  15. package/src/preact/dateRangeSelector/date-range-selector.stories.tsx +2 -3
  16. package/src/preact/lineageFilter/lineage-filter.stories.tsx +2 -3
  17. package/src/preact/locationFilter/fetchAutocompletionList.ts +1 -14
  18. package/src/preact/locationFilter/location-filter.stories.tsx +2 -3
  19. package/src/preact/mutationFilter/mutation-filter.stories.tsx +2 -3
  20. package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +1 -1
  21. package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.tsx +1 -1
  22. package/src/preact/shared/floating-ui/hooks.ts +1 -1
  23. package/src/preact/textInput/text-input.stories.tsx +2 -3
  24. package/src/web-components/app.stories.ts +0 -2
  25. package/src/web-components/errorHandling.mdx +8 -0
  26. package/src/web-components/input/gs-date-range-selector.stories.ts +2 -3
  27. package/src/web-components/input/gs-lineage-filter.stories.ts +2 -3
  28. package/src/web-components/input/gs-location-filter.stories.ts +2 -3
  29. package/src/web-components/input/gs-mutation-filter.stories.ts +2 -3
  30. package/src/web-components/input/gs-text-input.stories.ts +2 -3
  31. package/standalone-bundle/dashboard-components.js +1719 -1686
  32. package/standalone-bundle/dashboard-components.js.map +1 -1
@@ -178,6 +178,12 @@ export declare class DateRangeSelectorComponent extends PreactLitAdapter {
178
178
  render(): JSX_2.Element;
179
179
  }
180
180
 
181
+ declare class ErrorEvent_2 extends Event {
182
+ readonly error: Error;
183
+ constructor(error: Error);
184
+ }
185
+ export { ErrorEvent_2 as ErrorEvent }
186
+
181
187
  declare type LapisFilter = Record<string, string | number | null | boolean>;
182
188
 
183
189
  /**
@@ -948,11 +954,23 @@ export declare class TextInputComponent extends PreactLitAdapter {
948
954
  render(): JSX_2.Element;
949
955
  }
950
956
 
957
+ export declare class UserFacingError extends Error {
958
+ readonly headline: string;
959
+ constructor(headline: string, message: string);
960
+ }
961
+
951
962
  declare type View = 'table';
952
963
 
953
964
  export { }
954
965
 
955
966
 
967
+ declare global {
968
+ interface HTMLElementEventMap {
969
+ 'gs-error': ErrorEvent;
970
+ }
971
+ }
972
+
973
+
956
974
  declare global {
957
975
  interface HTMLElementTagNameMap {
958
976
  'gs-app': App;
@@ -1021,41 +1039,41 @@ declare global {
1021
1039
 
1022
1040
  declare global {
1023
1041
  interface HTMLElementTagNameMap {
1024
- 'gs-text-input': TextInputComponent;
1042
+ 'gs-location-filter': LocationFilterComponent;
1025
1043
  }
1026
1044
  interface HTMLElementEventMap {
1027
- 'gs-text-input-changed': CustomEvent<Record<string, string>>;
1045
+ 'gs-location-changed': CustomEvent<Record<string, string>>;
1028
1046
  }
1029
1047
  }
1030
1048
 
1031
1049
 
1032
1050
  declare global {
1033
1051
  interface HTMLElementTagNameMap {
1034
- 'gs-location-filter': LocationFilterComponent;
1052
+ 'gs-text-input': TextInputComponent;
1035
1053
  }
1036
1054
  interface HTMLElementEventMap {
1037
- 'gs-location-changed': CustomEvent<Record<string, string>>;
1055
+ 'gs-text-input-changed': CustomEvent<Record<string, string>>;
1038
1056
  }
1039
1057
  }
1040
1058
 
1041
1059
 
1042
1060
  declare global {
1043
1061
  interface HTMLElementTagNameMap {
1044
- 'gs-mutation-filter': MutationFilterComponent;
1062
+ 'gs-lineage-filter': LineageFilterComponent;
1045
1063
  }
1046
1064
  interface HTMLElementEventMap {
1047
- 'gs-mutation-filter-changed': CustomEvent<SelectedMutationFilterStrings>;
1048
- 'gs-mutation-filter-on-blur': CustomEvent<SelectedMutationFilterStrings>;
1065
+ 'gs-lineage-filter-changed': CustomEvent<Record<string, string>>;
1049
1066
  }
1050
1067
  }
1051
1068
 
1052
1069
 
1053
1070
  declare global {
1054
1071
  interface HTMLElementTagNameMap {
1055
- 'gs-lineage-filter': LineageFilterComponent;
1072
+ 'gs-mutation-filter': MutationFilterComponent;
1056
1073
  }
1057
1074
  interface HTMLElementEventMap {
1058
- 'gs-lineage-filter-changed': CustomEvent<Record<string, string>>;
1075
+ 'gs-mutation-filter-changed': CustomEvent<SelectedMutationFilterStrings>;
1076
+ 'gs-mutation-filter-on-blur': CustomEvent<SelectedMutationFilterStrings>;
1059
1077
  }
1060
1078
  }
1061
1079
 
package/dist/style.css CHANGED
@@ -3372,9 +3372,9 @@ input.tab:checked + .tab-content,
3372
3372
  --tw-text-opacity: 1;
3373
3373
  color: rgb(30 64 175 / var(--tw-text-opacity));
3374
3374
  }
3375
- .hover\:text-gray-300:hover {
3375
+ .hover\:text-gray-400:hover {
3376
3376
  --tw-text-opacity: 1;
3377
- color: rgb(209 213 219 / var(--tw-text-opacity));
3377
+ color: rgb(156 163 175 / var(--tw-text-opacity));
3378
3378
  }
3379
3379
  .hover\:text-gray-700:hover {
3380
3380
  --tw-text-opacity: 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genspectrum/dashboard-components",
3
- "version": "0.6.14",
3
+ "version": "0.6.15",
4
4
  "description": "GenSpectrum web components for building dashboards",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-only",
@@ -93,8 +93,8 @@
93
93
  "@storybook/web-components-vite": "^8.0.9",
94
94
  "@types/node": "^22.0.0",
95
95
  "@types/object-hash": "^3.0.6",
96
- "@typescript-eslint/eslint-plugin": "^7.14.1",
97
- "@typescript-eslint/parser": "^7.14.1",
96
+ "@typescript-eslint/eslint-plugin": "^8.2.0",
97
+ "@typescript-eslint/parser": "^8.2.0",
98
98
  "autoprefixer": "^10.4.19",
99
99
  "daisyui": "^4.10.2",
100
100
  "depcheck": "^1.4.7",
package/src/index.ts CHANGED
@@ -1 +1,9 @@
1
1
  export * from './web-components';
2
+
3
+ export { type ErrorEvent, UserFacingError } from './preact/components/error-display';
4
+
5
+ declare global {
6
+ interface HTMLElementEventMap {
7
+ 'gs-error': ErrorEvent;
8
+ }
9
+ }
@@ -15,6 +15,7 @@ export class UnknownLapisError extends Error {
15
15
  constructor(
16
16
  message: string,
17
17
  public readonly status: number,
18
+ public readonly requestedData: string,
18
19
  ) {
19
20
  super(message);
20
21
  this.name = 'UnknownLapisError';
@@ -26,6 +27,7 @@ export class LapisError extends Error {
26
27
  message: string,
27
28
  public readonly status: number,
28
29
  public readonly problemDetail: ProblemDetail,
30
+ public readonly requestedData: string,
29
31
  ) {
30
32
  super(message);
31
33
  this.name = 'LapisError';
@@ -42,7 +44,7 @@ export async function fetchAggregated(lapisUrl: string, body: LapisBaseRequest,
42
44
  signal,
43
45
  });
44
46
 
45
- await handleErrors(response);
47
+ await handleErrors(response, 'aggregated data');
46
48
 
47
49
  return aggregatedResponse.parse(await response.json());
48
50
  }
@@ -62,7 +64,7 @@ export async function fetchInsertions(
62
64
  signal,
63
65
  });
64
66
 
65
- await handleErrors(response);
67
+ await handleErrors(response, `${sequenceType} insertions`);
66
68
 
67
69
  return insertionsResponse.parse(await response.json());
68
70
  }
@@ -82,7 +84,7 @@ export async function fetchSubstitutionsOrDeletions(
82
84
  signal,
83
85
  });
84
86
 
85
- await handleErrors(response);
87
+ await handleErrors(response, `${sequenceType} mutations`);
86
88
 
87
89
  return mutationsResponse.parse(await response.json());
88
90
  }
@@ -96,11 +98,11 @@ export async function fetchReferenceGenome(lapisUrl: string, signal?: AbortSigna
96
98
  signal,
97
99
  });
98
100
 
99
- await handleErrors(response);
101
+ await handleErrors(response, 'the reference genomes');
100
102
  return referenceGenomeResponse.parse(await response.json());
101
103
  }
102
104
 
103
- const handleErrors = async (response: Response) => {
105
+ const handleErrors = async (response: Response, requestedData: string) => {
104
106
  if (!response.ok) {
105
107
  if (response.status >= 400 && response.status < 500) {
106
108
  const json = await response.json();
@@ -111,6 +113,7 @@ const handleErrors = async (response: Response) => {
111
113
  response.statusText + lapisErrorResult.data.error.detail,
112
114
  response.status,
113
115
  lapisErrorResult.data.error,
116
+ requestedData,
114
117
  );
115
118
  }
116
119
 
@@ -120,12 +123,17 @@ const handleErrors = async (response: Response) => {
120
123
  response.statusText + problemDetailResult.data.detail,
121
124
  response.status,
122
125
  problemDetailResult.data,
126
+ requestedData,
123
127
  );
124
128
  }
125
129
 
126
- throw new UnknownLapisError(`${response.statusText}: ${JSON.stringify(json)}`, response.status);
130
+ throw new UnknownLapisError(
131
+ `${response.statusText}: ${JSON.stringify(json)}`,
132
+ response.status,
133
+ requestedData,
134
+ );
127
135
  }
128
- throw new UnknownLapisError(`${response.statusText}: ${response.status}`, response.status);
136
+ throw new UnknownLapisError(`${response.statusText}: ${response.status}`, response.status, requestedData);
129
137
  }
130
138
  };
131
139
 
@@ -14,7 +14,7 @@ const meta: Meta<ColorScaleSelectorDropdownProps> = {
14
14
 
15
15
  export default meta;
16
16
 
17
- const WrapperWithState: FunctionComponent<{}> = () => {
17
+ const WrapperWithState: FunctionComponent = () => {
18
18
  const [colorScale, setColorScale] = useState<ColorScale>({ min: 0, max: 1, color: 'indigo' });
19
19
 
20
20
  return <ColorScaleSelectorDropdown colorScale={colorScale} setColorScale={setColorScale} />;
@@ -2,11 +2,14 @@ import { type Meta, type StoryObj } from '@storybook/preact';
2
2
  import { expect, waitFor, within } from '@storybook/test';
3
3
 
4
4
  import { ErrorBoundary } from './error-boundary';
5
+ import { UserFacingError } from './error-display';
5
6
 
6
7
  const meta: Meta = {
7
8
  title: 'Component/Error boundary',
8
9
  component: ErrorBoundary,
9
- parameters: { fetchMock: {} },
10
+ parameters: {
11
+ fetchMock: {},
12
+ },
10
13
  argTypes: {
11
14
  size: { control: 'object' },
12
15
  defaultSize: { control: 'object' },
@@ -34,7 +37,7 @@ export const ErrorBoundaryWithoutErrorStory: StoryObj = {
34
37
  export const ErrorBoundaryWithErrorStory: StoryObj = {
35
38
  render: (args) => (
36
39
  <ErrorBoundary size={args.size}>
37
- <ContentThatThrowsError />
40
+ <ContentThatThrowsError error={() => new Error('Some error')} />
38
41
  </ErrorBoundary>
39
42
  ),
40
43
  play: async ({ canvasElement }) => {
@@ -45,6 +48,20 @@ export const ErrorBoundaryWithErrorStory: StoryObj = {
45
48
  },
46
49
  };
47
50
 
48
- const ContentThatThrowsError = () => {
49
- throw new Error('Some error');
51
+ export const ErrorBoundaryWithUserFacingErrorStory: StoryObj = {
52
+ render: (args) => (
53
+ <ErrorBoundary size={args.size}>
54
+ <ContentThatThrowsError error={() => new UserFacingError('Error Headline', 'Some error')} />
55
+ </ErrorBoundary>
56
+ ),
57
+ play: async ({ canvasElement }) => {
58
+ const canvas = within(canvasElement);
59
+ const content = canvas.queryByText('Some content.', { exact: false });
60
+ await waitFor(() => expect(content).not.toBeInTheDocument());
61
+ await waitFor(() => expect(canvas.getByText('Error - Error Headline')).toBeInTheDocument());
62
+ },
63
+ };
64
+
65
+ const ContentThatThrowsError = (props: { error: () => Error }) => {
66
+ throw props.error();
50
67
  };
@@ -1,5 +1,5 @@
1
1
  import { type Meta, type StoryObj } from '@storybook/preact';
2
- import { expect, userEvent, waitFor, within } from '@storybook/test';
2
+ import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
3
3
 
4
4
  import { ErrorDisplay, UserFacingError } from './error-display';
5
5
  import { ResizeContainer } from './resize-container';
@@ -12,7 +12,7 @@ const meta: Meta = {
12
12
 
13
13
  export default meta;
14
14
 
15
- export const ErrorStory: StoryObj = {
15
+ export const GenericErrorStory: StoryObj = {
16
16
  render: () => (
17
17
  <ResizeContainer size={{ height: '600px', width: '100%' }}>
18
18
  <ErrorDisplay error={new Error('some message')} />
@@ -48,3 +48,21 @@ export const UserFacingErrorStory: StoryObj = {
48
48
  });
49
49
  },
50
50
  };
51
+
52
+ export const FiresEvent: StoryObj = {
53
+ render: () => (
54
+ <ResizeContainer size={{ height: '600px', width: '100%' }}>
55
+ <ErrorDisplay error={new UserFacingError('Error Title', 'some message')} />
56
+ </ResizeContainer>
57
+ ),
58
+
59
+ play: async ({ canvasElement }) => {
60
+ const listenerMock = fn();
61
+ canvasElement.addEventListener('gs-error', listenerMock);
62
+
63
+ await waitFor(() => {
64
+ expect(listenerMock.mock.calls.at(-1)[0].error.name).toStrictEqual('UserFacingError');
65
+ expect(listenerMock.mock.calls.at(-1)[0].error.message).toStrictEqual('some message');
66
+ });
67
+ },
68
+ };
@@ -1,5 +1,18 @@
1
1
  import { type FunctionComponent } from 'preact';
2
- import { useRef } from 'preact/hooks';
2
+ import { useEffect, useRef } from 'preact/hooks';
3
+
4
+ import { LapisError, UnknownLapisError } from '../../lapisApi/lapisApi';
5
+
6
+ export const GS_ERROR_EVENT_TYPE = 'gs-error';
7
+
8
+ export class ErrorEvent extends Event {
9
+ constructor(public readonly error: Error) {
10
+ super(GS_ERROR_EVENT_TYPE, {
11
+ bubbles: true,
12
+ composed: true,
13
+ });
14
+ }
15
+ }
3
16
 
4
17
  export class UserFacingError extends Error {
5
18
  constructor(
@@ -14,20 +27,27 @@ export class UserFacingError extends Error {
14
27
  export const ErrorDisplay: FunctionComponent<{ error: Error }> = ({ error }) => {
15
28
  console.error(error);
16
29
 
30
+ const containerRef = useRef<HTMLInputElement>(null);
17
31
  const ref = useRef<HTMLDialogElement>(null);
18
32
 
33
+ useEffect(() => {
34
+ containerRef.current?.dispatchEvent(new ErrorEvent(error));
35
+ });
36
+
37
+ const { headline, details } = getDisplayedErrorMessage(error);
38
+
19
39
  return (
20
- <div className='h-full w-full rounded-md border-2 border-gray-100 p-2 flex items-center justify-center flex-col'>
21
- <div className='text-red-700 font-bold'>Error</div>
40
+ <div
41
+ ref={containerRef}
42
+ className='h-full w-full rounded-md border-2 border-gray-100 p-2 flex items-center justify-center flex-col'
43
+ >
44
+ <div className='text-red-700 font-bold'>{headline}</div>
22
45
  <div>
23
46
  Oops! Something went wrong.
24
- {error instanceof UserFacingError && (
47
+ {details !== undefined && (
25
48
  <>
26
49
  {' '}
27
- <button
28
- className='text-sm text-gray-600 hover:text-gray-300'
29
- onClick={() => ref.current?.showModal()}
30
- >
50
+ <button className='underline hover:text-gray-400' onClick={() => ref.current?.showModal()}>
31
51
  Show details.
32
52
  </button>
33
53
  <dialog ref={ref} class='modal'>
@@ -37,8 +57,8 @@ export const ErrorDisplay: FunctionComponent<{ error: Error }> = ({ error }) =>
37
57
 
38
58
  </button>
39
59
  </form>
40
- <h1 class='text-lg'>{error.headline}</h1>
41
- <p class='py-4'>{error.message}</p>
60
+ <h1 class='text-lg'>{details.headline}</h1>
61
+ <p class='py-4'>{details.message}</p>
42
62
  </div>
43
63
  <form method='dialog' class='modal-backdrop'>
44
64
  <button>close</button>
@@ -50,3 +70,37 @@ export const ErrorDisplay: FunctionComponent<{ error: Error }> = ({ error }) =>
50
70
  </div>
51
71
  );
52
72
  };
73
+
74
+ function getDisplayedErrorMessage(error: Error) {
75
+ if (error instanceof UserFacingError) {
76
+ return {
77
+ headline: `Error - ${error.headline}`,
78
+ details: {
79
+ headline: error.headline,
80
+ message: error.message,
81
+ },
82
+ };
83
+ }
84
+
85
+ if (error instanceof LapisError) {
86
+ return {
87
+ headline: `Error - Failed fetching ${error.requestedData} from LAPIS`,
88
+ details: {
89
+ headline: `LAPIS request failed: ${error.requestedData} - ${error.problemDetail.status} ${error.problemDetail.title}`,
90
+ message: error.problemDetail.detail ?? error.message,
91
+ },
92
+ };
93
+ }
94
+
95
+ if (error instanceof UnknownLapisError) {
96
+ return {
97
+ headline: `Error - Failed fetching ${error.requestedData} from LAPIS`,
98
+ details: {
99
+ headline: `LAPIS request failed: An unexpected error occurred while fetching ${error.requestedData}`,
100
+ message: error.message,
101
+ },
102
+ };
103
+ }
104
+
105
+ return { headline: 'Error', details: undefined };
106
+ }
@@ -1,9 +1,9 @@
1
1
  import { type Meta, type StoryObj } from '@storybook/preact';
2
2
  import { expect, userEvent, waitFor, within } from '@storybook/test';
3
3
 
4
- import Info, { type InfoProps } from './info';
4
+ import Info from './info';
5
5
 
6
- const meta: Meta<InfoProps> = {
6
+ const meta: Meta = {
7
7
  title: 'Component/Info',
8
8
  component: Info,
9
9
  parameters: { fetchMock: {} },
@@ -13,7 +13,7 @@ export default meta;
13
13
 
14
14
  const tooltipText = 'This is a tooltip which shows some information.';
15
15
 
16
- export const InfoStory: StoryObj<InfoProps> = {
16
+ export const InfoStory: StoryObj = {
17
17
  render: (args) => (
18
18
  <div class='flex justify-center px-4 py-16'>
19
19
  <Info {...args}>{tooltipText}</Info>
@@ -21,7 +21,7 @@ export const InfoStory: StoryObj<InfoProps> = {
21
21
  ),
22
22
  };
23
23
 
24
- export const OpenInfo: StoryObj<InfoProps> = {
24
+ export const OpenInfo: StoryObj = {
25
25
  ...InfoStory,
26
26
  play: async ({ canvasElement }) => {
27
27
  const canvas = within(canvasElement);
@@ -30,7 +30,7 @@ export const OpenInfo: StoryObj<InfoProps> = {
30
30
  },
31
31
  };
32
32
 
33
- export const ShowsAndClosesInfoOnClick: StoryObj<InfoProps> = {
33
+ export const ShowsAndClosesInfoOnClick: StoryObj = {
34
34
  ...InfoStory,
35
35
  play: async ({ canvasElement, step }) => {
36
36
  const canvas = within(canvasElement);
@@ -1,9 +1,7 @@
1
1
  import { type FunctionComponent } from 'preact';
2
2
  import { useRef } from 'preact/hooks';
3
3
 
4
- export interface InfoProps {}
5
-
6
- const Info: FunctionComponent<InfoProps> = ({ children }) => {
4
+ const Info: FunctionComponent = ({ children }) => {
7
5
  const dialogRef = useRef<HTMLDialogElement>(null);
8
6
 
9
7
  const toggleHelp = () => {
@@ -1,4 +1,3 @@
1
- import { withActions } from '@storybook/addon-actions/decorator';
2
1
  import { type Meta, type StoryObj } from '@storybook/preact';
3
2
  import { expect, waitFor, within } from '@storybook/test';
4
3
  import dayjs from 'dayjs/esm';
@@ -13,6 +12,7 @@ import {
13
12
  PRESET_VALUE_LAST_6_MONTHS,
14
13
  PRESET_VALUE_LAST_MONTH,
15
14
  } from './selectableOptions';
15
+ import { previewHandles } from '../../../.storybook/preview';
16
16
  import { LAPIS_URL } from '../../constants';
17
17
  import { LapisUrlContext } from '../LapisUrlContext';
18
18
 
@@ -23,7 +23,7 @@ const meta: Meta<DateRangeSelectorProps<'CustomDateRange'>> = {
23
23
  component: DateRangeSelector,
24
24
  parameters: {
25
25
  actions: {
26
- handles: ['gs-date-range-changed'],
26
+ handles: ['gs-date-range-changed', ...previewHandles],
27
27
  },
28
28
  fetchMock: {},
29
29
  },
@@ -68,7 +68,6 @@ const meta: Meta<DateRangeSelectorProps<'CustomDateRange'>> = {
68
68
  initialDateFrom: '',
69
69
  initialDateTo: '',
70
70
  },
71
- decorators: [withActions],
72
71
  };
73
72
 
74
73
  export default meta;
@@ -1,7 +1,7 @@
1
- import { withActions } from '@storybook/addon-actions/decorator';
2
1
  import { type Meta, type StoryObj } from '@storybook/preact';
3
2
 
4
3
  import { LineageFilter, type LineageFilterProps } from './lineage-filter';
4
+ import { previewHandles } from '../../../.storybook/preview';
5
5
  import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
6
6
  import aggregatedData from '../../preact/lineageFilter/__mockData__/aggregated.json';
7
7
  import { LapisUrlContext } from '../LapisUrlContext';
@@ -11,7 +11,7 @@ const meta: Meta = {
11
11
  component: LineageFilter,
12
12
  parameters: {
13
13
  actions: {
14
- handles: ['gs-lineage-filter-changed'],
14
+ handles: ['gs-lineage-filter-changed', ...previewHandles],
15
15
  },
16
16
  fetchMock: {
17
17
  mocks: [
@@ -31,7 +31,6 @@ const meta: Meta = {
31
31
  ],
32
32
  },
33
33
  },
34
- decorators: [withActions],
35
34
  };
36
35
 
37
36
  export default meta;
@@ -1,6 +1,4 @@
1
- import { LapisError } from '../../lapisApi/lapisApi';
2
1
  import { FetchAggregatedOperator } from '../../operator/FetchAggregatedOperator';
3
- import { UserFacingError } from '../components/error-display';
4
2
 
5
3
  export async function fetchAutocompletionList(fields: string[], lapis: string, signal?: AbortSignal) {
6
4
  const toAncestorInHierarchyOverwriteValues = Array(fields.length - 1)
@@ -10,18 +8,7 @@ export async function fetchAutocompletionList(fields: string[], lapis: string, s
10
8
 
11
9
  const fetchAggregatedOperator = new FetchAggregatedOperator<Record<string, string | null>>({}, fields);
12
10
 
13
- let data;
14
- try {
15
- data = (await fetchAggregatedOperator.evaluate(lapis, signal)).content;
16
- } catch (error) {
17
- if (error instanceof LapisError) {
18
- throw new UserFacingError(
19
- `Failed to fetch autocomplete list from LAPIS: ${error.problemDetail.status} ${error.problemDetail.title ?? ''}`,
20
- error.problemDetail.detail ?? error.message,
21
- );
22
- }
23
- throw error;
24
- }
11
+ const data = (await fetchAggregatedOperator.evaluate(lapis, signal)).content;
25
12
 
26
13
  const locationValues = data
27
14
  .map((entry) => fields.reduce((acc, field) => ({ ...acc, [field]: entry[field] }), {}))
@@ -1,8 +1,8 @@
1
- import { withActions } from '@storybook/addon-actions/decorator';
2
1
  import { type Meta, type StoryObj } from '@storybook/preact';
3
2
 
4
3
  import data from './__mockData__/aggregated.json';
5
4
  import { LocationFilter, type LocationFilterProps } from './location-filter';
5
+ import { previewHandles } from '../../../.storybook/preview';
6
6
  import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
7
7
  import { LapisUrlContext } from '../LapisUrlContext';
8
8
 
@@ -28,7 +28,7 @@ const meta: Meta<LocationFilterProps> = {
28
28
  ],
29
29
  },
30
30
  actions: {
31
- handles: ['gs-location-changed'],
31
+ handles: ['gs-location-changed', ...previewHandles],
32
32
  },
33
33
  },
34
34
  args: {
@@ -59,7 +59,6 @@ const meta: Meta<LocationFilterProps> = {
59
59
  },
60
60
  },
61
61
  },
62
- decorators: [withActions],
63
62
  };
64
63
 
65
64
  export default meta;
@@ -1,9 +1,9 @@
1
- import { withActions } from '@storybook/addon-actions/decorator';
2
1
  import { type Meta, type PreactRenderer, type StoryObj } from '@storybook/preact';
3
2
  import { expect, fireEvent, fn, userEvent, waitFor, within } from '@storybook/test';
4
3
  import { type StepFunction } from '@storybook/types';
5
4
 
6
5
  import { MutationFilter, type MutationFilterProps } from './mutation-filter';
6
+ import { previewHandles } from '../../../.storybook/preview';
7
7
  import { LAPIS_URL } from '../../constants';
8
8
  import referenceGenome from '../../lapisApi/__mockData__/referenceGenome.json';
9
9
  import { LapisUrlContext } from '../LapisUrlContext';
@@ -14,7 +14,7 @@ const meta: Meta<MutationFilterProps> = {
14
14
  component: MutationFilter,
15
15
  parameters: {
16
16
  actions: {
17
- handles: ['gs-mutation-filter-changed', 'gs-mutation-filter-on-blur'],
17
+ handles: ['gs-mutation-filter-changed', 'gs-mutation-filter-on-blur', ...previewHandles],
18
18
  },
19
19
  fetchMock: {},
20
20
  },
@@ -26,7 +26,6 @@ const meta: Meta<MutationFilterProps> = {
26
26
  },
27
27
  },
28
28
  },
29
- decorators: [withActions],
30
29
  };
31
30
 
32
31
  export default meta;
@@ -69,7 +69,7 @@ export const PrevalenceOverTimeInner: FunctionComponent<PrevalenceOverTimeProps>
69
69
  lapis,
70
70
  lapisDateField,
71
71
  ),
72
- [lapis, numeratorFilter, denominatorFilter, granularity, smoothingWindow],
72
+ [lapis, numeratorFilter, denominatorFilter, granularity, smoothingWindow, lapisDateField],
73
73
  );
74
74
 
75
75
  if (isLoading) {
@@ -66,7 +66,7 @@ export const RelativeGrowthAdvantageInner: FunctionComponent<RelativeGrowthAdvan
66
66
 
67
67
  const { data, error, isLoading } = useQuery(
68
68
  () => queryRelativeGrowthAdvantage(numeratorFilter, denominatorFilter, generationTime, lapis, lapisDateField),
69
- [lapis, numeratorFilter, denominatorFilter, generationTime, views],
69
+ [lapis, numeratorFilter, denominatorFilter, generationTime, views, lapisDateField],
70
70
  );
71
71
 
72
72
  if (isLoading) {
@@ -9,7 +9,7 @@ export function useFloatingUi(
9
9
  middleware?: Array<Middleware | null | undefined | false>,
10
10
  placement?: Placement,
11
11
  ) {
12
- const cleanupRef = useRef<Function | null>(null);
12
+ const cleanupRef = useRef<() => void | null>(null);
13
13
 
14
14
  useEffect(() => {
15
15
  if (!referenceRef.current || !floatingRef.current) {
@@ -1,9 +1,9 @@
1
- import { withActions } from '@storybook/addon-actions/decorator';
2
1
  import { type Meta, type StoryObj } from '@storybook/preact';
3
2
  import { expect, waitFor, within } from '@storybook/test';
4
3
 
5
4
  import data from './__mockData__/aggregated_hosts.json';
6
5
  import { TextInput, type TextInputProps } from './text-input';
6
+ import { previewHandles } from '../../../.storybook/preview';
7
7
  import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
8
8
  import { LapisUrlContext } from '../LapisUrlContext';
9
9
 
@@ -12,7 +12,7 @@ const meta: Meta<TextInputProps> = {
12
12
  component: TextInput,
13
13
  parameters: {
14
14
  actions: {
15
- handles: ['gs-text-input-changed'],
15
+ handles: ['gs-text-input-changed', ...previewHandles],
16
16
  },
17
17
  fetchMock: {
18
18
  mocks: [
@@ -32,7 +32,6 @@ const meta: Meta<TextInputProps> = {
32
32
  ],
33
33
  },
34
34
  },
35
- decorators: [withActions],
36
35
  argTypes: {
37
36
  lapisField: {
38
37
  control: {