@genspectrum/dashboard-components 1.14.1 → 1.15.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/dist/util.d.ts CHANGED
@@ -753,19 +753,32 @@ declare const queriesOverTimeSchema: default_2.ZodObject<{
753
753
  nucleotideInsertions?: string[] | undefined;
754
754
  aminoAcidInsertions?: string[] | undefined;
755
755
  }>>;
756
- queries: default_2.ZodArray<default_2.ZodObject<{
756
+ queries: default_2.ZodEffects<default_2.ZodArray<default_2.ZodObject<{
757
757
  displayLabel: default_2.ZodString;
758
+ description: default_2.ZodOptional<default_2.ZodString>;
758
759
  countQuery: default_2.ZodString;
759
760
  coverageQuery: default_2.ZodString;
760
761
  }, "strip", default_2.ZodTypeAny, {
761
762
  displayLabel: string;
762
763
  countQuery: string;
763
764
  coverageQuery: string;
765
+ description?: string | undefined;
764
766
  }, {
765
767
  displayLabel: string;
766
768
  countQuery: string;
767
769
  coverageQuery: string;
768
- }>, "many">;
770
+ description?: string | undefined;
771
+ }>, "many">, {
772
+ displayLabel: string;
773
+ countQuery: string;
774
+ coverageQuery: string;
775
+ description?: string | undefined;
776
+ }[], {
777
+ displayLabel: string;
778
+ countQuery: string;
779
+ coverageQuery: string;
780
+ description?: string | undefined;
781
+ }[]>;
769
782
  views: default_2.ZodArray<default_2.ZodLiteral<"grid">, "many">;
770
783
  granularity: default_2.ZodUnion<[default_2.ZodLiteral<"day">, default_2.ZodLiteral<"week">, default_2.ZodLiteral<"month">, default_2.ZodLiteral<"year">]>;
771
784
  lapisDateField: default_2.ZodString;
@@ -804,6 +817,7 @@ declare const queriesOverTimeSchema: default_2.ZodObject<{
804
817
  displayLabel: string;
805
818
  countQuery: string;
806
819
  coverageQuery: string;
820
+ description?: string | undefined;
807
821
  }[];
808
822
  width: string;
809
823
  views: "grid"[];
@@ -831,6 +845,7 @@ declare const queriesOverTimeSchema: default_2.ZodObject<{
831
845
  displayLabel: string;
832
846
  countQuery: string;
833
847
  coverageQuery: string;
848
+ description?: string | undefined;
834
849
  }[];
835
850
  width: string;
836
851
  views: "grid"[];
@@ -856,17 +871,17 @@ declare const queriesOverTimeViewSchema: default_2.ZodLiteral<"grid">;
856
871
  export declare type QueryDefinition = default_2.infer<typeof queryDefinition>;
857
872
 
858
873
  declare const queryDefinition: default_2.ZodObject<{
859
- displayLabel: default_2.ZodString;
874
+ displayLabel: default_2.ZodOptional<default_2.ZodString>;
860
875
  countQuery: default_2.ZodString;
861
876
  coverageQuery: default_2.ZodString;
862
877
  }, "strip", default_2.ZodTypeAny, {
863
- displayLabel: string;
864
878
  countQuery: string;
865
879
  coverageQuery: string;
880
+ displayLabel?: string | undefined;
866
881
  }, {
867
- displayLabel: string;
868
882
  countQuery: string;
869
883
  coverageQuery: string;
884
+ displayLabel?: string | undefined;
870
885
  }>;
871
886
 
872
887
  export declare type RelativeGrowthAdvantageProps = default_2.infer<typeof relativeGrowthAdvantagePropsSchema>;
@@ -1106,11 +1121,7 @@ declare global {
1106
1121
 
1107
1122
  declare global {
1108
1123
  interface HTMLElementTagNameMap {
1109
- 'gs-date-range-filter': DateRangeFilterComponent;
1110
- }
1111
- interface HTMLElementEventMap {
1112
- [gsEventNames.dateRangeFilterChanged]: CustomEvent<Record<string, string>>;
1113
- [gsEventNames.dateRangeOptionChanged]: DateRangeOptionChangedEvent;
1124
+ 'gs-genome-data-viewer': GenomeDataViewerComponent;
1114
1125
  }
1115
1126
  }
1116
1127
 
@@ -1118,7 +1129,7 @@ declare global {
1118
1129
  declare global {
1119
1130
  namespace JSX {
1120
1131
  interface IntrinsicElements {
1121
- 'gs-date-range-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1132
+ 'gs-genome-data-viewer': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1122
1133
  }
1123
1134
  }
1124
1135
  }
@@ -1126,10 +1137,7 @@ declare global {
1126
1137
 
1127
1138
  declare global {
1128
1139
  interface HTMLElementTagNameMap {
1129
- 'gs-location-filter': LocationFilterComponent;
1130
- }
1131
- interface HTMLElementEventMap {
1132
- [gsEventNames.locationChanged]: LocationChangedEvent;
1140
+ 'gs-mutation-comparison': MutationComparisonComponent;
1133
1141
  }
1134
1142
  }
1135
1143
 
@@ -1137,7 +1145,7 @@ declare global {
1137
1145
  declare global {
1138
1146
  namespace JSX {
1139
1147
  interface IntrinsicElements {
1140
- 'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1148
+ 'gs-mutation-comparison': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1141
1149
  }
1142
1150
  }
1143
1151
  }
@@ -1145,10 +1153,7 @@ declare global {
1145
1153
 
1146
1154
  declare global {
1147
1155
  interface HTMLElementTagNameMap {
1148
- 'gs-text-filter': TextFilterComponent;
1149
- }
1150
- interface HTMLElementEventMap {
1151
- [gsEventNames.textFilterChanged]: TextFilterChangedEvent;
1156
+ 'gs-mutations': MutationsComponent;
1152
1157
  }
1153
1158
  }
1154
1159
 
@@ -1156,7 +1161,7 @@ declare global {
1156
1161
  declare global {
1157
1162
  namespace JSX {
1158
1163
  interface IntrinsicElements {
1159
- 'gs-text-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1164
+ 'gs-mutations': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1160
1165
  }
1161
1166
  }
1162
1167
  }
@@ -1164,10 +1169,7 @@ declare global {
1164
1169
 
1165
1170
  declare global {
1166
1171
  interface HTMLElementTagNameMap {
1167
- 'gs-mutation-filter': MutationFilterComponent;
1168
- }
1169
- interface HTMLElementEventMap {
1170
- [gsEventNames.mutationFilterChanged]: CustomEvent<MutationsFilter>;
1172
+ 'gs-prevalence-over-time': PrevalenceOverTimeComponent;
1171
1173
  }
1172
1174
  }
1173
1175
 
@@ -1175,7 +1177,7 @@ declare global {
1175
1177
  declare global {
1176
1178
  namespace JSX {
1177
1179
  interface IntrinsicElements {
1178
- 'gs-mutation-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1180
+ 'gs-prevalence-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1179
1181
  }
1180
1182
  }
1181
1183
  }
@@ -1183,11 +1185,7 @@ declare global {
1183
1185
 
1184
1186
  declare global {
1185
1187
  interface HTMLElementTagNameMap {
1186
- 'gs-lineage-filter': LineageFilterComponent;
1187
- }
1188
- interface HTMLElementEventMap {
1189
- [gsEventNames.lineageFilterChanged]: LineageFilterChangedEvent;
1190
- [gsEventNames.lineageFilterMultiChanged]: LineageMultiFilterChangedEvent;
1188
+ 'gs-relative-growth-advantage': RelativeGrowthAdvantageComponent;
1191
1189
  }
1192
1190
  }
1193
1191
 
@@ -1195,7 +1193,7 @@ declare global {
1195
1193
  declare global {
1196
1194
  namespace JSX {
1197
1195
  interface IntrinsicElements {
1198
- 'gs-lineage-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1196
+ 'gs-relative-growth-advantage': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1199
1197
  }
1200
1198
  }
1201
1199
  }
@@ -1203,11 +1201,7 @@ declare global {
1203
1201
 
1204
1202
  declare global {
1205
1203
  interface HTMLElementTagNameMap {
1206
- 'gs-number-range-filter': NumberRangeFilterComponent;
1207
- }
1208
- interface HTMLElementEventMap {
1209
- [gsEventNames.numberRangeFilterChanged]: NumberRangeFilterChangedEvent;
1210
- [gsEventNames.numberRangeValueChanged]: NumberRangeValueChangedEvent;
1204
+ 'gs-aggregate': AggregateComponent;
1211
1205
  }
1212
1206
  }
1213
1207
 
@@ -1215,7 +1209,7 @@ declare global {
1215
1209
  declare global {
1216
1210
  namespace JSX {
1217
1211
  interface IntrinsicElements {
1218
- 'gs-number-range-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1212
+ 'gs-aggregate': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1219
1213
  }
1220
1214
  }
1221
1215
  }
@@ -1223,7 +1217,7 @@ declare global {
1223
1217
 
1224
1218
  declare global {
1225
1219
  interface HTMLElementTagNameMap {
1226
- 'gs-genome-data-viewer': GenomeDataViewerComponent;
1220
+ 'gs-number-sequences-over-time': NumberSequencesOverTimeComponent;
1227
1221
  }
1228
1222
  }
1229
1223
 
@@ -1231,7 +1225,7 @@ declare global {
1231
1225
  declare global {
1232
1226
  namespace JSX {
1233
1227
  interface IntrinsicElements {
1234
- 'gs-genome-data-viewer': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1228
+ 'gs-number-sequences-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1235
1229
  }
1236
1230
  }
1237
1231
  }
@@ -1239,7 +1233,7 @@ declare global {
1239
1233
 
1240
1234
  declare global {
1241
1235
  interface HTMLElementTagNameMap {
1242
- 'gs-mutation-comparison': MutationComparisonComponent;
1236
+ 'gs-queries-over-time': QueriesOverTimeComponent;
1243
1237
  }
1244
1238
  }
1245
1239
 
@@ -1247,7 +1241,7 @@ declare global {
1247
1241
  declare global {
1248
1242
  namespace JSX {
1249
1243
  interface IntrinsicElements {
1250
- 'gs-mutation-comparison': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1244
+ 'gs-queries-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1251
1245
  }
1252
1246
  }
1253
1247
  }
@@ -1255,7 +1249,7 @@ declare global {
1255
1249
 
1256
1250
  declare global {
1257
1251
  interface HTMLElementTagNameMap {
1258
- 'gs-mutations': MutationsComponent;
1252
+ 'gs-mutations-over-time': MutationsOverTimeComponent;
1259
1253
  }
1260
1254
  }
1261
1255
 
@@ -1263,7 +1257,7 @@ declare global {
1263
1257
  declare global {
1264
1258
  namespace JSX {
1265
1259
  interface IntrinsicElements {
1266
- 'gs-mutations': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1260
+ 'gs-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1267
1261
  }
1268
1262
  }
1269
1263
  }
@@ -1271,7 +1265,7 @@ declare global {
1271
1265
 
1272
1266
  declare global {
1273
1267
  interface HTMLElementTagNameMap {
1274
- 'gs-prevalence-over-time': PrevalenceOverTimeComponent;
1268
+ 'gs-sequences-by-location': SequencesByLocationComponent;
1275
1269
  }
1276
1270
  }
1277
1271
 
@@ -1279,7 +1273,7 @@ declare global {
1279
1273
  declare global {
1280
1274
  namespace JSX {
1281
1275
  interface IntrinsicElements {
1282
- 'gs-prevalence-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1276
+ 'gs-sequences-by-location': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1283
1277
  }
1284
1278
  }
1285
1279
  }
@@ -1287,7 +1281,7 @@ declare global {
1287
1281
 
1288
1282
  declare global {
1289
1283
  interface HTMLElementTagNameMap {
1290
- 'gs-relative-growth-advantage': RelativeGrowthAdvantageComponent;
1284
+ 'gs-statistics': StatisticsComponent;
1291
1285
  }
1292
1286
  }
1293
1287
 
@@ -1295,7 +1289,7 @@ declare global {
1295
1289
  declare global {
1296
1290
  namespace JSX {
1297
1291
  interface IntrinsicElements {
1298
- 'gs-relative-growth-advantage': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1292
+ 'gs-statistics': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1299
1293
  }
1300
1294
  }
1301
1295
  }
@@ -1303,7 +1297,11 @@ declare global {
1303
1297
 
1304
1298
  declare global {
1305
1299
  interface HTMLElementTagNameMap {
1306
- 'gs-aggregate': AggregateComponent;
1300
+ 'gs-date-range-filter': DateRangeFilterComponent;
1301
+ }
1302
+ interface HTMLElementEventMap {
1303
+ [gsEventNames.dateRangeFilterChanged]: CustomEvent<Record<string, string>>;
1304
+ [gsEventNames.dateRangeOptionChanged]: DateRangeOptionChangedEvent;
1307
1305
  }
1308
1306
  }
1309
1307
 
@@ -1311,7 +1309,7 @@ declare global {
1311
1309
  declare global {
1312
1310
  namespace JSX {
1313
1311
  interface IntrinsicElements {
1314
- 'gs-aggregate': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1312
+ 'gs-date-range-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1315
1313
  }
1316
1314
  }
1317
1315
  }
@@ -1319,7 +1317,10 @@ declare global {
1319
1317
 
1320
1318
  declare global {
1321
1319
  interface HTMLElementTagNameMap {
1322
- 'gs-number-sequences-over-time': NumberSequencesOverTimeComponent;
1320
+ 'gs-location-filter': LocationFilterComponent;
1321
+ }
1322
+ interface HTMLElementEventMap {
1323
+ [gsEventNames.locationChanged]: LocationChangedEvent;
1323
1324
  }
1324
1325
  }
1325
1326
 
@@ -1327,7 +1328,7 @@ declare global {
1327
1328
  declare global {
1328
1329
  namespace JSX {
1329
1330
  interface IntrinsicElements {
1330
- 'gs-number-sequences-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1331
+ 'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1331
1332
  }
1332
1333
  }
1333
1334
  }
@@ -1335,7 +1336,10 @@ declare global {
1335
1336
 
1336
1337
  declare global {
1337
1338
  interface HTMLElementTagNameMap {
1338
- 'gs-mutations-over-time': MutationsOverTimeComponent;
1339
+ 'gs-text-filter': TextFilterComponent;
1340
+ }
1341
+ interface HTMLElementEventMap {
1342
+ [gsEventNames.textFilterChanged]: TextFilterChangedEvent;
1339
1343
  }
1340
1344
  }
1341
1345
 
@@ -1343,7 +1347,7 @@ declare global {
1343
1347
  declare global {
1344
1348
  namespace JSX {
1345
1349
  interface IntrinsicElements {
1346
- 'gs-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1350
+ 'gs-text-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1347
1351
  }
1348
1352
  }
1349
1353
  }
@@ -1351,7 +1355,10 @@ declare global {
1351
1355
 
1352
1356
  declare global {
1353
1357
  interface HTMLElementTagNameMap {
1354
- 'gs-sequences-by-location': SequencesByLocationComponent;
1358
+ 'gs-mutation-filter': MutationFilterComponent;
1359
+ }
1360
+ interface HTMLElementEventMap {
1361
+ [gsEventNames.mutationFilterChanged]: CustomEvent<MutationsFilter>;
1355
1362
  }
1356
1363
  }
1357
1364
 
@@ -1359,7 +1366,7 @@ declare global {
1359
1366
  declare global {
1360
1367
  namespace JSX {
1361
1368
  interface IntrinsicElements {
1362
- 'gs-sequences-by-location': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1369
+ 'gs-mutation-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1363
1370
  }
1364
1371
  }
1365
1372
  }
@@ -1367,7 +1374,11 @@ declare global {
1367
1374
 
1368
1375
  declare global {
1369
1376
  interface HTMLElementTagNameMap {
1370
- 'gs-statistics': StatisticsComponent;
1377
+ 'gs-lineage-filter': LineageFilterComponent;
1378
+ }
1379
+ interface HTMLElementEventMap {
1380
+ [gsEventNames.lineageFilterChanged]: LineageFilterChangedEvent;
1381
+ [gsEventNames.lineageFilterMultiChanged]: LineageMultiFilterChangedEvent;
1371
1382
  }
1372
1383
  }
1373
1384
 
@@ -1375,7 +1386,7 @@ declare global {
1375
1386
  declare global {
1376
1387
  namespace JSX {
1377
1388
  interface IntrinsicElements {
1378
- 'gs-statistics': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1389
+ 'gs-lineage-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1379
1390
  }
1380
1391
  }
1381
1392
  }
@@ -1383,7 +1394,11 @@ declare global {
1383
1394
 
1384
1395
  declare global {
1385
1396
  interface HTMLElementTagNameMap {
1386
- 'gs-queries-over-time': QueriesOverTimeComponent;
1397
+ 'gs-number-range-filter': NumberRangeFilterComponent;
1398
+ }
1399
+ interface HTMLElementEventMap {
1400
+ [gsEventNames.numberRangeFilterChanged]: NumberRangeFilterChangedEvent;
1401
+ [gsEventNames.numberRangeValueChanged]: NumberRangeValueChangedEvent;
1387
1402
  }
1388
1403
  }
1389
1404
 
@@ -1391,7 +1406,7 @@ declare global {
1391
1406
  declare global {
1392
1407
  namespace JSX {
1393
1408
  interface IntrinsicElements {
1394
- 'gs-queries-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1409
+ 'gs-number-range-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1395
1410
  }
1396
1411
  }
1397
1412
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genspectrum/dashboard-components",
3
- "version": "1.14.1",
3
+ "version": "1.15.0",
4
4
  "description": "GenSpectrum web components for building dashboards",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-only",
@@ -126,7 +126,6 @@
126
126
  "depcheck": "^1.4.7",
127
127
  "eslint": "^9.31.0",
128
128
  "eslint-plugin-import": "^2.29.1",
129
- "eslint-plugin-jest": "^28.2.0",
130
129
  "eslint-plugin-react": "^7.37.5",
131
130
  "eslint-plugin-react-hooks": "^5.2.0",
132
131
  "eslint-plugin-storybook": "^0.12.0",
@@ -68,7 +68,7 @@ export const mutationsOverTimeResponse = makeLapisResponse(
68
68
  export type MutationsOverTimeResponse = z.infer<typeof mutationsOverTimeResponse>;
69
69
 
70
70
  const queryDefinition = z.object({
71
- displayLabel: z.string(),
71
+ displayLabel: z.string().optional(),
72
72
  countQuery: z.string(),
73
73
  coverageQuery: z.string(),
74
74
  });
@@ -30,7 +30,7 @@ export type CustomColumn = z.infer<typeof customColumnSchema>;
30
30
  export interface FeatureRenderer<D> {
31
31
  asString(value: D): string;
32
32
  renderRowLabel(value: D): JSX.Element;
33
- renderTooltip(value: D, temporal: Temporal, proportionValue: ProportionValue | undefined): JSX.Element;
33
+ renderTooltip(value: D, temporal: Temporal, proportionValue: ProportionValue): JSX.Element;
34
34
  }
35
35
 
36
36
  export interface FeaturesOverTimeGridProps<F> {
@@ -99,12 +99,20 @@ function FeaturesOverTimeGrid<F>({
99
99
  </div>
100
100
  ),
101
101
  cell: ({ getValue, row, column, table }) => {
102
- const value = getValue();
102
+ const valueRaw = getValue();
103
+ const value = valueRaw ?? null;
103
104
  const rowIndex = row.index;
104
105
  const columnIndex = column.getIndex();
105
106
  const numberOfRows = table.getRowModel().rows.length;
106
107
  const numberOfColumns = table.getAllColumns().length;
107
108
 
109
+ if (valueRaw === undefined) {
110
+ // eslint-disable-next-line no-console -- We want to warn that something might be wrong.
111
+ console.error(
112
+ `Found undefined value for ${row.original.feature} - ${date.dateString}. This shouldn't happen.`,
113
+ );
114
+ }
115
+
108
116
  const tooltip = featureRenderer.renderTooltip(row.original.feature, date, value);
109
117
 
110
118
  return (
@@ -0,0 +1,60 @@
1
+ import { type Meta, type StoryObj } from '@storybook/preact';
2
+ import { expect, within } from '@storybook/test';
3
+
4
+ import {
5
+ QueriesOverTimeRowLabelTooltip,
6
+ type QueriesOverTimeRowLabelTooltipProps,
7
+ } from './queries-over-time-row-label-tooltip';
8
+
9
+ const meta: Meta<QueriesOverTimeRowLabelTooltipProps> = {
10
+ title: 'Component/Queries over time row label tooltip',
11
+ component: QueriesOverTimeRowLabelTooltip,
12
+ argTypes: {
13
+ query: { control: 'object' },
14
+ },
15
+ parameters: {
16
+ fetchMock: {},
17
+ },
18
+ };
19
+
20
+ export default meta;
21
+
22
+ export const Default: StoryObj<QueriesOverTimeRowLabelTooltipProps> = {
23
+ render: (args) => <QueriesOverTimeRowLabelTooltip {...args} />,
24
+ args: {
25
+ query: {
26
+ displayLabel: 'S:F456L (single mutation)',
27
+ description: 'This mutation is associated with increased transmissibility.',
28
+ countQuery: 'S:456L',
29
+ coverageQuery: '!S:456N',
30
+ },
31
+ },
32
+ play: async ({ canvasElement }) => {
33
+ const canvas = within(canvasElement);
34
+ await expect(canvas.getByText('S:F456L (single mutation)', { exact: true })).toBeVisible();
35
+ await expect(canvas.getByText('This mutation is associated with increased transmissibility.')).toBeVisible();
36
+ await expect(canvas.getByText('Count query:')).toBeVisible();
37
+ await expect(canvas.getByText('S:456L')).toBeVisible();
38
+ await expect(canvas.getByText('Coverage query:')).toBeVisible();
39
+ await expect(canvas.getByText('!S:456N')).toBeVisible();
40
+ },
41
+ };
42
+
43
+ export const WithoutDescription: StoryObj<QueriesOverTimeRowLabelTooltipProps> = {
44
+ render: (args) => <QueriesOverTimeRowLabelTooltip {...args} />,
45
+ args: {
46
+ query: {
47
+ displayLabel: 'S:R346T',
48
+ countQuery: 'S:346T',
49
+ coverageQuery: '!S:346N',
50
+ },
51
+ },
52
+ play: async ({ canvasElement }) => {
53
+ const canvas = within(canvasElement);
54
+ await expect(canvas.getByText('S:R346T', { exact: true })).toBeVisible();
55
+ await expect(canvas.getByText('Count query:')).toBeVisible();
56
+ await expect(canvas.getByText('S:346T')).toBeVisible();
57
+ await expect(canvas.getByText('Coverage query:')).toBeVisible();
58
+ await expect(canvas.getByText('!S:346N')).toBeVisible();
59
+ },
60
+ };
@@ -0,0 +1,34 @@
1
+ import type { FunctionComponent } from 'preact';
2
+
3
+ import type { CountCoverageQuery } from './queries-over-time';
4
+
5
+ export type QueriesOverTimeRowLabelTooltipProps = {
6
+ query: CountCoverageQuery;
7
+ };
8
+
9
+ export const QueriesOverTimeRowLabelTooltip: FunctionComponent<QueriesOverTimeRowLabelTooltipProps> = ({ query }) => {
10
+ return (
11
+ <div className='flex flex-col gap-2'>
12
+ <div className='font-bold'>{query.displayLabel}</div>
13
+ {query.description && <div className='text-sm text-gray-700'>{query.description}</div>}
14
+ <div className='flex flex-col gap-1'>
15
+ <div className='text-sm'>
16
+ <span className='text-gray-600'>Count query:</span>
17
+ <div className='p-2 border border-gray-200 rounded bg-gray-50 overflow-x-auto'>
18
+ <pre className='text-xs'>
19
+ <code>{query.countQuery}</code>
20
+ </pre>
21
+ </div>
22
+ </div>
23
+ <div className='text-sm'>
24
+ <span className='text-gray-600'>Coverage query:</span>
25
+ <div className='p-2 border border-gray-200 rounded bg-gray-50 overflow-x-auto'>
26
+ <pre className='text-xs'>
27
+ <code>{query.coverageQuery}</code>
28
+ </pre>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ </div>
33
+ );
34
+ };
@@ -466,6 +466,30 @@ export const WithNoLapisDateFieldField: StoryObj<QueriesOverTimeProps> = {
466
466
  },
467
467
  };
468
468
 
469
+ export const WithDuplicateDisplayLabels: StoryObj<QueriesOverTimeProps> = {
470
+ ...Default,
471
+ args: {
472
+ ...Default.args,
473
+ queries: [
474
+ {
475
+ displayLabel: 'S:F456L (single mutation)',
476
+ countQuery: 'S:456L',
477
+ coverageQuery: '!S:456N',
478
+ },
479
+ {
480
+ displayLabel: 'S:F456L (single mutation)',
481
+ countQuery: 'S:346T & S:456L',
482
+ coverageQuery: '!S:346N & !S:456N',
483
+ },
484
+ ],
485
+ },
486
+ play: async ({ canvasElement, step }) => {
487
+ await step('expect error message', async () => {
488
+ await expectInvalidAttributesErrorMessage(canvasElement, 'Display labels must be unique');
489
+ });
490
+ },
491
+ };
492
+
469
493
  async function expectQueryOnPage(canvas: Canvas, query: string) {
470
494
  await waitFor(async () => {
471
495
  const queryOnPage = canvas.getAllByText(query)[0];