@genspectrum/dashboard-components 0.16.3 → 0.16.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{mutationOverTimeWorker-DJcZmEH9.js.map → mutationOverTimeWorker-CPfQDLe6.js.map} +1 -1
- package/dist/components.d.ts +30 -29
- package/dist/components.js +833 -794
- package/dist/components.js.map +1 -1
- package/dist/style.css +5 -0
- package/dist/util.d.ts +77 -33
- package/package.json +2 -1
- package/src/preact/components/annotated-mutation.stories.tsx +2 -1
- package/src/preact/components/annotated-mutation.tsx +6 -2
- package/src/preact/mutationComparison/mutation-comparison-table.tsx +14 -1
- package/src/preact/mutationComparison/mutation-comparison-venn.tsx +39 -8
- package/src/preact/mutationComparison/mutation-comparison.stories.tsx +36 -12
- package/src/preact/mutationComparison/mutation-comparison.tsx +2 -0
- package/src/preact/mutations/mutations.stories.tsx +3 -9
- package/src/preact/mutationsOverTime/mutations-over-time.stories.tsx +3 -8
- package/src/preact/shared/stories/expectMutationAnnotation.ts +13 -0
- package/src/utilEntrypoint.ts +2 -0
- package/src/web-components/visualization/gs-mutation-comparison.stories.ts +18 -1
- package/src/web-components/visualization/gs-mutation-comparison.tsx +19 -8
- package/src/web-components/visualization/gs-mutations-over-time.stories.ts +2 -1
- package/src/web-components/visualization/gs-mutations.stories.ts +2 -1
- package/standalone-bundle/assets/mutationOverTimeWorker-CERZSdcA.js.map +1 -1
- package/standalone-bundle/dashboard-components.js +12787 -12215
- package/standalone-bundle/dashboard-components.js.map +1 -1
- package/standalone-bundle/style.css +1 -1
package/dist/style.css
CHANGED
|
@@ -3292,6 +3292,11 @@ input.tab:checked + .tab-content,
|
|
|
3292
3292
|
.cursor-pointer {
|
|
3293
3293
|
cursor: pointer;
|
|
3294
3294
|
}
|
|
3295
|
+
.select-text {
|
|
3296
|
+
-webkit-user-select: text;
|
|
3297
|
+
-moz-user-select: text;
|
|
3298
|
+
user-select: text;
|
|
3299
|
+
}
|
|
3295
3300
|
.list-inside {
|
|
3296
3301
|
list-style-position: inside;
|
|
3297
3302
|
}
|
package/dist/util.d.ts
CHANGED
|
@@ -202,6 +202,50 @@ declare const mapSourceSchema: default_2.ZodObject<{
|
|
|
202
202
|
topologyObjectsKey: string;
|
|
203
203
|
}>;
|
|
204
204
|
|
|
205
|
+
export declare type MutationAnnotation = default_2.infer<typeof mutationAnnotationSchema>;
|
|
206
|
+
|
|
207
|
+
export declare type MutationAnnotations = default_2.infer<typeof mutationAnnotationsSchema>;
|
|
208
|
+
|
|
209
|
+
declare const mutationAnnotationSchema: default_2.ZodObject<{
|
|
210
|
+
name: default_2.ZodString;
|
|
211
|
+
description: default_2.ZodString;
|
|
212
|
+
symbol: default_2.ZodString;
|
|
213
|
+
nucleotideMutations: default_2.ZodArray<default_2.ZodString, "many">;
|
|
214
|
+
aminoAcidMutations: default_2.ZodArray<default_2.ZodString, "many">;
|
|
215
|
+
}, "strip", default_2.ZodTypeAny, {
|
|
216
|
+
symbol: string;
|
|
217
|
+
name: string;
|
|
218
|
+
description: string;
|
|
219
|
+
nucleotideMutations: string[];
|
|
220
|
+
aminoAcidMutations: string[];
|
|
221
|
+
}, {
|
|
222
|
+
symbol: string;
|
|
223
|
+
name: string;
|
|
224
|
+
description: string;
|
|
225
|
+
nucleotideMutations: string[];
|
|
226
|
+
aminoAcidMutations: string[];
|
|
227
|
+
}>;
|
|
228
|
+
|
|
229
|
+
declare const mutationAnnotationsSchema: default_2.ZodArray<default_2.ZodObject<{
|
|
230
|
+
name: default_2.ZodString;
|
|
231
|
+
description: default_2.ZodString;
|
|
232
|
+
symbol: default_2.ZodString;
|
|
233
|
+
nucleotideMutations: default_2.ZodArray<default_2.ZodString, "many">;
|
|
234
|
+
aminoAcidMutations: default_2.ZodArray<default_2.ZodString, "many">;
|
|
235
|
+
}, "strip", default_2.ZodTypeAny, {
|
|
236
|
+
symbol: string;
|
|
237
|
+
name: string;
|
|
238
|
+
description: string;
|
|
239
|
+
nucleotideMutations: string[];
|
|
240
|
+
aminoAcidMutations: string[];
|
|
241
|
+
}, {
|
|
242
|
+
symbol: string;
|
|
243
|
+
name: string;
|
|
244
|
+
description: string;
|
|
245
|
+
nucleotideMutations: string[];
|
|
246
|
+
aminoAcidMutations: string[];
|
|
247
|
+
}>, "many">;
|
|
248
|
+
|
|
205
249
|
export declare type MutationComparisonProps = default_2.infer<typeof mutationComparisonPropsSchema>;
|
|
206
250
|
|
|
207
251
|
declare const mutationComparisonPropsSchema: default_2.ZodObject<{
|
|
@@ -247,6 +291,7 @@ declare const mutationComparisonPropsSchema: default_2.ZodObject<{
|
|
|
247
291
|
pageSize: default_2.ZodUnion<[default_2.ZodBoolean, default_2.ZodNumber]>;
|
|
248
292
|
}, "strip", default_2.ZodTypeAny, {
|
|
249
293
|
width: string;
|
|
294
|
+
sequenceType: "nucleotide" | "amino acid";
|
|
250
295
|
pageSize: number | boolean;
|
|
251
296
|
lapisFilters: {
|
|
252
297
|
lapisFilter: Record<string, string | number | boolean | string[] | null | undefined> & {
|
|
@@ -257,11 +302,11 @@ declare const mutationComparisonPropsSchema: default_2.ZodObject<{
|
|
|
257
302
|
};
|
|
258
303
|
displayName: string;
|
|
259
304
|
}[];
|
|
260
|
-
sequenceType: "nucleotide" | "amino acid";
|
|
261
305
|
views: ("table" | "venn")[];
|
|
262
306
|
height?: string | undefined;
|
|
263
307
|
}, {
|
|
264
308
|
width: string;
|
|
309
|
+
sequenceType: "nucleotide" | "amino acid";
|
|
265
310
|
pageSize: number | boolean;
|
|
266
311
|
lapisFilters: {
|
|
267
312
|
lapisFilter: Record<string, string | number | boolean | string[] | null | undefined> & {
|
|
@@ -272,7 +317,6 @@ declare const mutationComparisonPropsSchema: default_2.ZodObject<{
|
|
|
272
317
|
};
|
|
273
318
|
displayName: string;
|
|
274
319
|
}[];
|
|
275
|
-
sequenceType: "nucleotide" | "amino acid";
|
|
276
320
|
views: ("table" | "venn")[];
|
|
277
321
|
height?: string | undefined;
|
|
278
322
|
}>;
|
|
@@ -348,8 +392,8 @@ declare const mutationsPropsSchema: default_2.ZodObject<{
|
|
|
348
392
|
aminoAcidInsertions?: string[] | undefined;
|
|
349
393
|
};
|
|
350
394
|
width: string;
|
|
351
|
-
pageSize: number | boolean;
|
|
352
395
|
sequenceType: "nucleotide" | "amino acid";
|
|
396
|
+
pageSize: number | boolean;
|
|
353
397
|
views: ("table" | "grid" | "insertions")[];
|
|
354
398
|
height?: string | undefined;
|
|
355
399
|
baselineLapisFilter?: (Record<string, string | number | boolean | string[] | null | undefined> & {
|
|
@@ -366,8 +410,8 @@ declare const mutationsPropsSchema: default_2.ZodObject<{
|
|
|
366
410
|
aminoAcidInsertions?: string[] | undefined;
|
|
367
411
|
};
|
|
368
412
|
width: string;
|
|
369
|
-
pageSize: number | boolean;
|
|
370
413
|
sequenceType: "nucleotide" | "amino acid";
|
|
414
|
+
pageSize: number | boolean;
|
|
371
415
|
views: ("table" | "grid" | "insertions")[];
|
|
372
416
|
height?: string | undefined;
|
|
373
417
|
baselineLapisFilter?: (Record<string, string | number | boolean | string[] | null | undefined> & {
|
|
@@ -880,7 +924,7 @@ declare global {
|
|
|
880
924
|
|
|
881
925
|
declare global {
|
|
882
926
|
interface HTMLElementTagNameMap {
|
|
883
|
-
'gs-
|
|
927
|
+
'gs-prevalence-over-time': PrevalenceOverTimeComponent;
|
|
884
928
|
}
|
|
885
929
|
}
|
|
886
930
|
|
|
@@ -888,7 +932,7 @@ declare global {
|
|
|
888
932
|
declare global {
|
|
889
933
|
namespace JSX {
|
|
890
934
|
interface IntrinsicElements {
|
|
891
|
-
'gs-
|
|
935
|
+
'gs-prevalence-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
892
936
|
}
|
|
893
937
|
}
|
|
894
938
|
}
|
|
@@ -896,7 +940,7 @@ declare global {
|
|
|
896
940
|
|
|
897
941
|
declare global {
|
|
898
942
|
interface HTMLElementTagNameMap {
|
|
899
|
-
'gs-
|
|
943
|
+
'gs-relative-growth-advantage': RelativeGrowthAdvantageComponent;
|
|
900
944
|
}
|
|
901
945
|
}
|
|
902
946
|
|
|
@@ -904,7 +948,7 @@ declare global {
|
|
|
904
948
|
declare global {
|
|
905
949
|
namespace JSX {
|
|
906
950
|
interface IntrinsicElements {
|
|
907
|
-
'gs-
|
|
951
|
+
'gs-relative-growth-advantage': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
908
952
|
}
|
|
909
953
|
}
|
|
910
954
|
}
|
|
@@ -912,7 +956,7 @@ declare global {
|
|
|
912
956
|
|
|
913
957
|
declare global {
|
|
914
958
|
interface HTMLElementTagNameMap {
|
|
915
|
-
'gs-
|
|
959
|
+
'gs-aggregate': AggregateComponent;
|
|
916
960
|
}
|
|
917
961
|
}
|
|
918
962
|
|
|
@@ -920,7 +964,7 @@ declare global {
|
|
|
920
964
|
declare global {
|
|
921
965
|
namespace JSX {
|
|
922
966
|
interface IntrinsicElements {
|
|
923
|
-
'gs-
|
|
967
|
+
'gs-aggregate': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
924
968
|
}
|
|
925
969
|
}
|
|
926
970
|
}
|
|
@@ -928,7 +972,7 @@ declare global {
|
|
|
928
972
|
|
|
929
973
|
declare global {
|
|
930
974
|
interface HTMLElementTagNameMap {
|
|
931
|
-
'gs-
|
|
975
|
+
'gs-number-sequences-over-time': NumberSequencesOverTimeComponent;
|
|
932
976
|
}
|
|
933
977
|
}
|
|
934
978
|
|
|
@@ -936,7 +980,7 @@ declare global {
|
|
|
936
980
|
declare global {
|
|
937
981
|
namespace JSX {
|
|
938
982
|
interface IntrinsicElements {
|
|
939
|
-
'gs-
|
|
983
|
+
'gs-number-sequences-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
940
984
|
}
|
|
941
985
|
}
|
|
942
986
|
}
|
|
@@ -944,7 +988,7 @@ declare global {
|
|
|
944
988
|
|
|
945
989
|
declare global {
|
|
946
990
|
interface HTMLElementTagNameMap {
|
|
947
|
-
'gs-
|
|
991
|
+
'gs-mutations-over-time': MutationsOverTimeComponent;
|
|
948
992
|
}
|
|
949
993
|
}
|
|
950
994
|
|
|
@@ -952,7 +996,7 @@ declare global {
|
|
|
952
996
|
declare global {
|
|
953
997
|
namespace JSX {
|
|
954
998
|
interface IntrinsicElements {
|
|
955
|
-
'gs-
|
|
999
|
+
'gs-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
956
1000
|
}
|
|
957
1001
|
}
|
|
958
1002
|
}
|
|
@@ -960,7 +1004,7 @@ declare global {
|
|
|
960
1004
|
|
|
961
1005
|
declare global {
|
|
962
1006
|
interface HTMLElementTagNameMap {
|
|
963
|
-
'gs-
|
|
1007
|
+
'gs-sequences-by-location': SequencesByLocationComponent;
|
|
964
1008
|
}
|
|
965
1009
|
}
|
|
966
1010
|
|
|
@@ -968,7 +1012,7 @@ declare global {
|
|
|
968
1012
|
declare global {
|
|
969
1013
|
namespace JSX {
|
|
970
1014
|
interface IntrinsicElements {
|
|
971
|
-
'gs-
|
|
1015
|
+
'gs-sequences-by-location': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
972
1016
|
}
|
|
973
1017
|
}
|
|
974
1018
|
}
|
|
@@ -976,10 +1020,7 @@ declare global {
|
|
|
976
1020
|
|
|
977
1021
|
declare global {
|
|
978
1022
|
interface HTMLElementTagNameMap {
|
|
979
|
-
'gs-
|
|
980
|
-
}
|
|
981
|
-
interface HTMLElementEventMap {
|
|
982
|
-
'gs-location-changed': LocationChangedEvent;
|
|
1023
|
+
'gs-statistics': StatisticsComponent;
|
|
983
1024
|
}
|
|
984
1025
|
}
|
|
985
1026
|
|
|
@@ -987,7 +1028,7 @@ declare global {
|
|
|
987
1028
|
declare global {
|
|
988
1029
|
namespace JSX {
|
|
989
1030
|
interface IntrinsicElements {
|
|
990
|
-
'gs-
|
|
1031
|
+
'gs-statistics': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
991
1032
|
}
|
|
992
1033
|
}
|
|
993
1034
|
}
|
|
@@ -995,7 +1036,11 @@ declare global {
|
|
|
995
1036
|
|
|
996
1037
|
declare global {
|
|
997
1038
|
interface HTMLElementTagNameMap {
|
|
998
|
-
'gs-
|
|
1039
|
+
'gs-date-range-filter': DateRangeFilterComponent;
|
|
1040
|
+
}
|
|
1041
|
+
interface HTMLElementEventMap {
|
|
1042
|
+
'gs-date-range-filter-changed': CustomEvent<Record<string, string>>;
|
|
1043
|
+
'gs-date-range-option-changed': DateRangeOptionChangedEvent;
|
|
999
1044
|
}
|
|
1000
1045
|
}
|
|
1001
1046
|
|
|
@@ -1003,7 +1048,7 @@ declare global {
|
|
|
1003
1048
|
declare global {
|
|
1004
1049
|
namespace JSX {
|
|
1005
1050
|
interface IntrinsicElements {
|
|
1006
|
-
'gs-
|
|
1051
|
+
'gs-date-range-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1007
1052
|
}
|
|
1008
1053
|
}
|
|
1009
1054
|
}
|
|
@@ -1027,11 +1072,10 @@ declare global {
|
|
|
1027
1072
|
|
|
1028
1073
|
declare global {
|
|
1029
1074
|
interface HTMLElementTagNameMap {
|
|
1030
|
-
'gs-
|
|
1075
|
+
'gs-location-filter': LocationFilterComponent;
|
|
1031
1076
|
}
|
|
1032
1077
|
interface HTMLElementEventMap {
|
|
1033
|
-
'gs-
|
|
1034
|
-
'gs-date-range-option-changed': DateRangeOptionChangedEvent;
|
|
1078
|
+
'gs-location-changed': LocationChangedEvent;
|
|
1035
1079
|
}
|
|
1036
1080
|
}
|
|
1037
1081
|
|
|
@@ -1039,7 +1083,7 @@ declare global {
|
|
|
1039
1083
|
declare global {
|
|
1040
1084
|
namespace JSX {
|
|
1041
1085
|
interface IntrinsicElements {
|
|
1042
|
-
'gs-
|
|
1086
|
+
'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1043
1087
|
}
|
|
1044
1088
|
}
|
|
1045
1089
|
}
|
|
@@ -1066,10 +1110,10 @@ declare global {
|
|
|
1066
1110
|
|
|
1067
1111
|
declare global {
|
|
1068
1112
|
interface HTMLElementTagNameMap {
|
|
1069
|
-
'gs-
|
|
1113
|
+
'gs-lineage-filter': LineageFilterComponent;
|
|
1070
1114
|
}
|
|
1071
1115
|
interface HTMLElementEventMap {
|
|
1072
|
-
'gs-
|
|
1116
|
+
'gs-lineage-filter-changed': LineageFilterChangedEvent;
|
|
1073
1117
|
}
|
|
1074
1118
|
}
|
|
1075
1119
|
|
|
@@ -1077,7 +1121,7 @@ declare global {
|
|
|
1077
1121
|
declare global {
|
|
1078
1122
|
namespace JSX {
|
|
1079
1123
|
interface IntrinsicElements {
|
|
1080
|
-
'gs-
|
|
1124
|
+
'gs-lineage-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1081
1125
|
}
|
|
1082
1126
|
}
|
|
1083
1127
|
}
|
|
@@ -1085,10 +1129,10 @@ declare global {
|
|
|
1085
1129
|
|
|
1086
1130
|
declare global {
|
|
1087
1131
|
interface HTMLElementTagNameMap {
|
|
1088
|
-
'gs-
|
|
1132
|
+
'gs-mutation-filter': MutationFilterComponent;
|
|
1089
1133
|
}
|
|
1090
1134
|
interface HTMLElementEventMap {
|
|
1091
|
-
'gs-
|
|
1135
|
+
'gs-mutation-filter-changed': CustomEvent<MutationsFilter>;
|
|
1092
1136
|
}
|
|
1093
1137
|
}
|
|
1094
1138
|
|
|
@@ -1096,7 +1140,7 @@ declare global {
|
|
|
1096
1140
|
declare global {
|
|
1097
1141
|
namespace JSX {
|
|
1098
1142
|
interface IntrinsicElements {
|
|
1099
|
-
'gs-
|
|
1143
|
+
'gs-mutation-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1100
1144
|
}
|
|
1101
1145
|
}
|
|
1102
1146
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genspectrum/dashboard-components",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.4",
|
|
4
4
|
"description": "GenSpectrum web components for building dashboards",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -87,6 +87,7 @@
|
|
|
87
87
|
"chartjs-chart-error-bars": "^4.4.0",
|
|
88
88
|
"chartjs-chart-venn": "^4.3.0",
|
|
89
89
|
"dayjs": "^1.11.10",
|
|
90
|
+
"dompurify": "^3.2.4",
|
|
90
91
|
"downshift": "^9.0.8",
|
|
91
92
|
"flatpickr": "^4.6.13",
|
|
92
93
|
"gridjs": "^6.2.0",
|
|
@@ -66,7 +66,7 @@ export const MutationWithAnnotationEntry: StoryObj<AnnotatedMutationProps & { an
|
|
|
66
66
|
annotations: [
|
|
67
67
|
{
|
|
68
68
|
name: 'Test annotation',
|
|
69
|
-
description: 'This is a test annotation',
|
|
69
|
+
description: 'This is a test annotation <a class="link" href="/">with a link.</a>',
|
|
70
70
|
symbol: '*',
|
|
71
71
|
nucleotideMutations: ['A23403G'],
|
|
72
72
|
aminoAcidMutations: [],
|
|
@@ -81,6 +81,7 @@ export const MutationWithAnnotationEntry: StoryObj<AnnotatedMutationProps & { an
|
|
|
81
81
|
|
|
82
82
|
await userEvent.click(canvas.getByText('A23403G'));
|
|
83
83
|
await waitFor(() => expect(getAnnotationName(canvas)).toBeVisible());
|
|
84
|
+
await expect(canvas.getByRole('link', { name: 'with a link.' })).toBeVisible();
|
|
84
85
|
},
|
|
85
86
|
};
|
|
86
87
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import DOMPurify from 'dompurify';
|
|
1
2
|
import { useRef } from 'gridjs';
|
|
2
3
|
import { Fragment, type FunctionComponent, type RefObject } from 'preact';
|
|
3
4
|
|
|
@@ -56,14 +57,17 @@ const AnnotatedMutationWithoutContext: FunctionComponent<AnnotatedMutationWithou
|
|
|
56
57
|
{mutationAnnotations.map((annotation) => (
|
|
57
58
|
<Fragment key={annotation.name}>
|
|
58
59
|
<InfoHeadline2>{annotation.name}</InfoHeadline2>
|
|
59
|
-
<InfoParagraph>
|
|
60
|
+
<InfoParagraph>
|
|
61
|
+
{/* eslint-disable-next-line react/no-danger */}
|
|
62
|
+
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(annotation.description) }} />
|
|
63
|
+
</InfoParagraph>
|
|
60
64
|
</Fragment>
|
|
61
65
|
))}
|
|
62
66
|
</div>
|
|
63
67
|
);
|
|
64
68
|
|
|
65
69
|
return (
|
|
66
|
-
<ButtonWithModalDialog modalContent={modalContent} modalRef={modalRef}>
|
|
70
|
+
<ButtonWithModalDialog buttonClassName={'select-text'} modalContent={modalContent} modalRef={modalRef}>
|
|
67
71
|
{mutation.code}
|
|
68
72
|
<sup>
|
|
69
73
|
{mutationAnnotations
|
|
@@ -3,7 +3,10 @@ import { type FunctionComponent } from 'preact';
|
|
|
3
3
|
import { getMutationComparisonTableData } from './getMutationComparisonTableData';
|
|
4
4
|
import { type MutationData } from './queryMutationData';
|
|
5
5
|
import { type Dataset } from '../../operator/Dataset';
|
|
6
|
+
import type { SequenceType } from '../../types';
|
|
6
7
|
import { type DeletionClass, type SubstitutionClass } from '../../utils/mutations';
|
|
8
|
+
import { useMutationAnnotationsProvider } from '../MutationAnnotationsContext';
|
|
9
|
+
import { GridJsAnnotatedMutation } from '../components/annotated-mutation';
|
|
7
10
|
import { type ProportionInterval } from '../components/proportion-selector';
|
|
8
11
|
import { Table } from '../components/table';
|
|
9
12
|
import { sortSubstitutionsAndDeletions } from '../shared/sort/sortSubstitutionsAndDeletions';
|
|
@@ -13,20 +16,30 @@ export interface MutationsTableProps {
|
|
|
13
16
|
data: Dataset<MutationData>;
|
|
14
17
|
proportionInterval: ProportionInterval;
|
|
15
18
|
pageSize: boolean | number;
|
|
19
|
+
sequenceType: SequenceType;
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
export const MutationComparisonTable: FunctionComponent<MutationsTableProps> = ({
|
|
19
23
|
data,
|
|
20
24
|
proportionInterval,
|
|
21
25
|
pageSize,
|
|
26
|
+
sequenceType,
|
|
22
27
|
}) => {
|
|
28
|
+
const annotationsProvider = useMutationAnnotationsProvider();
|
|
29
|
+
|
|
23
30
|
const headers = [
|
|
24
31
|
{
|
|
25
32
|
name: 'Mutation',
|
|
26
33
|
sort: {
|
|
27
34
|
compare: sortSubstitutionsAndDeletions,
|
|
28
35
|
},
|
|
29
|
-
formatter: (cell: SubstitutionClass | DeletionClass) =>
|
|
36
|
+
formatter: (cell: SubstitutionClass | DeletionClass) => (
|
|
37
|
+
<GridJsAnnotatedMutation
|
|
38
|
+
mutation={cell}
|
|
39
|
+
sequenceType={sequenceType}
|
|
40
|
+
annotationsProvider={annotationsProvider}
|
|
41
|
+
/>
|
|
42
|
+
),
|
|
30
43
|
},
|
|
31
44
|
{
|
|
32
45
|
name: 'Prevalence',
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { type ActiveElement, Chart, type ChartConfiguration, type ChartEvent, registerables } from 'chart.js';
|
|
2
2
|
import { ArcSlice, extractSets, VennDiagramController } from 'chartjs-chart-venn';
|
|
3
|
-
import { type FunctionComponent } from 'preact';
|
|
3
|
+
import { Fragment, type FunctionComponent } from 'preact';
|
|
4
4
|
import { useMemo, useState } from 'preact/hooks';
|
|
5
5
|
|
|
6
6
|
import { type MutationData } from './queryMutationData';
|
|
7
7
|
import { type Dataset } from '../../operator/Dataset';
|
|
8
|
+
import { type SequenceType } from '../../types';
|
|
9
|
+
import { DeletionClass, SubstitutionClass } from '../../utils/mutations';
|
|
10
|
+
import { AnnotatedMutation } from '../components/annotated-mutation';
|
|
8
11
|
import GsChart from '../components/chart';
|
|
9
12
|
import { type ProportionInterval } from '../components/proportion-selector';
|
|
10
13
|
|
|
@@ -14,12 +17,14 @@ export interface MutationComparisonVennProps {
|
|
|
14
17
|
data: Dataset<MutationData>;
|
|
15
18
|
proportionInterval: ProportionInterval;
|
|
16
19
|
maintainAspectRatio: boolean;
|
|
20
|
+
sequenceType: SequenceType;
|
|
17
21
|
}
|
|
18
22
|
|
|
19
23
|
export const MutationComparisonVenn: FunctionComponent<MutationComparisonVennProps> = ({
|
|
20
24
|
data,
|
|
21
25
|
proportionInterval,
|
|
22
26
|
maintainAspectRatio,
|
|
27
|
+
sequenceType,
|
|
23
28
|
}) => {
|
|
24
29
|
const [selectedDatasetIndex, setSelectedDatasetIndex] = useState<null | number>(null);
|
|
25
30
|
|
|
@@ -105,22 +110,48 @@ export const MutationComparisonVenn: FunctionComponent<MutationComparisonVennPro
|
|
|
105
110
|
<div className='flex-1'>
|
|
106
111
|
<GsChart configuration={config} />
|
|
107
112
|
</div>
|
|
108
|
-
<p class='flex flex-wrap break-words m-2'>
|
|
113
|
+
<p class='flex flex-wrap break-words m-2'>
|
|
114
|
+
<SelectedMutationsDescription
|
|
115
|
+
selectedDatasetIndex={selectedDatasetIndex}
|
|
116
|
+
sets={sets}
|
|
117
|
+
sequenceType={sequenceType}
|
|
118
|
+
/>
|
|
119
|
+
</p>
|
|
109
120
|
</div>
|
|
110
121
|
);
|
|
111
122
|
};
|
|
112
123
|
|
|
113
124
|
const noElementSelectedMessage = 'You have no elements selected. Click in the venn diagram to select.';
|
|
114
125
|
|
|
115
|
-
|
|
116
|
-
selectedDatasetIndex: number | null
|
|
117
|
-
sets: ReturnType<typeof extractSets<string
|
|
118
|
-
|
|
126
|
+
type SelectedMutationsDescriptionProps = {
|
|
127
|
+
selectedDatasetIndex: number | null;
|
|
128
|
+
sets: ReturnType<typeof extractSets<string>>;
|
|
129
|
+
sequenceType: SequenceType;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const SelectedMutationsDescription: FunctionComponent<SelectedMutationsDescriptionProps> = ({
|
|
133
|
+
selectedDatasetIndex,
|
|
134
|
+
sets,
|
|
135
|
+
sequenceType,
|
|
136
|
+
}) => {
|
|
119
137
|
if (selectedDatasetIndex === null) {
|
|
120
138
|
return noElementSelectedMessage;
|
|
121
139
|
}
|
|
122
140
|
|
|
123
141
|
const values = sets.datasets[0].data[selectedDatasetIndex].values;
|
|
124
142
|
const label = sets.datasets[0].data[selectedDatasetIndex].label;
|
|
125
|
-
return
|
|
126
|
-
|
|
143
|
+
return (
|
|
144
|
+
<span>
|
|
145
|
+
{`${label}: `}
|
|
146
|
+
{values
|
|
147
|
+
.map((value) => SubstitutionClass.parse(value) ?? DeletionClass.parse(value))
|
|
148
|
+
.filter((value) => value !== null)
|
|
149
|
+
.map((value, index) => (
|
|
150
|
+
<Fragment key={value}>
|
|
151
|
+
{index > 0 && ', '}
|
|
152
|
+
<AnnotatedMutation mutation={value} sequenceType={sequenceType} />
|
|
153
|
+
</Fragment>
|
|
154
|
+
))}
|
|
155
|
+
</span>
|
|
156
|
+
);
|
|
157
|
+
};
|
|
@@ -7,7 +7,9 @@ import { MutationComparison, type MutationComparisonProps } from './mutation-com
|
|
|
7
7
|
import { LAPIS_URL, NUCLEOTIDE_MUTATIONS_ENDPOINT } from '../../constants';
|
|
8
8
|
import referenceGenome from '../../lapisApi/__mockData__/referenceGenome.json';
|
|
9
9
|
import { LapisUrlContextProvider } from '../LapisUrlContext';
|
|
10
|
+
import { MutationAnnotationsContextProvider } from '../MutationAnnotationsContext';
|
|
10
11
|
import { ReferenceGenomeContext } from '../ReferenceGenomeContext';
|
|
12
|
+
import { expectMutationAnnotation } from '../shared/stories/expectMutationAnnotation';
|
|
11
13
|
|
|
12
14
|
const dateToSomeDataset = '2022-01-01';
|
|
13
15
|
|
|
@@ -74,20 +76,39 @@ const meta: Meta<MutationComparisonProps> = {
|
|
|
74
76
|
|
|
75
77
|
export default meta;
|
|
76
78
|
|
|
79
|
+
const mutationAnnotations = [
|
|
80
|
+
{
|
|
81
|
+
name: 'I am a mutation annotation!',
|
|
82
|
+
description: 'This describes what is special about these mutations.',
|
|
83
|
+
symbol: '#',
|
|
84
|
+
nucleotideMutations: ['G199-', 'C3037T'],
|
|
85
|
+
aminoAcidMutations: ['N:G204R'],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: 'I am another mutation annotation!',
|
|
89
|
+
description: 'This describes what is special about these other mutations.',
|
|
90
|
+
symbol: '+',
|
|
91
|
+
nucleotideMutations: ['C3037T', 'A23403G'],
|
|
92
|
+
aminoAcidMutations: ['ORF1a:I2230T'],
|
|
93
|
+
},
|
|
94
|
+
];
|
|
95
|
+
|
|
77
96
|
const Template: StoryObj<MutationComparisonProps> = {
|
|
78
97
|
render: (args) => (
|
|
79
|
-
<
|
|
80
|
-
<
|
|
81
|
-
<
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
98
|
+
<MutationAnnotationsContextProvider value={mutationAnnotations}>
|
|
99
|
+
<LapisUrlContextProvider value={LAPIS_URL}>
|
|
100
|
+
<ReferenceGenomeContext.Provider value={referenceGenome}>
|
|
101
|
+
<MutationComparison
|
|
102
|
+
lapisFilters={args.lapisFilters}
|
|
103
|
+
sequenceType={args.sequenceType}
|
|
104
|
+
views={args.views}
|
|
105
|
+
width={args.width}
|
|
106
|
+
height={args.height}
|
|
107
|
+
pageSize={args.pageSize}
|
|
108
|
+
/>
|
|
109
|
+
</ReferenceGenomeContext.Provider>
|
|
110
|
+
</LapisUrlContextProvider>
|
|
111
|
+
</MutationAnnotationsContextProvider>
|
|
91
112
|
),
|
|
92
113
|
};
|
|
93
114
|
|
|
@@ -114,6 +135,9 @@ export const TwoVariants: StoryObj<MutationComparisonProps> = {
|
|
|
114
135
|
width: '100%',
|
|
115
136
|
pageSize: 10,
|
|
116
137
|
},
|
|
138
|
+
play: async ({ canvasElement }) => {
|
|
139
|
+
await expectMutationAnnotation(canvasElement, 'C3037T');
|
|
140
|
+
},
|
|
117
141
|
};
|
|
118
142
|
|
|
119
143
|
export const FilterForOnlyDeletions: StoryObj<MutationComparisonProps> = {
|
|
@@ -104,6 +104,7 @@ const MutationComparisonTabs: FunctionComponent<MutationComparisonTabsProps> = (
|
|
|
104
104
|
data={{ content: filteredData }}
|
|
105
105
|
proportionInterval={proportionInterval}
|
|
106
106
|
pageSize={originalComponentProps.pageSize}
|
|
107
|
+
sequenceType={originalComponentProps.sequenceType}
|
|
107
108
|
/>
|
|
108
109
|
),
|
|
109
110
|
};
|
|
@@ -115,6 +116,7 @@ const MutationComparisonTabs: FunctionComponent<MutationComparisonTabsProps> = (
|
|
|
115
116
|
data={{ content: filteredData }}
|
|
116
117
|
proportionInterval={proportionInterval}
|
|
117
118
|
maintainAspectRatio={maintainAspectRatio}
|
|
119
|
+
sequenceType={originalComponentProps.sequenceType}
|
|
118
120
|
/>
|
|
119
121
|
),
|
|
120
122
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Meta, type StoryObj } from '@storybook/preact';
|
|
2
|
-
import { expect,
|
|
2
|
+
import { expect, waitFor, within } from '@storybook/test';
|
|
3
3
|
|
|
4
4
|
import nucleotideInsertions from './__mockData__/nucleotideInsertions.json';
|
|
5
5
|
import nucleotideMutations from './__mockData__/nucleotideMutations.json';
|
|
@@ -16,6 +16,7 @@ import overallVariantCount from '../../preact/mutations/__mockData__/overallVari
|
|
|
16
16
|
import { LapisUrlContextProvider } from '../LapisUrlContext';
|
|
17
17
|
import { MutationAnnotationsContextProvider } from '../MutationAnnotationsContext';
|
|
18
18
|
import { ReferenceGenomeContext } from '../ReferenceGenomeContext';
|
|
19
|
+
import { expectMutationAnnotation } from '../shared/stories/expectMutationAnnotation';
|
|
19
20
|
|
|
20
21
|
const meta: Meta<MutationsProps> = {
|
|
21
22
|
title: 'Visualization/Mutations',
|
|
@@ -165,13 +166,6 @@ export const TableTab: StoryObj<MutationsProps> = {
|
|
|
165
166
|
views: ['table'],
|
|
166
167
|
},
|
|
167
168
|
play: async ({ canvasElement }) => {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
await waitFor(async () => {
|
|
171
|
-
const annotatedMutation = canvas.getByText('C241T');
|
|
172
|
-
await expect(annotatedMutation).toBeVisible();
|
|
173
|
-
await userEvent.click(annotatedMutation);
|
|
174
|
-
});
|
|
175
|
-
await waitFor(() => expect(canvas.getByText('Annotations for C241T')).toBeVisible());
|
|
169
|
+
await expectMutationAnnotation(canvasElement, 'C241T');
|
|
176
170
|
},
|
|
177
171
|
};
|
|
@@ -8,6 +8,7 @@ import { LapisUrlContextProvider } from '../LapisUrlContext';
|
|
|
8
8
|
import { MutationAnnotationsContextProvider } from '../MutationAnnotationsContext';
|
|
9
9
|
import { ReferenceGenomeContext } from '../ReferenceGenomeContext';
|
|
10
10
|
import { expectInvalidAttributesErrorMessage } from '../shared/stories/expectErrorMessage';
|
|
11
|
+
import { expectMutationAnnotation } from '../shared/stories/expectMutationAnnotation';
|
|
11
12
|
|
|
12
13
|
const meta: Meta<MutationsOverTimeProps> = {
|
|
13
14
|
title: 'Visualization/Mutation over time',
|
|
@@ -75,14 +76,8 @@ export const Default: StoryObj<MutationsOverTimeProps> = {
|
|
|
75
76
|
lapisDateField: 'date',
|
|
76
77
|
initialMeanProportionInterval: { min: 0.05, max: 0.9 },
|
|
77
78
|
},
|
|
78
|
-
play: async ({
|
|
79
|
-
await
|
|
80
|
-
const annotatedMutation = canvas.getAllByText('C44T')[0];
|
|
81
|
-
await expect(annotatedMutation).toBeVisible();
|
|
82
|
-
await userEvent.click(annotatedMutation);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
await waitFor(() => expect(canvas.getByText('Annotations for C44T')).toBeVisible());
|
|
79
|
+
play: async ({ canvasElement }) => {
|
|
80
|
+
await expectMutationAnnotation(canvasElement, 'C44T');
|
|
86
81
|
},
|
|
87
82
|
};
|
|
88
83
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { expect, userEvent, waitFor, within } from '@storybook/test';
|
|
2
|
+
|
|
3
|
+
export async function expectMutationAnnotation(canvasElement: HTMLElement, mutation: string) {
|
|
4
|
+
const canvas = within(canvasElement);
|
|
5
|
+
|
|
6
|
+
await waitFor(async () => {
|
|
7
|
+
const annotatedMutation = canvas.getAllByText(mutation)[0];
|
|
8
|
+
await expect(annotatedMutation).toBeVisible();
|
|
9
|
+
await userEvent.click(annotatedMutation);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
await waitFor(() => expect(canvas.getByText(`Annotations for ${mutation}`)).toBeVisible());
|
|
13
|
+
}
|