@genspectrum/dashboard-components 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/util.d.ts CHANGED
@@ -949,7 +949,7 @@ declare global {
949
949
 
950
950
  declare global {
951
951
  interface HTMLElementTagNameMap {
952
- 'gs-mutations': MutationsComponent;
952
+ 'gs-prevalence-over-time': PrevalenceOverTimeComponent;
953
953
  }
954
954
  }
955
955
 
@@ -957,7 +957,7 @@ declare global {
957
957
  declare global {
958
958
  namespace JSX {
959
959
  interface IntrinsicElements {
960
- 'gs-mutations': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
960
+ 'gs-prevalence-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
961
961
  }
962
962
  }
963
963
  }
@@ -965,7 +965,7 @@ declare global {
965
965
 
966
966
  declare global {
967
967
  interface HTMLElementTagNameMap {
968
- 'gs-prevalence-over-time': PrevalenceOverTimeComponent;
968
+ 'gs-mutations': MutationsComponent;
969
969
  }
970
970
  }
971
971
 
@@ -973,7 +973,7 @@ declare global {
973
973
  declare global {
974
974
  namespace JSX {
975
975
  interface IntrinsicElements {
976
- 'gs-prevalence-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
976
+ 'gs-mutations': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
977
977
  }
978
978
  }
979
979
  }
@@ -1093,11 +1093,10 @@ declare global {
1093
1093
 
1094
1094
  declare global {
1095
1095
  interface HTMLElementTagNameMap {
1096
- 'gs-date-range-filter': DateRangeFilterComponent;
1096
+ 'gs-location-filter': LocationFilterComponent;
1097
1097
  }
1098
1098
  interface HTMLElementEventMap {
1099
- [gsEventNames.dateRangeFilterChanged]: CustomEvent<Record<string, string>>;
1100
- [gsEventNames.dateRangeOptionChanged]: DateRangeOptionChangedEvent;
1099
+ [gsEventNames.locationChanged]: LocationChangedEvent;
1101
1100
  }
1102
1101
  }
1103
1102
 
@@ -1105,7 +1104,7 @@ declare global {
1105
1104
  declare global {
1106
1105
  namespace JSX {
1107
1106
  interface IntrinsicElements {
1108
- 'gs-date-range-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1107
+ 'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1109
1108
  }
1110
1109
  }
1111
1110
  }
@@ -1113,10 +1112,10 @@ declare global {
1113
1112
 
1114
1113
  declare global {
1115
1114
  interface HTMLElementTagNameMap {
1116
- 'gs-location-filter': LocationFilterComponent;
1115
+ 'gs-text-filter': TextFilterComponent;
1117
1116
  }
1118
1117
  interface HTMLElementEventMap {
1119
- [gsEventNames.locationChanged]: LocationChangedEvent;
1118
+ [gsEventNames.textFilterChanged]: TextFilterChangedEvent;
1120
1119
  }
1121
1120
  }
1122
1121
 
@@ -1124,7 +1123,7 @@ declare global {
1124
1123
  declare global {
1125
1124
  namespace JSX {
1126
1125
  interface IntrinsicElements {
1127
- 'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1126
+ 'gs-text-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1128
1127
  }
1129
1128
  }
1130
1129
  }
@@ -1132,10 +1131,11 @@ declare global {
1132
1131
 
1133
1132
  declare global {
1134
1133
  interface HTMLElementTagNameMap {
1135
- 'gs-text-filter': TextFilterComponent;
1134
+ 'gs-date-range-filter': DateRangeFilterComponent;
1136
1135
  }
1137
1136
  interface HTMLElementEventMap {
1138
- [gsEventNames.textFilterChanged]: TextFilterChangedEvent;
1137
+ [gsEventNames.dateRangeFilterChanged]: CustomEvent<Record<string, string>>;
1138
+ [gsEventNames.dateRangeOptionChanged]: DateRangeOptionChangedEvent;
1139
1139
  }
1140
1140
  }
1141
1141
 
@@ -1143,7 +1143,7 @@ declare global {
1143
1143
  declare global {
1144
1144
  namespace JSX {
1145
1145
  interface IntrinsicElements {
1146
- 'gs-text-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1146
+ 'gs-date-range-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1147
1147
  }
1148
1148
  }
1149
1149
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genspectrum/dashboard-components",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "GenSpectrum web components for building dashboards",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-only",
@@ -2,7 +2,7 @@ import z from 'zod';
2
2
 
3
3
  const lineage = z.object({
4
4
  parents: z.array(z.string()).optional(),
5
- aliases: z.array(z.string()),
5
+ aliases: z.array(z.string()).optional(),
6
6
  });
7
7
 
8
8
  export const lineageDefinitionResponseSchema = z.record(lineage);
@@ -16,7 +16,12 @@ type MutationAnnotationPerSequenceType = {
16
16
  position: Map<string, MutationAnnotations>;
17
17
  };
18
18
 
19
- const MutationAnnotationsContext = createContext<Record<SequenceType, MutationAnnotationPerSequenceType>>({
19
+ type MutationAnnotationsContextValue = Record<SequenceType, MutationAnnotationPerSequenceType> & {
20
+ rawAnnotations: MutationAnnotations;
21
+ };
22
+
23
+ const MutationAnnotationsContext = createContext<MutationAnnotationsContextValue>({
24
+ rawAnnotations: [],
20
25
  nucleotide: {
21
26
  mutation: new Map(),
22
27
  position: new Map(),
@@ -75,6 +80,7 @@ export function getMutationAnnotationsContext(value: MutationAnnotations) {
75
80
  });
76
81
 
77
82
  return {
83
+ rawAnnotations: value,
78
84
  nucleotide: { mutation: nucleotideMap, position: nucleotidePositions },
79
85
  'amino acid': { mutation: aminoAcidMap, position: aminoAcidPositions },
80
86
  };
@@ -85,15 +91,17 @@ function addAnnotationToMap(map: Map<string, MutationAnnotations>, code: string,
85
91
  map.set(code.toUpperCase(), [...oldAnnotations, annotation]);
86
92
  }
87
93
 
94
+ export function useRawMutationAnnotations() {
95
+ return useContext(MutationAnnotationsContext).rawAnnotations;
96
+ }
97
+
88
98
  export function useMutationAnnotationsProvider() {
89
99
  const mutationAnnotations = useContext(MutationAnnotationsContext);
90
100
 
91
101
  return getMutationAnnotationsProvider(mutationAnnotations);
92
102
  }
93
103
 
94
- export function getMutationAnnotationsProvider(
95
- mutationAnnotations: Record<SequenceType, MutationAnnotationPerSequenceType>,
96
- ) {
104
+ export function getMutationAnnotationsProvider(mutationAnnotations: MutationAnnotationsContextValue) {
97
105
  return (mutation: Mutation, sequenceType: SequenceType) => {
98
106
  const position =
99
107
  mutation.segment === undefined
@@ -110,11 +118,11 @@ export function getMutationAnnotationsProvider(
110
118
 
111
119
  const uniqueNames = new Set<string>();
112
120
 
113
- return annotations?.filter((item) => {
114
- if (uniqueNames.has(item.name)) {
121
+ return annotations?.filter((annotation) => {
122
+ if (uniqueNames.has(annotation.name)) {
115
123
  return false;
116
124
  }
117
- uniqueNames.add(item.name);
125
+ uniqueNames.add(annotation.name);
118
126
  return true;
119
127
  });
120
128
  };
@@ -0,0 +1,109 @@
1
+ import { type StoryObj } from '@storybook/preact';
2
+ import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
3
+ import { type Meta } from '@storybook/web-components';
4
+ import { useState, type Dispatch, type StateUpdater } from 'preact/hooks';
5
+
6
+ import {
7
+ MutationsOverTimeMutationsFilter,
8
+ type MutationsOverTimeMutationsFilterProps,
9
+ } from './mutations-over-time-mutations-filter';
10
+ import { MutationAnnotationsContextProvider } from '../MutationAnnotationsContext';
11
+ import { type MutationFilter } from '../mutationsOverTime/getFilteredMutationsOverTimeData';
12
+
13
+ const meta: Meta = {
14
+ title: 'Component/Mutations over time mutations filter',
15
+ component: 'MutationsOverTimeTextFilter',
16
+ parameters: { fetchMock: {} },
17
+ };
18
+
19
+ export default meta;
20
+
21
+ const WrapperWithState = ({
22
+ setFilterValue,
23
+ value,
24
+ }: {
25
+ setFilterValue: Dispatch<StateUpdater<MutationFilter>>;
26
+ value: MutationFilter;
27
+ }) => {
28
+ const [state, setState] = useState(value);
29
+
30
+ return (
31
+ <MutationAnnotationsContextProvider
32
+ value={[
33
+ {
34
+ name: 'Test Annotation 1',
35
+ description: 'Test Annotation 1',
36
+ symbol: '#',
37
+ },
38
+ {
39
+ name: 'Test Annotation 2',
40
+ description: 'Test Annotation 2',
41
+ symbol: '+',
42
+ },
43
+ ]}
44
+ >
45
+ <MutationsOverTimeMutationsFilter
46
+ setFilterValue={(value) => {
47
+ setFilterValue(value);
48
+ setState(value);
49
+ }}
50
+ value={state}
51
+ />
52
+ </MutationAnnotationsContextProvider>
53
+ );
54
+ };
55
+
56
+ export const FilterByText: StoryObj<MutationsOverTimeMutationsFilterProps> = {
57
+ render: (args) => {
58
+ return <WrapperWithState setFilterValue={args.setFilterValue} value={args.value} />;
59
+ },
60
+ args: {
61
+ setFilterValue: fn(),
62
+ value: { textFilter: 'Test', annotationNameFilter: new Set([]) },
63
+ },
64
+ play: async ({ canvasElement, step }) => {
65
+ const canvas = within(canvasElement);
66
+
67
+ await step('Expect initial value to show on the button', async () => {
68
+ const button = canvas.getByRole('button');
69
+ await expect(button).toHaveTextContent('Test');
70
+ });
71
+
72
+ await step('Change filter and expect it to show on the button', async () => {
73
+ const button = canvas.getByRole('button');
74
+ await userEvent.click(button);
75
+
76
+ const inputField = canvas.getByRole('textbox');
77
+ await userEvent.clear(inputField);
78
+ await userEvent.type(inputField, 'OtherText');
79
+
80
+ await waitFor(() => expect(button).toHaveTextContent('OtherText'));
81
+ });
82
+ },
83
+ };
84
+
85
+ export const FilterByAnnotation: StoryObj<MutationsOverTimeMutationsFilterProps> = {
86
+ ...FilterByText,
87
+ args: {
88
+ setFilterValue: fn(),
89
+ value: { textFilter: '', annotationNameFilter: new Set() },
90
+ },
91
+ play: async ({ canvasElement, step }) => {
92
+ const canvas = within(canvasElement);
93
+
94
+ await step('Expect default text to show on the button', async () => {
95
+ const button = canvas.getByRole('button');
96
+ await expect(button).toHaveTextContent('Filter mutations');
97
+ });
98
+
99
+ await step('Change filter and expect it to show on the button', async () => {
100
+ const button = canvas.getByRole('button');
101
+ await userEvent.click(button);
102
+
103
+ const inputField = canvas.getByRole('checkbox', { name: /Test Annotation 1/ });
104
+ await userEvent.click(inputField);
105
+
106
+ await waitFor(() => expect(button).toHaveTextContent('Test Annotation 1'));
107
+ });
108
+ },
109
+ };
@@ -0,0 +1,139 @@
1
+ import { type FunctionComponent, type h } from 'preact';
2
+ import { type Dispatch, type StateUpdater, useCallback, useEffect, useState } from 'preact/hooks';
3
+
4
+ import { Dropdown } from './dropdown';
5
+ import { useRawMutationAnnotations } from '../MutationAnnotationsContext';
6
+ import { type MutationFilter } from '../mutationsOverTime/getFilteredMutationsOverTimeData';
7
+ import { DeleteIcon } from '../shared/icons/DeleteIcon';
8
+
9
+ export type MutationsOverTimeMutationsFilterProps = {
10
+ setFilterValue: Dispatch<StateUpdater<MutationFilter>>;
11
+ value: MutationFilter;
12
+ };
13
+
14
+ export function MutationsOverTimeMutationsFilter({ setFilterValue, value }: MutationsOverTimeMutationsFilterProps) {
15
+ return (
16
+ <div className={'w-28 inline-flex'}>
17
+ <Dropdown buttonTitle={getButtonTitle(value)} placement={'bottom-start'}>
18
+ <TextInput value={value} setFilterValue={setFilterValue} />
19
+ <AnnotationCheckboxes value={value} setFilterValue={setFilterValue} />
20
+ </Dropdown>
21
+ </div>
22
+ );
23
+ }
24
+
25
+ function getButtonTitle(value: MutationFilter) {
26
+ if (value.textFilter === '' && value.annotationNameFilter.size === 0) {
27
+ return `Filter mutations`;
28
+ }
29
+
30
+ return [value.textFilter, ...value.annotationNameFilter].filter((it) => it !== '').join(', ');
31
+ }
32
+
33
+ const TextInput: FunctionComponent<MutationsOverTimeMutationsFilterProps> = ({ setFilterValue, value }) => {
34
+ const onInput = useCallback(
35
+ (newValue: string) => {
36
+ setFilterValue((previousFilter) => ({
37
+ ...previousFilter,
38
+ textFilter: newValue,
39
+ }));
40
+ },
41
+ [setFilterValue],
42
+ );
43
+
44
+ const onDeleteClick = () => {
45
+ setFilterValue((previousFilter) => ({
46
+ ...previousFilter,
47
+ textFilter: '',
48
+ }));
49
+ };
50
+
51
+ return (
52
+ <div>
53
+ <label className='flex gap-1 input input-xs'>
54
+ <DebouncedInput placeholder={'Filter'} onInput={onInput} value={value.textFilter} type='text' />
55
+ {value.textFilter !== '' && (
56
+ <button className={'cursor-pointer'} onClick={onDeleteClick}>
57
+ <DeleteIcon />
58
+ </button>
59
+ )}
60
+ </label>
61
+ </div>
62
+ );
63
+ };
64
+
65
+ function DebouncedInput({
66
+ value: initialValue,
67
+ onInput,
68
+ debounce = 500,
69
+ ...props
70
+ }: {
71
+ onInput: (value: string) => void;
72
+ debounce?: number;
73
+ value?: string;
74
+ } & Omit<h.JSX.IntrinsicElements['input'], 'onInput'>) {
75
+ const [value, setValue] = useState<string | undefined>(initialValue);
76
+
77
+ useEffect(() => {
78
+ setValue(initialValue);
79
+ }, [initialValue]);
80
+
81
+ useEffect(() => {
82
+ const timeout = setTimeout(() => {
83
+ onInput(value ?? '');
84
+ }, debounce);
85
+
86
+ return () => clearTimeout(timeout);
87
+ }, [value, debounce, onInput]);
88
+
89
+ const onChangeInput = useCallback((event: h.JSX.TargetedEvent<HTMLInputElement>) => {
90
+ setValue(event.currentTarget.value);
91
+ }, []);
92
+
93
+ return <input {...props} value={value} onInput={onChangeInput} />;
94
+ }
95
+
96
+ const AnnotationCheckboxes: FunctionComponent<MutationsOverTimeMutationsFilterProps> = ({ value, setFilterValue }) => {
97
+ const mutationAnnotations = useRawMutationAnnotations();
98
+
99
+ if (mutationAnnotations.length === 0) {
100
+ return null;
101
+ }
102
+
103
+ return (
104
+ <>
105
+ <div className='divider mt-0.5 mb-0' />
106
+ <div className='text-sm'>
107
+ <div className='font-bold mb-1'>Filter by annotations</div>
108
+ {mutationAnnotations.map((annotation, index) => (
109
+ <li className='flex flex-row items-center' key={annotation.name}>
110
+ <label>
111
+ <input
112
+ className={'mr-2'}
113
+ type='checkbox'
114
+ id={`item-${index}`}
115
+ checked={value.annotationNameFilter.has(annotation.name)}
116
+ onChange={() => {
117
+ setFilterValue((previousFilter) => {
118
+ const newAnnotationFilter = previousFilter.annotationNameFilter.has(
119
+ annotation.name,
120
+ )
121
+ ? [...previousFilter.annotationNameFilter].filter(
122
+ (name) => name !== annotation.name,
123
+ )
124
+ : [...previousFilter.annotationNameFilter, annotation.name];
125
+ return {
126
+ ...previousFilter,
127
+ annotationNameFilter: new Set(newAnnotationFilter),
128
+ };
129
+ });
130
+ }}
131
+ />
132
+ {annotation.name} (<span className='text-red-600'>{annotation.symbol}</span>)
133
+ </label>
134
+ </li>
135
+ ))}
136
+ </div>
137
+ </>
138
+ );
139
+ };
@@ -47,6 +47,44 @@ describe('fetchLineageAutocompleteList', () => {
47
47
  ]);
48
48
  });
49
49
 
50
+ test('should work without aliases', async () => {
51
+ lapisRequestMocks.aggregated(
52
+ { fields: [lineageField], ...lapisFilter },
53
+ {
54
+ data: [
55
+ {
56
+ [lineageField]: 'A',
57
+ count: 1,
58
+ },
59
+ ],
60
+ },
61
+ );
62
+
63
+ lapisRequestMocks.lineageDefinition(
64
+ {
65
+ A: {},
66
+ },
67
+ lineageField,
68
+ );
69
+
70
+ const result = await fetchLineageAutocompleteList({
71
+ lapisUrl: DUMMY_LAPIS_URL,
72
+ lapisField: lineageField,
73
+ lapisFilter,
74
+ });
75
+
76
+ expect(result).to.deep.equal([
77
+ {
78
+ lineage: 'A',
79
+ count: 1,
80
+ },
81
+ {
82
+ lineage: 'A*',
83
+ count: 1,
84
+ },
85
+ ]);
86
+ });
87
+
50
88
  test('should add sublineage values', async () => {
51
89
  lapisRequestMocks.aggregated(
52
90
  { fields: [lineageField], ...lapisFilter },
@@ -1,7 +1,7 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
 
3
3
  import { BaseMutationOverTimeDataMap } from './MutationOverTimeData';
4
- import { getFilteredMutationOverTimeData } from './getFilteredMutationsOverTimeData';
4
+ import { getFilteredMutationOverTimeData, type MutationFilter } from './getFilteredMutationsOverTimeData';
5
5
  import { type MutationOverTimeMutationValue } from '../../query/queryMutationsOverTime';
6
6
  import { type DeletionEntry, type SubstitutionEntry } from '../../types';
7
7
  import { type Deletion, type Substitution } from '../../utils/mutations';
@@ -28,7 +28,7 @@ describe('getFilteredMutationOverTimeData', () => {
28
28
  displayedMutationTypes: [],
29
29
  proportionInterval,
30
30
  displayMutations: undefined,
31
- mutationFilterValue: '',
31
+ mutationFilterValue: { textFilter: '', annotationNameFilter: new Set() },
32
32
  sequenceType: 'nucleotide',
33
33
  annotationProvider: () => {
34
34
  return [];
@@ -62,7 +62,7 @@ describe('getFilteredMutationOverTimeData', () => {
62
62
  },
63
63
  ],
64
64
  proportionInterval,
65
- mutationFilterValue: '',
65
+ mutationFilterValue: { textFilter: '', annotationNameFilter: new Set() },
66
66
  sequenceType: 'nucleotide',
67
67
  annotationProvider: () => {
68
68
  return [];
@@ -85,7 +85,7 @@ describe('getFilteredMutationOverTimeData', () => {
85
85
  displayedSegments: [],
86
86
  displayedMutationTypes: [],
87
87
  proportionInterval,
88
- mutationFilterValue: '',
88
+ mutationFilterValue: { textFilter: '', annotationNameFilter: new Set() },
89
89
  sequenceType: 'nucleotide',
90
90
  annotationProvider: () => {
91
91
  return [];
@@ -108,7 +108,7 @@ describe('getFilteredMutationOverTimeData', () => {
108
108
  displayedSegments: [],
109
109
  displayedMutationTypes: [],
110
110
  proportionInterval,
111
- mutationFilterValue: '',
111
+ mutationFilterValue: { textFilter: '', annotationNameFilter: new Set() },
112
112
  sequenceType: 'nucleotide',
113
113
  annotationProvider: () => {
114
114
  return [];
@@ -132,7 +132,7 @@ describe('getFilteredMutationOverTimeData', () => {
132
132
  displayedSegments: [],
133
133
  displayedMutationTypes: [],
134
134
  proportionInterval,
135
- mutationFilterValue: '',
135
+ mutationFilterValue: { textFilter: '', annotationNameFilter: new Set() },
136
136
  sequenceType: 'nucleotide',
137
137
  annotationProvider: () => {
138
138
  return [];
@@ -156,7 +156,7 @@ describe('getFilteredMutationOverTimeData', () => {
156
156
  displayedSegments: [],
157
157
  displayedMutationTypes: [],
158
158
  proportionInterval,
159
- mutationFilterValue: '',
159
+ mutationFilterValue: { textFilter: '', annotationNameFilter: new Set() },
160
160
  sequenceType: 'nucleotide',
161
161
  annotationProvider: () => {
162
162
  return [];
@@ -178,7 +178,7 @@ describe('getFilteredMutationOverTimeData', () => {
178
178
  displayedSegments: [],
179
179
  displayedMutationTypes: [],
180
180
  proportionInterval,
181
- mutationFilterValue: '',
181
+ mutationFilterValue: { textFilter: '', annotationNameFilter: new Set() },
182
182
  sequenceType: 'nucleotide',
183
183
  annotationProvider: () => {
184
184
  return [];
@@ -201,7 +201,7 @@ describe('getFilteredMutationOverTimeData', () => {
201
201
  displayedSegments: [],
202
202
  displayedMutationTypes: [],
203
203
  proportionInterval,
204
- mutationFilterValue: '',
204
+ mutationFilterValue: { textFilter: '', annotationNameFilter: new Set() },
205
205
  sequenceType: 'nucleotide',
206
206
  annotationProvider: () => {
207
207
  return [];
@@ -225,7 +225,7 @@ describe('getFilteredMutationOverTimeData', () => {
225
225
  displayedMutationTypes: [],
226
226
  proportionInterval,
227
227
  displayMutations: [anotherSubstitution.code, someDeletion.code],
228
- mutationFilterValue: '',
228
+ mutationFilterValue: { textFilter: '', annotationNameFilter: new Set() },
229
229
  sequenceType: 'nucleotide',
230
230
  annotationProvider: () => {
231
231
  return [];
@@ -235,7 +235,7 @@ describe('getFilteredMutationOverTimeData', () => {
235
235
  expect(result.getFirstAxisKeys()).to.deep.equal([anotherSubstitution, someDeletion]);
236
236
  });
237
237
 
238
- it('should filter by mutation filter value', () => {
238
+ it('should filter by mutation filter text value', () => {
239
239
  const { data, overallMutationData } = prepareMutationOverTimeData([
240
240
  someSubstitutionEntry,
241
241
  anotherSubstitutionEntry,
@@ -248,7 +248,7 @@ describe('getFilteredMutationOverTimeData', () => {
248
248
  displayedSegments: [],
249
249
  displayedMutationTypes: [],
250
250
  proportionInterval,
251
- mutationFilterValue: '23T',
251
+ mutationFilterValue: { textFilter: '23T', annotationNameFilter: new Set() },
252
252
  sequenceType: 'nucleotide',
253
253
  annotationProvider: () => {
254
254
  return [];
@@ -265,7 +265,7 @@ describe('getFilteredMutationOverTimeData', () => {
265
265
  someDeletionEntry,
266
266
  ]);
267
267
 
268
- const expectFilteredValue = (filterValue: string, annotations: MutationAnnotations) => {
268
+ const expectFilteredValue = (filterValue: MutationFilter, annotations: MutationAnnotations) => {
269
269
  const annotationProvider = getMutationAnnotationsProvider(getMutationAnnotationsContext(annotations));
270
270
 
271
271
  const result = getFilteredMutationOverTimeData({
@@ -283,7 +283,7 @@ describe('getFilteredMutationOverTimeData', () => {
283
283
  };
284
284
 
285
285
  it('with filter value in symbol', () => {
286
- expectFilteredValue('#', [
286
+ expectFilteredValue({ textFilter: '#', annotationNameFilter: new Set() }, [
287
287
  {
288
288
  name: 'Annotation 1',
289
289
  description: 'Description 1',
@@ -294,7 +294,7 @@ describe('getFilteredMutationOverTimeData', () => {
294
294
  });
295
295
 
296
296
  it('with filter value in name', () => {
297
- expectFilteredValue('Annota', [
297
+ expectFilteredValue({ textFilter: 'Annota', annotationNameFilter: new Set() }, [
298
298
  {
299
299
  name: 'Annotation 1 #',
300
300
  description: 'Description 1',
@@ -305,7 +305,18 @@ describe('getFilteredMutationOverTimeData', () => {
305
305
  });
306
306
 
307
307
  it('with filter value in name', () => {
308
- expectFilteredValue('Descr', [
308
+ expectFilteredValue({ textFilter: 'Descr', annotationNameFilter: new Set() }, [
309
+ {
310
+ name: 'Annotation 1',
311
+ description: 'Description 1',
312
+ symbol: '#',
313
+ nucleotideMutations: ['A123T'],
314
+ },
315
+ ]);
316
+ });
317
+
318
+ it('with annotation name filter', () => {
319
+ expectFilteredValue({ textFilter: '', annotationNameFilter: new Set(['Annotation 1']) }, [
309
320
  {
310
321
  name: 'Annotation 1',
311
322
  description: 'Description 1',