@genspectrum/dashboard-components 0.1.5 → 0.2.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/custom-elements.json +1013 -931
- package/dist/dashboard-components.js +350 -171
- package/dist/dashboard-components.js.map +1 -1
- package/dist/genspectrum-components.d.ts +48 -57
- package/dist/style.css +74 -23
- package/package.json +2 -2
- package/src/preact/aggregatedData/aggregate.tsx +28 -28
- package/src/preact/components/error-boundary.stories.tsx +62 -0
- package/src/preact/components/error-boundary.tsx +31 -0
- package/src/preact/components/error-display.stories.tsx +24 -3
- package/src/preact/components/error-display.tsx +14 -1
- package/src/preact/components/loading-display.stories.tsx +6 -6
- package/src/preact/components/loading-display.tsx +1 -1
- package/src/preact/components/no-data-display.tsx +5 -1
- package/src/preact/dateRangeSelector/date-range-selector.stories.tsx +17 -0
- package/src/preact/dateRangeSelector/date-range-selector.tsx +33 -5
- package/src/preact/locationFilter/location-filter.stories.tsx +23 -6
- package/src/preact/locationFilter/location-filter.tsx +29 -18
- package/src/preact/mutationComparison/mutation-comparison.tsx +29 -25
- package/src/preact/mutationFilter/mutation-filter.stories.tsx +17 -2
- package/src/preact/mutationFilter/mutation-filter.tsx +25 -7
- package/src/preact/mutations/mutations.tsx +23 -23
- package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +44 -28
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.tsx +43 -31
- package/src/preact/textInput/text-input.tsx +26 -3
- package/src/web-components/app.stories.ts +1 -2
- package/src/web-components/app.ts +4 -2
- package/src/web-components/index.ts +1 -1
- package/src/web-components/input/{date-range-selector-component.stories.ts → gs-date-range-selector.stories.ts} +19 -2
- package/src/web-components/input/{date-range-selector-component.tsx → gs-date-range-selector.tsx} +12 -0
- package/src/web-components/input/{location-filter-component.stories.ts → gs-location-filter.stories.ts} +29 -4
- package/src/web-components/input/{location-filter-component.tsx → gs-location-filter.tsx} +12 -1
- package/src/web-components/input/{mutation-filter-component.stories.ts → gs-mutation-filter.stories.ts} +20 -4
- package/src/web-components/input/{mutation-filter-component.tsx → gs-mutation-filter.tsx} +36 -5
- package/src/web-components/input/{text-input-component.stories.ts → gs-text-input.stories.ts} +31 -3
- package/src/web-components/input/{text-input-component.tsx → gs-text-input.tsx} +12 -0
- package/src/web-components/input/index.ts +4 -4
- package/src/web-components/visualization/data_visualization_statistical_analysis.mdx +26 -0
- package/src/web-components/{display/aggregate-component.stories.ts → visualization/gs-aggregate.stories.ts} +5 -6
- package/src/web-components/{display/aggregate-component.tsx → visualization/gs-aggregate.tsx} +1 -1
- package/src/web-components/{display/mutation-comparison-component.stories.ts → visualization/gs-mutation-comparison.stories.ts} +8 -9
- package/src/web-components/{display/mutation-comparison-component.tsx → visualization/gs-mutation-comparison.tsx} +1 -1
- package/src/web-components/{display/mutations-component.stories.ts → visualization/gs-mutations.stories.ts} +6 -7
- package/src/web-components/{display/mutations-component.tsx → visualization/gs-mutations.tsx} +2 -2
- package/src/web-components/{display/prevalence-over-time-component.stories.ts → visualization/gs-prevalence-over-time.stories.ts} +1 -2
- package/src/web-components/{display/prevalence-over-time-component.tsx → visualization/gs-prevalence-over-time.tsx} +3 -1
- package/src/web-components/{display/relative-growth-advantage-component.stories.ts → visualization/gs-relative-growth-advantage.stories.ts} +1 -2
- package/src/web-components/visualization/index.ts +5 -0
- package/src/web-components/display/index.ts +0 -5
- /package/src/web-components/{display/relative-growth-advantage-component.tsx → visualization/gs-relative-growth-advantage.tsx} +0 -0
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
} from '../../query/queryRelativeGrowthAdvantage';
|
|
9
9
|
import { type LapisFilter } from '../../types';
|
|
10
10
|
import { LapisUrlContext } from '../LapisUrlContext';
|
|
11
|
+
import { ErrorBoundary } from '../components/error-boundary';
|
|
11
12
|
import { ErrorDisplay } from '../components/error-display';
|
|
12
13
|
import Headline from '../components/headline';
|
|
13
14
|
import Info, { InfoHeadline1, InfoHeadline2, InfoLink, InfoParagraph } from '../components/info';
|
|
@@ -21,22 +22,49 @@ import { useQuery } from '../useQuery';
|
|
|
21
22
|
|
|
22
23
|
export type View = 'line';
|
|
23
24
|
|
|
24
|
-
export interface RelativeGrowthAdvantageProps {
|
|
25
|
+
export interface RelativeGrowthAdvantageProps extends RelativeGrowthAdvantagePropsInner {
|
|
26
|
+
size?: Size;
|
|
27
|
+
headline?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface RelativeGrowthAdvantagePropsInner {
|
|
25
31
|
numerator: LapisFilter;
|
|
26
32
|
denominator: LapisFilter;
|
|
27
33
|
generationTime: number;
|
|
28
34
|
views: View[];
|
|
29
|
-
size?: Size;
|
|
30
|
-
headline?: string;
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
export const RelativeGrowthAdvantage: FunctionComponent<RelativeGrowthAdvantageProps> = ({
|
|
38
|
+
views,
|
|
39
|
+
size,
|
|
34
40
|
numerator,
|
|
35
41
|
denominator,
|
|
36
42
|
generationTime,
|
|
37
|
-
views,
|
|
38
|
-
size,
|
|
39
43
|
headline = 'Relative growth advantage',
|
|
44
|
+
}) => {
|
|
45
|
+
const defaultSize = { height: '600px', width: '100%' };
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<ErrorBoundary size={size} defaultSize={defaultSize} headline={headline}>
|
|
49
|
+
<ResizeContainer size={size} defaultSize={defaultSize}>
|
|
50
|
+
<Headline heading={headline}>
|
|
51
|
+
<RelativeGrowthAdvantageInner
|
|
52
|
+
views={views}
|
|
53
|
+
numerator={numerator}
|
|
54
|
+
denominator={denominator}
|
|
55
|
+
generationTime={generationTime}
|
|
56
|
+
/>
|
|
57
|
+
</Headline>
|
|
58
|
+
</ResizeContainer>
|
|
59
|
+
</ErrorBoundary>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const RelativeGrowthAdvantageInner: FunctionComponent<RelativeGrowthAdvantageProps> = ({
|
|
64
|
+
numerator,
|
|
65
|
+
denominator,
|
|
66
|
+
generationTime,
|
|
67
|
+
views,
|
|
40
68
|
}) => {
|
|
41
69
|
const lapis = useContext(LapisUrlContext);
|
|
42
70
|
const [yAxisScaleType, setYAxisScaleType] = useState<ScaleType>('linear');
|
|
@@ -47,41 +75,25 @@ export const RelativeGrowthAdvantage: FunctionComponent<RelativeGrowthAdvantageP
|
|
|
47
75
|
);
|
|
48
76
|
|
|
49
77
|
if (isLoading) {
|
|
50
|
-
return
|
|
51
|
-
<Headline heading={headline}>
|
|
52
|
-
<LoadingDisplay />
|
|
53
|
-
</Headline>
|
|
54
|
-
);
|
|
78
|
+
return <LoadingDisplay />;
|
|
55
79
|
}
|
|
56
80
|
|
|
57
81
|
if (error !== null) {
|
|
58
|
-
return
|
|
59
|
-
<Headline heading={headline}>
|
|
60
|
-
<ErrorDisplay error={error} />
|
|
61
|
-
</Headline>
|
|
62
|
-
);
|
|
82
|
+
return <ErrorDisplay error={error} />;
|
|
63
83
|
}
|
|
64
84
|
|
|
65
85
|
if (data === null) {
|
|
66
|
-
return
|
|
67
|
-
<Headline heading={headline}>
|
|
68
|
-
<NoDataDisplay />
|
|
69
|
-
</Headline>
|
|
70
|
-
);
|
|
86
|
+
return <NoDataDisplay />;
|
|
71
87
|
}
|
|
72
88
|
|
|
73
89
|
return (
|
|
74
|
-
<
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
generationTime={generationTime}
|
|
82
|
-
/>
|
|
83
|
-
</Headline>
|
|
84
|
-
</ResizeContainer>
|
|
90
|
+
<RelativeGrowthAdvantageTabs
|
|
91
|
+
data={data}
|
|
92
|
+
yAxisScaleType={yAxisScaleType}
|
|
93
|
+
setYAxisScaleType={setYAxisScaleType}
|
|
94
|
+
views={views}
|
|
95
|
+
generationTime={generationTime}
|
|
96
|
+
/>
|
|
85
97
|
);
|
|
86
98
|
};
|
|
87
99
|
|
|
@@ -3,18 +3,41 @@ import { useContext, useRef } from 'preact/hooks';
|
|
|
3
3
|
|
|
4
4
|
import { fetchAutocompleteList } from './fetchAutocompleteList';
|
|
5
5
|
import { LapisUrlContext } from '../LapisUrlContext';
|
|
6
|
+
import { ErrorBoundary } from '../components/error-boundary';
|
|
6
7
|
import { ErrorDisplay } from '../components/error-display';
|
|
7
8
|
import { LoadingDisplay } from '../components/loading-display';
|
|
8
9
|
import { NoDataDisplay } from '../components/no-data-display';
|
|
10
|
+
import { ResizeContainer } from '../components/resize-container';
|
|
9
11
|
import { useQuery } from '../useQuery';
|
|
10
12
|
|
|
11
|
-
export interface
|
|
13
|
+
export interface TextInputInnerProps {
|
|
12
14
|
lapisField: string;
|
|
13
15
|
placeholderText?: string;
|
|
14
16
|
initialValue?: string;
|
|
15
17
|
}
|
|
16
18
|
|
|
17
|
-
export
|
|
19
|
+
export interface TextInputProps extends TextInputInnerProps {
|
|
20
|
+
width?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const TextInput: FunctionComponent<TextInputProps> = ({ width, lapisField, placeholderText, initialValue }) => {
|
|
24
|
+
const defaultSize = { width: '100%', height: '3rem' };
|
|
25
|
+
const size = width === undefined ? undefined : { width, height: defaultSize.height };
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<ErrorBoundary defaultSize={defaultSize} size={size}>
|
|
29
|
+
<ResizeContainer size={size} defaultSize={defaultSize}>
|
|
30
|
+
<TextInputInner lapisField={lapisField} placeholderText={placeholderText} initialValue={initialValue} />
|
|
31
|
+
</ResizeContainer>
|
|
32
|
+
</ErrorBoundary>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const TextInputInner: FunctionComponent<TextInputInnerProps> = ({
|
|
37
|
+
lapisField,
|
|
38
|
+
placeholderText,
|
|
39
|
+
initialValue,
|
|
40
|
+
}) => {
|
|
18
41
|
const lapis = useContext(LapisUrlContext);
|
|
19
42
|
|
|
20
43
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
@@ -58,7 +81,7 @@ export const TextInput: FunctionComponent<TextInputProps> = ({ lapisField, place
|
|
|
58
81
|
<>
|
|
59
82
|
<input
|
|
60
83
|
type='text'
|
|
61
|
-
class='input input-bordered'
|
|
84
|
+
class='input input-bordered w-full'
|
|
62
85
|
placeholder={placeholderText !== undefined ? placeholderText : lapisField}
|
|
63
86
|
onInput={onInput}
|
|
64
87
|
ref={inputRef}
|
|
@@ -25,7 +25,6 @@ const meta: Meta = {
|
|
|
25
25
|
parameters: withComponentDocs({
|
|
26
26
|
fetchMock: {},
|
|
27
27
|
componentDocs: {
|
|
28
|
-
tag: 'gs-app',
|
|
29
28
|
opensShadowDom: false,
|
|
30
29
|
expectsChildren: true,
|
|
31
30
|
codeExample,
|
|
@@ -92,7 +91,7 @@ export const FailsToFetchReferenceGenome: StoryObj<{ lapis: string }> = {
|
|
|
92
91
|
const canvas = within(canvasElement);
|
|
93
92
|
|
|
94
93
|
await waitFor(() => {
|
|
95
|
-
expect(canvas.getByText('Error')).toBeVisible();
|
|
94
|
+
expect(canvas.getByText('Error', { exact: false })).toBeVisible();
|
|
96
95
|
});
|
|
97
96
|
},
|
|
98
97
|
};
|
|
@@ -55,8 +55,10 @@ export class App extends LitElement {
|
|
|
55
55
|
override render() {
|
|
56
56
|
return this.updateReferenceGenome.render({
|
|
57
57
|
complete: () => html` <slot></slot>`,
|
|
58
|
-
error: () =>
|
|
59
|
-
|
|
58
|
+
error: () =>
|
|
59
|
+
html` <div class="m-2 w-full alert alert-error">
|
|
60
|
+
Error: Cannot fetch reference genome. Is LAPIS available?
|
|
61
|
+
</div>`,
|
|
60
62
|
});
|
|
61
63
|
}
|
|
62
64
|
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
PRESET_VALUE_LAST_6_MONTHS,
|
|
16
16
|
PRESET_VALUE_LAST_MONTH,
|
|
17
17
|
} from '../../preact/dateRangeSelector/date-range-selector';
|
|
18
|
-
import './date-range-selector
|
|
18
|
+
import './gs-date-range-selector';
|
|
19
19
|
import '../app';
|
|
20
20
|
import { toYYYYMMDD } from '../../preact/dateRangeSelector/dateConversion';
|
|
21
21
|
import { withinShadowRoot } from '../withinShadowRoot.story';
|
|
@@ -25,6 +25,7 @@ const codeExample = String.raw`
|
|
|
25
25
|
customSelectOptions='[{ "label": "Year 2021", "dateFrom": "2021-01-01", "dateTo": "2021-12-31" }]'
|
|
26
26
|
earliestDate="1970-01-01"
|
|
27
27
|
initialValue="${PRESET_VALUE_LAST_6_MONTHS}"
|
|
28
|
+
width="100%"
|
|
28
29
|
></gs-date-range-selector>`;
|
|
29
30
|
|
|
30
31
|
const meta: Meta<DateRangeSelectorProps<'CustomDateRange'>> = {
|
|
@@ -36,7 +37,6 @@ const meta: Meta<DateRangeSelectorProps<'CustomDateRange'>> = {
|
|
|
36
37
|
},
|
|
37
38
|
fetchMock: {},
|
|
38
39
|
componentDocs: {
|
|
39
|
-
tag: 'gs-date-range-selector',
|
|
40
40
|
opensShadowDom: true,
|
|
41
41
|
expectsChildren: false,
|
|
42
42
|
codeExample,
|
|
@@ -58,11 +58,27 @@ const meta: Meta<DateRangeSelectorProps<'CustomDateRange'>> = {
|
|
|
58
58
|
'CustomDateRange',
|
|
59
59
|
],
|
|
60
60
|
},
|
|
61
|
+
customSelectOptions: {
|
|
62
|
+
control: {
|
|
63
|
+
type: 'object',
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
earliestDate: {
|
|
67
|
+
control: {
|
|
68
|
+
type: 'text',
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
width: {
|
|
72
|
+
control: {
|
|
73
|
+
type: 'text',
|
|
74
|
+
},
|
|
75
|
+
},
|
|
61
76
|
},
|
|
62
77
|
args: {
|
|
63
78
|
customSelectOptions: [{ label: 'CustomDateRange', dateFrom: '2021-01-01', dateTo: '2021-12-31' }],
|
|
64
79
|
earliestDate: '1970-01-01',
|
|
65
80
|
initialValue: PRESET_VALUE_LAST_6_MONTHS,
|
|
81
|
+
width: '100%',
|
|
66
82
|
},
|
|
67
83
|
decorators: [withActions],
|
|
68
84
|
tags: ['autodocs'],
|
|
@@ -78,6 +94,7 @@ export const DateRangeSelectorStory: StoryObj<DateRangeSelectorProps<'CustomDate
|
|
|
78
94
|
.customSelectOptions=${args.customSelectOptions}
|
|
79
95
|
.earliestDate=${args.earliestDate}
|
|
80
96
|
.initialValue=${args.initialValue}
|
|
97
|
+
.width=${args.width}
|
|
81
98
|
></gs-date-range-selector>
|
|
82
99
|
</div>
|
|
83
100
|
</gs-app>`,
|
package/src/web-components/input/{date-range-selector-component.tsx → gs-date-range-selector.tsx}
RENAMED
|
@@ -64,12 +64,24 @@ export class DateRangeSelectorComponent extends PreactLitAdapter {
|
|
|
64
64
|
| string
|
|
65
65
|
| undefined = 'last6Months';
|
|
66
66
|
|
|
67
|
+
/**
|
|
68
|
+
* The width of the component.
|
|
69
|
+
*
|
|
70
|
+
* If not set, the component will take the full width of its container.
|
|
71
|
+
*
|
|
72
|
+
* The width should be a string with a unit in css style, e.g. '100%', '500px' or '50vw'.
|
|
73
|
+
* If the unit is %, the size will be relative to the container of the component.
|
|
74
|
+
*/
|
|
75
|
+
@property({ type: Object })
|
|
76
|
+
width: string | undefined = undefined;
|
|
77
|
+
|
|
67
78
|
override render() {
|
|
68
79
|
return (
|
|
69
80
|
<DateRangeSelector
|
|
70
81
|
customSelectOptions={this.customSelectOptions}
|
|
71
82
|
earliestDate={this.earliestDate}
|
|
72
83
|
initialValue={this.initialValue}
|
|
84
|
+
width={this.width}
|
|
73
85
|
/>
|
|
74
86
|
);
|
|
75
87
|
}
|
|
@@ -7,11 +7,18 @@ import { ifDefined } from 'lit/directives/if-defined.js';
|
|
|
7
7
|
import { withComponentDocs } from '../../../.storybook/ComponentDocsBlock';
|
|
8
8
|
import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
|
|
9
9
|
import '../app';
|
|
10
|
-
import './location-filter
|
|
10
|
+
import './gs-location-filter';
|
|
11
11
|
import data from '../../preact/locationFilter/__mockData__/aggregated.json';
|
|
12
12
|
import { type LocationFilterProps } from '../../preact/locationFilter/location-filter';
|
|
13
13
|
import { withinShadowRoot } from '../withinShadowRoot.story';
|
|
14
14
|
|
|
15
|
+
const codeExample = String.raw`
|
|
16
|
+
<gs-location-filter
|
|
17
|
+
fields="['region', 'country']"
|
|
18
|
+
value='Europe / Switzerland'
|
|
19
|
+
width="100%"
|
|
20
|
+
></gs-location-filter>`;
|
|
21
|
+
|
|
15
22
|
const meta: Meta = {
|
|
16
23
|
title: 'Input/Location filter',
|
|
17
24
|
component: 'gs-location-filter',
|
|
@@ -20,12 +27,28 @@ const meta: Meta = {
|
|
|
20
27
|
handles: ['gs-location-changed'],
|
|
21
28
|
},
|
|
22
29
|
componentDocs: {
|
|
23
|
-
tag: 'gs-location-filter',
|
|
24
30
|
opensShadowDom: true,
|
|
25
31
|
expectsChildren: false,
|
|
26
|
-
codeExample
|
|
32
|
+
codeExample,
|
|
27
33
|
},
|
|
28
34
|
}),
|
|
35
|
+
argTypes: {
|
|
36
|
+
fields: {
|
|
37
|
+
control: {
|
|
38
|
+
type: 'object',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
initialValue: {
|
|
42
|
+
control: {
|
|
43
|
+
type: 'text',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
width: {
|
|
47
|
+
control: {
|
|
48
|
+
type: 'text',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
29
52
|
decorators: [withActions],
|
|
30
53
|
tags: ['autodocs'],
|
|
31
54
|
};
|
|
@@ -39,6 +62,7 @@ const Template: StoryObj<LocationFilterProps> = {
|
|
|
39
62
|
<gs-location-filter
|
|
40
63
|
.fields=${args.fields}
|
|
41
64
|
initialValue=${ifDefined(args.initialValue)}
|
|
65
|
+
.width=${args.width}
|
|
42
66
|
></gs-location-filter>
|
|
43
67
|
</div>
|
|
44
68
|
</gs-app>`;
|
|
@@ -46,6 +70,7 @@ const Template: StoryObj<LocationFilterProps> = {
|
|
|
46
70
|
args: {
|
|
47
71
|
fields: ['region', 'country', 'division', 'location'],
|
|
48
72
|
initialValue: '',
|
|
73
|
+
width: '100%',
|
|
49
74
|
},
|
|
50
75
|
};
|
|
51
76
|
|
|
@@ -119,7 +144,7 @@ export const FetchingLocationsFails: StoryObj<LocationFilterProps> = {
|
|
|
119
144
|
const canvas = await withinShadowRoot(canvasElement, 'gs-location-filter');
|
|
120
145
|
|
|
121
146
|
await waitFor(() =>
|
|
122
|
-
expect(canvas.getByText('
|
|
147
|
+
expect(canvas.getByText('Oops! Something went wrong.', { exact: false })).toBeInTheDocument(),
|
|
123
148
|
);
|
|
124
149
|
},
|
|
125
150
|
};
|
|
@@ -48,8 +48,19 @@ export class LocationFilterComponent extends PreactLitAdapter {
|
|
|
48
48
|
@property({ type: Array })
|
|
49
49
|
fields: string[] = [];
|
|
50
50
|
|
|
51
|
+
/**
|
|
52
|
+
* The width of the component.
|
|
53
|
+
*
|
|
54
|
+
* If not set, the component will take the full width of its container.
|
|
55
|
+
*
|
|
56
|
+
* The width should be a string with a unit in css style, e.g. '100%', '500px' or '50vw'.
|
|
57
|
+
* If the unit is %, the size will be relative to the container of the component.
|
|
58
|
+
*/
|
|
59
|
+
@property({ type: Object })
|
|
60
|
+
width: string | undefined = undefined;
|
|
61
|
+
|
|
51
62
|
override render() {
|
|
52
|
-
return <LocationFilter initialValue={this.initialValue} fields={this.fields} />;
|
|
63
|
+
return <LocationFilter initialValue={this.initialValue} fields={this.fields} width={this.width} />;
|
|
53
64
|
}
|
|
54
65
|
}
|
|
55
66
|
|
|
@@ -8,9 +8,13 @@ import { LAPIS_URL } from '../../constants';
|
|
|
8
8
|
import '../app';
|
|
9
9
|
import { type MutationFilterProps } from '../../preact/mutationFilter/mutation-filter';
|
|
10
10
|
import { withinShadowRoot } from '../withinShadowRoot.story';
|
|
11
|
-
import './mutation-filter
|
|
11
|
+
import './gs-mutation-filter';
|
|
12
12
|
|
|
13
|
-
const codeExample = String.raw
|
|
13
|
+
const codeExample = String.raw`
|
|
14
|
+
<gs-mutation-filter
|
|
15
|
+
initialValue='["A123T"]'
|
|
16
|
+
size='{ "width": "100%", "height": "6.5rem" }'
|
|
17
|
+
></gs-mutation-filter>`;
|
|
14
18
|
|
|
15
19
|
const meta: Meta<MutationFilterProps> = {
|
|
16
20
|
title: 'Input/Mutation filter',
|
|
@@ -21,12 +25,23 @@ const meta: Meta<MutationFilterProps> = {
|
|
|
21
25
|
},
|
|
22
26
|
fetchMock: {},
|
|
23
27
|
componentDocs: {
|
|
24
|
-
tag: 'gs-mutation-filter',
|
|
25
28
|
opensShadowDom: true,
|
|
26
29
|
expectsChildren: false,
|
|
27
30
|
codeExample,
|
|
28
31
|
},
|
|
29
32
|
}),
|
|
33
|
+
argTypes: {
|
|
34
|
+
initialValue: {
|
|
35
|
+
control: {
|
|
36
|
+
type: 'object',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
size: {
|
|
40
|
+
control: {
|
|
41
|
+
type: 'object',
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
30
45
|
decorators: [withActions],
|
|
31
46
|
tags: ['autodocs'],
|
|
32
47
|
};
|
|
@@ -37,12 +52,13 @@ const Template: StoryObj<MutationFilterProps> = {
|
|
|
37
52
|
render: (args) => {
|
|
38
53
|
return html` <gs-app lapis="${LAPIS_URL}">
|
|
39
54
|
<div class="max-w-screen-lg">
|
|
40
|
-
<gs-mutation-filter .initialValue=${args.initialValue}></gs-mutation-filter>
|
|
55
|
+
<gs-mutation-filter .initialValue=${args.initialValue} .size=${args.size}></gs-mutation-filter>
|
|
41
56
|
</div>
|
|
42
57
|
</gs-app>`;
|
|
43
58
|
},
|
|
44
59
|
args: {
|
|
45
60
|
initialValue: [],
|
|
61
|
+
size: { width: '100%', height: '3rem' },
|
|
46
62
|
},
|
|
47
63
|
};
|
|
48
64
|
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { customElement, property } from 'lit/decorators.js';
|
|
2
2
|
|
|
3
|
-
import { type TextInputComponent } from './text-input-component';
|
|
4
3
|
import { ReferenceGenomesAwaiter } from '../../preact/components/ReferenceGenomesAwaiter';
|
|
5
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
MutationFilter,
|
|
6
|
+
type MutationFilterProps,
|
|
7
|
+
type SelectedMutationFilterStrings,
|
|
8
|
+
} from '../../preact/mutationFilter/mutation-filter';
|
|
9
|
+
import type { Equals, Expect } from '../../utils/typeAssertions';
|
|
6
10
|
import { PreactLitAdapter } from '../PreactLitAdapter';
|
|
7
11
|
|
|
8
12
|
/**
|
|
@@ -53,6 +57,8 @@ import { PreactLitAdapter } from '../PreactLitAdapter';
|
|
|
53
57
|
*/
|
|
54
58
|
@customElement('gs-mutation-filter')
|
|
55
59
|
export class MutationFilterComponent extends PreactLitAdapter {
|
|
60
|
+
// prettier-ignore
|
|
61
|
+
// The multiline union type must not start with `|` because it looks weird in the Storybook docs
|
|
56
62
|
/**
|
|
57
63
|
* The initial value to use for this mutation filter.
|
|
58
64
|
* Must be either
|
|
@@ -60,12 +66,31 @@ export class MutationFilterComponent extends PreactLitAdapter {
|
|
|
60
66
|
* - an object with the keys `nucleotideMutations`, `aminoAcidMutations`, `nucleotideInsertions` and `aminoAcidInsertions` and corresponding string arrays.
|
|
61
67
|
*/
|
|
62
68
|
@property()
|
|
63
|
-
initialValue:
|
|
69
|
+
initialValue:
|
|
70
|
+
{
|
|
71
|
+
nucleotideMutations: string[];
|
|
72
|
+
aminoAcidMutations: string[];
|
|
73
|
+
nucleotideInsertions: string[];
|
|
74
|
+
aminoAcidInsertions: string[];
|
|
75
|
+
}
|
|
76
|
+
| string[]
|
|
77
|
+
| undefined = undefined;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The size of the component.
|
|
81
|
+
*
|
|
82
|
+
* If not set, the component will take the full width of its container with height 700px.
|
|
83
|
+
*
|
|
84
|
+
* The width and height should be a string with a unit in css style, e.g. '100%', '500px' or '50vh'.
|
|
85
|
+
* If the unit is %, the size will be relative to the container of the component.
|
|
86
|
+
*/
|
|
87
|
+
@property({ type: Object })
|
|
88
|
+
size: { width?: string; height?: string } | undefined = undefined;
|
|
64
89
|
|
|
65
90
|
override render() {
|
|
66
91
|
return (
|
|
67
92
|
<ReferenceGenomesAwaiter>
|
|
68
|
-
<MutationFilter initialValue={this.initialValue} />
|
|
93
|
+
<MutationFilter initialValue={this.initialValue} size={this.size} />
|
|
69
94
|
</ReferenceGenomesAwaiter>
|
|
70
95
|
);
|
|
71
96
|
}
|
|
@@ -73,7 +98,7 @@ export class MutationFilterComponent extends PreactLitAdapter {
|
|
|
73
98
|
|
|
74
99
|
declare global {
|
|
75
100
|
interface HTMLElementTagNameMap {
|
|
76
|
-
'gs-mutation-filter':
|
|
101
|
+
'gs-mutation-filter': MutationFilterComponent;
|
|
77
102
|
}
|
|
78
103
|
|
|
79
104
|
interface HTMLElementEventMap {
|
|
@@ -81,3 +106,9 @@ declare global {
|
|
|
81
106
|
'gs-mutation-filter-on-blur': CustomEvent<SelectedMutationFilterStrings>;
|
|
82
107
|
}
|
|
83
108
|
}
|
|
109
|
+
|
|
110
|
+
/* eslint-disable @typescript-eslint/no-unused-vars, no-unused-vars */
|
|
111
|
+
type InitialValueMatches = Expect<
|
|
112
|
+
Equals<typeof MutationFilterComponent.prototype.initialValue, MutationFilterProps['initialValue']>
|
|
113
|
+
>;
|
|
114
|
+
/* eslint-enable @typescript-eslint/no-unused-vars, no-unused-vars */
|
package/src/web-components/input/{text-input-component.stories.ts → gs-text-input.stories.ts}
RENAMED
|
@@ -6,13 +6,18 @@ import { html } from 'lit';
|
|
|
6
6
|
import { withComponentDocs } from '../../../.storybook/ComponentDocsBlock';
|
|
7
7
|
import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
|
|
8
8
|
import '../app';
|
|
9
|
-
import './text-input
|
|
9
|
+
import './gs-text-input';
|
|
10
10
|
import data from '../../preact/textInput/__mockData__/aggregated_hosts.json';
|
|
11
11
|
import type { TextInputProps } from '../../preact/textInput/text-input';
|
|
12
12
|
import { withinShadowRoot } from '../withinShadowRoot.story';
|
|
13
13
|
|
|
14
14
|
const codeExample = String.raw`
|
|
15
|
-
<gs-text-input
|
|
15
|
+
<gs-text-input
|
|
16
|
+
lapisField="host"
|
|
17
|
+
placeholderText="Enter host name"
|
|
18
|
+
initialValue="Homo sapiens"
|
|
19
|
+
width="50%">
|
|
20
|
+
</gs-text-input>`;
|
|
16
21
|
|
|
17
22
|
const meta: Meta<TextInputProps> = {
|
|
18
23
|
title: 'Input/Text input',
|
|
@@ -39,12 +44,33 @@ const meta: Meta<TextInputProps> = {
|
|
|
39
44
|
],
|
|
40
45
|
},
|
|
41
46
|
componentDocs: {
|
|
42
|
-
tag: 'gs-text-input',
|
|
43
47
|
opensShadowDom: true,
|
|
44
48
|
expectsChildren: false,
|
|
45
49
|
codeExample,
|
|
46
50
|
},
|
|
47
51
|
}),
|
|
52
|
+
argTypes: {
|
|
53
|
+
lapisField: {
|
|
54
|
+
control: {
|
|
55
|
+
type: 'text',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
placeholderText: {
|
|
59
|
+
control: {
|
|
60
|
+
type: 'text',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
initialValue: {
|
|
64
|
+
control: {
|
|
65
|
+
type: 'text',
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
width: {
|
|
69
|
+
control: {
|
|
70
|
+
type: 'text',
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
},
|
|
48
74
|
decorators: [withActions],
|
|
49
75
|
tags: ['autodocs'],
|
|
50
76
|
};
|
|
@@ -59,6 +85,7 @@ export const Default: StoryObj<TextInputProps> = {
|
|
|
59
85
|
.lapisField=${args.lapisField}
|
|
60
86
|
.placeholderText=${args.placeholderText}
|
|
61
87
|
.initialValue=${args.initialValue}
|
|
88
|
+
.width=${args.width}
|
|
62
89
|
></gs-text-input>
|
|
63
90
|
</div>
|
|
64
91
|
</gs-app>`;
|
|
@@ -67,6 +94,7 @@ export const Default: StoryObj<TextInputProps> = {
|
|
|
67
94
|
lapisField: 'host',
|
|
68
95
|
placeholderText: 'Enter host name',
|
|
69
96
|
initialValue: 'Homo sapiens',
|
|
97
|
+
width: '100%',
|
|
70
98
|
},
|
|
71
99
|
};
|
|
72
100
|
|
|
@@ -39,12 +39,24 @@ export class TextInputComponent extends PreactLitAdapter {
|
|
|
39
39
|
@property()
|
|
40
40
|
placeholderText: string | undefined = '';
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* The width of the component.
|
|
44
|
+
*
|
|
45
|
+
* If not set, the component will take the full width of its container.
|
|
46
|
+
*
|
|
47
|
+
* The width should be a string with a unit in css style, e.g. '100%', '500px' or '50vw'.
|
|
48
|
+
* If the unit is %, the size will be relative to the container of the component.
|
|
49
|
+
*/
|
|
50
|
+
@property({ type: Object })
|
|
51
|
+
width: string | undefined = undefined;
|
|
52
|
+
|
|
42
53
|
override render() {
|
|
43
54
|
return (
|
|
44
55
|
<TextInput
|
|
45
56
|
lapisField={this.lapisField}
|
|
46
57
|
placeholderText={this.placeholderText}
|
|
47
58
|
initialValue={this.initialValue}
|
|
59
|
+
width={this.width}
|
|
48
60
|
/>
|
|
49
61
|
);
|
|
50
62
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { DateRangeSelectorComponent } from './date-range-selector
|
|
2
|
-
export { LocationFilterComponent } from './location-filter
|
|
3
|
-
export { TextInputComponent } from './text-input
|
|
4
|
-
export { MutationFilterComponent } from './mutation-filter
|
|
1
|
+
export { DateRangeSelectorComponent } from './gs-date-range-selector';
|
|
2
|
+
export { LocationFilterComponent } from './gs-location-filter';
|
|
3
|
+
export { TextInputComponent } from './gs-text-input';
|
|
4
|
+
export { MutationFilterComponent } from './gs-mutation-filter';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Meta } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
<Meta title='Visualization/Data Visualization and Statistical Analysis' />
|
|
4
|
+
|
|
5
|
+
# Data Visualization and Statistical Analysis
|
|
6
|
+
|
|
7
|
+
## Scales
|
|
8
|
+
|
|
9
|
+
On most plots, users can select the y-axis scaling through a dropdown.
|
|
10
|
+
They can choose between linear, logarithmic and logistic scaling.
|
|
11
|
+
By default, it is set to a linear scale.
|
|
12
|
+
|
|
13
|
+
In general, for each scale the displayed height of a value is calculated by applying the corresponding scale function.
|
|
14
|
+
|
|
15
|
+
- Linear: `value`
|
|
16
|
+
- Logarithmic: `ln(value)`
|
|
17
|
+
- Logistic: `ln(value / (1 - value))`
|
|
18
|
+
|
|
19
|
+
## Confidence Intervals
|
|
20
|
+
|
|
21
|
+
On bar and line plots, users can choose to display confidence intervals.
|
|
22
|
+
For line plots, this is done by shading the area between the upper and lower bounds.
|
|
23
|
+
For bar plots, this is done by adding error bars to the top of each bar.
|
|
24
|
+
|
|
25
|
+
Currently, only one method is available for calculating the confidence intervals:
|
|
26
|
+
the [wilson score interval](https://en.wikipedia.org/wiki/Binomial_proportion_confidence_interval#Wilson_score_interval) with a confidence level of 95%.
|