@genspectrum/dashboard-components 0.6.17 → 0.6.19
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/README.md +5 -12
- package/custom-elements.json +4 -4
- package/dist/assets/mutationOverTimeWorker-BdzqDqvO.js.map +1 -0
- package/dist/dashboard-components.js +216 -214
- package/dist/dashboard-components.js.map +1 -1
- package/dist/genspectrum-components.d.ts +40 -40
- package/dist/style.css +3 -2
- package/package.json +13 -2
- package/src/operator/FetchInsertionsOperator.ts +2 -2
- package/src/operator/FetchSubstitutionsOrDeletionsOperator.ts +3 -3
- package/src/preact/mutationComparison/fetchMutationData.spec.ts +3 -3
- package/src/preact/mutationComparison/getMutationComparisonTableData.spec.ts +11 -11
- package/src/preact/mutationComparison/getMutationComparisonTableData.ts +4 -4
- package/src/preact/mutationComparison/mutation-comparison-table.tsx +2 -2
- package/src/preact/mutationFilter/mutation-filter.tsx +27 -18
- package/src/preact/mutationFilter/parseAndValidateMutation.ts +4 -4
- package/src/preact/mutationFilter/parseMutation.spec.ts +17 -17
- package/src/preact/mutations/getInsertionsTableData.spec.ts +3 -3
- package/src/preact/mutations/getMutationsGridData.spec.ts +9 -9
- package/src/preact/mutations/getMutationsTableData.spec.ts +7 -7
- package/src/preact/mutations/mutations-insertions-table.tsx +3 -3
- package/src/preact/mutations/mutations-table.tsx +3 -3
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutationsByDay.ts +45686 -0
- package/src/preact/mutationsOverTime/__mockData__/byWeek.ts +58989 -0
- package/src/preact/mutationsOverTime/__mockData__/defaultMockData.ts +103991 -0
- package/src/preact/mutationsOverTime/__mockData__/mockConversion.ts +54 -0
- package/src/preact/mutationsOverTime/__mockData__/showsMessageWhenTooManyMutations.ts +63690 -0
- package/src/preact/mutationsOverTime/getFilteredMutationsOverTime.spec.ts +176 -159
- package/src/preact/mutationsOverTime/getFilteredMutationsOverTimeData.ts +17 -59
- package/src/preact/mutationsOverTime/mutationOverTimeWorker.mock.ts +27 -0
- package/src/preact/mutationsOverTime/mutationOverTimeWorker.ts +29 -0
- package/src/preact/mutationsOverTime/mutations-over-time-grid.tsx +13 -14
- package/src/preact/mutationsOverTime/mutations-over-time.stories.tsx +9 -334
- package/src/preact/mutationsOverTime/mutations-over-time.tsx +68 -52
- package/src/preact/numberSequencesOverTime/getNumberOfSequencesOverTimeTableData.ts +3 -3
- package/src/preact/prevalenceOverTime/getPrevalenceOverTimeTableData.spec.ts +5 -5
- package/src/preact/prevalenceOverTime/prevalence-over-time-bubble-chart.tsx +1 -1
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage-chart.tsx +2 -2
- package/src/preact/shared/sort/sortInsertions.spec.ts +11 -11
- package/src/preact/shared/sort/sortInsertions.ts +2 -2
- package/src/preact/shared/sort/sortSubstitutionsAndDeletions.spec.ts +13 -13
- package/src/preact/shared/sort/sortSubstitutionsAndDeletions.ts +7 -4
- package/src/preact/webWorkers/useWebWorker.ts +51 -0
- package/src/preact/webWorkers/workerFunction.ts +14 -0
- package/src/query/queryAggregatedDataOverTime.ts +3 -3
- package/src/query/queryMutationsOverTime.spec.ts +272 -51
- package/src/query/queryMutationsOverTime.ts +114 -45
- package/src/query/queryPrevalenceOverTime.ts +2 -2
- package/src/query/queryRelativeGrowthAdvantage.ts +3 -3
- package/src/types.ts +25 -5
- package/src/utils/map2d.spec.ts +29 -1
- package/src/utils/map2d.ts +22 -1
- package/src/utils/mutations.spec.ts +20 -20
- package/src/utils/mutations.ts +80 -17
- package/src/utils/sort.ts +5 -2
- package/src/utils/temporal.spec.ts +27 -24
- package/src/utils/{temporal.ts → temporalClass.ts} +170 -72
- package/src/utils/temporalTestHelpers.ts +3 -3
- package/src/web-components/input/gs-text-input.tsx +1 -1
- package/src/web-components/introduction.mdx +46 -0
- package/src/web-components/visualization/gs-mutations-over-time.stories.ts +6 -699
- package/src/web-components/visualization/gs-mutations-over-time.tsx +2 -2
- package/standalone-bundle/dashboard-components.js +13763 -13754
- package/standalone-bundle/dashboard-components.js.map +1 -1
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_01.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_02.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_03.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_04.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_05.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_06.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_2024_07.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_20_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_21_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_22_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_23_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_24_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_25_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_26_01_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_byDay.json +0 -38
- package/src/preact/mutationsOverTime/__mockData__/aggregated_byWeek.json +0 -122
- package/src/preact/mutationsOverTime/__mockData__/aggregated_date.json +0 -642
- package/src/preact/mutationsOverTime/__mockData__/aggregated_tooManyMutations.json +0 -1470
- package/src/preact/mutationsOverTime/__mockData__/aggregated_tooManyMutations_total.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_week3_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_week4_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_week5_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_week6_2024.json +0 -13
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_20_01_2024.json +0 -6778
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_21_01_2024.json +0 -7129
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_22_01_2024.json +0 -4681
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_23_01_2024.json +0 -10738
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_24_01_2024.json +0 -11710
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_25_01_2024.json +0 -11557
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_26_01_2024.json +0 -8596
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_byDayOverall.json +0 -4726
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_01.json +0 -1747
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_02.json +0 -1774
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_03.json +0 -1819
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_04.json +0 -1864
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_05.json +0 -1927
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_06.json +0 -1864
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_2024_07.json +0 -9
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_byMonthOverall.json +0 -11143
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_byWeekOverall.json +0 -9154
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_tooManyMutations.json +0 -16453
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week3_2024.json +0 -8812
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week4_2024.json +0 -9730
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week5_2024.json +0 -9865
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week6_2024.json +0 -11314
|
@@ -13,37 +13,37 @@ dayjs.extend(advancedFormat);
|
|
|
13
13
|
const FORMAT_ISO_WEEK_YEAR_WEEK = 'GGGG-[W]WW';
|
|
14
14
|
|
|
15
15
|
export class TemporalCache {
|
|
16
|
-
private yearMonthDayCache = new Map<string,
|
|
17
|
-
private yearWeekCache = new Map<string,
|
|
18
|
-
private yearMonthCache = new Map<string,
|
|
19
|
-
private yearCache = new Map<string,
|
|
16
|
+
private yearMonthDayCache = new Map<string, YearMonthDayClass>();
|
|
17
|
+
private yearWeekCache = new Map<string, YearWeekClass>();
|
|
18
|
+
private yearMonthCache = new Map<string, YearMonthClass>();
|
|
19
|
+
private yearCache = new Map<string, YearClass>();
|
|
20
20
|
|
|
21
21
|
private constructor() {}
|
|
22
22
|
|
|
23
|
-
getYearMonthDay(s: string):
|
|
23
|
+
getYearMonthDay(s: string): YearMonthDayClass {
|
|
24
24
|
if (!this.yearMonthDayCache.has(s)) {
|
|
25
|
-
this.yearMonthDayCache.set(s,
|
|
25
|
+
this.yearMonthDayCache.set(s, YearMonthDayClass.parse(s, this));
|
|
26
26
|
}
|
|
27
27
|
return this.yearMonthDayCache.get(s)!;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
getYearMonth(s: string):
|
|
30
|
+
getYearMonth(s: string): YearMonthClass {
|
|
31
31
|
if (!this.yearMonthCache.has(s)) {
|
|
32
|
-
this.yearMonthCache.set(s,
|
|
32
|
+
this.yearMonthCache.set(s, YearMonthClass.parse(s, this));
|
|
33
33
|
}
|
|
34
34
|
return this.yearMonthCache.get(s)!;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
getYearWeek(s: string):
|
|
37
|
+
getYearWeek(s: string): YearWeekClass {
|
|
38
38
|
if (!this.yearWeekCache.has(s)) {
|
|
39
|
-
this.yearWeekCache.set(s,
|
|
39
|
+
this.yearWeekCache.set(s, YearWeekClass.parse(s, this));
|
|
40
40
|
}
|
|
41
41
|
return this.yearWeekCache.get(s)!;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
getYear(s: string):
|
|
44
|
+
getYear(s: string): YearClass {
|
|
45
45
|
if (!this.yearCache.has(s)) {
|
|
46
|
-
this.yearCache.set(s,
|
|
46
|
+
this.yearCache.set(s, YearClass.parse(s, this));
|
|
47
47
|
}
|
|
48
48
|
return this.yearCache.get(s)!;
|
|
49
49
|
}
|
|
@@ -55,9 +55,19 @@ export class TemporalCache {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
interface YearMonthDay {
|
|
59
|
+
type: 'YearMonthDay';
|
|
60
|
+
yearNumber: number;
|
|
61
|
+
monthNumber: number;
|
|
62
|
+
dayNumber: number;
|
|
63
|
+
dateString: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export class YearMonthDayClass implements YearMonthDay {
|
|
67
|
+
readonly type = 'YearMonthDay';
|
|
59
68
|
readonly date;
|
|
60
69
|
readonly dayjs;
|
|
70
|
+
readonly dateString;
|
|
61
71
|
|
|
62
72
|
constructor(
|
|
63
73
|
readonly yearNumber: number,
|
|
@@ -67,6 +77,7 @@ export class YearMonthDay {
|
|
|
67
77
|
) {
|
|
68
78
|
this.date = new Date(this.yearNumber, this.monthNumber - 1, this.dayNumber);
|
|
69
79
|
this.dayjs = dayjs(this.date);
|
|
80
|
+
this.dateString = this.toString();
|
|
70
81
|
}
|
|
71
82
|
|
|
72
83
|
get text(): string {
|
|
@@ -81,48 +92,60 @@ export class YearMonthDay {
|
|
|
81
92
|
return this.dayjs.format('dddd, MMMM D, YYYY');
|
|
82
93
|
}
|
|
83
94
|
|
|
84
|
-
get firstDay():
|
|
95
|
+
get firstDay(): YearMonthDayClass {
|
|
85
96
|
return this;
|
|
86
97
|
}
|
|
87
98
|
|
|
88
|
-
get lastDay():
|
|
99
|
+
get lastDay(): YearMonthDayClass {
|
|
89
100
|
return this;
|
|
90
101
|
}
|
|
91
102
|
|
|
92
|
-
get year():
|
|
103
|
+
get year(): YearClass {
|
|
93
104
|
return this.cache.getYear(`${this.yearNumber}`);
|
|
94
105
|
}
|
|
95
106
|
|
|
96
|
-
get month():
|
|
107
|
+
get month(): YearMonthClass {
|
|
97
108
|
return this.cache.getYearMonth(this.dayjs.format('YYYY-MM'));
|
|
98
109
|
}
|
|
99
110
|
|
|
100
|
-
get week():
|
|
111
|
+
get week(): YearWeekClass {
|
|
101
112
|
return this.cache.getYearWeek(this.dayjs.format(FORMAT_ISO_WEEK_YEAR_WEEK));
|
|
102
113
|
}
|
|
103
114
|
|
|
104
|
-
addDays(days: number):
|
|
115
|
+
addDays(days: number): YearMonthDayClass {
|
|
105
116
|
const date = this.dayjs.add(days, 'day');
|
|
106
117
|
const s = date.format('YYYY-MM-DD');
|
|
107
118
|
return this.cache.getYearMonthDay(s);
|
|
108
119
|
}
|
|
109
120
|
|
|
110
|
-
minus(other:
|
|
121
|
+
minus(other: YearMonthDayClass): number {
|
|
111
122
|
return this.dayjs.diff(other.dayjs, 'day');
|
|
112
123
|
}
|
|
113
124
|
|
|
114
|
-
static parse(s: string, cache: TemporalCache):
|
|
125
|
+
static parse(s: string, cache: TemporalCache): YearMonthDayClass {
|
|
115
126
|
const [year, month, day] = s.split('-').map((s) => parseInt(s, 10));
|
|
116
|
-
return new
|
|
127
|
+
return new YearMonthDayClass(year, month, day, cache);
|
|
117
128
|
}
|
|
118
129
|
}
|
|
119
130
|
|
|
120
|
-
|
|
131
|
+
interface YearWeek {
|
|
132
|
+
type: 'YearWeek';
|
|
133
|
+
isoYearNumber: number;
|
|
134
|
+
isoWeekNumber: number;
|
|
135
|
+
dateString: string;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export class YearWeekClass implements YearWeek {
|
|
139
|
+
readonly type = 'YearWeek';
|
|
140
|
+
readonly dateString;
|
|
141
|
+
|
|
121
142
|
constructor(
|
|
122
143
|
readonly isoYearNumber: number,
|
|
123
144
|
readonly isoWeekNumber: number,
|
|
124
145
|
readonly cache: TemporalCache,
|
|
125
|
-
) {
|
|
146
|
+
) {
|
|
147
|
+
this.dateString = this.toString();
|
|
148
|
+
}
|
|
126
149
|
|
|
127
150
|
get text(): string {
|
|
128
151
|
return this.firstDay.dayjs.format(FORMAT_ISO_WEEK_YEAR_WEEK);
|
|
@@ -136,7 +159,7 @@ export class YearWeek {
|
|
|
136
159
|
return `Week ${this.isoWeekNumber}, ${this.isoYearNumber}`;
|
|
137
160
|
}
|
|
138
161
|
|
|
139
|
-
get firstDay():
|
|
162
|
+
get firstDay(): YearMonthDayClass {
|
|
140
163
|
// "The first week of the year, hence, always contains 4 January." https://en.wikipedia.org/wiki/ISO_week_date
|
|
141
164
|
const firstDay = dayjs()
|
|
142
165
|
.year(this.isoYearNumber)
|
|
@@ -147,7 +170,7 @@ export class YearWeek {
|
|
|
147
170
|
return this.cache.getYearMonthDay(firstDay.format('YYYY-MM-DD'));
|
|
148
171
|
}
|
|
149
172
|
|
|
150
|
-
get lastDay():
|
|
173
|
+
get lastDay(): YearMonthDayClass {
|
|
151
174
|
const firstDay = dayjs()
|
|
152
175
|
.year(this.isoYearNumber)
|
|
153
176
|
.startOf('year')
|
|
@@ -159,32 +182,44 @@ export class YearWeek {
|
|
|
159
182
|
return this.cache.getYearMonthDay(lastDay.format('YYYY-MM-DD'));
|
|
160
183
|
}
|
|
161
184
|
|
|
162
|
-
get year():
|
|
185
|
+
get year(): YearClass {
|
|
163
186
|
return this.cache.getYear(`${this.isoYearNumber}`);
|
|
164
187
|
}
|
|
165
188
|
|
|
166
|
-
addWeeks(weeks: number):
|
|
189
|
+
addWeeks(weeks: number): YearWeekClass {
|
|
167
190
|
const date = this.firstDay.dayjs.add(weeks, 'week');
|
|
168
191
|
const s = date.format(FORMAT_ISO_WEEK_YEAR_WEEK);
|
|
169
192
|
return this.cache.getYearWeek(s);
|
|
170
193
|
}
|
|
171
194
|
|
|
172
|
-
minus(other:
|
|
195
|
+
minus(other: YearWeekClass): number {
|
|
173
196
|
return this.firstDay.dayjs.diff(other.firstDay.dayjs, 'week');
|
|
174
197
|
}
|
|
175
198
|
|
|
176
|
-
static parse(s: string, cache: TemporalCache):
|
|
199
|
+
static parse(s: string, cache: TemporalCache): YearWeekClass {
|
|
177
200
|
const [year, week] = s.split('-W').map((s) => parseInt(s, 10));
|
|
178
|
-
return new
|
|
201
|
+
return new YearWeekClass(year, week, cache);
|
|
179
202
|
}
|
|
180
203
|
}
|
|
181
204
|
|
|
182
|
-
|
|
205
|
+
interface YearMonth {
|
|
206
|
+
type: 'YearMonth';
|
|
207
|
+
yearNumber: number;
|
|
208
|
+
monthNumber: number;
|
|
209
|
+
dateString: string;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export class YearMonthClass implements YearMonth {
|
|
213
|
+
readonly type = 'YearMonth';
|
|
214
|
+
readonly dateString;
|
|
215
|
+
|
|
183
216
|
constructor(
|
|
184
217
|
readonly yearNumber: number,
|
|
185
218
|
readonly monthNumber: number,
|
|
186
219
|
readonly cache: TemporalCache,
|
|
187
|
-
) {
|
|
220
|
+
) {
|
|
221
|
+
this.dateString = this.toString();
|
|
222
|
+
}
|
|
188
223
|
|
|
189
224
|
get text(): string {
|
|
190
225
|
return this.firstDay.dayjs.format('YYYY-MM');
|
|
@@ -198,41 +233,52 @@ export class YearMonth {
|
|
|
198
233
|
return `${monthName(this.monthNumber)} ${this.yearNumber}`;
|
|
199
234
|
}
|
|
200
235
|
|
|
201
|
-
get firstDay():
|
|
236
|
+
get firstDay(): YearMonthDayClass {
|
|
202
237
|
return this.cache.getYearMonthDay(dayjs(`${this.yearNumber}-${this.monthNumber}-01`).format('YYYY-MM-DD'));
|
|
203
238
|
}
|
|
204
239
|
|
|
205
|
-
get lastDay():
|
|
240
|
+
get lastDay(): YearMonthDayClass {
|
|
206
241
|
return this.cache.getYearMonthDay(
|
|
207
242
|
dayjs(`${this.yearNumber}-${this.monthNumber}-01`).endOf('month').format('YYYY-MM-DD'),
|
|
208
243
|
);
|
|
209
244
|
}
|
|
210
245
|
|
|
211
|
-
get year():
|
|
246
|
+
get year(): YearClass {
|
|
212
247
|
return this.cache.getYear(`${this.yearNumber}`);
|
|
213
248
|
}
|
|
214
249
|
|
|
215
|
-
addMonths(months: number):
|
|
250
|
+
addMonths(months: number): YearMonthClass {
|
|
216
251
|
const date = this.firstDay.dayjs.add(months, 'month');
|
|
217
252
|
const s = date.format('YYYY-MM');
|
|
218
253
|
return this.cache.getYearMonth(s);
|
|
219
254
|
}
|
|
220
255
|
|
|
221
|
-
minus(other:
|
|
256
|
+
minus(other: YearMonthClass): number {
|
|
222
257
|
return this.firstDay.dayjs.diff(other.firstDay.dayjs, 'month');
|
|
223
258
|
}
|
|
224
259
|
|
|
225
|
-
static parse(s: string, cache: TemporalCache):
|
|
260
|
+
static parse(s: string, cache: TemporalCache): YearMonthClass {
|
|
226
261
|
const [year, month] = s.split('-').map((s) => parseInt(s, 10));
|
|
227
|
-
return new
|
|
262
|
+
return new YearMonthClass(year, month, cache);
|
|
228
263
|
}
|
|
229
264
|
}
|
|
230
265
|
|
|
231
|
-
|
|
266
|
+
interface Year {
|
|
267
|
+
type: 'Year';
|
|
268
|
+
year: number;
|
|
269
|
+
dateString: string;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export class YearClass implements Year {
|
|
273
|
+
readonly type = 'Year';
|
|
274
|
+
readonly dateString;
|
|
275
|
+
|
|
232
276
|
constructor(
|
|
233
277
|
readonly year: number,
|
|
234
278
|
readonly cache: TemporalCache,
|
|
235
|
-
) {
|
|
279
|
+
) {
|
|
280
|
+
this.dateString = this.toString();
|
|
281
|
+
}
|
|
236
282
|
|
|
237
283
|
get text(): string {
|
|
238
284
|
return this.firstDay.dayjs.format('YYYY');
|
|
@@ -246,35 +292,35 @@ export class Year {
|
|
|
246
292
|
return this.year.toString();
|
|
247
293
|
}
|
|
248
294
|
|
|
249
|
-
get firstMonth():
|
|
295
|
+
get firstMonth(): YearMonthClass {
|
|
250
296
|
return this.cache.getYearMonth(`${this.year}-01`);
|
|
251
297
|
}
|
|
252
298
|
|
|
253
|
-
get lastMonth():
|
|
299
|
+
get lastMonth(): YearMonthClass {
|
|
254
300
|
return this.cache.getYearMonth(`${this.year}-12`);
|
|
255
301
|
}
|
|
256
302
|
|
|
257
|
-
get firstDay():
|
|
303
|
+
get firstDay(): YearMonthDayClass {
|
|
258
304
|
return this.firstMonth.firstDay;
|
|
259
305
|
}
|
|
260
306
|
|
|
261
|
-
get lastDay():
|
|
307
|
+
get lastDay(): YearMonthDayClass {
|
|
262
308
|
return this.lastMonth.lastDay;
|
|
263
309
|
}
|
|
264
310
|
|
|
265
|
-
addYears(years: number):
|
|
311
|
+
addYears(years: number): YearClass {
|
|
266
312
|
const date = this.firstDay.dayjs.add(years, 'year');
|
|
267
313
|
const s = date.format('YYYY');
|
|
268
314
|
return this.cache.getYear(s);
|
|
269
315
|
}
|
|
270
316
|
|
|
271
|
-
minus(other:
|
|
317
|
+
minus(other: YearClass): number {
|
|
272
318
|
return this.firstDay.dayjs.diff(other.firstDay.dayjs, 'year');
|
|
273
319
|
}
|
|
274
320
|
|
|
275
|
-
static parse(s: string, cache: TemporalCache):
|
|
321
|
+
static parse(s: string, cache: TemporalCache): YearClass {
|
|
276
322
|
const year = parseInt(s, 10);
|
|
277
|
-
return new
|
|
323
|
+
return new YearClass(year, cache);
|
|
278
324
|
}
|
|
279
325
|
}
|
|
280
326
|
|
|
@@ -284,9 +330,61 @@ function monthName(month: number): string {
|
|
|
284
330
|
.format('MMMM');
|
|
285
331
|
}
|
|
286
332
|
|
|
333
|
+
export type TemporalClass = YearMonthDayClass | YearWeekClass | YearMonthClass | YearClass;
|
|
287
334
|
export type Temporal = YearMonthDay | YearWeek | YearMonth | Year;
|
|
288
335
|
|
|
289
|
-
export function
|
|
336
|
+
export function toTemporalClass(temporal: Temporal) {
|
|
337
|
+
switch (temporal.type) {
|
|
338
|
+
case 'YearMonthDay':
|
|
339
|
+
return new YearMonthDayClass(
|
|
340
|
+
temporal.yearNumber,
|
|
341
|
+
temporal.monthNumber,
|
|
342
|
+
temporal.dayNumber,
|
|
343
|
+
TemporalCache.getInstance(),
|
|
344
|
+
);
|
|
345
|
+
case 'YearWeek':
|
|
346
|
+
return new YearWeekClass(temporal.isoYearNumber, temporal.isoWeekNumber, TemporalCache.getInstance());
|
|
347
|
+
case 'YearMonth':
|
|
348
|
+
return new YearMonthClass(temporal.yearNumber, temporal.monthNumber, TemporalCache.getInstance());
|
|
349
|
+
case 'Year':
|
|
350
|
+
return new YearClass(temporal.year, TemporalCache.getInstance());
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
export function toTemporal(temporalClass: TemporalClass): Temporal {
|
|
355
|
+
switch (temporalClass.type) {
|
|
356
|
+
case 'YearMonthDay':
|
|
357
|
+
return {
|
|
358
|
+
type: 'YearMonthDay',
|
|
359
|
+
yearNumber: temporalClass.yearNumber,
|
|
360
|
+
monthNumber: temporalClass.monthNumber,
|
|
361
|
+
dayNumber: temporalClass.dayNumber,
|
|
362
|
+
dateString: temporalClass.dateString,
|
|
363
|
+
};
|
|
364
|
+
case 'YearWeek':
|
|
365
|
+
return {
|
|
366
|
+
type: 'YearWeek',
|
|
367
|
+
isoYearNumber: temporalClass.isoYearNumber,
|
|
368
|
+
isoWeekNumber: temporalClass.isoWeekNumber,
|
|
369
|
+
dateString: temporalClass.dateString,
|
|
370
|
+
};
|
|
371
|
+
case 'YearMonth':
|
|
372
|
+
return {
|
|
373
|
+
type: 'YearMonth',
|
|
374
|
+
yearNumber: temporalClass.yearNumber,
|
|
375
|
+
monthNumber: temporalClass.monthNumber,
|
|
376
|
+
dateString: temporalClass.dateString,
|
|
377
|
+
};
|
|
378
|
+
case 'Year':
|
|
379
|
+
return {
|
|
380
|
+
type: 'Year',
|
|
381
|
+
year: temporalClass.year,
|
|
382
|
+
dateString: temporalClass.dateString,
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
export function generateAllDaysInRange(start: YearMonthDayClass, end: YearMonthDayClass): YearMonthDayClass[] {
|
|
290
388
|
const days = [];
|
|
291
389
|
const daysInBetween = end.minus(start);
|
|
292
390
|
for (let i = 0; i <= daysInBetween; i++) {
|
|
@@ -295,7 +393,7 @@ export function generateAllDaysInRange(start: YearMonthDay, end: YearMonthDay):
|
|
|
295
393
|
return days;
|
|
296
394
|
}
|
|
297
395
|
|
|
298
|
-
export function generateAllWeeksInRange(start:
|
|
396
|
+
export function generateAllWeeksInRange(start: YearWeekClass, end: YearWeekClass): YearWeekClass[] {
|
|
299
397
|
const weeks = [];
|
|
300
398
|
const weeksInBetween = end.minus(start);
|
|
301
399
|
for (let i = 0; i <= weeksInBetween; i++) {
|
|
@@ -304,7 +402,7 @@ export function generateAllWeeksInRange(start: YearWeek, end: YearWeek): YearWee
|
|
|
304
402
|
return weeks;
|
|
305
403
|
}
|
|
306
404
|
|
|
307
|
-
export function generateAllMonthsInRange(start:
|
|
405
|
+
export function generateAllMonthsInRange(start: YearMonthClass, end: YearMonthClass): YearMonthClass[] {
|
|
308
406
|
const months = [];
|
|
309
407
|
const monthsInBetween = end.minus(start);
|
|
310
408
|
for (let i = 0; i <= monthsInBetween; i++) {
|
|
@@ -313,7 +411,7 @@ export function generateAllMonthsInRange(start: YearMonth, end: YearMonth): Year
|
|
|
313
411
|
return months;
|
|
314
412
|
}
|
|
315
413
|
|
|
316
|
-
export function generateAllYearsInRange(start:
|
|
414
|
+
export function generateAllYearsInRange(start: YearClass, end: YearClass): YearClass[] {
|
|
317
415
|
const years = [];
|
|
318
416
|
const yearsInBetween = end.minus(start);
|
|
319
417
|
for (let i = 0; i <= yearsInBetween; i++) {
|
|
@@ -322,42 +420,42 @@ export function generateAllYearsInRange(start: Year, end: Year): Year[] {
|
|
|
322
420
|
return years;
|
|
323
421
|
}
|
|
324
422
|
|
|
325
|
-
export function generateAllInRange(start:
|
|
423
|
+
export function generateAllInRange(start: TemporalClass | null, end: TemporalClass | null): TemporalClass[] {
|
|
326
424
|
if (start === null || end === null) {
|
|
327
425
|
return [];
|
|
328
426
|
}
|
|
329
|
-
if (start instanceof
|
|
427
|
+
if (start instanceof YearMonthDayClass && end instanceof YearMonthDayClass) {
|
|
330
428
|
return generateAllDaysInRange(start, end);
|
|
331
429
|
}
|
|
332
|
-
if (start instanceof
|
|
430
|
+
if (start instanceof YearWeekClass && end instanceof YearWeekClass) {
|
|
333
431
|
return generateAllWeeksInRange(start, end);
|
|
334
432
|
}
|
|
335
|
-
if (start instanceof
|
|
433
|
+
if (start instanceof YearMonthClass && end instanceof YearMonthClass) {
|
|
336
434
|
return generateAllMonthsInRange(start, end);
|
|
337
435
|
}
|
|
338
|
-
if (start instanceof
|
|
436
|
+
if (start instanceof YearClass && end instanceof YearClass) {
|
|
339
437
|
return generateAllYearsInRange(start, end);
|
|
340
438
|
}
|
|
341
439
|
throw new Error(`Invalid arguments: start and end must be of the same type: ${start}, ${end}`);
|
|
342
440
|
}
|
|
343
441
|
|
|
344
|
-
export function minusTemporal(a:
|
|
345
|
-
if (a instanceof
|
|
442
|
+
export function minusTemporal(a: TemporalClass, b: TemporalClass): number {
|
|
443
|
+
if (a instanceof YearMonthDayClass && b instanceof YearMonthDayClass) {
|
|
346
444
|
return a.minus(b);
|
|
347
445
|
}
|
|
348
|
-
if (a instanceof
|
|
446
|
+
if (a instanceof YearWeekClass && b instanceof YearWeekClass) {
|
|
349
447
|
return a.minus(b);
|
|
350
448
|
}
|
|
351
|
-
if (a instanceof
|
|
449
|
+
if (a instanceof YearMonthClass && b instanceof YearMonthClass) {
|
|
352
450
|
return a.minus(b);
|
|
353
451
|
}
|
|
354
|
-
if (a instanceof
|
|
452
|
+
if (a instanceof YearClass && b instanceof YearClass) {
|
|
355
453
|
return a.minus(b);
|
|
356
454
|
}
|
|
357
455
|
throw new Error(`Cannot compare ${a} and ${b}`);
|
|
358
456
|
}
|
|
359
457
|
|
|
360
|
-
export function compareTemporal(a:
|
|
458
|
+
export function compareTemporal(a: TemporalClass | null, b: TemporalClass | null): number {
|
|
361
459
|
if (a === null) {
|
|
362
460
|
return 1;
|
|
363
461
|
}
|
|
@@ -374,7 +472,7 @@ export function compareTemporal(a: Temporal | null, b: Temporal | null): number
|
|
|
374
472
|
return 0;
|
|
375
473
|
}
|
|
376
474
|
|
|
377
|
-
export function getMinMaxTemporal<T extends
|
|
475
|
+
export function getMinMaxTemporal<T extends TemporalClass>(values: Iterable<T | null>) {
|
|
378
476
|
let min: T | null = null;
|
|
379
477
|
let max: T | null = null;
|
|
380
478
|
for (const value of values) {
|
|
@@ -394,17 +492,17 @@ export function getMinMaxTemporal<T extends Temporal>(values: Iterable<T | null>
|
|
|
394
492
|
return { min, max };
|
|
395
493
|
}
|
|
396
494
|
|
|
397
|
-
export function addUnit(temporal:
|
|
398
|
-
if (temporal instanceof
|
|
495
|
+
export function addUnit(temporal: TemporalClass, amount: number): TemporalClass {
|
|
496
|
+
if (temporal instanceof YearMonthDayClass) {
|
|
399
497
|
return temporal.addDays(amount);
|
|
400
498
|
}
|
|
401
|
-
if (temporal instanceof
|
|
499
|
+
if (temporal instanceof YearWeekClass) {
|
|
402
500
|
return temporal.addWeeks(amount);
|
|
403
501
|
}
|
|
404
|
-
if (temporal instanceof
|
|
502
|
+
if (temporal instanceof YearMonthClass) {
|
|
405
503
|
return temporal.addMonths(amount);
|
|
406
504
|
}
|
|
407
|
-
if (temporal instanceof
|
|
505
|
+
if (temporal instanceof YearClass) {
|
|
408
506
|
return temporal.addYears(amount);
|
|
409
507
|
}
|
|
410
508
|
throw new Error(`Invalid argument: ${temporal}`);
|
|
@@ -425,7 +523,7 @@ export function parseDateStringToTemporal(date: string, granularity: TemporalGra
|
|
|
425
523
|
}
|
|
426
524
|
}
|
|
427
525
|
|
|
428
|
-
export function dateRangeCompare(a: { dateRange:
|
|
526
|
+
export function dateRangeCompare(a: { dateRange: TemporalClass | null }, b: { dateRange: TemporalClass | null }) {
|
|
429
527
|
if (a.dateRange === null) {
|
|
430
528
|
return 1;
|
|
431
529
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { TemporalCache,
|
|
1
|
+
import { TemporalCache, YearMonthClass, YearMonthDayClass } from './temporalClass';
|
|
2
2
|
|
|
3
3
|
export function yearMonthDay(date: string) {
|
|
4
|
-
return
|
|
4
|
+
return YearMonthDayClass.parse(date, TemporalCache.getInstance());
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export function yearMonth(date: string) {
|
|
8
|
-
return
|
|
8
|
+
return YearMonthClass.parse(date, TemporalCache.getInstance());
|
|
9
9
|
}
|
|
@@ -78,7 +78,7 @@ declare global {
|
|
|
78
78
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
79
79
|
namespace JSX {
|
|
80
80
|
interface IntrinsicElements {
|
|
81
|
-
'gs-text-input
|
|
81
|
+
'gs-text-input': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
}
|
|
@@ -4,6 +4,21 @@ import { Meta } from '@storybook/blocks';
|
|
|
4
4
|
|
|
5
5
|
# Introduction
|
|
6
6
|
|
|
7
|
+
<a
|
|
8
|
+
style={{ display: 'flex', 'align-items': 'center', 'justify-content': 'right' }}
|
|
9
|
+
href='https://github.com/GenSpectrum/dashboard-components'
|
|
10
|
+
>
|
|
11
|
+
<svg style={{ width: '3%', height: '3%' }} viewBox='0 0 98 96' xmlns='http://www.w3.org/2000/svg'>
|
|
12
|
+
<path
|
|
13
|
+
fill-rule='evenodd'
|
|
14
|
+
clip-rule='evenodd'
|
|
15
|
+
d='M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z'
|
|
16
|
+
fill='#24292f'
|
|
17
|
+
/>
|
|
18
|
+
</svg>
|
|
19
|
+
<span style={{ 'margin-left': '4px' }}>Visit on GitHub</span>
|
|
20
|
+
</a>
|
|
21
|
+
|
|
7
22
|
This package provides a collection of web components to build interactive dashboards that visualize
|
|
8
23
|
data of a specific instance of [LAPIS](https://github.com/GenSpectrum/LAPIS).
|
|
9
24
|
|
|
@@ -13,3 +28,34 @@ We primarily provide two kinds of components:
|
|
|
13
28
|
Those components fetch data from the LAPIS instance and visualize it.
|
|
14
29
|
- Input components that let you specify sequence filters for the LAPIS requests.
|
|
15
30
|
Input changes will fire events that can be listened to by the visualization components. It is the responsibility of the dashbaord maintainer to listen to those events and to wire the data correctly into the visualization components.
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm i @genspectrum/dashboard-components
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
All components must be children of a `gs-app` element.
|
|
41
|
+
|
|
42
|
+
```html
|
|
43
|
+
<gs-app lapis="https://url.to.lapis">
|
|
44
|
+
<gs-location-filter
|
|
45
|
+
fields='["region", "country"]'
|
|
46
|
+
initialValue="Europe / Switzerland"
|
|
47
|
+
width="100%"
|
|
48
|
+
placeholderText="Enter a location"
|
|
49
|
+
></gs-location-filter>
|
|
50
|
+
<gs-aggregate
|
|
51
|
+
fields='["division", "host"]'
|
|
52
|
+
filter='{"country": "USA"}'
|
|
53
|
+
views='["table"]'
|
|
54
|
+
width="100%"
|
|
55
|
+
height="700px"
|
|
56
|
+
initialSortField="count"
|
|
57
|
+
initialSortDirection="descending"
|
|
58
|
+
pageSize="10"
|
|
59
|
+
></gs-aggregate>
|
|
60
|
+
</gs-app>
|
|
61
|
+
```
|