@genspectrum/dashboard-components 0.1.4 → 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 +1021 -804
- package/dist/dashboard-components.js +647 -218
- package/dist/dashboard-components.js.map +1 -1
- package/dist/genspectrum-components.d.ts +336 -126
- package/dist/style.css +214 -36
- package/package.json +4 -4
- package/src/preact/aggregatedData/aggregate.stories.tsx +2 -0
- package/src/preact/aggregatedData/aggregate.tsx +33 -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/headline.stories.tsx +19 -1
- package/src/preact/components/headline.tsx +9 -1
- package/src/preact/components/info.stories.tsx +24 -3
- package/src/preact/components/info.tsx +49 -5
- 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 +43 -15
- 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.stories.tsx +3 -0
- package/src/preact/mutationComparison/mutation-comparison.tsx +31 -27
- package/src/preact/mutationFilter/mutation-filter.stories.tsx +17 -2
- package/src/preact/mutationFilter/mutation-filter.tsx +26 -8
- package/src/preact/mutations/mutations.stories.tsx +3 -0
- package/src/preact/mutations/mutations.tsx +32 -26
- package/src/preact/prevalenceOverTime/prevalence-over-time.stories.tsx +4 -0
- package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +57 -31
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.stories.tsx +3 -0
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.tsx +89 -32
- 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} +35 -3
- package/src/web-components/input/gs-date-range-selector.tsx +110 -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} +30 -4
- package/src/web-components/input/gs-mutation-filter.tsx +114 -0
- package/src/web-components/input/{text-input-component.stories.ts → gs-text-input.stories.ts} +42 -3
- package/src/web-components/input/gs-text-input.tsx +73 -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} +8 -6
- package/src/web-components/{display/aggregate-component.tsx → visualization/gs-aggregate.tsx} +16 -2
- package/src/web-components/{display/mutation-comparison-component.stories.ts → visualization/gs-mutation-comparison.stories.ts} +11 -9
- package/src/web-components/{display/mutation-comparison-component.tsx → visualization/gs-mutation-comparison.tsx} +8 -1
- package/src/web-components/{display/mutations-component.stories.ts → visualization/gs-mutations.stories.ts} +30 -11
- package/src/web-components/visualization/gs-mutations.tsx +94 -0
- package/src/web-components/{display/prevalence-over-time-component.stories.ts → visualization/gs-prevalence-over-time.stories.ts} +24 -1
- package/src/web-components/visualization/gs-prevalence-over-time.tsx +148 -0
- package/src/web-components/{display/relative-growth-advantage-component.stories.ts → visualization/gs-relative-growth-advantage.stories.ts} +21 -1
- package/src/web-components/visualization/gs-relative-growth-advantage.tsx +100 -0
- package/src/web-components/visualization/index.ts +5 -0
- package/src/web-components/display/index.ts +0 -5
- package/src/web-components/display/mutations-component.tsx +0 -40
- package/src/web-components/display/prevalence-over-time-component.tsx +0 -58
- package/src/web-components/display/relative-growth-advantage-component.tsx +0 -49
- package/src/web-components/input/date-range-selector-component.tsx +0 -46
- package/src/web-components/input/mutation-filter-component.tsx +0 -35
- package/src/web-components/input/text-input-component.tsx +0 -39
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { customElement, property } from 'lit/decorators.js';
|
|
2
|
+
|
|
3
|
+
import { ReferenceGenomesAwaiter } from '../../preact/components/ReferenceGenomesAwaiter';
|
|
4
|
+
import {
|
|
5
|
+
MutationFilter,
|
|
6
|
+
type MutationFilterProps,
|
|
7
|
+
type SelectedMutationFilterStrings,
|
|
8
|
+
} from '../../preact/mutationFilter/mutation-filter';
|
|
9
|
+
import type { Equals, Expect } from '../../utils/typeAssertions';
|
|
10
|
+
import { PreactLitAdapter } from '../PreactLitAdapter';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* ## Context
|
|
14
|
+
* This component provides an input field to specify filters for nucleotide and amino acid mutations and insertions.
|
|
15
|
+
*
|
|
16
|
+
* Input values have to be provided one at a time and submitted by pressing the Enter key or by clicking the '+' button.
|
|
17
|
+
* After submission, the component validates the input and fires an event with the selected mutations.
|
|
18
|
+
* All previously selected mutations are displayed at the input field and added to the event.
|
|
19
|
+
* Users can remove a mutation by clicking the 'x' button next to the mutation.
|
|
20
|
+
*
|
|
21
|
+
* Validation of the input is performed according to the following rules:
|
|
22
|
+
*
|
|
23
|
+
* Mutations have to conform to the following format: `<gene/segment>:<symbol at reference><position><Substituted symbol/Deletion>`
|
|
24
|
+
* - Gene/segment: The gene or segment where the mutation occurs. Must be contained in the reference genome
|
|
25
|
+
* (Optional for elements with only one gene/segment)
|
|
26
|
+
* - Symbol at reference: The symbol at the reference position. (Optional)
|
|
27
|
+
* - Position: The position of the mutation. (Required)
|
|
28
|
+
* - Substituted symbol/Deletion: The substituted symbol or '-' for a deletion. (Required)
|
|
29
|
+
* Example: S:614G, 614G, 614- or 614G
|
|
30
|
+
*
|
|
31
|
+
* Insertions have to conform to the following format: `ins_<gene/segment>:<position>:<Inserted symbols>`
|
|
32
|
+
* - Gene/segment: The gene or segment where the insertion occurs. Must be contained in the reference genome
|
|
33
|
+
* (Optional for elements with only one gene/segment)
|
|
34
|
+
* - Position: The position of the insertion. (Required)
|
|
35
|
+
* - Inserted symbols: The symbols that are inserted. (Required)
|
|
36
|
+
* Example: ins_S:614:G, ins_614:G
|
|
37
|
+
*
|
|
38
|
+
* @fires {CustomEvent<{
|
|
39
|
+
* nucleotideMutations: string[],
|
|
40
|
+
* aminoAcidMutations: string[],
|
|
41
|
+
* nucleotideInsertions: string[],
|
|
42
|
+
* aminoAcidInsertions: string[]
|
|
43
|
+
* }>} gs-mutation-filter-changed
|
|
44
|
+
* Fired when:
|
|
45
|
+
* - The user has submitted a valid mutation or insertion
|
|
46
|
+
* - The user has removed a mutation or insertion
|
|
47
|
+
*
|
|
48
|
+
* @fires {CustomEvent<{
|
|
49
|
+
* nucleotideMutations: string[],
|
|
50
|
+
* aminoAcidMutations: string[],
|
|
51
|
+
* nucleotideInsertions: string[],
|
|
52
|
+
* aminoAcidInsertions: string[]
|
|
53
|
+
* }>} gs-mutation-filter-on-blur
|
|
54
|
+
* Fired when:
|
|
55
|
+
* - the mutation filter has lost focus
|
|
56
|
+
* Contains the selected mutations in the format
|
|
57
|
+
*/
|
|
58
|
+
@customElement('gs-mutation-filter')
|
|
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
|
|
62
|
+
/**
|
|
63
|
+
* The initial value to use for this mutation filter.
|
|
64
|
+
* Must be either
|
|
65
|
+
* - an array of strings of valid mutations.
|
|
66
|
+
* - an object with the keys `nucleotideMutations`, `aminoAcidMutations`, `nucleotideInsertions` and `aminoAcidInsertions` and corresponding string arrays.
|
|
67
|
+
*/
|
|
68
|
+
@property()
|
|
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;
|
|
89
|
+
|
|
90
|
+
override render() {
|
|
91
|
+
return (
|
|
92
|
+
<ReferenceGenomesAwaiter>
|
|
93
|
+
<MutationFilter initialValue={this.initialValue} size={this.size} />
|
|
94
|
+
</ReferenceGenomesAwaiter>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
declare global {
|
|
100
|
+
interface HTMLElementTagNameMap {
|
|
101
|
+
'gs-mutation-filter': MutationFilterComponent;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
interface HTMLElementEventMap {
|
|
105
|
+
'gs-mutation-filter-changed': CustomEvent<SelectedMutationFilterStrings>;
|
|
106
|
+
'gs-mutation-filter-on-blur': CustomEvent<SelectedMutationFilterStrings>;
|
|
107
|
+
}
|
|
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
|
@@ -3,17 +3,26 @@ import { expect, fn, userEvent, waitFor } from '@storybook/test';
|
|
|
3
3
|
import type { Meta, StoryObj } from '@storybook/web-components';
|
|
4
4
|
import { html } from 'lit';
|
|
5
5
|
|
|
6
|
+
import { withComponentDocs } from '../../../.storybook/ComponentDocsBlock';
|
|
6
7
|
import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
|
|
7
8
|
import '../app';
|
|
8
|
-
import './text-input
|
|
9
|
+
import './gs-text-input';
|
|
9
10
|
import data from '../../preact/textInput/__mockData__/aggregated_hosts.json';
|
|
10
11
|
import type { TextInputProps } from '../../preact/textInput/text-input';
|
|
11
12
|
import { withinShadowRoot } from '../withinShadowRoot.story';
|
|
12
13
|
|
|
13
|
-
const
|
|
14
|
+
const codeExample = String.raw`
|
|
15
|
+
<gs-text-input
|
|
16
|
+
lapisField="host"
|
|
17
|
+
placeholderText="Enter host name"
|
|
18
|
+
initialValue="Homo sapiens"
|
|
19
|
+
width="50%">
|
|
20
|
+
</gs-text-input>`;
|
|
21
|
+
|
|
22
|
+
const meta: Meta<TextInputProps> = {
|
|
14
23
|
title: 'Input/Text input',
|
|
15
24
|
component: 'gs-text-input',
|
|
16
|
-
parameters: {
|
|
25
|
+
parameters: withComponentDocs({
|
|
17
26
|
actions: {
|
|
18
27
|
handles: ['gs-text-input-changed'],
|
|
19
28
|
},
|
|
@@ -34,8 +43,36 @@ const meta: Meta = {
|
|
|
34
43
|
},
|
|
35
44
|
],
|
|
36
45
|
},
|
|
46
|
+
componentDocs: {
|
|
47
|
+
opensShadowDom: true,
|
|
48
|
+
expectsChildren: false,
|
|
49
|
+
codeExample,
|
|
50
|
+
},
|
|
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
|
+
},
|
|
37
73
|
},
|
|
38
74
|
decorators: [withActions],
|
|
75
|
+
tags: ['autodocs'],
|
|
39
76
|
};
|
|
40
77
|
|
|
41
78
|
export default meta;
|
|
@@ -48,6 +85,7 @@ export const Default: StoryObj<TextInputProps> = {
|
|
|
48
85
|
.lapisField=${args.lapisField}
|
|
49
86
|
.placeholderText=${args.placeholderText}
|
|
50
87
|
.initialValue=${args.initialValue}
|
|
88
|
+
.width=${args.width}
|
|
51
89
|
></gs-text-input>
|
|
52
90
|
</div>
|
|
53
91
|
</gs-app>`;
|
|
@@ -56,6 +94,7 @@ export const Default: StoryObj<TextInputProps> = {
|
|
|
56
94
|
lapisField: 'host',
|
|
57
95
|
placeholderText: 'Enter host name',
|
|
58
96
|
initialValue: 'Homo sapiens',
|
|
97
|
+
width: '100%',
|
|
59
98
|
},
|
|
60
99
|
};
|
|
61
100
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { customElement, property } from 'lit/decorators.js';
|
|
2
|
+
|
|
3
|
+
import { TextInput } from '../../preact/textInput/text-input';
|
|
4
|
+
import { PreactLitAdapter } from '../PreactLitAdapter';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* ## Context
|
|
9
|
+
*
|
|
10
|
+
* This component provides a text input field to specify filters for arbitrary fields of this Lapis instance.
|
|
11
|
+
*
|
|
12
|
+
* @fires {CustomEvent<Record<string, string>>} gs-text-input-changed
|
|
13
|
+
* Fired when the input field is changed.
|
|
14
|
+
* The `details` of this event contain an object with the `lapisField` as key and the input value as value.
|
|
15
|
+
* Example:
|
|
16
|
+
* ```
|
|
17
|
+
* {
|
|
18
|
+
* "host": "Homo sapiens"
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
@customElement('gs-text-input')
|
|
23
|
+
export class TextInputComponent extends PreactLitAdapter {
|
|
24
|
+
/**
|
|
25
|
+
* The initial value to use for this text input.
|
|
26
|
+
*/
|
|
27
|
+
@property()
|
|
28
|
+
initialValue: string | undefined = '';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The Lapis field name to use for this text input.
|
|
32
|
+
*/
|
|
33
|
+
@property()
|
|
34
|
+
lapisField = '';
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The placeholder text to display in the input field.
|
|
38
|
+
*/
|
|
39
|
+
@property()
|
|
40
|
+
placeholderText: string | undefined = '';
|
|
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
|
+
|
|
53
|
+
override render() {
|
|
54
|
+
return (
|
|
55
|
+
<TextInput
|
|
56
|
+
lapisField={this.lapisField}
|
|
57
|
+
placeholderText={this.placeholderText}
|
|
58
|
+
initialValue={this.initialValue}
|
|
59
|
+
width={this.width}
|
|
60
|
+
/>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
declare global {
|
|
66
|
+
interface HTMLElementTagNameMap {
|
|
67
|
+
'gs-text-input': TextInputComponent;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface HTMLElementEventMap {
|
|
71
|
+
'gs-text-input-changed': CustomEvent<Record<string, string>>;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -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%.
|
|
@@ -6,12 +6,12 @@ import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
|
|
|
6
6
|
import aggregatedData from '../../preact/aggregatedData/__mockData__/aggregated.json';
|
|
7
7
|
import type { AggregateProps } from '../../preact/aggregatedData/aggregate';
|
|
8
8
|
|
|
9
|
-
import './aggregate
|
|
9
|
+
import './gs-aggregate';
|
|
10
10
|
import '../app';
|
|
11
11
|
|
|
12
12
|
const meta: Meta<AggregateProps> = {
|
|
13
13
|
title: 'Visualization/Aggregate',
|
|
14
|
-
component: 'gs-aggregate
|
|
14
|
+
component: 'gs-aggregate',
|
|
15
15
|
argTypes: {
|
|
16
16
|
fields: [{ control: 'object' }],
|
|
17
17
|
views: {
|
|
@@ -19,6 +19,7 @@ const meta: Meta<AggregateProps> = {
|
|
|
19
19
|
control: { type: 'check' },
|
|
20
20
|
},
|
|
21
21
|
size: [{ control: 'object' }],
|
|
22
|
+
headline: { control: 'text' },
|
|
22
23
|
},
|
|
23
24
|
parameters: withComponentDocs({
|
|
24
25
|
fetchMock: {
|
|
@@ -40,10 +41,9 @@ const meta: Meta<AggregateProps> = {
|
|
|
40
41
|
],
|
|
41
42
|
},
|
|
42
43
|
componentDocs: {
|
|
43
|
-
tag: 'gs-aggregate-component',
|
|
44
44
|
opensShadowDom: true,
|
|
45
45
|
expectsChildren: false,
|
|
46
|
-
codeExample: `<gs-aggregate
|
|
46
|
+
codeExample: `<gs-aggregate fields='["division", "host"]' filter='{"country": "USA"}' views='["table"]'></gs-aggregate>`,
|
|
47
47
|
},
|
|
48
48
|
}),
|
|
49
49
|
tags: ['autodocs'],
|
|
@@ -54,12 +54,13 @@ export default meta;
|
|
|
54
54
|
export const Table: StoryObj<AggregateProps> = {
|
|
55
55
|
render: (args) => html`
|
|
56
56
|
<gs-app lapis="${LAPIS_URL}">
|
|
57
|
-
<gs-aggregate
|
|
57
|
+
<gs-aggregate
|
|
58
58
|
.fields=${args.fields}
|
|
59
59
|
.filter=${args.filter}
|
|
60
60
|
.views=${args.views}
|
|
61
61
|
.size=${args.size}
|
|
62
|
-
|
|
62
|
+
.headline=${args.headline}
|
|
63
|
+
></gs-aggregate>
|
|
63
64
|
</gs-app>
|
|
64
65
|
`,
|
|
65
66
|
args: {
|
|
@@ -69,5 +70,6 @@ export const Table: StoryObj<AggregateProps> = {
|
|
|
69
70
|
country: 'USA',
|
|
70
71
|
},
|
|
71
72
|
size: { width: '100%', height: '700px' },
|
|
73
|
+
headline: 'Aggregate',
|
|
72
74
|
},
|
|
73
75
|
};
|
package/src/web-components/{display/aggregate-component.tsx → visualization/gs-aggregate.tsx}
RENAMED
|
@@ -11,7 +11,7 @@ import { PreactLitAdapterWithGridJsStyles } from '../PreactLitAdapterWithGridJsS
|
|
|
11
11
|
*
|
|
12
12
|
* It expects a list of fields to aggregate by and a filter to apply to the data.
|
|
13
13
|
*/
|
|
14
|
-
@customElement('gs-aggregate
|
|
14
|
+
@customElement('gs-aggregate')
|
|
15
15
|
export class AggregateComponent extends PreactLitAdapterWithGridJsStyles {
|
|
16
16
|
/**
|
|
17
17
|
* The fields to aggregate by.
|
|
@@ -46,8 +46,22 @@ export class AggregateComponent extends PreactLitAdapterWithGridJsStyles {
|
|
|
46
46
|
@property({ type: Object })
|
|
47
47
|
size: { width?: string; height?: string } | undefined = undefined;
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* The headline of the component. Set to an empty string to hide the headline.
|
|
51
|
+
*/
|
|
52
|
+
@property({ type: String })
|
|
53
|
+
headline: string | undefined = 'Aggregate';
|
|
54
|
+
|
|
49
55
|
override render() {
|
|
50
|
-
return
|
|
56
|
+
return (
|
|
57
|
+
<Aggregate
|
|
58
|
+
fields={this.fields}
|
|
59
|
+
views={this.views}
|
|
60
|
+
filter={this.filter}
|
|
61
|
+
size={this.size}
|
|
62
|
+
headline={this.headline}
|
|
63
|
+
/>
|
|
64
|
+
);
|
|
51
65
|
}
|
|
52
66
|
}
|
|
53
67
|
|
|
@@ -2,7 +2,7 @@ import { expect, fireEvent, waitFor } from '@storybook/test';
|
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/web-components';
|
|
3
3
|
import { html } from 'lit';
|
|
4
4
|
|
|
5
|
-
import './mutation-comparison
|
|
5
|
+
import './gs-mutation-comparison';
|
|
6
6
|
import '../app';
|
|
7
7
|
import { withComponentDocs } from '../../../.storybook/ComponentDocsBlock';
|
|
8
8
|
import { LAPIS_URL, NUCLEOTIDE_MUTATIONS_ENDPOINT } from '../../constants';
|
|
@@ -12,15 +12,15 @@ import { type MutationComparisonProps } from '../../preact/mutationComparison/mu
|
|
|
12
12
|
import { withinShadowRoot } from '../withinShadowRoot.story';
|
|
13
13
|
|
|
14
14
|
const codeExample = String.raw`
|
|
15
|
-
<gs-mutation-comparison
|
|
15
|
+
<gs-mutation-comparison
|
|
16
16
|
variants='[{ "displayName": "variant1", "lapisFilter": { "country": "Switzerland" }}, { "displayName": "variant2", "lapisFilter": { "country": "Germany" }}]'
|
|
17
17
|
sequenceType="nucleotide"
|
|
18
18
|
views='["table", "venn"]'
|
|
19
|
-
></gs-mutation-comparison
|
|
19
|
+
></gs-mutation-comparison>`;
|
|
20
20
|
|
|
21
21
|
const meta: Meta<MutationComparisonProps> = {
|
|
22
22
|
title: 'Visualization/Mutation comparison',
|
|
23
|
-
component: 'gs-mutation-comparison
|
|
23
|
+
component: 'gs-mutation-comparison',
|
|
24
24
|
argTypes: {
|
|
25
25
|
variants: { control: 'object' },
|
|
26
26
|
sequenceType: {
|
|
@@ -32,10 +32,10 @@ const meta: Meta<MutationComparisonProps> = {
|
|
|
32
32
|
control: { type: 'check' },
|
|
33
33
|
},
|
|
34
34
|
size: { control: 'object' },
|
|
35
|
+
headline: { control: 'text' },
|
|
35
36
|
},
|
|
36
37
|
parameters: withComponentDocs({
|
|
37
38
|
componentDocs: {
|
|
38
|
-
tag: 'gs-mutation-comparison-component',
|
|
39
39
|
opensShadowDom: true,
|
|
40
40
|
expectsChildren: false,
|
|
41
41
|
codeExample,
|
|
@@ -49,12 +49,13 @@ export default meta;
|
|
|
49
49
|
const Template: StoryObj<MutationComparisonProps> = {
|
|
50
50
|
render: (args) => html`
|
|
51
51
|
<gs-app lapis="${LAPIS_URL}">
|
|
52
|
-
<gs-mutation-comparison
|
|
52
|
+
<gs-mutation-comparison
|
|
53
53
|
.variants=${args.variants}
|
|
54
54
|
.sequenceType=${args.sequenceType}
|
|
55
55
|
.views=${args.views}
|
|
56
56
|
.size=${args.size}
|
|
57
|
-
|
|
57
|
+
.headline=${args.headline}
|
|
58
|
+
></gs-mutation-comparison>
|
|
58
59
|
</gs-app>
|
|
59
60
|
`,
|
|
60
61
|
};
|
|
@@ -83,6 +84,7 @@ export const Default: StoryObj<MutationComparisonProps> = {
|
|
|
83
84
|
sequenceType: 'nucleotide',
|
|
84
85
|
views: ['table', 'venn'],
|
|
85
86
|
size: { width: '100%', height: '700px' },
|
|
87
|
+
headline: 'Mutation comparison',
|
|
86
88
|
},
|
|
87
89
|
parameters: {
|
|
88
90
|
fetchMock: {
|
|
@@ -124,7 +126,7 @@ export const Default: StoryObj<MutationComparisonProps> = {
|
|
|
124
126
|
},
|
|
125
127
|
},
|
|
126
128
|
play: async ({ canvasElement, step }) => {
|
|
127
|
-
const canvas = await withinShadowRoot(canvasElement, 'gs-mutation-comparison
|
|
129
|
+
const canvas = await withinShadowRoot(canvasElement, 'gs-mutation-comparison');
|
|
128
130
|
|
|
129
131
|
await step('Min and max proportions should be 50% and 100%', async () => {
|
|
130
132
|
const minInput = () => canvas.getAllByLabelText('%')[0];
|
|
@@ -139,7 +141,7 @@ export const Default: StoryObj<MutationComparisonProps> = {
|
|
|
139
141
|
export const VennDiagram: StoryObj<MutationComparisonProps> = {
|
|
140
142
|
...Default,
|
|
141
143
|
play: async ({ canvasElement, step }) => {
|
|
142
|
-
const canvas = await withinShadowRoot(canvasElement, 'gs-mutation-comparison
|
|
144
|
+
const canvas = await withinShadowRoot(canvasElement, 'gs-mutation-comparison');
|
|
143
145
|
|
|
144
146
|
await step('Switch to Venn diagram view', async () => {
|
|
145
147
|
await waitFor(() => expect(canvas.getByRole('button', { name: 'Venn' })).toBeInTheDocument());
|
|
@@ -32,7 +32,7 @@ import { PreactLitAdapterWithGridJsStyles } from '../PreactLitAdapterWithGridJsS
|
|
|
32
32
|
* Thus, changing the proportion interval may change a mutations from being "common" between variant
|
|
33
33
|
* to being "for one variant only".
|
|
34
34
|
*/
|
|
35
|
-
@customElement('gs-mutation-comparison
|
|
35
|
+
@customElement('gs-mutation-comparison')
|
|
36
36
|
export class MutationComparisonComponent extends PreactLitAdapterWithGridJsStyles {
|
|
37
37
|
/**
|
|
38
38
|
* An array of variants to compare.
|
|
@@ -72,6 +72,12 @@ export class MutationComparisonComponent extends PreactLitAdapterWithGridJsStyle
|
|
|
72
72
|
@property({ type: Object })
|
|
73
73
|
size: { width?: string; height?: string } | undefined = undefined;
|
|
74
74
|
|
|
75
|
+
/**
|
|
76
|
+
* The headline of the component. Set to an empty string to hide the headline.
|
|
77
|
+
*/
|
|
78
|
+
@property({ type: String })
|
|
79
|
+
headline: string | undefined = 'Mutation comparison';
|
|
80
|
+
|
|
75
81
|
override render() {
|
|
76
82
|
return (
|
|
77
83
|
<MutationComparison
|
|
@@ -79,6 +85,7 @@ export class MutationComparisonComponent extends PreactLitAdapterWithGridJsStyle
|
|
|
79
85
|
sequenceType={this.sequenceType}
|
|
80
86
|
views={this.views}
|
|
81
87
|
size={this.size}
|
|
88
|
+
headline={this.headline}
|
|
82
89
|
/>
|
|
83
90
|
);
|
|
84
91
|
}
|
|
@@ -2,14 +2,22 @@ import { expect, fireEvent, waitFor } from '@storybook/test';
|
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/web-components';
|
|
3
3
|
import { html } from 'lit';
|
|
4
4
|
|
|
5
|
-
import './mutations
|
|
5
|
+
import './gs-mutations';
|
|
6
6
|
import '../app';
|
|
7
|
+
import { withComponentDocs } from '../../../.storybook/ComponentDocsBlock';
|
|
7
8
|
import { LAPIS_URL, NUCLEOTIDE_INSERTIONS_ENDPOINT, NUCLEOTIDE_MUTATIONS_ENDPOINT } from '../../constants';
|
|
8
9
|
import nucleotideInsertions from '../../preact/mutations/__mockData__/nucleotideInsertions.json';
|
|
9
10
|
import nucleotideMutations from '../../preact/mutations/__mockData__/nucleotideMutations.json';
|
|
10
11
|
import { type MutationsProps } from '../../preact/mutations/mutations';
|
|
11
12
|
import { withinShadowRoot } from '../withinShadowRoot.story';
|
|
12
13
|
|
|
14
|
+
const codeExample = String.raw`
|
|
15
|
+
<gs-mutations
|
|
16
|
+
variant='{ "country": "Switzerland", "pangoLineage": "B.1.1.7", "dateTo": "2022-01-01" }'
|
|
17
|
+
sequenceType="nucleotide"
|
|
18
|
+
views='["grid", "table", "insertions"]'
|
|
19
|
+
></gs-mutations>`;
|
|
20
|
+
|
|
13
21
|
const meta: Meta<MutationsProps> = {
|
|
14
22
|
title: 'Visualization/Mutations',
|
|
15
23
|
component: 'gs-mutations',
|
|
@@ -24,7 +32,23 @@ const meta: Meta<MutationsProps> = {
|
|
|
24
32
|
control: { type: 'check' },
|
|
25
33
|
},
|
|
26
34
|
size: { control: 'object' },
|
|
35
|
+
headline: { control: 'text' },
|
|
36
|
+
},
|
|
37
|
+
args: {
|
|
38
|
+
variant: { country: 'Switzerland', pangoLineage: 'B.1.1.7', dateTo: '2022-01-01' },
|
|
39
|
+
sequenceType: 'nucleotide',
|
|
40
|
+
views: ['grid', 'table', 'insertions'],
|
|
41
|
+
size: { width: '100%', height: '700px' },
|
|
42
|
+
headline: 'Mutations',
|
|
27
43
|
},
|
|
44
|
+
parameters: withComponentDocs({
|
|
45
|
+
componentDocs: {
|
|
46
|
+
opensShadowDom: true,
|
|
47
|
+
expectsChildren: false,
|
|
48
|
+
codeExample,
|
|
49
|
+
},
|
|
50
|
+
}),
|
|
51
|
+
tags: ['autodocs'],
|
|
28
52
|
};
|
|
29
53
|
|
|
30
54
|
export default meta;
|
|
@@ -32,24 +56,19 @@ export default meta;
|
|
|
32
56
|
const Template: StoryObj<MutationsProps> = {
|
|
33
57
|
render: (args) => html`
|
|
34
58
|
<gs-app lapis="${LAPIS_URL}">
|
|
35
|
-
<gs-mutations
|
|
59
|
+
<gs-mutations
|
|
36
60
|
.variant=${args.variant}
|
|
37
61
|
.sequenceType=${args.sequenceType}
|
|
38
62
|
.views=${args.views}
|
|
39
63
|
.size=${args.size}
|
|
40
|
-
|
|
64
|
+
.headline=${args.headline}
|
|
65
|
+
></gs-mutations>
|
|
41
66
|
</gs-app>
|
|
42
67
|
`,
|
|
43
68
|
};
|
|
44
69
|
|
|
45
70
|
export const Default: StoryObj<MutationsProps> = {
|
|
46
71
|
...Template,
|
|
47
|
-
args: {
|
|
48
|
-
variant: { country: 'Switzerland', pangoLineage: 'B.1.1.7', dateTo: '2022-01-01' },
|
|
49
|
-
sequenceType: 'nucleotide',
|
|
50
|
-
views: ['grid', 'table', 'insertions'],
|
|
51
|
-
size: { width: '100%', height: '700px' },
|
|
52
|
-
},
|
|
53
72
|
parameters: {
|
|
54
73
|
fetchMock: {
|
|
55
74
|
mocks: [
|
|
@@ -88,7 +107,7 @@ export const Default: StoryObj<MutationsProps> = {
|
|
|
88
107
|
export const OnTableTab: StoryObj<MutationsProps> = {
|
|
89
108
|
...Default,
|
|
90
109
|
play: async ({ canvasElement }) => {
|
|
91
|
-
const canvas = await withinShadowRoot(canvasElement, 'gs-mutations
|
|
110
|
+
const canvas = await withinShadowRoot(canvasElement, 'gs-mutations');
|
|
92
111
|
|
|
93
112
|
await waitFor(() => expect(canvas.getByRole('button', { name: 'Table' })).toBeInTheDocument());
|
|
94
113
|
|
|
@@ -99,7 +118,7 @@ export const OnTableTab: StoryObj<MutationsProps> = {
|
|
|
99
118
|
export const OnInsertionsTab: StoryObj<MutationsProps> = {
|
|
100
119
|
...Default,
|
|
101
120
|
play: async ({ canvasElement }) => {
|
|
102
|
-
const canvas = await withinShadowRoot(canvasElement, 'gs-mutations
|
|
121
|
+
const canvas = await withinShadowRoot(canvasElement, 'gs-mutations');
|
|
103
122
|
|
|
104
123
|
await waitFor(() => expect(canvas.getByRole('button', { name: 'Insertions' })).toBeInTheDocument());
|
|
105
124
|
|