@genspectrum/dashboard-components 0.7.1 → 0.8.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 +1 -24
- package/dist/assets/mutationOverTimeWorker-BOCXtKzd.js.map +1 -1
- package/dist/dashboard-components.js +28 -27
- package/dist/dashboard-components.js.map +1 -1
- package/dist/genspectrum-components.d.ts +39 -50
- package/package.json +2 -2
- package/src/operator/SlidingOperator.ts +3 -0
- package/src/preact/components/error-display.tsx +1 -0
- package/src/preact/mutationFilter/mutation-filter.stories.tsx +5 -34
- package/src/preact/mutationFilter/mutation-filter.tsx +0 -13
- package/src/preact/mutationsOverTime/mutations-over-time.tsx +10 -4
- package/src/preact/prevalenceOverTime/__mockData__/numeratorFilterNoData.json +11 -0
- package/src/preact/prevalenceOverTime/prevalence-over-time-bar-chart.tsx +13 -6
- package/src/preact/prevalenceOverTime/prevalence-over-time-bubble-chart.tsx +13 -6
- package/src/preact/prevalenceOverTime/prevalence-over-time-line-chart.tsx +13 -6
- package/src/preact/prevalenceOverTime/prevalence-over-time.stories.tsx +74 -11
- package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +1 -1
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.stories.tsx +12 -5
- package/src/preact/webWorkers/useWebWorker.ts +4 -8
- package/src/web-components/input/gs-mutation-filter.stories.ts +1 -27
- package/src/web-components/input/gs-mutation-filter.tsx +0 -11
- package/standalone-bundle/dashboard-components.js +2384 -2383
- package/standalone-bundle/dashboard-components.js.map +1 -1
|
@@ -450,16 +450,6 @@ export declare class MutationComparisonComponent extends PreactLitAdapterWithGri
|
|
|
450
450
|
* Fired when:
|
|
451
451
|
* - The user has submitted a valid mutation or insertion
|
|
452
452
|
* - The user has removed a mutation or insertion
|
|
453
|
-
*
|
|
454
|
-
* @fires {CustomEvent<{
|
|
455
|
-
* nucleotideMutations: string[],
|
|
456
|
-
* aminoAcidMutations: string[],
|
|
457
|
-
* nucleotideInsertions: string[],
|
|
458
|
-
* aminoAcidInsertions: string[]
|
|
459
|
-
* }>} gs-mutation-filter-on-blur
|
|
460
|
-
* Fired when:
|
|
461
|
-
* - the mutation filter has lost focus
|
|
462
|
-
* Contains the selected mutations in the format
|
|
463
453
|
*/
|
|
464
454
|
export declare class MutationFilterComponent extends PreactLitAdapter {
|
|
465
455
|
/**
|
|
@@ -1039,10 +1029,7 @@ declare global {
|
|
|
1039
1029
|
|
|
1040
1030
|
declare global {
|
|
1041
1031
|
interface HTMLElementTagNameMap {
|
|
1042
|
-
'gs-
|
|
1043
|
-
}
|
|
1044
|
-
interface HTMLElementEventMap {
|
|
1045
|
-
'gs-date-range-changed': CustomEvent<Record<string, string>>;
|
|
1032
|
+
'gs-mutation-comparison-component': MutationComparisonComponent;
|
|
1046
1033
|
}
|
|
1047
1034
|
}
|
|
1048
1035
|
|
|
@@ -1050,7 +1037,7 @@ declare global {
|
|
|
1050
1037
|
declare global {
|
|
1051
1038
|
namespace JSX {
|
|
1052
1039
|
interface IntrinsicElements {
|
|
1053
|
-
'gs-
|
|
1040
|
+
'gs-mutation-comparison-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1054
1041
|
}
|
|
1055
1042
|
}
|
|
1056
1043
|
}
|
|
@@ -1058,10 +1045,7 @@ declare global {
|
|
|
1058
1045
|
|
|
1059
1046
|
declare global {
|
|
1060
1047
|
interface HTMLElementTagNameMap {
|
|
1061
|
-
'gs-
|
|
1062
|
-
}
|
|
1063
|
-
interface HTMLElementEventMap {
|
|
1064
|
-
'gs-text-input-changed': CustomEvent<Record<string, string>>;
|
|
1048
|
+
'gs-mutations-component': MutationsComponent;
|
|
1065
1049
|
}
|
|
1066
1050
|
}
|
|
1067
1051
|
|
|
@@ -1069,7 +1053,7 @@ declare global {
|
|
|
1069
1053
|
declare global {
|
|
1070
1054
|
namespace JSX {
|
|
1071
1055
|
interface IntrinsicElements {
|
|
1072
|
-
'gs-
|
|
1056
|
+
'gs-mutations-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1073
1057
|
}
|
|
1074
1058
|
}
|
|
1075
1059
|
}
|
|
@@ -1077,10 +1061,7 @@ declare global {
|
|
|
1077
1061
|
|
|
1078
1062
|
declare global {
|
|
1079
1063
|
interface HTMLElementTagNameMap {
|
|
1080
|
-
'gs-
|
|
1081
|
-
}
|
|
1082
|
-
interface HTMLElementEventMap {
|
|
1083
|
-
'gs-location-changed': CustomEvent<Record<string, string>>;
|
|
1064
|
+
'gs-prevalence-over-time': PrevalenceOverTimeComponent;
|
|
1084
1065
|
}
|
|
1085
1066
|
}
|
|
1086
1067
|
|
|
@@ -1088,7 +1069,7 @@ declare global {
|
|
|
1088
1069
|
declare global {
|
|
1089
1070
|
namespace JSX {
|
|
1090
1071
|
interface IntrinsicElements {
|
|
1091
|
-
'gs-
|
|
1072
|
+
'gs-prevalence-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1092
1073
|
}
|
|
1093
1074
|
}
|
|
1094
1075
|
}
|
|
@@ -1096,11 +1077,7 @@ declare global {
|
|
|
1096
1077
|
|
|
1097
1078
|
declare global {
|
|
1098
1079
|
interface HTMLElementTagNameMap {
|
|
1099
|
-
'gs-
|
|
1100
|
-
}
|
|
1101
|
-
interface HTMLElementEventMap {
|
|
1102
|
-
'gs-mutation-filter-changed': CustomEvent<SelectedMutationFilterStrings>;
|
|
1103
|
-
'gs-mutation-filter-on-blur': CustomEvent<SelectedMutationFilterStrings>;
|
|
1080
|
+
'gs-relative-growth-advantage': RelativeGrowthAdvantageComponent;
|
|
1104
1081
|
}
|
|
1105
1082
|
}
|
|
1106
1083
|
|
|
@@ -1108,7 +1085,7 @@ declare global {
|
|
|
1108
1085
|
declare global {
|
|
1109
1086
|
namespace JSX {
|
|
1110
1087
|
interface IntrinsicElements {
|
|
1111
|
-
'gs-
|
|
1088
|
+
'gs-relative-growth-advantage': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1112
1089
|
}
|
|
1113
1090
|
}
|
|
1114
1091
|
}
|
|
@@ -1116,10 +1093,7 @@ declare global {
|
|
|
1116
1093
|
|
|
1117
1094
|
declare global {
|
|
1118
1095
|
interface HTMLElementTagNameMap {
|
|
1119
|
-
'gs-
|
|
1120
|
-
}
|
|
1121
|
-
interface HTMLElementEventMap {
|
|
1122
|
-
'gs-lineage-filter-changed': CustomEvent<Record<string, string>>;
|
|
1096
|
+
'gs-aggregate-component': AggregateComponent;
|
|
1123
1097
|
}
|
|
1124
1098
|
}
|
|
1125
1099
|
|
|
@@ -1127,7 +1101,7 @@ declare global {
|
|
|
1127
1101
|
declare global {
|
|
1128
1102
|
namespace JSX {
|
|
1129
1103
|
interface IntrinsicElements {
|
|
1130
|
-
'gs-
|
|
1104
|
+
'gs-aggregate-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1131
1105
|
}
|
|
1132
1106
|
}
|
|
1133
1107
|
}
|
|
@@ -1135,7 +1109,7 @@ declare global {
|
|
|
1135
1109
|
|
|
1136
1110
|
declare global {
|
|
1137
1111
|
interface HTMLElementTagNameMap {
|
|
1138
|
-
'gs-
|
|
1112
|
+
'gs-number-sequences-over-time': NumberSequencesOverTimeComponent;
|
|
1139
1113
|
}
|
|
1140
1114
|
}
|
|
1141
1115
|
|
|
@@ -1143,7 +1117,7 @@ declare global {
|
|
|
1143
1117
|
declare global {
|
|
1144
1118
|
namespace JSX {
|
|
1145
1119
|
interface IntrinsicElements {
|
|
1146
|
-
'gs-
|
|
1120
|
+
'gs-number-sequences-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1147
1121
|
}
|
|
1148
1122
|
}
|
|
1149
1123
|
}
|
|
@@ -1151,7 +1125,7 @@ declare global {
|
|
|
1151
1125
|
|
|
1152
1126
|
declare global {
|
|
1153
1127
|
interface HTMLElementTagNameMap {
|
|
1154
|
-
'gs-mutations-
|
|
1128
|
+
'gs-mutations-over-time': MutationsOverTimeComponent;
|
|
1155
1129
|
}
|
|
1156
1130
|
}
|
|
1157
1131
|
|
|
@@ -1159,7 +1133,7 @@ declare global {
|
|
|
1159
1133
|
declare global {
|
|
1160
1134
|
namespace JSX {
|
|
1161
1135
|
interface IntrinsicElements {
|
|
1162
|
-
'gs-mutations-
|
|
1136
|
+
'gs-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1163
1137
|
}
|
|
1164
1138
|
}
|
|
1165
1139
|
}
|
|
@@ -1167,7 +1141,10 @@ declare global {
|
|
|
1167
1141
|
|
|
1168
1142
|
declare global {
|
|
1169
1143
|
interface HTMLElementTagNameMap {
|
|
1170
|
-
'gs-
|
|
1144
|
+
'gs-date-range-selector': DateRangeSelectorComponent;
|
|
1145
|
+
}
|
|
1146
|
+
interface HTMLElementEventMap {
|
|
1147
|
+
'gs-date-range-changed': CustomEvent<Record<string, string>>;
|
|
1171
1148
|
}
|
|
1172
1149
|
}
|
|
1173
1150
|
|
|
@@ -1175,7 +1152,7 @@ declare global {
|
|
|
1175
1152
|
declare global {
|
|
1176
1153
|
namespace JSX {
|
|
1177
1154
|
interface IntrinsicElements {
|
|
1178
|
-
'gs-
|
|
1155
|
+
'gs-date-range-selector': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1179
1156
|
}
|
|
1180
1157
|
}
|
|
1181
1158
|
}
|
|
@@ -1183,7 +1160,10 @@ declare global {
|
|
|
1183
1160
|
|
|
1184
1161
|
declare global {
|
|
1185
1162
|
interface HTMLElementTagNameMap {
|
|
1186
|
-
'gs-
|
|
1163
|
+
'gs-location-filter': LocationFilterComponent;
|
|
1164
|
+
}
|
|
1165
|
+
interface HTMLElementEventMap {
|
|
1166
|
+
'gs-location-changed': CustomEvent<Record<string, string>>;
|
|
1187
1167
|
}
|
|
1188
1168
|
}
|
|
1189
1169
|
|
|
@@ -1191,7 +1171,7 @@ declare global {
|
|
|
1191
1171
|
declare global {
|
|
1192
1172
|
namespace JSX {
|
|
1193
1173
|
interface IntrinsicElements {
|
|
1194
|
-
'gs-
|
|
1174
|
+
'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1195
1175
|
}
|
|
1196
1176
|
}
|
|
1197
1177
|
}
|
|
@@ -1199,7 +1179,10 @@ declare global {
|
|
|
1199
1179
|
|
|
1200
1180
|
declare global {
|
|
1201
1181
|
interface HTMLElementTagNameMap {
|
|
1202
|
-
'gs-
|
|
1182
|
+
'gs-text-input': TextInputComponent;
|
|
1183
|
+
}
|
|
1184
|
+
interface HTMLElementEventMap {
|
|
1185
|
+
'gs-text-input-changed': CustomEvent<Record<string, string>>;
|
|
1203
1186
|
}
|
|
1204
1187
|
}
|
|
1205
1188
|
|
|
@@ -1207,7 +1190,7 @@ declare global {
|
|
|
1207
1190
|
declare global {
|
|
1208
1191
|
namespace JSX {
|
|
1209
1192
|
interface IntrinsicElements {
|
|
1210
|
-
'gs-
|
|
1193
|
+
'gs-text-input': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1211
1194
|
}
|
|
1212
1195
|
}
|
|
1213
1196
|
}
|
|
@@ -1215,7 +1198,10 @@ declare global {
|
|
|
1215
1198
|
|
|
1216
1199
|
declare global {
|
|
1217
1200
|
interface HTMLElementTagNameMap {
|
|
1218
|
-
'gs-
|
|
1201
|
+
'gs-mutation-filter': MutationFilterComponent;
|
|
1202
|
+
}
|
|
1203
|
+
interface HTMLElementEventMap {
|
|
1204
|
+
'gs-mutation-filter-changed': CustomEvent<SelectedMutationFilterStrings>;
|
|
1219
1205
|
}
|
|
1220
1206
|
}
|
|
1221
1207
|
|
|
@@ -1223,7 +1209,7 @@ declare global {
|
|
|
1223
1209
|
declare global {
|
|
1224
1210
|
namespace JSX {
|
|
1225
1211
|
interface IntrinsicElements {
|
|
1226
|
-
'gs-
|
|
1212
|
+
'gs-mutation-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1227
1213
|
}
|
|
1228
1214
|
}
|
|
1229
1215
|
}
|
|
@@ -1231,7 +1217,10 @@ declare global {
|
|
|
1231
1217
|
|
|
1232
1218
|
declare global {
|
|
1233
1219
|
interface HTMLElementTagNameMap {
|
|
1234
|
-
'gs-
|
|
1220
|
+
'gs-lineage-filter': LineageFilterComponent;
|
|
1221
|
+
}
|
|
1222
|
+
interface HTMLElementEventMap {
|
|
1223
|
+
'gs-lineage-filter-changed': CustomEvent<Record<string, string>>;
|
|
1235
1224
|
}
|
|
1236
1225
|
}
|
|
1237
1226
|
|
|
@@ -1239,7 +1228,7 @@ declare global {
|
|
|
1239
1228
|
declare global {
|
|
1240
1229
|
namespace JSX {
|
|
1241
1230
|
interface IntrinsicElements {
|
|
1242
|
-
'gs-
|
|
1231
|
+
'gs-lineage-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1243
1232
|
}
|
|
1244
1233
|
}
|
|
1245
1234
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genspectrum/dashboard-components",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "GenSpectrum web components for building dashboards",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
"eslint-config-preact": "^1.3.0",
|
|
112
112
|
"eslint-plugin-import": "^2.29.1",
|
|
113
113
|
"eslint-plugin-jest": "^28.2.0",
|
|
114
|
-
"eslint-plugin-storybook": "^0.
|
|
114
|
+
"eslint-plugin-storybook": "^0.11.0",
|
|
115
115
|
"http-server": "^14.1.1",
|
|
116
116
|
"lit-analyzer": "^2.0.3",
|
|
117
117
|
"msw": "^2.2.14",
|
|
@@ -14,6 +14,9 @@ export class SlidingOperator<Data, AggregationResult> implements Operator<Aggreg
|
|
|
14
14
|
async evaluate(lapis: string, signal?: AbortSignal) {
|
|
15
15
|
const childEvaluated = await this.child.evaluate(lapis, signal);
|
|
16
16
|
const content = new Array<AggregationResult>();
|
|
17
|
+
if (childEvaluated.content.length === 0) {
|
|
18
|
+
return { content };
|
|
19
|
+
}
|
|
17
20
|
const numberOfWindows = Math.max(childEvaluated.content.length - this.windowSize, 0) + 1;
|
|
18
21
|
for (let i = 0; i < numberOfWindows; i++) {
|
|
19
22
|
content.push(this.aggregate(childEvaluated.content.slice(i, i + this.windowSize)));
|
|
@@ -25,6 +25,7 @@ export class UserFacingError extends Error {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export const ErrorDisplay: FunctionComponent<{ error: Error }> = ({ error }) => {
|
|
28
|
+
// eslint-disable-next-line no-console -- Currently we use the following statement for our error handling
|
|
28
29
|
console.error(error);
|
|
29
30
|
|
|
30
31
|
const containerRef = useRef<HTMLInputElement>(null);
|
|
@@ -14,7 +14,7 @@ const meta: Meta<MutationFilterProps> = {
|
|
|
14
14
|
component: MutationFilter,
|
|
15
15
|
parameters: {
|
|
16
16
|
actions: {
|
|
17
|
-
handles: ['gs-mutation-filter-changed',
|
|
17
|
+
handles: ['gs-mutation-filter-changed', ...previewHandles],
|
|
18
18
|
},
|
|
19
19
|
fetchMock: {},
|
|
20
20
|
},
|
|
@@ -120,32 +120,6 @@ export const FiresFilterChangedEvents: StoryObj<MutationFilterProps> = {
|
|
|
120
120
|
},
|
|
121
121
|
};
|
|
122
122
|
|
|
123
|
-
export const FiresFilterOnBlurEvent: StoryObj<MutationFilterProps> = {
|
|
124
|
-
...Default,
|
|
125
|
-
play: async ({ canvasElement, step }) => {
|
|
126
|
-
const { canvas, onBlurListenerMock } = await prepare(canvasElement, step);
|
|
127
|
-
|
|
128
|
-
await step('Move outside of input', async () => {
|
|
129
|
-
await submitMutation(canvas, 'A234T');
|
|
130
|
-
await submitMutation(canvas, 'S:A123G');
|
|
131
|
-
await submitMutation(canvas, 'ins_123:AAA');
|
|
132
|
-
await submitMutation(canvas, 'ins_S:123:AAA');
|
|
133
|
-
await userEvent.tab();
|
|
134
|
-
|
|
135
|
-
await expect(onBlurListenerMock).toHaveBeenCalledWith(
|
|
136
|
-
expect.objectContaining({
|
|
137
|
-
detail: {
|
|
138
|
-
nucleotideMutations: ['A234T'],
|
|
139
|
-
aminoAcidMutations: ['S:A123G'],
|
|
140
|
-
nucleotideInsertions: ['ins_123:AAA'],
|
|
141
|
-
aminoAcidInsertions: ['ins_S:123:AAA'],
|
|
142
|
-
},
|
|
143
|
-
}),
|
|
144
|
-
);
|
|
145
|
-
});
|
|
146
|
-
},
|
|
147
|
-
};
|
|
148
|
-
|
|
149
123
|
export const WithInitialValue: StoryObj<MutationFilterProps> = {
|
|
150
124
|
render: (args) => (
|
|
151
125
|
<LapisUrlContext.Provider value={LAPIS_URL}>
|
|
@@ -164,13 +138,12 @@ export const WithInitialValue: StoryObj<MutationFilterProps> = {
|
|
|
164
138
|
width: '100%',
|
|
165
139
|
},
|
|
166
140
|
play: async ({ canvasElement, step }) => {
|
|
167
|
-
const { canvas,
|
|
141
|
+
const { canvas, changedListenerMock } = await prepare(canvasElement, step);
|
|
168
142
|
|
|
169
|
-
await step('
|
|
143
|
+
await step('Enter additional input', async () => {
|
|
170
144
|
await submitMutation(canvas, 'G500T');
|
|
171
|
-
await userEvent.tab();
|
|
172
145
|
|
|
173
|
-
await expect(
|
|
146
|
+
await expect(changedListenerMock).toHaveBeenCalledWith(
|
|
174
147
|
expect.objectContaining({
|
|
175
148
|
detail: {
|
|
176
149
|
nucleotideMutations: ['A234T', 'G500T'],
|
|
@@ -187,10 +160,8 @@ export const WithInitialValue: StoryObj<MutationFilterProps> = {
|
|
|
187
160
|
async function prepare(canvasElement: HTMLElement, step: StepFunction<PreactRenderer, unknown>) {
|
|
188
161
|
const canvas = within(canvasElement);
|
|
189
162
|
|
|
190
|
-
const onBlurListenerMock = fn();
|
|
191
163
|
const changedListenerMock = fn();
|
|
192
164
|
await step('Setup event listener mock', async () => {
|
|
193
|
-
canvasElement.addEventListener('gs-mutation-filter-on-blur', onBlurListenerMock);
|
|
194
165
|
canvasElement.addEventListener('gs-mutation-filter-changed', changedListenerMock);
|
|
195
166
|
});
|
|
196
167
|
|
|
@@ -200,7 +171,7 @@ async function prepare(canvasElement: HTMLElement, step: StepFunction<PreactRend
|
|
|
200
171
|
});
|
|
201
172
|
});
|
|
202
173
|
|
|
203
|
-
return { canvas,
|
|
174
|
+
return { canvas, changedListenerMock };
|
|
204
175
|
}
|
|
205
176
|
|
|
206
177
|
const submitMutation = async (canvas: ReturnType<typeof within>, mutation: string) => {
|
|
@@ -87,18 +87,6 @@ export const MutationFilterInner: FunctionComponent<MutationFilterInnerProps> =
|
|
|
87
87
|
);
|
|
88
88
|
};
|
|
89
89
|
|
|
90
|
-
const handleOnBlur = () => {
|
|
91
|
-
const detail = mapToMutationFilterStrings(selectedFilters);
|
|
92
|
-
|
|
93
|
-
formRef.current?.dispatchEvent(
|
|
94
|
-
new CustomEvent<SelectedMutationFilterStrings>('gs-mutation-filter-on-blur', {
|
|
95
|
-
detail,
|
|
96
|
-
bubbles: true,
|
|
97
|
-
composed: true,
|
|
98
|
-
}),
|
|
99
|
-
);
|
|
100
|
-
};
|
|
101
|
-
|
|
102
90
|
const handleInputChange = (event: Event) => {
|
|
103
91
|
setInputValue((event.target as HTMLInputElement).value);
|
|
104
92
|
setIsError(false);
|
|
@@ -124,7 +112,6 @@ export const MutationFilterInner: FunctionComponent<MutationFilterInnerProps> =
|
|
|
124
112
|
value={inputValue}
|
|
125
113
|
onInput={handleInputChange}
|
|
126
114
|
placeholder={getPlaceholder(referenceGenome)}
|
|
127
|
-
onBlur={handleOnBlur}
|
|
128
115
|
/>
|
|
129
116
|
<button type='submit' className='btn btn-xs m-1'>
|
|
130
117
|
+
|
|
@@ -63,15 +63,21 @@ export const MutationsOverTimeInner: FunctionComponent<MutationsOverTimeProps> =
|
|
|
63
63
|
const lapis = useContext(LapisUrlContext);
|
|
64
64
|
const { lapisFilter, sequenceType, granularity, lapisDateField } = componentProps;
|
|
65
65
|
|
|
66
|
-
const
|
|
67
|
-
{
|
|
66
|
+
const messageToWorker = useMemo(() => {
|
|
67
|
+
return {
|
|
68
68
|
lapisFilter,
|
|
69
69
|
sequenceType,
|
|
70
70
|
granularity,
|
|
71
71
|
lapisDateField,
|
|
72
72
|
lapis,
|
|
73
|
-
}
|
|
74
|
-
|
|
73
|
+
};
|
|
74
|
+
}, [granularity, lapis, lapisDateField, lapisFilter, sequenceType]);
|
|
75
|
+
|
|
76
|
+
const worker = useMemo(() => new MutationOverTimeWorker(), []);
|
|
77
|
+
|
|
78
|
+
const { data, error, isLoading } = useWebWorker<MutationOverTimeQuery, MutationOverTimeWorkerResponse>(
|
|
79
|
+
messageToWorker,
|
|
80
|
+
worker,
|
|
75
81
|
);
|
|
76
82
|
|
|
77
83
|
if (isLoading) {
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from '../../query/queryPrevalenceOverTime';
|
|
10
10
|
import { sortNullToBeginningThenByDate } from '../../utils/sort';
|
|
11
11
|
import GsChart from '../components/chart';
|
|
12
|
+
import { NoDataDisplay } from '../components/no-data-display';
|
|
12
13
|
import { LogitScale } from '../shared/charts/LogitScale';
|
|
13
14
|
import { singleGraphColorRGBAById } from '../shared/charts/colors';
|
|
14
15
|
import { type ConfidenceIntervalMethod, wilson95PercentConfidenceInterval } from '../shared/charts/confideceInterval';
|
|
@@ -30,12 +31,18 @@ const PrevalenceOverTimeBarChart = ({
|
|
|
30
31
|
confidenceIntervalMethod,
|
|
31
32
|
yAxisMaxConfig,
|
|
32
33
|
}: PrevalenceOverTimeBarChartProps) => {
|
|
33
|
-
const nullFirstData = data
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
const nullFirstData = data
|
|
35
|
+
.filter((prevalenceOverTimeData) => prevalenceOverTimeData.content.length > 0)
|
|
36
|
+
.map((variantData) => {
|
|
37
|
+
return {
|
|
38
|
+
content: variantData.content.sort(sortNullToBeginningThenByDate),
|
|
39
|
+
displayName: variantData.displayName,
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
if (nullFirstData.length === 0) {
|
|
44
|
+
return <NoDataDisplay />;
|
|
45
|
+
}
|
|
39
46
|
|
|
40
47
|
const datasets = nullFirstData.map((graphData, index) => getDataset(graphData, index, confidenceIntervalMethod));
|
|
41
48
|
|
|
@@ -5,6 +5,7 @@ import { type PrevalenceOverTimeData } from '../../query/queryPrevalenceOverTime
|
|
|
5
5
|
import { addUnit, minusTemporal } from '../../utils/temporalClass';
|
|
6
6
|
import { getMinMaxNumber } from '../../utils/utils';
|
|
7
7
|
import GsChart from '../components/chart';
|
|
8
|
+
import { NoDataDisplay } from '../components/no-data-display';
|
|
8
9
|
import { LogitScale } from '../shared/charts/LogitScale';
|
|
9
10
|
import { singleGraphColorRGBAById } from '../shared/charts/colors';
|
|
10
11
|
import { getYAxisMax, type YAxisMaxConfig } from '../shared/charts/getYAxisMax';
|
|
@@ -23,12 +24,18 @@ const PrevalenceOverTimeBubbleChart = ({
|
|
|
23
24
|
yAxisScaleType,
|
|
24
25
|
yAxisMaxConfig,
|
|
25
26
|
}: PrevalenceOverTimeBubbleChartProps) => {
|
|
26
|
-
const nonNullDateRangeData = data
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
const nonNullDateRangeData = data
|
|
28
|
+
.filter((prevalenceOverTimeData) => prevalenceOverTimeData.content.length > 0)
|
|
29
|
+
.map((variantData) => {
|
|
30
|
+
return {
|
|
31
|
+
content: variantData.content.filter((dataPoint) => dataPoint.dateRange !== null),
|
|
32
|
+
displayName: variantData.displayName,
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
if (nonNullDateRangeData.length === 0) {
|
|
37
|
+
return <NoDataDisplay />;
|
|
38
|
+
}
|
|
32
39
|
|
|
33
40
|
const firstDate = nonNullDateRangeData[0].content[0].dateRange!;
|
|
34
41
|
const total = nonNullDateRangeData.map((graphData) => graphData.content.map((dataPoint) => dataPoint.total)).flat();
|
|
@@ -4,6 +4,7 @@ import { type TooltipItem } from 'chart.js/dist/types';
|
|
|
4
4
|
import { maxInData } from './prevalence-over-time';
|
|
5
5
|
import { type PrevalenceOverTimeData, type PrevalenceOverTimeVariantData } from '../../query/queryPrevalenceOverTime';
|
|
6
6
|
import GsChart from '../components/chart';
|
|
7
|
+
import { NoDataDisplay } from '../components/no-data-display';
|
|
7
8
|
import { LogitScale } from '../shared/charts/LogitScale';
|
|
8
9
|
import { singleGraphColorRGBAById } from '../shared/charts/colors';
|
|
9
10
|
import {
|
|
@@ -29,12 +30,18 @@ const PrevalenceOverTimeLineChart = ({
|
|
|
29
30
|
confidenceIntervalMethod,
|
|
30
31
|
yAxisMaxConfig,
|
|
31
32
|
}: PrevalenceOverTimeLineChartProps) => {
|
|
32
|
-
const nonNullDateRangeData = data
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
const nonNullDateRangeData = data
|
|
34
|
+
.filter((prevalenceOverTimeData) => prevalenceOverTimeData.content.length > 0)
|
|
35
|
+
.map((variantData) => {
|
|
36
|
+
return {
|
|
37
|
+
content: variantData.content.filter((dataPoint) => dataPoint.dateRange !== null),
|
|
38
|
+
displayName: variantData.displayName,
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (nonNullDateRangeData.length === 0) {
|
|
43
|
+
return <NoDataDisplay />;
|
|
44
|
+
}
|
|
38
45
|
|
|
39
46
|
const datasets = nonNullDateRangeData
|
|
40
47
|
.map((graphData, index) => getDataset(graphData, index, confidenceIntervalMethod))
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
+
import type { StoryObj } from '@storybook/preact';
|
|
2
|
+
import { expect, waitFor } from '@storybook/test';
|
|
3
|
+
|
|
4
|
+
import { LapisUrlContext } from '../LapisUrlContext';
|
|
1
5
|
import denominatorFilter from './__mockData__/denominatorFilter.json';
|
|
2
6
|
import denominatorOneDataset from './__mockData__/denominatorFilterOneDataset.json';
|
|
3
7
|
import numeratorFilterEG from './__mockData__/numeratorFilterEG.json';
|
|
4
8
|
import numeratorFilterJN1 from './__mockData__/numeratorFilterJN1.json';
|
|
9
|
+
import numeratorFilterNoData from './__mockData__/numeratorFilterNoData.json';
|
|
5
10
|
import numeratorOneDataset from './__mockData__/numeratorFilterOneDataset.json';
|
|
6
11
|
import { PrevalenceOverTime, type PrevalenceOverTimeProps } from './prevalence-over-time';
|
|
7
12
|
import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
|
|
8
|
-
import { LapisUrlContext } from '../LapisUrlContext';
|
|
9
13
|
|
|
10
14
|
export default {
|
|
11
15
|
title: 'Visualization/PrevalenceOverTime',
|
|
@@ -58,7 +62,7 @@ const Template = {
|
|
|
58
62
|
),
|
|
59
63
|
};
|
|
60
64
|
|
|
61
|
-
export const TwoVariants = {
|
|
65
|
+
export const TwoVariants: StoryObj<PrevalenceOverTimeProps> = {
|
|
62
66
|
...Template,
|
|
63
67
|
args: {
|
|
64
68
|
numeratorFilter: [
|
|
@@ -74,10 +78,8 @@ export const TwoVariants = {
|
|
|
74
78
|
height: '700px',
|
|
75
79
|
lapisDateField: 'date',
|
|
76
80
|
pageSize: 10,
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
logarithmic: 1,
|
|
80
|
-
},
|
|
81
|
+
yAxisMaxLinear: 1,
|
|
82
|
+
yAxisMaxLogarithmic: 1,
|
|
81
83
|
},
|
|
82
84
|
parameters: {
|
|
83
85
|
fetchMock: {
|
|
@@ -134,7 +136,7 @@ export const TwoVariants = {
|
|
|
134
136
|
},
|
|
135
137
|
};
|
|
136
138
|
|
|
137
|
-
export const OneVariant = {
|
|
139
|
+
export const OneVariant: StoryObj<PrevalenceOverTimeProps> = {
|
|
138
140
|
...Template,
|
|
139
141
|
args: {
|
|
140
142
|
numeratorFilter: {
|
|
@@ -150,10 +152,8 @@ export const OneVariant = {
|
|
|
150
152
|
height: '700px',
|
|
151
153
|
lapisDateField: 'date',
|
|
152
154
|
pageSize: 10,
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
logarithmic: 1,
|
|
156
|
-
},
|
|
155
|
+
yAxisMaxLinear: 1,
|
|
156
|
+
yAxisMaxLogarithmic: 1,
|
|
157
157
|
},
|
|
158
158
|
parameters: {
|
|
159
159
|
fetchMock: {
|
|
@@ -193,3 +193,66 @@ export const OneVariant = {
|
|
|
193
193
|
},
|
|
194
194
|
},
|
|
195
195
|
};
|
|
196
|
+
|
|
197
|
+
export const ShowsNoDataBanner: StoryObj<PrevalenceOverTimeProps> = {
|
|
198
|
+
...Template,
|
|
199
|
+
args: {
|
|
200
|
+
numeratorFilter: {
|
|
201
|
+
displayName: 'EG',
|
|
202
|
+
lapisFilter: { country: 'USA', pangoLineage: 'BA.2.86*', dateFrom: '2023-10-01' },
|
|
203
|
+
},
|
|
204
|
+
denominatorFilter: { country: 'USA', dateFrom: '2023-10-01' },
|
|
205
|
+
granularity: 'day',
|
|
206
|
+
smoothingWindow: 7,
|
|
207
|
+
views: ['bar', 'line', 'bubble', 'table'],
|
|
208
|
+
confidenceIntervalMethods: ['wilson'],
|
|
209
|
+
width: '100%',
|
|
210
|
+
height: '700px',
|
|
211
|
+
lapisDateField: 'date',
|
|
212
|
+
pageSize: 10,
|
|
213
|
+
yAxisMaxLinear: 1,
|
|
214
|
+
yAxisMaxLogarithmic: 1,
|
|
215
|
+
},
|
|
216
|
+
parameters: {
|
|
217
|
+
fetchMock: {
|
|
218
|
+
mocks: [
|
|
219
|
+
{
|
|
220
|
+
matcher: {
|
|
221
|
+
name: 'numeratorOneVariant',
|
|
222
|
+
url: AGGREGATED_ENDPOINT,
|
|
223
|
+
body: {
|
|
224
|
+
country: 'USA',
|
|
225
|
+
pangoLineage: 'BA.2.86*',
|
|
226
|
+
dateFrom: '2023-10-01',
|
|
227
|
+
fields: ['date'],
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
response: {
|
|
231
|
+
status: 200,
|
|
232
|
+
body: numeratorFilterNoData,
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
matcher: {
|
|
237
|
+
name: 'denominatorOneVariant',
|
|
238
|
+
url: AGGREGATED_ENDPOINT,
|
|
239
|
+
body: {
|
|
240
|
+
country: 'USA',
|
|
241
|
+
dateFrom: '2023-10-01',
|
|
242
|
+
fields: ['date'],
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
response: {
|
|
246
|
+
status: 200,
|
|
247
|
+
body: numeratorFilterNoData,
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
],
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
play: async ({ canvas }) => {
|
|
254
|
+
await waitFor(() => expect(canvas.getByText('No data available.', { exact: false })).toBeVisible(), {
|
|
255
|
+
timeout: 10000,
|
|
256
|
+
});
|
|
257
|
+
},
|
|
258
|
+
};
|
|
@@ -80,7 +80,7 @@ export const PrevalenceOverTimeInner: FunctionComponent<PrevalenceOverTimeProps>
|
|
|
80
80
|
return <ErrorDisplay error={error} />;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
if (data === null) {
|
|
83
|
+
if (data === null || data.every((variant) => variant.content.length === 0)) {
|
|
84
84
|
return <NoDataDisplay />;
|
|
85
85
|
}
|
|
86
86
|
|