@genspectrum/dashboard-components 0.19.8 → 0.20.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.
Files changed (28) hide show
  1. package/custom-elements.json +32 -14
  2. package/dist/{NumberRangeFilterChangedEvent-RZ8haPHq.js → NumberRangeFilterChangedEvent-RqWinxhE.js} +50 -41
  3. package/dist/NumberRangeFilterChangedEvent-RqWinxhE.js.map +1 -0
  4. package/dist/assets/mutationOverTimeWorker-BzmkceEA.js.map +1 -0
  5. package/dist/components.d.ts +35 -35
  6. package/dist/components.js +5 -7
  7. package/dist/components.js.map +1 -1
  8. package/dist/util.d.ts +46 -64
  9. package/dist/util.js +1 -1
  10. package/package.json +1 -1
  11. package/src/preact/dateRangeFilter/date-range-filter.stories.tsx +3 -3
  12. package/src/preact/dateRangeFilter/dateRangeOption.ts +71 -45
  13. package/src/web-components/input/gs-date-range-filter.stories.ts +4 -4
  14. package/src/web-components/input/introduction.mdx +57 -2
  15. package/src/web-components/tutorials/CreateYourFirstOwnDashboard.mdx +85 -0
  16. package/src/web-components/tutorials/UseTheComponentsWithPlainJavaScript.mdx +140 -0
  17. package/src/web-components/tutorials/UseTheComponentsWithReact.mdx +166 -0
  18. package/src/web-components/visualization/gs-mutations.tsx +2 -2
  19. package/src/web-components/visualization/introduction.mdx +51 -0
  20. package/standalone-bundle/assets/mutationOverTimeWorker-jUeItsGM.js.map +1 -0
  21. package/standalone-bundle/dashboard-components.js +7088 -7112
  22. package/standalone-bundle/dashboard-components.js.map +1 -1
  23. package/dist/NumberRangeFilterChangedEvent-RZ8haPHq.js.map +0 -1
  24. package/dist/assets/mutationOverTimeWorker-CBXsEsiT.js.map +0 -1
  25. package/src/web-components/visualization/data_visualization_statistical_analysis.mdx +0 -26
  26. package/standalone-bundle/assets/mutationOverTimeWorker-CN4SJC7C.js.map +0 -1
  27. /package/src/web-components/{MutationAnnotations.mdx → mutationAnnotations.mdx} +0 -0
  28. /package/src/web-components/{ResizeContainer.mdx → sizeOfComponents.mdx} +0 -0
package/dist/util.d.ts CHANGED
@@ -77,38 +77,20 @@ export declare class DateRangeOptionChangedEvent extends CustomEvent<DateRangeVa
77
77
  constructor(detail: DateRangeValue);
78
78
  }
79
79
 
80
+ declare type DateRangeOptionPresets = {
81
+ last2Weeks: DateRangeOption;
82
+ lastMonth: DateRangeOption;
83
+ last2Months: DateRangeOption;
84
+ last3Months: DateRangeOption;
85
+ last6Months: DateRangeOption;
86
+ lastYear: DateRangeOption;
87
+ allTimes: DateRangeOption;
88
+ };
89
+
80
90
  /**
81
91
  * Presets for the `gs-date-range-filter` component that can be used as `dateRangeOptions`.
82
92
  */
83
- export declare const dateRangeOptionPresets: {
84
- last2Weeks: {
85
- label: string;
86
- dateFrom: string;
87
- };
88
- lastMonth: {
89
- label: string;
90
- dateFrom: string;
91
- };
92
- last2Months: {
93
- label: string;
94
- dateFrom: string;
95
- };
96
- last3Months: {
97
- label: string;
98
- dateFrom: string;
99
- };
100
- last6Months: {
101
- label: string;
102
- dateFrom: string;
103
- };
104
- lastYear: {
105
- label: string;
106
- dateFrom: string;
107
- };
108
- allTimes: {
109
- label: string;
110
- };
111
- };
93
+ export declare const dateRangeOptionPresets: () => DateRangeOptionPresets;
112
94
 
113
95
  /**
114
96
  * A date range option that can be used in the `gs-date-range-filter` component.
@@ -970,7 +952,7 @@ declare global {
970
952
 
971
953
  declare global {
972
954
  interface HTMLElementTagNameMap {
973
- 'gs-mutations-component': MutationsComponent;
955
+ 'gs-mutations': MutationsComponent;
974
956
  }
975
957
  }
976
958
 
@@ -978,7 +960,7 @@ declare global {
978
960
  declare global {
979
961
  namespace JSX {
980
962
  interface IntrinsicElements {
981
- 'gs-mutations-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
963
+ 'gs-mutations': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
982
964
  }
983
965
  }
984
966
  }
@@ -1002,7 +984,7 @@ declare global {
1002
984
 
1003
985
  declare global {
1004
986
  interface HTMLElementTagNameMap {
1005
- 'gs-relative-growth-advantage': RelativeGrowthAdvantageComponent;
987
+ 'gs-aggregate': AggregateComponent;
1006
988
  }
1007
989
  }
1008
990
 
@@ -1010,7 +992,7 @@ declare global {
1010
992
  declare global {
1011
993
  namespace JSX {
1012
994
  interface IntrinsicElements {
1013
- 'gs-relative-growth-advantage': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
995
+ 'gs-aggregate': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1014
996
  }
1015
997
  }
1016
998
  }
@@ -1018,7 +1000,7 @@ declare global {
1018
1000
 
1019
1001
  declare global {
1020
1002
  interface HTMLElementTagNameMap {
1021
- 'gs-aggregate': AggregateComponent;
1003
+ 'gs-relative-growth-advantage': RelativeGrowthAdvantageComponent;
1022
1004
  }
1023
1005
  }
1024
1006
 
@@ -1026,7 +1008,7 @@ declare global {
1026
1008
  declare global {
1027
1009
  namespace JSX {
1028
1010
  interface IntrinsicElements {
1029
- 'gs-aggregate': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1011
+ 'gs-relative-growth-advantage': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1030
1012
  }
1031
1013
  }
1032
1014
  }
@@ -1034,7 +1016,7 @@ declare global {
1034
1016
 
1035
1017
  declare global {
1036
1018
  interface HTMLElementTagNameMap {
1037
- 'gs-number-sequences-over-time': NumberSequencesOverTimeComponent;
1019
+ 'gs-mutations-over-time': MutationsOverTimeComponent;
1038
1020
  }
1039
1021
  }
1040
1022
 
@@ -1042,7 +1024,7 @@ declare global {
1042
1024
  declare global {
1043
1025
  namespace JSX {
1044
1026
  interface IntrinsicElements {
1045
- 'gs-number-sequences-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1027
+ 'gs-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1046
1028
  }
1047
1029
  }
1048
1030
  }
@@ -1050,7 +1032,7 @@ declare global {
1050
1032
 
1051
1033
  declare global {
1052
1034
  interface HTMLElementTagNameMap {
1053
- 'gs-mutations-over-time': MutationsOverTimeComponent;
1035
+ 'gs-number-sequences-over-time': NumberSequencesOverTimeComponent;
1054
1036
  }
1055
1037
  }
1056
1038
 
@@ -1058,7 +1040,7 @@ declare global {
1058
1040
  declare global {
1059
1041
  namespace JSX {
1060
1042
  interface IntrinsicElements {
1061
- 'gs-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1043
+ 'gs-number-sequences-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1062
1044
  }
1063
1045
  }
1064
1046
  }
@@ -1082,11 +1064,7 @@ declare global {
1082
1064
 
1083
1065
  declare global {
1084
1066
  interface HTMLElementTagNameMap {
1085
- 'gs-date-range-filter': DateRangeFilterComponent;
1086
- }
1087
- interface HTMLElementEventMap {
1088
- [gsEventNames.dateRangeFilterChanged]: CustomEvent<Record<string, string>>;
1089
- [gsEventNames.dateRangeOptionChanged]: DateRangeOptionChangedEvent;
1067
+ 'gs-statistics': StatisticsComponent;
1090
1068
  }
1091
1069
  }
1092
1070
 
@@ -1094,7 +1072,7 @@ declare global {
1094
1072
  declare global {
1095
1073
  namespace JSX {
1096
1074
  interface IntrinsicElements {
1097
- 'gs-date-range-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1075
+ 'gs-statistics': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1098
1076
  }
1099
1077
  }
1100
1078
  }
@@ -1102,10 +1080,7 @@ declare global {
1102
1080
 
1103
1081
  declare global {
1104
1082
  interface HTMLElementTagNameMap {
1105
- 'gs-location-filter': LocationFilterComponent;
1106
- }
1107
- interface HTMLElementEventMap {
1108
- [gsEventNames.locationChanged]: LocationChangedEvent;
1083
+ 'gs-wastewater-mutations-over-time': WastewaterMutationsOverTimeComponent;
1109
1084
  }
1110
1085
  }
1111
1086
 
@@ -1113,7 +1088,7 @@ declare global {
1113
1088
  declare global {
1114
1089
  namespace JSX {
1115
1090
  interface IntrinsicElements {
1116
- 'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1091
+ 'gs-wastewater-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1117
1092
  }
1118
1093
  }
1119
1094
  }
@@ -1121,7 +1096,11 @@ declare global {
1121
1096
 
1122
1097
  declare global {
1123
1098
  interface HTMLElementTagNameMap {
1124
- 'gs-statistics': StatisticsComponent;
1099
+ 'gs-date-range-filter': DateRangeFilterComponent;
1100
+ }
1101
+ interface HTMLElementEventMap {
1102
+ [gsEventNames.dateRangeFilterChanged]: CustomEvent<Record<string, string>>;
1103
+ [gsEventNames.dateRangeOptionChanged]: DateRangeOptionChangedEvent;
1125
1104
  }
1126
1105
  }
1127
1106
 
@@ -1129,7 +1108,7 @@ declare global {
1129
1108
  declare global {
1130
1109
  namespace JSX {
1131
1110
  interface IntrinsicElements {
1132
- 'gs-statistics': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1111
+ 'gs-date-range-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1133
1112
  }
1134
1113
  }
1135
1114
  }
@@ -1137,10 +1116,10 @@ declare global {
1137
1116
 
1138
1117
  declare global {
1139
1118
  interface HTMLElementTagNameMap {
1140
- 'gs-text-filter': TextFilterComponent;
1119
+ 'gs-location-filter': LocationFilterComponent;
1141
1120
  }
1142
1121
  interface HTMLElementEventMap {
1143
- [gsEventNames.textFilterChanged]: TextFilterChangedEvent;
1122
+ [gsEventNames.locationChanged]: LocationChangedEvent;
1144
1123
  }
1145
1124
  }
1146
1125
 
@@ -1148,7 +1127,7 @@ declare global {
1148
1127
  declare global {
1149
1128
  namespace JSX {
1150
1129
  interface IntrinsicElements {
1151
- 'gs-text-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1130
+ 'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1152
1131
  }
1153
1132
  }
1154
1133
  }
@@ -1156,10 +1135,10 @@ declare global {
1156
1135
 
1157
1136
  declare global {
1158
1137
  interface HTMLElementTagNameMap {
1159
- 'gs-lineage-filter': LineageFilterComponent;
1138
+ 'gs-text-filter': TextFilterComponent;
1160
1139
  }
1161
1140
  interface HTMLElementEventMap {
1162
- [gsEventNames.lineageFilterChanged]: LineageFilterChangedEvent;
1141
+ [gsEventNames.textFilterChanged]: TextFilterChangedEvent;
1163
1142
  }
1164
1143
  }
1165
1144
 
@@ -1167,7 +1146,7 @@ declare global {
1167
1146
  declare global {
1168
1147
  namespace JSX {
1169
1148
  interface IntrinsicElements {
1170
- 'gs-lineage-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1149
+ 'gs-text-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1171
1150
  }
1172
1151
  }
1173
1152
  }
@@ -1194,11 +1173,10 @@ declare global {
1194
1173
 
1195
1174
  declare global {
1196
1175
  interface HTMLElementTagNameMap {
1197
- 'gs-number-range-filter': NumberRangeFilterComponent;
1176
+ 'gs-lineage-filter': LineageFilterComponent;
1198
1177
  }
1199
1178
  interface HTMLElementEventMap {
1200
- [gsEventNames.numberRangeFilterChanged]: NumberRangeFilterChangedEvent;
1201
- [gsEventNames.numberRangeValueChanged]: NumberRangeValueChangedEvent;
1179
+ [gsEventNames.lineageFilterChanged]: LineageFilterChangedEvent;
1202
1180
  }
1203
1181
  }
1204
1182
 
@@ -1206,7 +1184,7 @@ declare global {
1206
1184
  declare global {
1207
1185
  namespace JSX {
1208
1186
  interface IntrinsicElements {
1209
- 'gs-number-range-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1187
+ 'gs-lineage-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1210
1188
  }
1211
1189
  }
1212
1190
  }
@@ -1214,7 +1192,11 @@ declare global {
1214
1192
 
1215
1193
  declare global {
1216
1194
  interface HTMLElementTagNameMap {
1217
- 'gs-wastewater-mutations-over-time': WastewaterMutationsOverTimeComponent;
1195
+ 'gs-number-range-filter': NumberRangeFilterComponent;
1196
+ }
1197
+ interface HTMLElementEventMap {
1198
+ [gsEventNames.numberRangeFilterChanged]: NumberRangeFilterChangedEvent;
1199
+ [gsEventNames.numberRangeValueChanged]: NumberRangeValueChangedEvent;
1218
1200
  }
1219
1201
  }
1220
1202
 
@@ -1222,7 +1204,7 @@ declare global {
1222
1204
  declare global {
1223
1205
  namespace JSX {
1224
1206
  interface IntrinsicElements {
1225
- 'gs-wastewater-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1207
+ 'gs-number-range-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1226
1208
  }
1227
1209
  }
1228
1210
  }
package/dist/util.js CHANGED
@@ -1,4 +1,4 @@
1
- import { D, a, L, N, b, T, d, g, v } from "./NumberRangeFilterChangedEvent-RZ8haPHq.js";
1
+ import { D, a, L, N, b, T, d, g, v } from "./NumberRangeFilterChangedEvent-RqWinxhE.js";
2
2
  export {
3
3
  D as DateRangeOptionChangedEvent,
4
4
  a as LineageFilterChangedEvent,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genspectrum/dashboard-components",
3
- "version": "0.19.8",
3
+ "version": "0.20.0",
4
4
  "description": "GenSpectrum web components for building dashboards",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-only",
@@ -55,7 +55,7 @@ const meta: Meta<DateRangeFilterProps> = {
55
55
  },
56
56
  },
57
57
  args: {
58
- dateRangeOptions: [dateRangeOptionPresets.lastMonth, dateRangeOptionPresets.allTimes, customDateRange],
58
+ dateRangeOptions: [dateRangeOptionPresets().lastMonth, dateRangeOptionPresets().allTimes, customDateRange],
59
59
  earliestDate,
60
60
  value: null,
61
61
  lapisDateField: 'aDateColumn',
@@ -150,7 +150,7 @@ export const SetsValueOnBlur: StoryObj<DateRangeFilterProps> = {
150
150
  ...Primary,
151
151
  args: {
152
152
  ...Primary.args,
153
- value: dateRangeOptionPresets.lastMonth.label,
153
+ value: dateRangeOptionPresets().lastMonth.label,
154
154
  },
155
155
  play: async ({ canvasElement, step }) => {
156
156
  const { canvas, filterChangedListenerMock, optionChangedListenerMock } = await prepare(canvasElement, step);
@@ -211,7 +211,7 @@ export const ChangingTheValueProgrammatically: StoryObj<DateRangeFilterProps> =
211
211
  <button className='btn' onClick={() => setValue(customDateRange.label)}>
212
212
  Set to Custom
213
213
  </button>
214
- <button className='btn' onClick={() => setValue(dateRangeOptionPresets.lastMonth.label)}>
214
+ <button className='btn' onClick={() => setValue(dateRangeOptionPresets().lastMonth.label)}>
215
215
  Set to Last month
216
216
  </button>
217
217
  </div>
@@ -45,55 +45,81 @@ export class DateRangeOptionChangedEvent extends CustomEvent<DateRangeValue> {
45
45
  }
46
46
  }
47
47
 
48
- const today = new Date();
48
+ type DateRangeOptionPresets = {
49
+ last2Weeks: DateRangeOption;
50
+ lastMonth: DateRangeOption;
51
+ last2Months: DateRangeOption;
52
+ last3Months: DateRangeOption;
53
+ last6Months: DateRangeOption;
54
+ lastYear: DateRangeOption;
55
+ allTimes: DateRangeOption;
56
+ };
49
57
 
50
- const twoWeeksAgo = new Date();
51
- twoWeeksAgo.setDate(today.getDate() - 14);
58
+ let dateRangeOptionsPresetsCacheDate: string | null = null;
59
+ let dateRangeOptionPresetsCache: DateRangeOptionPresets | null = null;
52
60
 
53
- const lastMonth = new Date(today);
54
- lastMonth.setMonth(today.getMonth() - 1);
61
+ /**
62
+ * Presets for the `gs-date-range-filter` component that can be used as `dateRangeOptions`.
63
+ */
64
+ export const dateRangeOptionPresets = (): DateRangeOptionPresets => {
65
+ const today = new Date();
66
+ const todayString = new Date().toISOString().slice(0, 10);
55
67
 
56
- const last2Months = new Date(today);
57
- last2Months.setMonth(today.getMonth() - 2);
68
+ if (
69
+ dateRangeOptionPresetsCache === null ||
70
+ dateRangeOptionsPresetsCacheDate === null ||
71
+ dateRangeOptionsPresetsCacheDate !== todayString
72
+ ) {
73
+ dateRangeOptionsPresetsCacheDate = todayString;
58
74
 
59
- const last3Months = new Date(today);
60
- last3Months.setMonth(today.getMonth() - 3);
75
+ const twoWeeksAgo = new Date();
76
+ twoWeeksAgo.setDate(today.getDate() - 14);
61
77
 
62
- const last6Months = new Date(today);
63
- last6Months.setMonth(today.getMonth() - 6);
78
+ const lastMonth = new Date(today);
79
+ lastMonth.setMonth(today.getMonth() - 1);
64
80
 
65
- const lastYear = new Date(today);
66
- lastYear.setFullYear(today.getFullYear() - 1);
81
+ const last2Months = new Date(today);
82
+ last2Months.setMonth(today.getMonth() - 2);
67
83
 
68
- /**
69
- * Presets for the `gs-date-range-filter` component that can be used as `dateRangeOptions`.
70
- */
71
- export const dateRangeOptionPresets = {
72
- last2Weeks: {
73
- label: 'Last 2 weeks',
74
- dateFrom: toYYYYMMDD(twoWeeksAgo),
75
- },
76
- lastMonth: {
77
- label: 'Last month',
78
- dateFrom: toYYYYMMDD(lastMonth),
79
- },
80
- last2Months: {
81
- label: 'Last 2 months',
82
- dateFrom: toYYYYMMDD(last2Months),
83
- },
84
- last3Months: {
85
- label: 'Last 3 months',
86
- dateFrom: toYYYYMMDD(last3Months),
87
- },
88
- last6Months: {
89
- label: 'Last 6 months',
90
- dateFrom: toYYYYMMDD(last6Months),
91
- },
92
- lastYear: {
93
- label: 'Last year',
94
- dateFrom: toYYYYMMDD(lastYear),
95
- },
96
- allTimes: {
97
- label: 'All times',
98
- },
99
- } satisfies Record<string, DateRangeOption>;
84
+ const last3Months = new Date(today);
85
+ last3Months.setMonth(today.getMonth() - 3);
86
+
87
+ const last6Months = new Date(today);
88
+ last6Months.setMonth(today.getMonth() - 6);
89
+
90
+ const lastYear = new Date(today);
91
+ lastYear.setFullYear(today.getFullYear() - 1);
92
+
93
+ dateRangeOptionPresetsCache = {
94
+ last2Weeks: {
95
+ label: 'Last 2 weeks',
96
+ dateFrom: toYYYYMMDD(twoWeeksAgo),
97
+ },
98
+ lastMonth: {
99
+ label: 'Last month',
100
+ dateFrom: toYYYYMMDD(lastMonth),
101
+ },
102
+ last2Months: {
103
+ label: 'Last 2 months',
104
+ dateFrom: toYYYYMMDD(last2Months),
105
+ },
106
+ last3Months: {
107
+ label: 'Last 3 months',
108
+ dateFrom: toYYYYMMDD(last3Months),
109
+ },
110
+ last6Months: {
111
+ label: 'Last 6 months',
112
+ dateFrom: toYYYYMMDD(last6Months),
113
+ },
114
+ lastYear: {
115
+ label: 'Last year',
116
+ dateFrom: toYYYYMMDD(lastYear),
117
+ },
118
+ allTimes: {
119
+ label: 'All times',
120
+ },
121
+ };
122
+ }
123
+
124
+ return dateRangeOptionPresetsCache;
125
+ };
@@ -59,14 +59,14 @@ const meta: Meta<Required<DateRangeFilterProps>> = {
59
59
  },
60
60
  args: {
61
61
  dateRangeOptions: [
62
- dateRangeOptionPresets.lastMonth,
63
- dateRangeOptionPresets.last3Months,
64
- dateRangeOptionPresets.allTimes,
62
+ dateRangeOptionPresets().lastMonth,
63
+ dateRangeOptionPresets().last3Months,
64
+ dateRangeOptionPresets().allTimes,
65
65
  { label: '2021', dateFrom: '2021-01-01', dateTo: '2021-12-31' },
66
66
  customDateRange,
67
67
  ],
68
68
  earliestDate: '1970-01-01',
69
- value: dateRangeOptionPresets.lastMonth.label,
69
+ value: dateRangeOptionPresets().lastMonth.label,
70
70
  lapisDateField: 'aDateColumn',
71
71
  width: '100%',
72
72
  placeholder: 'Date range',
@@ -7,5 +7,60 @@ import { Meta } from '@storybook/blocks';
7
7
  The components in this section let the user specify values for LAPIS filters.
8
8
  The filters can then be used as input to the visualization components.
9
9
 
10
- Every component fires `CustomEvent`s when the user interacts with it, which can be used to update the LAPIS filters.
11
- The `detail` of the event is designed such that it can be directly passed to the LAPIS API.
10
+ Every component fires `CustomEvent`s when the user interacts with it.
11
+ `event.detail` contains the payload of the event.
12
+
13
+ Every component fires an event that can be used to update the LAPIS filters.
14
+ It is supposed to be used in the style of:
15
+
16
+ ```javascript
17
+ component.addEventListener('gs-example-event', (event) => {
18
+ setNewLapisFilter({
19
+ ...previousLapisFilter,
20
+ ...event.detail,
21
+ });
22
+ });
23
+ ```
24
+
25
+ ## Controlled Input Components
26
+
27
+ HTML input components can be controlled or uncontrolled.
28
+ In a controlled component, the value is controlled by surrounding Javascript code.
29
+ In an uncontrolled component, the value is controlled by the DOM and the surrounding Javascript code only reads the value
30
+ (e.g. by listening to events).
31
+
32
+ All our input components can be used in both ways.
33
+ Every component fires one or two events.
34
+ If the event details can be used to update the LAPIS filter
35
+ _and_ the value then the component will only fire one event,
36
+ otherwise it will fire one event to update the LAPIS filter and one to update the value of the component.
37
+ Refer to the documentation of the individual components for details on which event you can use for which purpose.
38
+
39
+ **Example**: A controlled input component in a React app could conceptually look like this:
40
+
41
+ ```javascript
42
+ import { useEffect, useRef, useState } from 'react';
43
+
44
+ const ExampleInput = () => {
45
+ const [value, setValue] = useState('foo');
46
+ const inputRef = useRef(null);
47
+
48
+ useEffect(() => {
49
+ if (!inputRef.current) {
50
+ return;
51
+ }
52
+
53
+ const eventListener = (event) => {
54
+ setValue(event.detail);
55
+ };
56
+
57
+ inputRef.current.addEventListener('gs-input', eventListener);
58
+
59
+ return () => {
60
+ inputRef.current.removeEventListener('gs-input', eventListener);
61
+ };
62
+ }, []);
63
+
64
+ return <gs-example-input ref={inputRef} value={value} />;
65
+ };
66
+ ```
@@ -0,0 +1,85 @@
1
+ import { Meta } from '@storybook/blocks';
2
+
3
+ <Meta title='Tutorials/Create your first own dashboard' />
4
+
5
+ # Create your first own dashboard
6
+
7
+ In this tutorial, you’ll learn how to integrate our `visualization` components into your HTML page.
8
+ We’ll walk through building a simple dashboard that displays the number of sequences over time, along with some general statistics.
9
+ This example serves as a foundation for your own dashboards—you can easily extend it by adding more components as needed.
10
+ The data for these components must be provided by a LAPIS instance.
11
+ For this tutorial, we’ll use one of our own [LAPIS](https://lapis.cov-spectrum.org/open/v2/docs/) instances, but you’re free to use any LAPIS instance that supplies the required data.
12
+
13
+ ## Create your HTML page
14
+
15
+ Let's start by creating a simple HTML page. If you already have one, you can skip this step.
16
+ Name the file `index.html` and add the following code. This will be the main file for your dashboard.
17
+
18
+ ```html
19
+ <!doctype html>
20
+ <html lang="en">
21
+ <head>
22
+ <meta charset="UTF-8" />
23
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
24
+ <title>My dashboard</title>
25
+ </head>
26
+ <body>
27
+ We will fill this section later
28
+ </body>
29
+ </html>
30
+ ```
31
+
32
+ ## Include the dashboard components
33
+
34
+ To use the components, you need to include the dashboard bundle in your HTML file.
35
+ Add the following code to the `head` section:
36
+
37
+ ```html
38
+ <script
39
+ type="module"
40
+ src="https://unpkg.com/@genspectrum/dashboard-components@latest/standalone-bundle/dashboard-components.js"
41
+ ></script>
42
+ ```
43
+
44
+ This approach uses a standalone bundle, which includes all the code for the components in a single step.
45
+ It is the easiest way to get started, although the bundle size is larger.
46
+ Alternatively, you can use the components as modules, but this requires a build step.
47
+ For more information, see the "Use the Components with Plain JavaScript" tutorial.
48
+
49
+ ## Add the dashboard components to your HTML file
50
+
51
+ We are now ready to add the components to our HTML file.
52
+ You can do this by adding the following code to the `body` section of your HTML file:
53
+
54
+ ```html
55
+ <gs-app lapis="https://lapis.genspectrum.org/open/v2">
56
+ <h2>Statistics</h2>
57
+ <gs-statistics numeratorFilter='{"pangoLineage": "EG*"}' denominatorFilter="{}" width="100%"></gs-statistics>
58
+ <h2>Number of sequences over time</h2>
59
+ <gs-number-sequences-over-time
60
+ lapisFilters='[{ "displayName": "EG", "lapisFilter": { "pangoLineage": "EG*" } }]'
61
+ lapisDateField="date"
62
+ views='["bar", "line", "table"]'
63
+ width="100%"
64
+ granularity="month"
65
+ smoothingWindow="0"
66
+ pageSize="10"
67
+ ></gs-number-sequences-over-time>
68
+ </gs-app>
69
+ ```
70
+
71
+ Here, we are using three components:
72
+
73
+ - `gs-app`: This is the main component that wraps all the other components. It is used to provide the context for the other components. Each of our components needs to be wrapped in this component.
74
+ It provides the `lapis` attribute, which is the URL of the LAPIS server. This is the server that provides the data for the components. In this example, we are using the LAPIS server for open SARS-CoV-2 data.
75
+ - `gs-statistics` and `gs-number-sequences-over-time`: Visualization components that display data from the LAPIS server.
76
+
77
+ You can find more examples and detailed descriptions of each component in our documentation.
78
+
79
+ You now have your first dashboard. Open the `index.html` file in your browser to see it in action.
80
+ Feel free to change some parameters to see how they affect the dashboard, or explore our Storybook for more examples.
81
+
82
+ The parameters are currently fixed in the HTML file.
83
+ If you want users to be able to change them—especially the filters—we also provide input components.
84
+ To use them, add the input components to your HTML and connect them with JavaScript.
85
+ For more information, see the "Use the Components with Plain JavaScript" tutorial.