@genspectrum/dashboard-components 0.19.3 → 0.19.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/custom-elements.json +223 -0
- package/dist/{LineageFilterChangedEvent-b0iuroUL.js → LineageFilterChangedEvent-GgkxoF3X.js} +4 -2
- package/dist/{LineageFilterChangedEvent-b0iuroUL.js.map → LineageFilterChangedEvent-GgkxoF3X.js.map} +1 -1
- package/dist/components.d.ts +137 -20
- package/dist/components.js +589 -241
- package/dist/components.js.map +1 -1
- package/dist/util.d.ts +55 -20
- package/dist/util.js +1 -1
- package/package.json +1 -1
- package/src/preact/components/min-max-range-slider.tsx +19 -4
- package/src/preact/dateRangeFilter/date-range-filter.stories.tsx +4 -1
- package/src/preact/genomeViewer/loadGff3.spec.ts +1 -1
- package/src/preact/genomeViewer/loadGff3.ts +12 -6
- package/src/preact/mutationsOverTime/getFilteredMutationsOverTimeData.ts +4 -2
- package/src/preact/numberRangeFilter/NumberRangeFilterChangedEvent.ts +31 -0
- package/src/preact/numberRangeFilter/number-range-filter.stories.tsx +383 -0
- package/src/preact/numberRangeFilter/number-range-filter.tsx +159 -0
- package/src/preact/numberRangeFilter/useSelectedRangeReducer.ts +137 -0
- package/src/preact/wastewater/mutationsOverTime/wastewater-mutations-over-time.stories.tsx +35 -1
- package/src/preact/wastewater/mutationsOverTime/wastewater-mutations-over-time.tsx +40 -3
- package/src/utilEntrypoint.ts +2 -0
- package/src/utils/gsEventNames.ts +2 -0
- package/src/web-components/input/gs-number-range-filter.spec.ts +27 -0
- package/src/web-components/input/gs-number-range-filter.stories.ts +96 -0
- package/src/web-components/input/gs-number-range-filter.tsx +148 -0
- package/src/web-components/input/gs-text-filter.stories.ts +2 -2
- package/src/web-components/input/index.ts +1 -0
- package/standalone-bundle/dashboard-components.js +6991 -6688
- package/standalone-bundle/dashboard-components.js.map +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Meta, type StoryObj } from '@storybook/preact';
|
|
2
|
-
import { expect, userEvent } from '@storybook/test';
|
|
2
|
+
import { expect, userEvent, waitFor } from '@storybook/test';
|
|
3
|
+
import type { Canvas } from '@storybook/types';
|
|
3
4
|
|
|
4
5
|
import { WastewaterMutationsOverTime, type WastewaterMutationsOverTimeProps } from './wastewater-mutations-over-time';
|
|
5
6
|
import { WISE_DETAILS_ENDPOINT, WISE_LAPIS_URL } from '../../../constants';
|
|
@@ -7,6 +8,7 @@ import referenceGenome from '../../../lapisApi/__mockData__/referenceGenome.json
|
|
|
7
8
|
import { LapisUrlContextProvider } from '../../LapisUrlContext';
|
|
8
9
|
import { ReferenceGenomeContext } from '../../ReferenceGenomeContext';
|
|
9
10
|
import details from './__mockData__/details.json';
|
|
11
|
+
import type { MutationsOverTimeProps } from '../../mutationsOverTime/mutations-over-time';
|
|
10
12
|
|
|
11
13
|
const meta: Meta<WastewaterMutationsOverTimeProps> = {
|
|
12
14
|
title: 'Wastewater visualization/Wastewater mutations over time',
|
|
@@ -108,3 +110,35 @@ export const AminoAcids: StoryObj<WastewaterMutationsOverTimeProps> = {
|
|
|
108
110
|
});
|
|
109
111
|
},
|
|
110
112
|
};
|
|
113
|
+
|
|
114
|
+
export const UsesMutationFilter: StoryObj<MutationsOverTimeProps> = {
|
|
115
|
+
...Default,
|
|
116
|
+
play: async ({ canvas, step }) => {
|
|
117
|
+
await expectMutationOnPage(canvas, 'A966C');
|
|
118
|
+
|
|
119
|
+
await step('input filter', async () => {
|
|
120
|
+
const filterButton = canvas.getByRole('button', { name: 'Filter mutations' });
|
|
121
|
+
await userEvent.click(filterButton);
|
|
122
|
+
|
|
123
|
+
const filterInput = canvas.getByPlaceholderText('Filter');
|
|
124
|
+
await userEvent.type(filterInput, '26');
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
await step('should show only matching filter', async () => {
|
|
128
|
+
await expectMutationOnPage(canvas, 'T4026G');
|
|
129
|
+
await expectMutationOnPage(canvas, 'T5260C');
|
|
130
|
+
|
|
131
|
+
await waitFor(async () => {
|
|
132
|
+
const filteredMutation = canvas.queryByText('A966C');
|
|
133
|
+
await expect(filteredMutation).not.toBeInTheDocument();
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
async function expectMutationOnPage(canvas: Canvas, mutation: string) {
|
|
140
|
+
await waitFor(async () => {
|
|
141
|
+
const mutationOnFirstPage = canvas.getAllByText(mutation)[0];
|
|
142
|
+
await expect(mutationOnFirstPage).toBeVisible();
|
|
143
|
+
});
|
|
144
|
+
}
|
|
@@ -3,20 +3,23 @@ import { type Dispatch, type StateUpdater, useMemo, useState } from 'preact/hook
|
|
|
3
3
|
import z from 'zod';
|
|
4
4
|
|
|
5
5
|
import { computeWastewaterMutationsOverTimeDataPerLocation } from './computeWastewaterMutationsOverTimeDataPerLocation';
|
|
6
|
-
import { lapisFilterSchema, sequenceTypeSchema } from '../../../types';
|
|
6
|
+
import { lapisFilterSchema, type SequenceType, sequenceTypeSchema } from '../../../types';
|
|
7
7
|
import { Map2dView } from '../../../utils/map2d';
|
|
8
8
|
import { useLapisUrl } from '../../LapisUrlContext';
|
|
9
|
+
import { useMutationAnnotationsProvider } from '../../MutationAnnotationsContext';
|
|
9
10
|
import { type ColorScale } from '../../components/color-scale-selector';
|
|
10
11
|
import { ColorScaleSelectorDropdown } from '../../components/color-scale-selector-dropdown';
|
|
11
12
|
import { ErrorBoundary } from '../../components/error-boundary';
|
|
12
13
|
import { Fullscreen } from '../../components/fullscreen';
|
|
13
14
|
import Info, { InfoComponentCode, InfoHeadline1, InfoParagraph } from '../../components/info';
|
|
14
15
|
import { LoadingDisplay } from '../../components/loading-display';
|
|
16
|
+
import { MutationsOverTimeTextFilter } from '../../components/mutations-over-time-text-filter';
|
|
15
17
|
import { NoDataDisplay } from '../../components/no-data-display';
|
|
16
18
|
import { ResizeContainer } from '../../components/resize-container';
|
|
17
19
|
import { type DisplayedSegment, SegmentSelector } from '../../components/segment-selector';
|
|
18
20
|
import Tabs from '../../components/tabs';
|
|
19
21
|
import { type MutationOverTimeDataMap } from '../../mutationsOverTime/MutationOverTimeData';
|
|
22
|
+
import { mutationOrAnnotationDoNotMatchFilter } from '../../mutationsOverTime/getFilteredMutationsOverTimeData';
|
|
20
23
|
import MutationsOverTimeGrid from '../../mutationsOverTime/mutations-over-time-grid';
|
|
21
24
|
import { pageSizesSchema } from '../../shared/tanstackTable/pagination';
|
|
22
25
|
import { PageSizeContextProvider } from '../../shared/tanstackTable/pagination-context';
|
|
@@ -111,13 +114,23 @@ type MutationOverTimeTabsProps = {
|
|
|
111
114
|
function getFilteredMutationOverTimeData({
|
|
112
115
|
data,
|
|
113
116
|
displayedSegments,
|
|
117
|
+
mutationFilterValue,
|
|
118
|
+
annotationProvider,
|
|
119
|
+
sequenceType,
|
|
114
120
|
}: {
|
|
115
121
|
data: MutationOverTimeDataMap;
|
|
116
122
|
displayedSegments: DisplayedSegment[];
|
|
123
|
+
mutationFilterValue: string;
|
|
124
|
+
sequenceType: SequenceType;
|
|
125
|
+
annotationProvider: ReturnType<typeof useMutationAnnotationsProvider>;
|
|
117
126
|
}): MutationOverTimeDataMap {
|
|
118
127
|
const filteredData = new Map2dView(data);
|
|
119
128
|
|
|
120
129
|
const mutationsToFilterOut = data.getFirstAxisKeys().filter((entry) => {
|
|
130
|
+
if (mutationOrAnnotationDoNotMatchFilter(entry, sequenceType, mutationFilterValue, annotationProvider)) {
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
|
|
121
134
|
return displayedSegments.some((segment) => segment.segment === entry.segment && !segment.checked);
|
|
122
135
|
});
|
|
123
136
|
|
|
@@ -132,6 +145,9 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
|
|
|
132
145
|
mutationOverTimeDataPerLocation,
|
|
133
146
|
originalComponentProps,
|
|
134
147
|
}) => {
|
|
148
|
+
const [mutationFilterValue, setMutationFilterValue] = useState('');
|
|
149
|
+
const annotationProvider = useMutationAnnotationsProvider();
|
|
150
|
+
|
|
135
151
|
const [colorScale, setColorScale] = useState<ColorScale>({ min: 0, max: 1, color: 'indigo' });
|
|
136
152
|
const [displayedSegments, setDisplayedSegments] = useDisplayedSegments(mutationOverTimeDataPerLocation);
|
|
137
153
|
|
|
@@ -141,14 +157,28 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
|
|
|
141
157
|
title: location,
|
|
142
158
|
content: (
|
|
143
159
|
<MutationsOverTimeGrid
|
|
144
|
-
data={getFilteredMutationOverTimeData({
|
|
160
|
+
data={getFilteredMutationOverTimeData({
|
|
161
|
+
data,
|
|
162
|
+
displayedSegments,
|
|
163
|
+
mutationFilterValue,
|
|
164
|
+
annotationProvider,
|
|
165
|
+
sequenceType: originalComponentProps.sequenceType,
|
|
166
|
+
})}
|
|
145
167
|
colorScale={colorScale}
|
|
146
168
|
pageSizes={originalComponentProps.pageSizes}
|
|
147
169
|
sequenceType={originalComponentProps.sequenceType}
|
|
148
170
|
/>
|
|
149
171
|
),
|
|
150
172
|
})),
|
|
151
|
-
[
|
|
173
|
+
[
|
|
174
|
+
mutationOverTimeDataPerLocation,
|
|
175
|
+
displayedSegments,
|
|
176
|
+
mutationFilterValue,
|
|
177
|
+
annotationProvider,
|
|
178
|
+
colorScale,
|
|
179
|
+
originalComponentProps.pageSizes,
|
|
180
|
+
originalComponentProps.sequenceType,
|
|
181
|
+
],
|
|
152
182
|
);
|
|
153
183
|
|
|
154
184
|
const toolbar = (
|
|
@@ -159,6 +189,8 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
|
|
|
159
189
|
data={mutationOverTimeDataPerLocation}
|
|
160
190
|
displayedSegments={displayedSegments}
|
|
161
191
|
setDisplayedSegments={setDisplayedSegments}
|
|
192
|
+
setFilterValue={setMutationFilterValue}
|
|
193
|
+
mutationFilterValue={mutationFilterValue}
|
|
162
194
|
/>
|
|
163
195
|
);
|
|
164
196
|
|
|
@@ -176,6 +208,8 @@ type ToolbarProps = {
|
|
|
176
208
|
data: MutationOverTimeDataPerLocation;
|
|
177
209
|
displayedSegments: DisplayedSegment[];
|
|
178
210
|
setDisplayedSegments: (segments: DisplayedSegment[]) => void;
|
|
211
|
+
mutationFilterValue: string;
|
|
212
|
+
setFilterValue: (filterValue: string) => void;
|
|
179
213
|
};
|
|
180
214
|
|
|
181
215
|
const Toolbar: FunctionComponent<ToolbarProps> = ({
|
|
@@ -184,9 +218,12 @@ const Toolbar: FunctionComponent<ToolbarProps> = ({
|
|
|
184
218
|
originalComponentProps,
|
|
185
219
|
displayedSegments,
|
|
186
220
|
setDisplayedSegments,
|
|
221
|
+
setFilterValue,
|
|
222
|
+
mutationFilterValue,
|
|
187
223
|
}) => {
|
|
188
224
|
return (
|
|
189
225
|
<>
|
|
226
|
+
<MutationsOverTimeTextFilter setFilterValue={setFilterValue} value={mutationFilterValue} />
|
|
190
227
|
<ColorScaleSelectorDropdown colorScale={colorScale} setColorScale={setColorScale} />
|
|
191
228
|
<SegmentSelector
|
|
192
229
|
displayedSegments={displayedSegments}
|
package/src/utilEntrypoint.ts
CHANGED
|
@@ -40,3 +40,5 @@ export { TextFilterChangedEvent } from './preact/textFilter/TextFilterChangedEve
|
|
|
40
40
|
export type { MutationAnnotations, MutationAnnotation } from './web-components/mutation-annotations-context';
|
|
41
41
|
|
|
42
42
|
export { gsEventNames } from './utils/gsEventNames';
|
|
43
|
+
|
|
44
|
+
export { type NumberRange } from './preact/numberRangeFilter/NumberRangeFilterChangedEvent';
|
|
@@ -6,4 +6,6 @@ export const gsEventNames = {
|
|
|
6
6
|
lineageFilterChanged: 'gs-lineage-filter-changed',
|
|
7
7
|
locationChanged: 'gs-location-changed',
|
|
8
8
|
textFilterChanged: 'gs-text-filter-changed',
|
|
9
|
+
numberRangeFilterChanged: 'gs-number-range-filter-changed',
|
|
10
|
+
numberRangeValueChanged: 'gs-number-range-value-changed',
|
|
9
11
|
} as const;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { describe, expectTypeOf, test } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { NumberRangeFilterComponent } from './gs-number-range-filter';
|
|
4
|
+
import { type NumberRangeFilterProps } from '../../preact/numberRangeFilter/number-range-filter';
|
|
5
|
+
|
|
6
|
+
describe('gs-number-range-filter types', () => {
|
|
7
|
+
test('should match', ({}) => {
|
|
8
|
+
expectTypeOf(NumberRangeFilterComponent.prototype)
|
|
9
|
+
.toHaveProperty('value')
|
|
10
|
+
.toEqualTypeOf<NumberRangeFilterProps['value']>();
|
|
11
|
+
expectTypeOf(NumberRangeFilterComponent.prototype)
|
|
12
|
+
.toHaveProperty('lapisField')
|
|
13
|
+
.toEqualTypeOf<NumberRangeFilterProps['lapisField']>();
|
|
14
|
+
expectTypeOf(NumberRangeFilterComponent.prototype)
|
|
15
|
+
.toHaveProperty('sliderMin')
|
|
16
|
+
.toEqualTypeOf<NumberRangeFilterProps['sliderMin']>();
|
|
17
|
+
expectTypeOf(NumberRangeFilterComponent.prototype)
|
|
18
|
+
.toHaveProperty('sliderMax')
|
|
19
|
+
.toEqualTypeOf<NumberRangeFilterProps['sliderMax']>();
|
|
20
|
+
expectTypeOf(NumberRangeFilterComponent.prototype)
|
|
21
|
+
.toHaveProperty('sliderStep')
|
|
22
|
+
.toEqualTypeOf<NumberRangeFilterProps['sliderStep']>();
|
|
23
|
+
expectTypeOf(NumberRangeFilterComponent.prototype)
|
|
24
|
+
.toHaveProperty('width')
|
|
25
|
+
.toEqualTypeOf<NumberRangeFilterProps['width']>();
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import '../gs-app';
|
|
2
|
+
import './gs-number-range-filter';
|
|
3
|
+
|
|
4
|
+
import { type Meta, type StoryObj } from '@storybook/web-components';
|
|
5
|
+
import { html } from 'lit';
|
|
6
|
+
|
|
7
|
+
import { withComponentDocs } from '../../../.storybook/ComponentDocsBlock';
|
|
8
|
+
import { LAPIS_URL } from '../../constants';
|
|
9
|
+
import { type NumberRangeFilterProps } from '../../preact/numberRangeFilter/number-range-filter';
|
|
10
|
+
import { gsEventNames } from '../../utils/gsEventNames';
|
|
11
|
+
|
|
12
|
+
const codeExample = String.raw`
|
|
13
|
+
<gs-number-range-filter
|
|
14
|
+
value='{"ageFrom": 10, "ageTo": 90}'
|
|
15
|
+
lapisField="age"
|
|
16
|
+
sliderMin="0"
|
|
17
|
+
sliderMax="100"
|
|
18
|
+
sliderStep="1"
|
|
19
|
+
width="50%"
|
|
20
|
+
></gs-number-range-filter>`;
|
|
21
|
+
|
|
22
|
+
const meta: Meta<NumberRangeFilterProps> = {
|
|
23
|
+
title: 'Input/Number range filter',
|
|
24
|
+
component: 'gs-number-range-filter',
|
|
25
|
+
parameters: withComponentDocs({
|
|
26
|
+
actions: {
|
|
27
|
+
handles: [gsEventNames.numberRangeFilterChanged, gsEventNames.numberRangeValueChanged],
|
|
28
|
+
},
|
|
29
|
+
componentDocs: {
|
|
30
|
+
opensShadowDom: true,
|
|
31
|
+
expectsChildren: false,
|
|
32
|
+
codeExample,
|
|
33
|
+
},
|
|
34
|
+
}),
|
|
35
|
+
tags: ['autodocs'],
|
|
36
|
+
argTypes: {
|
|
37
|
+
value: {
|
|
38
|
+
control: {
|
|
39
|
+
type: 'object',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
lapisField: {
|
|
43
|
+
control: {
|
|
44
|
+
type: 'text',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
sliderMin: {
|
|
48
|
+
control: {
|
|
49
|
+
type: 'number',
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
sliderMax: {
|
|
53
|
+
control: {
|
|
54
|
+
type: 'number',
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
sliderStep: {
|
|
58
|
+
control: {
|
|
59
|
+
type: 'number',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
width: {
|
|
63
|
+
control: {
|
|
64
|
+
type: 'text',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export default meta;
|
|
71
|
+
|
|
72
|
+
export const Default: StoryObj<NumberRangeFilterProps> = {
|
|
73
|
+
render: (args) => {
|
|
74
|
+
return html`
|
|
75
|
+
<gs-app lapis="${LAPIS_URL}">
|
|
76
|
+
<gs-number-range-filter
|
|
77
|
+
.value=${args.value}
|
|
78
|
+
.lapisField=${args.lapisField}
|
|
79
|
+
.sliderMin=${args.sliderMin}
|
|
80
|
+
.sliderMax=${args.sliderMax}
|
|
81
|
+
.sliderStep=${args.sliderStep}
|
|
82
|
+
.width=${args.width}
|
|
83
|
+
>
|
|
84
|
+
</gs-number-range-filter>
|
|
85
|
+
</gs-app>
|
|
86
|
+
`;
|
|
87
|
+
},
|
|
88
|
+
args: {
|
|
89
|
+
lapisField: 'age',
|
|
90
|
+
value: { min: 10, max: 90 },
|
|
91
|
+
sliderMin: 0,
|
|
92
|
+
sliderMax: 100,
|
|
93
|
+
sliderStep: 0.1,
|
|
94
|
+
width: '100%',
|
|
95
|
+
},
|
|
96
|
+
};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { customElement, property } from 'lit/decorators.js';
|
|
2
|
+
import type { DetailedHTMLProps, HTMLAttributes } from 'react';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
type NumberRangeFilterChangedEvent,
|
|
6
|
+
type NumberRangeValueChangedEvent,
|
|
7
|
+
} from '../../preact/numberRangeFilter/NumberRangeFilterChangedEvent';
|
|
8
|
+
import { NumberRangeFilter } from '../../preact/numberRangeFilter/number-range-filter';
|
|
9
|
+
import { type gsEventNames } from '../../utils/gsEventNames';
|
|
10
|
+
import { PreactLitAdapter } from '../PreactLitAdapter';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
* ## Context
|
|
15
|
+
*
|
|
16
|
+
* This component lets the user specify filters for a `float` or `int` field in LAPIS.
|
|
17
|
+
* It consists of two text input fields and a slider.
|
|
18
|
+
*
|
|
19
|
+
* The slider must be restricted to a certain range.
|
|
20
|
+
* Users can however still enter values outside of this range in the text input fields.
|
|
21
|
+
*
|
|
22
|
+
* @fires {CustomEvent<Record<string, string | undefined>>} gs-number-range-filter-changed
|
|
23
|
+
* Fired when the slider is released,
|
|
24
|
+
* `onBlur` on the input fields after the user has typed a valid range in the input fields,
|
|
25
|
+
* or when one of the input fields is cleared.
|
|
26
|
+
* The `details` of this event contain an object with `${lapisField}From` and `${lapisField}To` as keys.
|
|
27
|
+
* The values are the numbers from the input fields or `undefined` if the input field is empty:
|
|
28
|
+
* ```
|
|
29
|
+
* {
|
|
30
|
+
* [`${lapisField}From`]: number | undefined
|
|
31
|
+
* [`${lapisField}To`]: number | undefined
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
* Example:
|
|
35
|
+
* ```
|
|
36
|
+
* {
|
|
37
|
+
* ageFrom: 18,
|
|
38
|
+
* ageTo: undefined
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @fires {CustomEvent<Record<string, string | undefined>>} gs-number-range-value-changed
|
|
43
|
+
* Similar to the `gs-number-range-filter-changed` event,
|
|
44
|
+
* but contains an `event.detail` that has a fixed format:
|
|
45
|
+
* ```
|
|
46
|
+
* {
|
|
47
|
+
* min: number | undefined
|
|
48
|
+
* max: number | undefined
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
* This event should be used when you want to control this component externally.
|
|
52
|
+
* The `event.detail` can be used as the value of the component.
|
|
53
|
+
* Example:
|
|
54
|
+
* ```
|
|
55
|
+
* {
|
|
56
|
+
* min: 18,
|
|
57
|
+
* max: undefined
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
@customElement('gs-number-range-filter')
|
|
62
|
+
export class NumberRangeFilterComponent extends PreactLitAdapter {
|
|
63
|
+
/**
|
|
64
|
+
* The value to use for this number filter.
|
|
65
|
+
*
|
|
66
|
+
* Must be of the form:
|
|
67
|
+
* ```
|
|
68
|
+
* {
|
|
69
|
+
* [`${lapisField}From`]: number | undefined
|
|
70
|
+
* [`${lapisField}To`]: number | undefined
|
|
71
|
+
* }
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* This is the same format that the `gs-number-value-changed` event will emit.
|
|
75
|
+
*/
|
|
76
|
+
@property({ type: Object })
|
|
77
|
+
value: { min?: number; max?: number } = {};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Required.
|
|
81
|
+
*
|
|
82
|
+
* The LAPIS field name to use for this text filter.
|
|
83
|
+
* The field must exist on this LAPIS instance.
|
|
84
|
+
*/
|
|
85
|
+
@property()
|
|
86
|
+
lapisField = '';
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The `min` value to use for the slider.
|
|
90
|
+
*/
|
|
91
|
+
@property({ type: Number })
|
|
92
|
+
sliderMin = 0;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* The `max` value to use for the slider.
|
|
96
|
+
*/
|
|
97
|
+
@property({ type: Number })
|
|
98
|
+
sliderMax = 100;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* The `step` value to use for the slider.
|
|
102
|
+
*
|
|
103
|
+
* This attribute has no effect on the text input.
|
|
104
|
+
*/
|
|
105
|
+
@property({ type: Number })
|
|
106
|
+
sliderStep = 1;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The width of the component.
|
|
110
|
+
*
|
|
111
|
+
* Visit https://genspectrum.github.io/dashboard-components/?path=/docs/concepts-size-of-components--docs for more information.
|
|
112
|
+
*/
|
|
113
|
+
@property({ type: String })
|
|
114
|
+
width: string = '100%';
|
|
115
|
+
|
|
116
|
+
override render() {
|
|
117
|
+
return (
|
|
118
|
+
<NumberRangeFilter
|
|
119
|
+
value={this.value}
|
|
120
|
+
lapisField={this.lapisField}
|
|
121
|
+
sliderMin={this.sliderMin}
|
|
122
|
+
sliderMax={this.sliderMax}
|
|
123
|
+
sliderStep={this.sliderStep}
|
|
124
|
+
width={this.width}
|
|
125
|
+
/>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
declare global {
|
|
131
|
+
interface HTMLElementTagNameMap {
|
|
132
|
+
'gs-number-range-filter': NumberRangeFilterComponent;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
interface HTMLElementEventMap {
|
|
136
|
+
[gsEventNames.numberRangeFilterChanged]: NumberRangeFilterChangedEvent;
|
|
137
|
+
[gsEventNames.numberRangeValueChanged]: NumberRangeValueChangedEvent;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
declare global {
|
|
142
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
143
|
+
namespace JSX {
|
|
144
|
+
interface IntrinsicElements {
|
|
145
|
+
'gs-number-range-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -18,8 +18,8 @@ const codeExample = String.raw`
|
|
|
18
18
|
lapisFilter='{"country": "Germany"}'
|
|
19
19
|
placeholderText="Enter host name"
|
|
20
20
|
value="Homo sapiens"
|
|
21
|
-
width="50%"
|
|
22
|
-
|
|
21
|
+
width="50%"
|
|
22
|
+
></gs-text-filter>`;
|
|
23
23
|
|
|
24
24
|
const meta: Meta<Required<TextFilterProps>> = {
|
|
25
25
|
title: 'Input/Text filter',
|
|
@@ -3,3 +3,4 @@ export { LocationFilterComponent } from './gs-location-filter';
|
|
|
3
3
|
export { TextFilterComponent } from './gs-text-filter';
|
|
4
4
|
export { MutationFilterComponent } from './gs-mutation-filter';
|
|
5
5
|
export { LineageFilterComponent } from './gs-lineage-filter';
|
|
6
|
+
export { NumberRangeFilterComponent } from './gs-number-range-filter';
|