@genspectrum/dashboard-components 1.0.1 → 1.2.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 +2 -2
- package/dist/{NumberRangeFilterChangedEvent-B64OQZjX.js → NumberRangeFilterChangedEvent-CQ32Qy8D.js} +2 -2
- package/dist/NumberRangeFilterChangedEvent-CQ32Qy8D.js.map +1 -0
- package/dist/assets/mutationOverTimeWorker-DpW4YOGl.js.map +1 -0
- package/dist/components.d.ts +29 -29
- package/dist/components.js +186 -145
- package/dist/components.js.map +1 -1
- package/dist/util.d.ts +29 -29
- package/dist/util.js +1 -1
- package/package.json +7 -3
- package/src/lapisApi/lapisApi.ts +2 -2
- package/src/operator/DivisionOperator.ts +4 -2
- package/src/operator/FetchDetailsOperator.ts +1 -1
- package/src/operator/RenameFieldOperator.ts +3 -3
- package/src/preact/MutationAnnotationsContext.tsx +15 -7
- package/src/preact/aggregatedData/aggregate.tsx +0 -5
- package/src/preact/components/annotated-mutation.tsx +0 -1
- package/src/preact/components/clearable-select.stories.tsx +1 -1
- package/src/preact/components/confidence-interval-selector.tsx +1 -1
- package/src/preact/components/error-boundary.tsx +1 -5
- package/src/preact/components/error-display.tsx +1 -1
- package/src/preact/components/fullscreen.tsx +2 -5
- package/src/preact/components/info.stories.tsx +1 -1
- package/src/preact/components/min-max-range-slider.tsx +1 -1
- package/src/preact/components/mutations-over-time-mutations-filter.stories.tsx +109 -0
- package/src/preact/components/mutations-over-time-mutations-filter.tsx +139 -0
- package/src/preact/components/proportion-selector.tsx +4 -4
- package/src/preact/components/select.tsx +1 -1
- package/src/preact/components/table.tsx +1 -1
- package/src/preact/components/tabs.tsx +1 -1
- package/src/preact/components/tooltip.stories.tsx +1 -1
- package/src/preact/components/tooltip.tsx +1 -1
- package/src/preact/genomeViewer/CDSPlot.tsx +3 -3
- package/src/preact/genomeViewer/loadGff3.ts +5 -8
- package/src/preact/lineageFilter/lineage-filter.tsx +1 -1
- package/src/preact/locationFilter/location-filter.tsx +4 -4
- package/src/preact/mutationComparison/getMutationComparisonTableData.ts +1 -3
- package/src/preact/mutationComparison/mutation-comparison-venn.tsx +1 -1
- package/src/preact/mutationComparison/mutation-comparison.tsx +0 -5
- package/src/preact/mutationFilter/mutation-filter-info.tsx +2 -2
- package/src/preact/mutationFilter/mutation-filter.tsx +1 -1
- package/src/preact/mutations/getMutationsGridData.ts +2 -6
- package/src/preact/mutations/getMutationsTableData.ts +1 -1
- package/src/preact/mutations/mutations-grid.tsx +1 -1
- package/src/preact/mutations/mutations.tsx +0 -5
- package/src/preact/mutationsOverTime/getFilteredMutationsOverTime.spec.ts +27 -16
- package/src/preact/mutationsOverTime/getFilteredMutationsOverTimeData.ts +45 -11
- package/src/preact/mutationsOverTime/mutations-over-time.tsx +16 -15
- package/src/preact/numberRangeFilter/number-range-filter.tsx +4 -4
- package/src/preact/numberSequencesOverTime/getNumberOfSequencesOverTimeTableData.ts +1 -4
- package/src/preact/numberSequencesOverTime/number-sequences-over-time.tsx +0 -5
- package/src/preact/prevalenceOverTime/prevalence-over-time-bar-chart.tsx +1 -1
- package/src/preact/prevalenceOverTime/prevalence-over-time-bubble-chart.tsx +1 -1
- package/src/preact/prevalenceOverTime/prevalence-over-time-line-chart.tsx +1 -1
- package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +1 -1
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage-chart.tsx +5 -5
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.tsx +1 -4
- package/src/preact/sequencesByLocation/loadMapSource.tsx +5 -2
- package/src/preact/shared/aspectRatio/AspectRatio.tsx +1 -1
- package/src/preact/shared/floating-ui/hooks.ts +2 -2
- package/src/preact/shared/sort/sortMutationPositions.ts +2 -2
- package/src/preact/shared/tanstackTable/pagination.tsx +2 -2
- package/src/preact/shared/tanstackTable/tanstackTable.tsx +1 -1
- package/src/preact/statistic/statistics.tsx +0 -5
- package/src/preact/textFilter/fetchStringAutocompleteList.ts +1 -10
- package/src/preact/textFilter/text-filter.tsx +1 -6
- package/src/preact/wastewater/mutationsOverTime/wastewater-mutations-over-time.tsx +14 -8
- package/src/preact/webWorkers/useWebWorker.ts +2 -1
- package/src/preact/webWorkers/workerFunction.ts +2 -2
- package/src/query/computeMapLocationData.ts +1 -1
- package/src/query/queryAggregatedDataOverTime.ts +3 -3
- package/src/query/queryMutationsOverTime.spec.ts +9 -9
- package/src/query/queryMutationsOverTime.ts +22 -16
- package/src/query/queryRelativeGrowthAdvantage.ts +5 -9
- package/src/query/queryWastewaterMutationsOverTime.ts +1 -1
- package/src/types.ts +1 -1
- package/src/utils/mutations.ts +10 -10
- package/src/utils/type-utils.ts +1 -1
- package/src/utils/typeAssertions.spec.ts +1 -1
- package/src/web-components/gs-app.spec-d.ts +1 -1
- package/src/web-components/gs-app.stories.ts +1 -1
- package/src/web-components/input/gs-date-range-filter.tsx +2 -2
- package/src/web-components/input/gs-lineage-filter.tsx +2 -2
- package/src/web-components/input/gs-location-filter.tsx +3 -3
- package/src/web-components/input/gs-mutation-filter.tsx +2 -2
- package/src/web-components/input/gs-number-range-filter.spec.ts +1 -1
- package/src/web-components/input/gs-text-filter.tsx +2 -2
- package/src/web-components/visualization/gs-aggregate.tsx +2 -2
- package/src/web-components/visualization/gs-genome-data-viewer.spec-d.ts +1 -1
- package/src/web-components/visualization/gs-mutation-comparison.tsx +2 -2
- package/src/web-components/visualization/gs-mutations.tsx +2 -2
- package/src/web-components/visualization/gs-number-sequences-over-time.tsx +2 -2
- package/src/web-components/visualization/gs-prevalence-over-time.tsx +2 -2
- package/src/web-components/visualization/gs-relative-growth-advantage.tsx +2 -2
- package/src/web-components/visualization/gs-sequences-by-location.tsx +2 -2
- package/src/web-components/visualization/gs-statistics.tsx +2 -2
- package/standalone-bundle/assets/mutationOverTimeWorker-CZVvQBze.js.map +1 -0
- package/standalone-bundle/dashboard-components.js +3989 -3923
- package/standalone-bundle/dashboard-components.js.map +1 -1
- package/dist/NumberRangeFilterChangedEvent-B64OQZjX.js.map +0 -1
- package/dist/assets/mutationOverTimeWorker-DjH04AQB.js.map +0 -1
- package/src/preact/components/mutations-over-time-text-filter.stories.tsx +0 -57
- package/src/preact/components/mutations-over-time-text-filter.tsx +0 -63
- package/standalone-bundle/assets/mutationOverTimeWorker-B6bf3R3j.js.map +0 -1
package/dist/util.d.ts
CHANGED
|
@@ -164,7 +164,7 @@ declare type LapisLineageFilter = Record<string, string | undefined>;
|
|
|
164
164
|
|
|
165
165
|
declare type LapisLocationFilter = default_2.infer<typeof lapisLocationFilterSchema>;
|
|
166
166
|
|
|
167
|
-
declare const lapisLocationFilterSchema: default_2.ZodRecord<default_2.ZodString, default_2.ZodUnion<[default_2.ZodString, default_2.ZodUndefined]>>;
|
|
167
|
+
declare const lapisLocationFilterSchema: default_2.ZodRecord<default_2.ZodString, default_2.ZodUnion<[default_2.ZodString, default_2.ZodUndefined, default_2.ZodNull]>>;
|
|
168
168
|
|
|
169
169
|
export declare type LapisNumberFilter = Record<string, number | undefined>;
|
|
170
170
|
|
|
@@ -917,7 +917,7 @@ declare global {
|
|
|
917
917
|
|
|
918
918
|
declare global {
|
|
919
919
|
interface HTMLElementTagNameMap {
|
|
920
|
-
'gs-
|
|
920
|
+
'gs-wastewater-mutations-over-time': WastewaterMutationsOverTimeComponent;
|
|
921
921
|
}
|
|
922
922
|
}
|
|
923
923
|
|
|
@@ -925,7 +925,7 @@ declare global {
|
|
|
925
925
|
declare global {
|
|
926
926
|
namespace JSX {
|
|
927
927
|
interface IntrinsicElements {
|
|
928
|
-
'gs-
|
|
928
|
+
'gs-wastewater-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
929
929
|
}
|
|
930
930
|
}
|
|
931
931
|
}
|
|
@@ -979,6 +979,22 @@ declare global {
|
|
|
979
979
|
}
|
|
980
980
|
|
|
981
981
|
|
|
982
|
+
declare global {
|
|
983
|
+
interface HTMLElementTagNameMap {
|
|
984
|
+
'gs-mutation-comparison-component': MutationComparisonComponent;
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
|
|
989
|
+
declare global {
|
|
990
|
+
namespace JSX {
|
|
991
|
+
interface IntrinsicElements {
|
|
992
|
+
'gs-mutation-comparison-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
|
|
982
998
|
declare global {
|
|
983
999
|
interface HTMLElementTagNameMap {
|
|
984
1000
|
'gs-aggregate': AggregateComponent;
|
|
@@ -1029,7 +1045,7 @@ declare global {
|
|
|
1029
1045
|
|
|
1030
1046
|
declare global {
|
|
1031
1047
|
interface HTMLElementTagNameMap {
|
|
1032
|
-
'gs-
|
|
1048
|
+
'gs-mutations-over-time': MutationsOverTimeComponent;
|
|
1033
1049
|
}
|
|
1034
1050
|
}
|
|
1035
1051
|
|
|
@@ -1037,7 +1053,7 @@ declare global {
|
|
|
1037
1053
|
declare global {
|
|
1038
1054
|
namespace JSX {
|
|
1039
1055
|
interface IntrinsicElements {
|
|
1040
|
-
'gs-
|
|
1056
|
+
'gs-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1041
1057
|
}
|
|
1042
1058
|
}
|
|
1043
1059
|
}
|
|
@@ -1045,7 +1061,7 @@ declare global {
|
|
|
1045
1061
|
|
|
1046
1062
|
declare global {
|
|
1047
1063
|
interface HTMLElementTagNameMap {
|
|
1048
|
-
'gs-
|
|
1064
|
+
'gs-sequences-by-location': SequencesByLocationComponent;
|
|
1049
1065
|
}
|
|
1050
1066
|
}
|
|
1051
1067
|
|
|
@@ -1053,7 +1069,7 @@ declare global {
|
|
|
1053
1069
|
declare global {
|
|
1054
1070
|
namespace JSX {
|
|
1055
1071
|
interface IntrinsicElements {
|
|
1056
|
-
'gs-
|
|
1072
|
+
'gs-sequences-by-location': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1057
1073
|
}
|
|
1058
1074
|
}
|
|
1059
1075
|
}
|
|
@@ -1135,10 +1151,10 @@ declare global {
|
|
|
1135
1151
|
|
|
1136
1152
|
declare global {
|
|
1137
1153
|
interface HTMLElementTagNameMap {
|
|
1138
|
-
'gs-
|
|
1154
|
+
'gs-mutation-filter': MutationFilterComponent;
|
|
1139
1155
|
}
|
|
1140
1156
|
interface HTMLElementEventMap {
|
|
1141
|
-
[gsEventNames.
|
|
1157
|
+
[gsEventNames.mutationFilterChanged]: CustomEvent<MutationsFilter>;
|
|
1142
1158
|
}
|
|
1143
1159
|
}
|
|
1144
1160
|
|
|
@@ -1146,7 +1162,7 @@ declare global {
|
|
|
1146
1162
|
declare global {
|
|
1147
1163
|
namespace JSX {
|
|
1148
1164
|
interface IntrinsicElements {
|
|
1149
|
-
'gs-
|
|
1165
|
+
'gs-mutation-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1150
1166
|
}
|
|
1151
1167
|
}
|
|
1152
1168
|
}
|
|
@@ -1154,10 +1170,10 @@ declare global {
|
|
|
1154
1170
|
|
|
1155
1171
|
declare global {
|
|
1156
1172
|
interface HTMLElementTagNameMap {
|
|
1157
|
-
'gs-
|
|
1173
|
+
'gs-lineage-filter': LineageFilterComponent;
|
|
1158
1174
|
}
|
|
1159
1175
|
interface HTMLElementEventMap {
|
|
1160
|
-
[gsEventNames.
|
|
1176
|
+
[gsEventNames.lineageFilterChanged]: LineageFilterChangedEvent;
|
|
1161
1177
|
}
|
|
1162
1178
|
}
|
|
1163
1179
|
|
|
@@ -1165,7 +1181,7 @@ declare global {
|
|
|
1165
1181
|
declare global {
|
|
1166
1182
|
namespace JSX {
|
|
1167
1183
|
interface IntrinsicElements {
|
|
1168
|
-
'gs-
|
|
1184
|
+
'gs-lineage-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1169
1185
|
}
|
|
1170
1186
|
}
|
|
1171
1187
|
}
|
|
@@ -1191,22 +1207,6 @@ declare global {
|
|
|
1191
1207
|
}
|
|
1192
1208
|
|
|
1193
1209
|
|
|
1194
|
-
declare global {
|
|
1195
|
-
interface HTMLElementTagNameMap {
|
|
1196
|
-
'gs-wastewater-mutations-over-time': WastewaterMutationsOverTimeComponent;
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
declare global {
|
|
1202
|
-
namespace JSX {
|
|
1203
|
-
interface IntrinsicElements {
|
|
1204
|
-
'gs-wastewater-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
1205
|
-
}
|
|
1206
|
-
}
|
|
1207
|
-
}
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
1210
|
declare module 'chart.js' {
|
|
1211
1211
|
interface CartesianScaleTypeRegistry {
|
|
1212
1212
|
logit: {
|
package/dist/util.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genspectrum/dashboard-components",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "GenSpectrum web components for building dashboards",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -99,6 +99,7 @@
|
|
|
99
99
|
},
|
|
100
100
|
"devDependencies": {
|
|
101
101
|
"@custom-elements-manifest/analyzer": "^0.10.2",
|
|
102
|
+
"@eslint/js": "^9.31.0",
|
|
102
103
|
"@iconify-json/mdi": "^1.1.67",
|
|
103
104
|
"@iconify-json/mdi-light": "^1.1.10",
|
|
104
105
|
"@iconify/tailwind4": "^1.0.6",
|
|
@@ -127,11 +128,13 @@
|
|
|
127
128
|
"autoprefixer": "^10.4.19",
|
|
128
129
|
"daisyui": "^5.0.0",
|
|
129
130
|
"depcheck": "^1.4.7",
|
|
130
|
-
"eslint": "^
|
|
131
|
-
"eslint-config-preact": "^1.3.0",
|
|
131
|
+
"eslint": "^9.31.0",
|
|
132
132
|
"eslint-plugin-import": "^2.29.1",
|
|
133
133
|
"eslint-plugin-jest": "^28.2.0",
|
|
134
|
+
"eslint-plugin-react": "^7.37.5",
|
|
135
|
+
"eslint-plugin-react-hooks": "^5.2.0",
|
|
134
136
|
"eslint-plugin-storybook": "^0.12.0",
|
|
137
|
+
"globals": "^16.3.0",
|
|
135
138
|
"happy-dom": "^17.1.1",
|
|
136
139
|
"http-server": "^14.1.1",
|
|
137
140
|
"lit-analyzer": "^2.0.3",
|
|
@@ -143,6 +146,7 @@
|
|
|
143
146
|
"storybook-addon-fetch-mock": "^2.0.0",
|
|
144
147
|
"tailwindcss": "^4.0.9",
|
|
145
148
|
"typescript": "^5.8.2",
|
|
149
|
+
"typescript-eslint": "^8.36.0",
|
|
146
150
|
"vite": "^6.0.3",
|
|
147
151
|
"vite-plugin-dts": "4.5.0",
|
|
148
152
|
"vitest": "^3.0.2"
|
package/src/lapisApi/lapisApi.ts
CHANGED
|
@@ -176,7 +176,7 @@ const handleErrors = async (response: Response, requestedData: string) => {
|
|
|
176
176
|
const lapisErrorResult = lapisError.safeParse(json);
|
|
177
177
|
if (lapisErrorResult.success) {
|
|
178
178
|
throw new LapisError(
|
|
179
|
-
response.statusText + lapisErrorResult.data.error.detail,
|
|
179
|
+
response.statusText + (lapisErrorResult.data.error.detail ?? ''),
|
|
180
180
|
response.status,
|
|
181
181
|
lapisErrorResult.data.error,
|
|
182
182
|
requestedData,
|
|
@@ -186,7 +186,7 @@ const handleErrors = async (response: Response, requestedData: string) => {
|
|
|
186
186
|
const problemDetailResult = problemDetail.safeParse(json);
|
|
187
187
|
if (problemDetailResult.success) {
|
|
188
188
|
throw new LapisError(
|
|
189
|
-
response.statusText + problemDetailResult.data.detail,
|
|
189
|
+
response.statusText + (problemDetailResult.data.detail ?? ''),
|
|
190
190
|
response.status,
|
|
191
191
|
problemDetailResult.data,
|
|
192
192
|
requestedData,
|
|
@@ -8,7 +8,8 @@ export type DivisionOperatorResult<
|
|
|
8
8
|
ResultField extends string,
|
|
9
9
|
NumeratorField extends string,
|
|
10
10
|
DenominatorField extends string,
|
|
11
|
-
> =
|
|
11
|
+
> = Record<KeyField, ValueObject[KeyField]> &
|
|
12
|
+
MappedNumber<ResultField> &
|
|
12
13
|
MappedNumber<NumeratorField> &
|
|
13
14
|
MappedNumber<DenominatorField>;
|
|
14
15
|
|
|
@@ -50,7 +51,8 @@ export class DivisionOperator<
|
|
|
50
51
|
[this.numeratorField]: numeratorValue as number,
|
|
51
52
|
[this.denominatorField]: row[this.valueField] as number,
|
|
52
53
|
[this.resultField]: (numeratorValue as number) / (row[this.valueField] as number),
|
|
53
|
-
} as
|
|
54
|
+
} as Record<KeyField, ValueObject[KeyField]> &
|
|
55
|
+
MappedNumber<ResultField> &
|
|
54
56
|
MappedNumber<NumeratorField> &
|
|
55
57
|
MappedNumber<DenominatorField>;
|
|
56
58
|
});
|
|
@@ -3,7 +3,7 @@ import { type Operator } from './Operator';
|
|
|
3
3
|
import { fetchDetails } from '../lapisApi/lapisApi';
|
|
4
4
|
import { type LapisFilter } from '../types';
|
|
5
5
|
|
|
6
|
-
type Details<Fields extends string> =
|
|
6
|
+
type Details<Fields extends string> = Record<Fields, string | number | boolean | null>;
|
|
7
7
|
|
|
8
8
|
export class FetchDetailsOperator<Fields extends string> implements Operator<Details<Fields>> {
|
|
9
9
|
constructor(
|
|
@@ -4,8 +4,8 @@ import type { Operator } from './Operator';
|
|
|
4
4
|
export class RenameFieldOperator<
|
|
5
5
|
OldFieldName extends string,
|
|
6
6
|
NewFieldName extends string,
|
|
7
|
-
Data extends
|
|
8
|
-
> extends MapOperator<Data, Data &
|
|
7
|
+
Data extends Record<OldFieldName, unknown>,
|
|
8
|
+
> extends MapOperator<Data, Data & Record<NewFieldName, Data[OldFieldName]>> {
|
|
9
9
|
constructor(child: Operator<Data>, oldFieldName: OldFieldName, newFieldName: NewFieldName) {
|
|
10
10
|
super(
|
|
11
11
|
child,
|
|
@@ -13,7 +13,7 @@ export class RenameFieldOperator<
|
|
|
13
13
|
({
|
|
14
14
|
...value,
|
|
15
15
|
[newFieldName]: value[oldFieldName],
|
|
16
|
-
}) as Data &
|
|
16
|
+
}) as Data & Record<NewFieldName, Data[OldFieldName]>,
|
|
17
17
|
);
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -16,7 +16,12 @@ type MutationAnnotationPerSequenceType = {
|
|
|
16
16
|
position: Map<string, MutationAnnotations>;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
type MutationAnnotationsContextValue = Record<SequenceType, MutationAnnotationPerSequenceType> & {
|
|
20
|
+
rawAnnotations: MutationAnnotations;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const MutationAnnotationsContext = createContext<MutationAnnotationsContextValue>({
|
|
24
|
+
rawAnnotations: [],
|
|
20
25
|
nucleotide: {
|
|
21
26
|
mutation: new Map(),
|
|
22
27
|
position: new Map(),
|
|
@@ -75,6 +80,7 @@ export function getMutationAnnotationsContext(value: MutationAnnotations) {
|
|
|
75
80
|
});
|
|
76
81
|
|
|
77
82
|
return {
|
|
83
|
+
rawAnnotations: value,
|
|
78
84
|
nucleotide: { mutation: nucleotideMap, position: nucleotidePositions },
|
|
79
85
|
'amino acid': { mutation: aminoAcidMap, position: aminoAcidPositions },
|
|
80
86
|
};
|
|
@@ -85,15 +91,17 @@ function addAnnotationToMap(map: Map<string, MutationAnnotations>, code: string,
|
|
|
85
91
|
map.set(code.toUpperCase(), [...oldAnnotations, annotation]);
|
|
86
92
|
}
|
|
87
93
|
|
|
94
|
+
export function useRawMutationAnnotations() {
|
|
95
|
+
return useContext(MutationAnnotationsContext).rawAnnotations;
|
|
96
|
+
}
|
|
97
|
+
|
|
88
98
|
export function useMutationAnnotationsProvider() {
|
|
89
99
|
const mutationAnnotations = useContext(MutationAnnotationsContext);
|
|
90
100
|
|
|
91
101
|
return getMutationAnnotationsProvider(mutationAnnotations);
|
|
92
102
|
}
|
|
93
103
|
|
|
94
|
-
export function getMutationAnnotationsProvider(
|
|
95
|
-
mutationAnnotations: Record<SequenceType, MutationAnnotationPerSequenceType>,
|
|
96
|
-
) {
|
|
104
|
+
export function getMutationAnnotationsProvider(mutationAnnotations: MutationAnnotationsContextValue) {
|
|
97
105
|
return (mutation: Mutation, sequenceType: SequenceType) => {
|
|
98
106
|
const position =
|
|
99
107
|
mutation.segment === undefined
|
|
@@ -110,11 +118,11 @@ export function getMutationAnnotationsProvider(
|
|
|
110
118
|
|
|
111
119
|
const uniqueNames = new Set<string>();
|
|
112
120
|
|
|
113
|
-
return annotations?.filter((
|
|
114
|
-
if (uniqueNames.has(
|
|
121
|
+
return annotations?.filter((annotation) => {
|
|
122
|
+
if (uniqueNames.has(annotation.name)) {
|
|
115
123
|
return false;
|
|
116
124
|
}
|
|
117
|
-
uniqueNames.add(
|
|
125
|
+
uniqueNames.add(annotation.name);
|
|
118
126
|
return true;
|
|
119
127
|
});
|
|
120
128
|
};
|
|
@@ -11,7 +11,6 @@ import { ErrorBoundary } from '../components/error-boundary';
|
|
|
11
11
|
import { Fullscreen } from '../components/fullscreen';
|
|
12
12
|
import Info, { InfoComponentCode, InfoHeadline1, InfoParagraph } from '../components/info';
|
|
13
13
|
import { LoadingDisplay } from '../components/loading-display';
|
|
14
|
-
import { NoDataDisplay } from '../components/no-data-display';
|
|
15
14
|
import { ResizeContainer } from '../components/resize-container';
|
|
16
15
|
import Tabs from '../components/tabs';
|
|
17
16
|
import { useQuery } from '../useQuery';
|
|
@@ -63,10 +62,6 @@ export const AggregateInner: FunctionComponent<AggregateProps> = (componentProps
|
|
|
63
62
|
throw error;
|
|
64
63
|
}
|
|
65
64
|
|
|
66
|
-
if (data === null) {
|
|
67
|
-
return <NoDataDisplay />;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
65
|
return <AggregatedDataTabs data={data} originalComponentProps={componentProps} />;
|
|
71
66
|
};
|
|
72
67
|
|
|
@@ -58,7 +58,6 @@ const AnnotatedMutationWithoutContext: FunctionComponent<AnnotatedMutationWithou
|
|
|
58
58
|
<Fragment key={annotation.name}>
|
|
59
59
|
<InfoHeadline2>{annotation.name}</InfoHeadline2>
|
|
60
60
|
<InfoParagraph>
|
|
61
|
-
{/* eslint-disable-next-line react/no-danger */}
|
|
62
61
|
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(annotation.description) }} />
|
|
63
62
|
</InfoParagraph>
|
|
64
63
|
</Fragment>
|
|
@@ -33,7 +33,7 @@ export const ConfidenceIntervalSelector: FunctionComponent<ConfidenceIntervalSel
|
|
|
33
33
|
return (
|
|
34
34
|
<Select
|
|
35
35
|
items={items}
|
|
36
|
-
selected={confidenceIntervalMethod
|
|
36
|
+
selected={confidenceIntervalMethod}
|
|
37
37
|
onChange={(event: Event) => {
|
|
38
38
|
const select = event.target as HTMLSelectElement;
|
|
39
39
|
const value = select.value as ConfidenceIntervalMethod;
|
|
@@ -19,7 +19,7 @@ export const ErrorBoundary = <T extends Record<string, unknown>>({
|
|
|
19
19
|
schema,
|
|
20
20
|
children,
|
|
21
21
|
}: RenderableProps<ErrorBoundaryProps<T>>) => {
|
|
22
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- useErrorBoundary unfortunately
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- useErrorBoundary unfortunately returns `[any, ...]`
|
|
23
23
|
const [internalError, resetError] = useErrorBoundary();
|
|
24
24
|
const componentPropsParseError = useCheckComponentProps(schema, componentProps);
|
|
25
25
|
|
|
@@ -54,10 +54,6 @@ export const ErrorBoundary = <T extends Record<string, unknown>>({
|
|
|
54
54
|
|
|
55
55
|
function useCheckComponentProps<T extends Record<string, unknown>>(schema: ZodSchema<T>, componentProps: T) {
|
|
56
56
|
return useMemo(() => {
|
|
57
|
-
if (schema === undefined || componentProps === undefined) {
|
|
58
|
-
return undefined;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
57
|
const parseResult = schema.safeParse(componentProps);
|
|
62
58
|
if (parseResult.success) {
|
|
63
59
|
return undefined;
|
|
@@ -151,7 +151,7 @@ function ZodErrorDetails({ error }: { error: InvalidPropsError }) {
|
|
|
151
151
|
</p>
|
|
152
152
|
)}
|
|
153
153
|
<p>This is a summary of the unexpected attribute values:</p>
|
|
154
|
-
<ul
|
|
154
|
+
<ul className='m-4 list-outside list-disc '>
|
|
155
155
|
{error.zodError.issues.map((issue, index) => {
|
|
156
156
|
const actual =
|
|
157
157
|
issue.path[0] in error.componentProps
|
|
@@ -33,14 +33,11 @@ function findComponentRoot(element: HTMLElement) {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
function findShadowRoot(element: HTMLElement) {
|
|
36
|
-
let current: Node = element;
|
|
37
|
-
while (current) {
|
|
36
|
+
let current: Node | null = element;
|
|
37
|
+
while (current !== null) {
|
|
38
38
|
if (current instanceof ShadowRoot) {
|
|
39
39
|
return current;
|
|
40
40
|
}
|
|
41
|
-
if (current.parentNode === null) {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
41
|
current = current.parentNode;
|
|
45
42
|
}
|
|
46
43
|
return null;
|
|
@@ -15,7 +15,7 @@ const tooltipText = 'This is a tooltip which shows some information.';
|
|
|
15
15
|
|
|
16
16
|
export const InfoStory: StoryObj = {
|
|
17
17
|
render: (args) => (
|
|
18
|
-
<div
|
|
18
|
+
<div className='flex justify-center px-4 py-16'>
|
|
19
19
|
<Info {...args}>{tooltipText}</Info>
|
|
20
20
|
</div>
|
|
21
21
|
),
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { type StoryObj } from '@storybook/preact';
|
|
2
|
+
import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
|
|
3
|
+
import { type Meta } from '@storybook/web-components';
|
|
4
|
+
import { useState, type Dispatch, type StateUpdater } from 'preact/hooks';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
MutationsOverTimeMutationsFilter,
|
|
8
|
+
type MutationsOverTimeMutationsFilterProps,
|
|
9
|
+
} from './mutations-over-time-mutations-filter';
|
|
10
|
+
import { MutationAnnotationsContextProvider } from '../MutationAnnotationsContext';
|
|
11
|
+
import { type MutationFilter } from '../mutationsOverTime/getFilteredMutationsOverTimeData';
|
|
12
|
+
|
|
13
|
+
const meta: Meta = {
|
|
14
|
+
title: 'Component/Mutations over time mutations filter',
|
|
15
|
+
component: 'MutationsOverTimeTextFilter',
|
|
16
|
+
parameters: { fetchMock: {} },
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default meta;
|
|
20
|
+
|
|
21
|
+
const WrapperWithState = ({
|
|
22
|
+
setFilterValue,
|
|
23
|
+
value,
|
|
24
|
+
}: {
|
|
25
|
+
setFilterValue: Dispatch<StateUpdater<MutationFilter>>;
|
|
26
|
+
value: MutationFilter;
|
|
27
|
+
}) => {
|
|
28
|
+
const [state, setState] = useState(value);
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<MutationAnnotationsContextProvider
|
|
32
|
+
value={[
|
|
33
|
+
{
|
|
34
|
+
name: 'Test Annotation 1',
|
|
35
|
+
description: 'Test Annotation 1',
|
|
36
|
+
symbol: '#',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'Test Annotation 2',
|
|
40
|
+
description: 'Test Annotation 2',
|
|
41
|
+
symbol: '+',
|
|
42
|
+
},
|
|
43
|
+
]}
|
|
44
|
+
>
|
|
45
|
+
<MutationsOverTimeMutationsFilter
|
|
46
|
+
setFilterValue={(value) => {
|
|
47
|
+
setFilterValue(value);
|
|
48
|
+
setState(value);
|
|
49
|
+
}}
|
|
50
|
+
value={state}
|
|
51
|
+
/>
|
|
52
|
+
</MutationAnnotationsContextProvider>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const FilterByText: StoryObj<MutationsOverTimeMutationsFilterProps> = {
|
|
57
|
+
render: (args) => {
|
|
58
|
+
return <WrapperWithState setFilterValue={args.setFilterValue} value={args.value} />;
|
|
59
|
+
},
|
|
60
|
+
args: {
|
|
61
|
+
setFilterValue: fn(),
|
|
62
|
+
value: { textFilter: 'Test', annotationNameFilter: new Set([]) },
|
|
63
|
+
},
|
|
64
|
+
play: async ({ canvasElement, step }) => {
|
|
65
|
+
const canvas = within(canvasElement);
|
|
66
|
+
|
|
67
|
+
await step('Expect initial value to show on the button', async () => {
|
|
68
|
+
const button = canvas.getByRole('button');
|
|
69
|
+
await expect(button).toHaveTextContent('Test');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
await step('Change filter and expect it to show on the button', async () => {
|
|
73
|
+
const button = canvas.getByRole('button');
|
|
74
|
+
await userEvent.click(button);
|
|
75
|
+
|
|
76
|
+
const inputField = canvas.getByRole('textbox');
|
|
77
|
+
await userEvent.clear(inputField);
|
|
78
|
+
await userEvent.type(inputField, 'OtherText');
|
|
79
|
+
|
|
80
|
+
await waitFor(() => expect(button).toHaveTextContent('OtherText'));
|
|
81
|
+
});
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export const FilterByAnnotation: StoryObj<MutationsOverTimeMutationsFilterProps> = {
|
|
86
|
+
...FilterByText,
|
|
87
|
+
args: {
|
|
88
|
+
setFilterValue: fn(),
|
|
89
|
+
value: { textFilter: '', annotationNameFilter: new Set() },
|
|
90
|
+
},
|
|
91
|
+
play: async ({ canvasElement, step }) => {
|
|
92
|
+
const canvas = within(canvasElement);
|
|
93
|
+
|
|
94
|
+
await step('Expect default text to show on the button', async () => {
|
|
95
|
+
const button = canvas.getByRole('button');
|
|
96
|
+
await expect(button).toHaveTextContent('Filter mutations');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
await step('Change filter and expect it to show on the button', async () => {
|
|
100
|
+
const button = canvas.getByRole('button');
|
|
101
|
+
await userEvent.click(button);
|
|
102
|
+
|
|
103
|
+
const inputField = canvas.getByRole('checkbox', { name: /Test Annotation 1/ });
|
|
104
|
+
await userEvent.click(inputField);
|
|
105
|
+
|
|
106
|
+
await waitFor(() => expect(button).toHaveTextContent('Test Annotation 1'));
|
|
107
|
+
});
|
|
108
|
+
},
|
|
109
|
+
};
|