@genspectrum/dashboard-components 0.16.1 → 0.16.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/custom-elements.json +72 -7
  2. package/dist/assets/mutationOverTimeWorker-DJcZmEH9.js.map +1 -0
  3. package/dist/components.d.ts +63 -25
  4. package/dist/components.js +310 -151
  5. package/dist/components.js.map +1 -1
  6. package/dist/style.css +16 -0
  7. package/dist/util.d.ts +25 -25
  8. package/package.json +4 -2
  9. package/src/preact/MutationAnnotationsContext.spec.tsx +58 -0
  10. package/src/preact/MutationAnnotationsContext.tsx +72 -0
  11. package/src/preact/components/annotated-mutation.stories.tsx +163 -0
  12. package/src/preact/components/annotated-mutation.tsx +80 -0
  13. package/src/preact/components/downshift-combobox.tsx +6 -4
  14. package/src/preact/components/error-display.tsx +9 -9
  15. package/src/preact/components/info.tsx +6 -13
  16. package/src/preact/components/modal.stories.tsx +7 -19
  17. package/src/preact/components/modal.tsx +35 -4
  18. package/src/preact/mutations/mutations-table.tsx +14 -2
  19. package/src/preact/mutations/mutations.stories.tsx +40 -2
  20. package/src/preact/mutations/mutations.tsx +1 -0
  21. package/src/preact/mutationsOverTime/mutations-over-time-grid.tsx +19 -8
  22. package/src/preact/mutationsOverTime/mutations-over-time.stories.tsx +34 -5
  23. package/src/preact/mutationsOverTime/mutations-over-time.tsx +13 -1
  24. package/src/preact/sequencesByLocation/sequences-by-location-map.tsx +28 -30
  25. package/src/preact/wastewater/mutationsOverTime/wastewater-mutations-over-time.tsx +7 -2
  26. package/src/web-components/gs-app.spec-d.ts +10 -0
  27. package/src/web-components/gs-app.stories.ts +24 -6
  28. package/src/web-components/gs-app.ts +17 -0
  29. package/src/web-components/mutation-annotations-context.ts +16 -0
  30. package/src/web-components/visualization/gs-mutations-over-time.stories.ts +18 -1
  31. package/src/web-components/visualization/gs-mutations-over-time.tsx +22 -11
  32. package/src/web-components/visualization/gs-mutations.stories.ts +18 -1
  33. package/src/web-components/visualization/gs-mutations.tsx +20 -9
  34. package/src/web-components/wastewaterVisualization/gs-wastewater-mutations-over-time.stories.ts +11 -1
  35. package/src/web-components/wastewaterVisualization/gs-wastewater-mutations-over-time.tsx +18 -7
  36. package/standalone-bundle/assets/mutationOverTimeWorker-CERZSdcA.js.map +1 -0
  37. package/standalone-bundle/dashboard-components.js +8094 -7963
  38. package/standalone-bundle/dashboard-components.js.map +1 -1
  39. package/standalone-bundle/style.css +1 -1
  40. package/dist/assets/mutationOverTimeWorker-BL50C-yi.js.map +0 -1
  41. package/standalone-bundle/assets/mutationOverTimeWorker-CFB5-Mdk.js.map +0 -1
@@ -10,6 +10,7 @@ import { lapisContext } from './lapis-context';
10
10
  import { referenceGenomeContext } from './reference-genome-context';
11
11
  import { withComponentDocs } from '../../.storybook/ComponentDocsBlock';
12
12
  import { LAPIS_URL, REFERENCE_GENOME_ENDPOINT } from '../constants';
13
+ import { type MutationAnnotations, mutationAnnotationsContext } from './mutation-annotations-context';
13
14
  import type { ReferenceGenome } from '../lapisApi/ReferenceGenome';
14
15
  import referenceGenome from '../lapisApi/__mockData__/referenceGenome.json';
15
16
 
@@ -34,18 +35,29 @@ const meta: Meta = {
34
35
 
35
36
  export default meta;
36
37
 
37
- const Template: StoryObj<{ lapis: string }> = {
38
+ type StoryProps = { lapis: string; mutationAnnotations: MutationAnnotations };
39
+
40
+ const Template: StoryObj<StoryProps> = {
38
41
  render: (args) => {
39
- return html` <gs-app lapis="${args.lapis}">
42
+ return html` <gs-app lapis="${args.lapis}" .mutationAnnotations="${args.mutationAnnotations}">
40
43
  <gs-app-display></gs-app-display>
41
44
  </gs-app>`;
42
45
  },
43
46
  args: {
44
47
  lapis: LAPIS_URL,
48
+ mutationAnnotations: [
49
+ {
50
+ name: 'I am an annotation!',
51
+ description: 'This describes what is special about these mutations.',
52
+ symbol: '*',
53
+ nucleotideMutations: ['C44T', 'C774T', 'G24872T', 'T23011-'],
54
+ aminoAcidMutations: ['S:501Y', 'S:S31-', 'ORF1a:S4286C'],
55
+ },
56
+ ],
45
57
  },
46
58
  };
47
59
 
48
- export const Default: StoryObj<{ lapis: string }> = {
60
+ export const Default: StoryObj<StoryProps> = {
49
61
  ...Template,
50
62
  play: async ({ canvasElement }) => {
51
63
  const canvas = within(canvasElement);
@@ -53,11 +65,12 @@ export const Default: StoryObj<{ lapis: string }> = {
53
65
  await waitFor(async () => {
54
66
  await expect(canvas.getByText(LAPIS_URL)).toBeVisible();
55
67
  await expect(canvas.getByText('"name": "ORF1a",', { exact: false })).toBeVisible();
68
+ await expect(canvas.getByText('I am an annotation!', { exact: false })).toBeVisible();
56
69
  });
57
70
  },
58
71
  };
59
72
 
60
- export const WithNoLapisUrl: StoryObj<{ lapis: string }> = {
73
+ export const WithNoLapisUrl: StoryObj<StoryProps> = {
61
74
  ...Default,
62
75
  args: {
63
76
  ...Default.args,
@@ -72,7 +85,7 @@ export const WithNoLapisUrl: StoryObj<{ lapis: string }> = {
72
85
  },
73
86
  };
74
87
 
75
- export const DelayFetchingReferenceGenome: StoryObj<{ lapis: string }> = {
88
+ export const DelayFetchingReferenceGenome: StoryObj<StoryProps> = {
76
89
  ...Template,
77
90
  parameters: {
78
91
  fetchMock: {
@@ -95,7 +108,7 @@ export const DelayFetchingReferenceGenome: StoryObj<{ lapis: string }> = {
95
108
  },
96
109
  };
97
110
 
98
- export const FailsToFetchReferenceGenome: StoryObj<{ lapis: string }> = {
111
+ export const FailsToFetchReferenceGenome: StoryObj<StoryProps> = {
99
112
  ...Template,
100
113
  args: {
101
114
  lapis: 'https://url.to.lapis-definitely-not-a-valid-url',
@@ -121,6 +134,9 @@ class AppDisplay extends LitElement {
121
134
  genes: [],
122
135
  };
123
136
 
137
+ @consume({ context: mutationAnnotationsContext, subscribe: true })
138
+ mutationAnnotations: MutationAnnotations = [];
139
+
124
140
  override render() {
125
141
  return html`
126
142
  <h1 class="text-xl font-bold">Dummy component</h1>
@@ -132,6 +148,8 @@ class AppDisplay extends LitElement {
132
148
  <p>${this.lapis}</p>
133
149
  <h2 class="text-lg font-bold">Reference genomes</h2>
134
150
  <pre><code>${JSON.stringify(this.referenceGenome, null, 2)}</code></pre>
151
+ <h2 class="text-lg font-bold">Mutation annotations</h2>
152
+ <pre><code>${JSON.stringify(this.mutationAnnotations, null, 2)}</code></pre>
135
153
  `;
136
154
  }
137
155
 
@@ -6,6 +6,7 @@ import type { DetailedHTMLProps, HTMLAttributes } from 'react';
6
6
  import z from 'zod';
7
7
 
8
8
  import { lapisContext } from './lapis-context';
9
+ import { mutationAnnotationsContext } from './mutation-annotations-context';
9
10
  import { referenceGenomeContext } from './reference-genome-context';
10
11
  import { type ReferenceGenome } from '../lapisApi/ReferenceGenome';
11
12
  import { fetchReferenceGenome } from '../lapisApi/lapisApi';
@@ -21,6 +22,7 @@ const lapisUrlSchema = z.string().url();
21
22
  * It makes use of the [Lit Context](https://lit.dev/docs/data/context/) to
22
23
  * - provide the URL to the LAPIS instance to all its children
23
24
  * - fetch the reference genomes from LAPIS and provide it to all its children
25
+ * - distribute the mutation annotations config to its children
24
26
  *
25
27
  * This will show an error message if the reference genome cannot be fetched
26
28
  * (e.g., due to an invalid LAPIS URL).
@@ -40,6 +42,21 @@ export class AppComponent extends LitElement {
40
42
  @property()
41
43
  lapis: string = '';
42
44
 
45
+ /**
46
+ * Supply lists of mutations that are especially relevant for the current organism.
47
+ * Whenever other components display mutations, matching mutations will be highlighted by appending the `symbol`.
48
+ * On hover, a tooltip with the `name` and `description` will be shown.
49
+ */
50
+ @provide({ context: mutationAnnotationsContext })
51
+ @property({ type: Array })
52
+ mutationAnnotations: {
53
+ name: string;
54
+ description: string;
55
+ symbol: string;
56
+ nucleotideMutations: string[];
57
+ aminoAcidMutations: string[];
58
+ }[] = [];
59
+
43
60
  /**
44
61
  * @internal
45
62
  */
@@ -0,0 +1,16 @@
1
+ import { createContext } from '@lit/context';
2
+ import z from 'zod';
3
+
4
+ const mutationAnnotationSchema = z.object({
5
+ name: z.string(),
6
+ description: z.string(),
7
+ symbol: z.string(),
8
+ nucleotideMutations: z.array(z.string()),
9
+ aminoAcidMutations: z.array(z.string()),
10
+ });
11
+ export type MutationAnnotation = z.infer<typeof mutationAnnotationSchema>;
12
+
13
+ export const mutationAnnotationsSchema = z.array(mutationAnnotationSchema);
14
+ export type MutationAnnotations = z.infer<typeof mutationAnnotationsSchema>;
15
+
16
+ export const mutationAnnotationsContext = createContext<MutationAnnotations>(Symbol('mutation-annotations-context'));
@@ -64,9 +64,26 @@ const meta: Meta<Required<MutationsOverTimeProps>> = {
64
64
 
65
65
  export default meta;
66
66
 
67
+ const mutationAnnotations = [
68
+ {
69
+ name: 'I am a mutation annotation!',
70
+ description: 'This describes what is special about these mutations.',
71
+ symbol: '#',
72
+ nucleotideMutations: ['C44T', 'C774T', 'G24872T', 'T23011-'],
73
+ aminoAcidMutations: ['S:501Y', 'S:S31-', 'ORF1a:S4286C'],
74
+ },
75
+ {
76
+ name: 'I am another mutation annotation!',
77
+ description: 'This describes what is special about these other mutations.',
78
+ symbol: '+',
79
+ nucleotideMutations: ['C44T', 'A13121T'],
80
+ aminoAcidMutations: ['S:501Y', 'S:S31-', 'ORF1a:S4286C'],
81
+ },
82
+ ];
83
+
67
84
  const Template: StoryObj<Required<MutationsOverTimeProps>> = {
68
85
  render: (args) => html`
69
- <gs-app lapis="${LAPIS_URL}">
86
+ <gs-app lapis="${LAPIS_URL}" .mutationAnnotations=${mutationAnnotations}>
70
87
  <gs-mutations-over-time
71
88
  .lapisFilter=${args.lapisFilter}
72
89
  .sequenceType=${args.sequenceType}
@@ -1,9 +1,12 @@
1
+ import { consume } from '@lit/context';
1
2
  import { customElement, property } from 'lit/decorators.js';
2
3
  import type { DetailedHTMLProps, HTMLAttributes } from 'react';
3
4
 
5
+ import { MutationAnnotationsContextProvider } from '../../preact/MutationAnnotationsContext';
4
6
  import { MutationsOverTime, type MutationsOverTimeProps } from '../../preact/mutationsOverTime/mutations-over-time';
5
7
  import type { Equals, Expect } from '../../utils/typeAssertions';
6
8
  import { PreactLitAdapterWithGridJsStyles } from '../PreactLitAdapterWithGridJsStyles';
9
+ import { type MutationAnnotations, mutationAnnotationsContext } from '../mutation-annotations-context';
7
10
 
8
11
  /**
9
12
  * ## Context
@@ -105,19 +108,27 @@ export class MutationsOverTimeComponent extends PreactLitAdapterWithGridJsStyles
105
108
  @property({ type: Object })
106
109
  initialMeanProportionInterval: { min: number; max: number } = { min: 0.05, max: 0.9 };
107
110
 
111
+ /**
112
+ * @internal
113
+ */
114
+ @consume({ context: mutationAnnotationsContext, subscribe: true })
115
+ mutationAnnotations: MutationAnnotations = [];
116
+
108
117
  override render() {
109
118
  return (
110
- <MutationsOverTime
111
- lapisFilter={this.lapisFilter}
112
- sequenceType={this.sequenceType}
113
- views={this.views}
114
- width={this.width}
115
- height={this.height}
116
- granularity={this.granularity}
117
- lapisDateField={this.lapisDateField}
118
- displayMutations={this.displayMutations}
119
- initialMeanProportionInterval={this.initialMeanProportionInterval}
120
- />
119
+ <MutationAnnotationsContextProvider value={this.mutationAnnotations}>
120
+ <MutationsOverTime
121
+ lapisFilter={this.lapisFilter}
122
+ sequenceType={this.sequenceType}
123
+ views={this.views}
124
+ width={this.width}
125
+ height={this.height}
126
+ granularity={this.granularity}
127
+ lapisDateField={this.lapisDateField}
128
+ displayMutations={this.displayMutations}
129
+ initialMeanProportionInterval={this.initialMeanProportionInterval}
130
+ />
131
+ </MutationAnnotationsContextProvider>
121
132
  );
122
133
  }
123
134
  }
@@ -68,9 +68,26 @@ const meta: Meta<Required<MutationsProps>> = {
68
68
 
69
69
  export default meta;
70
70
 
71
+ const mutationAnnotations = [
72
+ {
73
+ name: 'I am a mutation annotation!',
74
+ description: 'This describes what is special about these mutations.',
75
+ symbol: '#',
76
+ nucleotideMutations: ['C241T', 'C3037T'],
77
+ aminoAcidMutations: ['S:501Y', 'S:S31-', 'ORF1a:S4286C'],
78
+ },
79
+ {
80
+ name: 'I am another mutation annotation!',
81
+ description: 'This describes what is special about these other mutations.',
82
+ symbol: '+',
83
+ nucleotideMutations: ['C3037T', 'C11750T'],
84
+ aminoAcidMutations: ['S:501Y', 'S:S31-', 'ORF1a:S4286C'],
85
+ },
86
+ ];
87
+
71
88
  const Template: StoryObj<Required<MutationsProps>> = {
72
89
  render: (args) => html`
73
- <gs-app lapis="${LAPIS_URL}">
90
+ <gs-app lapis="${LAPIS_URL}" .mutationAnnotations=${mutationAnnotations}>
74
91
  <gs-mutations
75
92
  .lapisFilter=${args.lapisFilter}
76
93
  .baselineLapisFilter=${args.baselineLapisFilter}
@@ -1,9 +1,12 @@
1
+ import { consume } from '@lit/context';
1
2
  import { customElement, property } from 'lit/decorators.js';
2
3
  import type { DetailedHTMLProps, HTMLAttributes } from 'react';
3
4
 
5
+ import { MutationAnnotationsContextProvider } from '../../preact/MutationAnnotationsContext';
4
6
  import { Mutations, type MutationsProps } from '../../preact/mutations/mutations';
5
7
  import type { Equals, Expect } from '../../utils/typeAssertions';
6
8
  import { PreactLitAdapterWithGridJsStyles } from '../PreactLitAdapterWithGridJsStyles';
9
+ import { type MutationAnnotations, mutationAnnotationsContext } from '../mutation-annotations-context';
7
10
 
8
11
  /**
9
12
  * ## Context
@@ -120,17 +123,25 @@ export class MutationsComponent extends PreactLitAdapterWithGridJsStyles {
120
123
  @property({ type: Object })
121
124
  pageSize: boolean | number = false;
122
125
 
126
+ /**
127
+ * @internal
128
+ */
129
+ @consume({ context: mutationAnnotationsContext, subscribe: true })
130
+ mutationAnnotations: MutationAnnotations = [];
131
+
123
132
  override render() {
124
133
  return (
125
- <Mutations
126
- lapisFilter={this.lapisFilter}
127
- sequenceType={this.sequenceType}
128
- views={this.views}
129
- width={this.width}
130
- height={this.height}
131
- pageSize={this.pageSize}
132
- baselineLapisFilter={this.baselineLapisFilter}
133
- />
134
+ <MutationAnnotationsContextProvider value={this.mutationAnnotations}>
135
+ <Mutations
136
+ lapisFilter={this.lapisFilter}
137
+ sequenceType={this.sequenceType}
138
+ views={this.views}
139
+ width={this.width}
140
+ height={this.height}
141
+ pageSize={this.pageSize}
142
+ baselineLapisFilter={this.baselineLapisFilter}
143
+ />
144
+ </MutationAnnotationsContextProvider>
134
145
  );
135
146
  }
136
147
  }
@@ -52,9 +52,19 @@ const meta: Meta<WastewaterMutationsOverTimeProps & { infoText: string }> = {
52
52
 
53
53
  export default meta;
54
54
 
55
+ const mutationAnnotations = [
56
+ {
57
+ name: 'I am an annotation!',
58
+ description: 'This describes what is special about these mutations.',
59
+ symbol: '*',
60
+ nucleotideMutations: ['C3422A', 'G6661A', 'G7731A'],
61
+ aminoAcidMutations: ['S:501Y', 'S:S31-', 'ORF1a:S4286C'],
62
+ },
63
+ ];
64
+
55
65
  export const WastewaterMutationsOverTime: StoryObj<WastewaterMutationsOverTimeProps & { infoText: string }> = {
56
66
  render: (args) => html`
57
- <gs-app lapis="${WISE_LAPIS_URL}">
67
+ <gs-app lapis="${WISE_LAPIS_URL}" .mutationAnnotations=${mutationAnnotations}>
58
68
  <gs-wastewater-mutations-over-time
59
69
  .lapisFilter=${args.lapisFilter}
60
70
  .sequenceType=${args.sequenceType}
@@ -1,12 +1,15 @@
1
+ import { consume } from '@lit/context';
1
2
  import { customElement, property } from 'lit/decorators.js';
2
3
  import { type DetailedHTMLProps, type HTMLAttributes } from 'react';
3
4
 
5
+ import { MutationAnnotationsContextProvider } from '../../preact/MutationAnnotationsContext';
4
6
  import {
5
7
  WastewaterMutationsOverTime,
6
8
  type WastewaterMutationsOverTimeProps,
7
9
  } from '../../preact/wastewater/mutationsOverTime/wastewater-mutations-over-time';
8
10
  import { type Equals, type Expect } from '../../utils/typeAssertions';
9
11
  import { PreactLitAdapterWithGridJsStyles } from '../PreactLitAdapterWithGridJsStyles';
12
+ import { type MutationAnnotations, mutationAnnotationsContext } from '../mutation-annotations-context';
10
13
 
11
14
  /**
12
15
  * ## Context
@@ -71,15 +74,23 @@ export class WastewaterMutationsOverTimeComponent extends PreactLitAdapterWithGr
71
74
  @property({ type: Number })
72
75
  maxNumberOfGridRows: number = 100;
73
76
 
77
+ /**
78
+ * @internal
79
+ */
80
+ @consume({ context: mutationAnnotationsContext, subscribe: true })
81
+ mutationAnnotations: MutationAnnotations = [];
82
+
74
83
  override render() {
75
84
  return (
76
- <WastewaterMutationsOverTime
77
- lapisFilter={this.lapisFilter}
78
- sequenceType={this.sequenceType}
79
- width={this.width}
80
- height={this.height}
81
- maxNumberOfGridRows={this.maxNumberOfGridRows}
82
- />
85
+ <MutationAnnotationsContextProvider value={this.mutationAnnotations}>
86
+ <WastewaterMutationsOverTime
87
+ lapisFilter={this.lapisFilter}
88
+ sequenceType={this.sequenceType}
89
+ width={this.width}
90
+ height={this.height}
91
+ maxNumberOfGridRows={this.maxNumberOfGridRows}
92
+ />
93
+ </MutationAnnotationsContextProvider>
83
94
  );
84
95
  }
85
96
  }