@genspectrum/dashboard-components 1.14.2 → 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/custom-elements.json +5 -5
- package/dist/components.d.ts +11 -9
- package/dist/components.js +67 -11
- package/dist/components.js.map +1 -1
- package/dist/util.d.ts +28 -13
- package/package.json +1 -1
- package/src/lapisApi/lapisTypes.ts +1 -1
- package/src/preact/queriesOverTime/queries-over-time-row-label-tooltip.stories.tsx +60 -0
- package/src/preact/queriesOverTime/queries-over-time-row-label-tooltip.tsx +34 -0
- package/src/preact/queriesOverTime/queries-over-time.stories.tsx +24 -0
- package/src/preact/queriesOverTime/queries-over-time.tsx +63 -14
- package/src/web-components/visualization/gs-queries-over-time.stories.ts +4 -0
- package/src/web-components/visualization/gs-queries-over-time.tsx +3 -1
- package/standalone-bundle/dashboard-components.js +3575 -3527
- package/standalone-bundle/dashboard-components.js.map +1 -1
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
|
-
|
|
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>;
|
|
@@ -1154,7 +1169,7 @@ declare global {
|
|
|
1154
1169
|
|
|
1155
1170
|
declare global {
|
|
1156
1171
|
interface HTMLElementTagNameMap {
|
|
1157
|
-
'gs-
|
|
1172
|
+
'gs-prevalence-over-time': PrevalenceOverTimeComponent;
|
|
1158
1173
|
}
|
|
1159
1174
|
}
|
|
1160
1175
|
|
|
@@ -1162,7 +1177,7 @@ declare global {
|
|
|
1162
1177
|
declare global {
|
|
1163
1178
|
namespace JSX {
|
|
1164
1179
|
interface IntrinsicElements {
|
|
1165
|
-
'gs-
|
|
1180
|
+
'gs-prevalence-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1166
1181
|
}
|
|
1167
1182
|
}
|
|
1168
1183
|
}
|
|
@@ -1170,7 +1185,7 @@ declare global {
|
|
|
1170
1185
|
|
|
1171
1186
|
declare global {
|
|
1172
1187
|
interface HTMLElementTagNameMap {
|
|
1173
|
-
'gs-
|
|
1188
|
+
'gs-relative-growth-advantage': RelativeGrowthAdvantageComponent;
|
|
1174
1189
|
}
|
|
1175
1190
|
}
|
|
1176
1191
|
|
|
@@ -1178,7 +1193,7 @@ declare global {
|
|
|
1178
1193
|
declare global {
|
|
1179
1194
|
namespace JSX {
|
|
1180
1195
|
interface IntrinsicElements {
|
|
1181
|
-
'gs-
|
|
1196
|
+
'gs-relative-growth-advantage': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1182
1197
|
}
|
|
1183
1198
|
}
|
|
1184
1199
|
}
|
|
@@ -1218,7 +1233,7 @@ declare global {
|
|
|
1218
1233
|
|
|
1219
1234
|
declare global {
|
|
1220
1235
|
interface HTMLElementTagNameMap {
|
|
1221
|
-
'gs-
|
|
1236
|
+
'gs-queries-over-time': QueriesOverTimeComponent;
|
|
1222
1237
|
}
|
|
1223
1238
|
}
|
|
1224
1239
|
|
|
@@ -1226,7 +1241,7 @@ declare global {
|
|
|
1226
1241
|
declare global {
|
|
1227
1242
|
namespace JSX {
|
|
1228
1243
|
interface IntrinsicElements {
|
|
1229
|
-
'gs-
|
|
1244
|
+
'gs-queries-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1230
1245
|
}
|
|
1231
1246
|
}
|
|
1232
1247
|
}
|
|
@@ -1234,7 +1249,7 @@ declare global {
|
|
|
1234
1249
|
|
|
1235
1250
|
declare global {
|
|
1236
1251
|
interface HTMLElementTagNameMap {
|
|
1237
|
-
'gs-
|
|
1252
|
+
'gs-mutations-over-time': MutationsOverTimeComponent;
|
|
1238
1253
|
}
|
|
1239
1254
|
}
|
|
1240
1255
|
|
|
@@ -1242,7 +1257,7 @@ declare global {
|
|
|
1242
1257
|
declare global {
|
|
1243
1258
|
namespace JSX {
|
|
1244
1259
|
interface IntrinsicElements {
|
|
1245
|
-
'gs-
|
|
1260
|
+
'gs-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1246
1261
|
}
|
|
1247
1262
|
}
|
|
1248
1263
|
}
|
package/package.json
CHANGED
|
@@ -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
|
});
|
|
@@ -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];
|
|
@@ -5,6 +5,7 @@ import z from 'zod';
|
|
|
5
5
|
import { getFilteredQueryOverTimeData, type QueryFilter } from './getFilteredQueriesOverTimeData';
|
|
6
6
|
import { QueriesOverTimeFilter } from './queries-over-time-filter';
|
|
7
7
|
import { QueriesOverTimeGridTooltip } from './queries-over-time-grid-tooltip';
|
|
8
|
+
import { QueriesOverTimeRowLabelTooltip } from './queries-over-time-row-label-tooltip';
|
|
8
9
|
import { type ProportionValue, getProportion } from '../../query/queryMutationsOverTime';
|
|
9
10
|
import { queryQueriesOverTimeData } from '../../query/queryQueriesOverTime';
|
|
10
11
|
import { lapisFilterSchema, temporalGranularitySchema, views } from '../../types';
|
|
@@ -20,6 +21,7 @@ import { Fullscreen } from '../components/fullscreen';
|
|
|
20
21
|
import Info, { InfoComponentCode, InfoHeadline1, InfoParagraph } from '../components/info';
|
|
21
22
|
import { LoadingDisplay } from '../components/loading-display';
|
|
22
23
|
import { NoDataDisplay } from '../components/no-data-display';
|
|
24
|
+
import PortalTooltip from '../components/portal-tooltip';
|
|
23
25
|
import type { ProportionInterval } from '../components/proportion-selector';
|
|
24
26
|
import { ProportionSelectorDropdown } from '../components/proportion-selector-dropdown';
|
|
25
27
|
import { ResizeContainer } from '../components/resize-container';
|
|
@@ -37,17 +39,28 @@ const meanProportionIntervalSchema = z.object({
|
|
|
37
39
|
});
|
|
38
40
|
export type MeanProportionInterval = z.infer<typeof meanProportionIntervalSchema>;
|
|
39
41
|
|
|
42
|
+
const countCoverageQuerySchema = z.object({
|
|
43
|
+
displayLabel: z.string(),
|
|
44
|
+
description: z.string().optional(),
|
|
45
|
+
countQuery: z.string(),
|
|
46
|
+
coverageQuery: z.string(),
|
|
47
|
+
});
|
|
48
|
+
export type CountCoverageQuery = z.infer<typeof countCoverageQuerySchema>;
|
|
49
|
+
|
|
40
50
|
const queriesOverTimeSchema = z.object({
|
|
41
51
|
lapisFilter: lapisFilterSchema,
|
|
42
52
|
queries: z
|
|
43
|
-
.array(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
.array(countCoverageQuerySchema)
|
|
54
|
+
.min(1)
|
|
55
|
+
.superRefine((queries, ctx) => {
|
|
56
|
+
const duplicateDisplayLabels = findDuplicateStrings(queries.map((v) => v.displayLabel));
|
|
57
|
+
if (duplicateDisplayLabels.length > 0) {
|
|
58
|
+
ctx.addIssue({
|
|
59
|
+
code: z.ZodIssueCode.custom,
|
|
60
|
+
message: `Display labels must be unique. Duplicates: ${duplicateDisplayLabels.join(', ')}`,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}),
|
|
51
64
|
views: z.array(queriesOverTimeViewSchema),
|
|
52
65
|
granularity: temporalGranularitySchema,
|
|
53
66
|
lapisDateField: z.string().min(1),
|
|
@@ -136,19 +149,45 @@ const QueriesOverTimeTabs: FunctionComponent<QueriesOverTimeTabsProps> = ({
|
|
|
136
149
|
});
|
|
137
150
|
}, [queryOverTimeData, proportionInterval, hideGaps, queryFilterValue]);
|
|
138
151
|
|
|
152
|
+
const queryLookupMap = useMemo(
|
|
153
|
+
() => new Map(originalComponentProps.queries.map((query) => [query.displayLabel, query])),
|
|
154
|
+
[originalComponentProps.queries],
|
|
155
|
+
);
|
|
156
|
+
|
|
139
157
|
const queryRenderer = useMemo<FeatureRenderer<string>>(
|
|
140
158
|
() => ({
|
|
141
159
|
asString: (value: string) => value,
|
|
142
|
-
renderRowLabel: (value: string) =>
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
160
|
+
renderRowLabel: (value: string) => {
|
|
161
|
+
const queryObject = queryLookupMap.get(value);
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<PortalTooltip
|
|
165
|
+
content={
|
|
166
|
+
<QueriesOverTimeRowLabelTooltip
|
|
167
|
+
query={
|
|
168
|
+
queryObject ?? {
|
|
169
|
+
displayLabel: value,
|
|
170
|
+
description: undefined,
|
|
171
|
+
countQuery: '',
|
|
172
|
+
coverageQuery: '',
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/>
|
|
176
|
+
}
|
|
177
|
+
position='right'
|
|
178
|
+
portalTarget={tooltipPortalTarget}
|
|
179
|
+
>
|
|
180
|
+
<div className='text-center'>
|
|
181
|
+
<span>{value}</span>
|
|
182
|
+
</div>
|
|
183
|
+
</PortalTooltip>
|
|
184
|
+
);
|
|
185
|
+
},
|
|
147
186
|
renderTooltip: (value: string, temporal: Temporal, proportionValue: ProportionValue) => (
|
|
148
187
|
<QueriesOverTimeGridTooltip query={value} date={temporal} value={proportionValue} />
|
|
149
188
|
),
|
|
150
189
|
}),
|
|
151
|
-
[],
|
|
190
|
+
[tooltipPortalTarget, queryLookupMap],
|
|
152
191
|
);
|
|
153
192
|
|
|
154
193
|
const getTab = (view: QueriesOverTimeView) => {
|
|
@@ -302,3 +341,13 @@ function getDownloadData(filteredData: ReturnType<typeof getFilteredQueryOverTim
|
|
|
302
341
|
);
|
|
303
342
|
});
|
|
304
343
|
}
|
|
344
|
+
|
|
345
|
+
function findDuplicateStrings(items: string[]): string[] {
|
|
346
|
+
const counts = new Map<string, number>();
|
|
347
|
+
|
|
348
|
+
for (const item of items) {
|
|
349
|
+
counts.set(item, (counts.get(item) ?? 0) + 1);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return [...counts.entries()].filter(([, count]) => count > 1).map(([key]) => key);
|
|
353
|
+
}
|
|
@@ -15,11 +15,13 @@ const codeExample = String.raw`
|
|
|
15
15
|
queries='[
|
|
16
16
|
{
|
|
17
17
|
"displayLabel": "S:F456L (single mutation)",
|
|
18
|
+
"description": "This mutation is associated with increased transmissibility.",
|
|
18
19
|
"countQuery": "S:456L",
|
|
19
20
|
"coverageQuery": "!S:456N"
|
|
20
21
|
},
|
|
21
22
|
{
|
|
22
23
|
"displayLabel": "R346T + F456L (combination)",
|
|
24
|
+
"description": "Common mutation combination found in the JN.1 lineage.",
|
|
23
25
|
"countQuery": "S:346T & S:456L",
|
|
24
26
|
"coverageQuery": "!S:346N & !S:456N"
|
|
25
27
|
}
|
|
@@ -59,11 +61,13 @@ const meta: Meta<Required<QueriesOverTimeProps>> = {
|
|
|
59
61
|
queries: [
|
|
60
62
|
{
|
|
61
63
|
displayLabel: 'S:F456L (single mutation)',
|
|
64
|
+
description: 'This mutation is associated with increased transmissibility.',
|
|
62
65
|
countQuery: 'S:456L',
|
|
63
66
|
coverageQuery: '!S:456N',
|
|
64
67
|
},
|
|
65
68
|
{
|
|
66
69
|
displayLabel: 'R346T + F456L (combination)',
|
|
70
|
+
description: 'Common mutation combination found in the JN.1 lineage.',
|
|
67
71
|
countQuery: 'S:346T & S:456L',
|
|
68
72
|
coverageQuery: '!S:346N & !S:456N',
|
|
69
73
|
},
|
|
@@ -42,7 +42,8 @@ export class QueriesOverTimeComponent extends PreactLitAdapterWithGridJsStyles {
|
|
|
42
42
|
* Required.
|
|
43
43
|
*
|
|
44
44
|
* Array of queries to display. Each query has:
|
|
45
|
-
* - displayLabel: string - The name to show in the grid row label
|
|
45
|
+
* - displayLabel: string - The name to show in the grid row label. Must be unique.
|
|
46
|
+
* - description: string (optional) - Optional description shown in tooltip
|
|
46
47
|
* - countQuery: string - Query string to count matches
|
|
47
48
|
* - coverageQuery: string - Query string to determine coverage/denominator
|
|
48
49
|
*
|
|
@@ -51,6 +52,7 @@ export class QueriesOverTimeComponent extends PreactLitAdapterWithGridJsStyles {
|
|
|
51
52
|
@property({ type: Array })
|
|
52
53
|
queries: {
|
|
53
54
|
displayLabel: string;
|
|
55
|
+
description?: string;
|
|
54
56
|
countQuery: string;
|
|
55
57
|
coverageQuery: string;
|
|
56
58
|
}[] = [];
|