@genspectrum/dashboard-components 0.6.4 → 0.6.6
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 +36 -4
- package/dist/dashboard-components.js +181 -55
- package/dist/dashboard-components.js.map +1 -1
- package/dist/genspectrum-components.d.ts +13 -7
- package/dist/style.css +53 -2
- package/package.json +1 -1
- package/src/constants.ts +1 -0
- package/src/preact/components/tooltip.stories.tsx +12 -2
- package/src/preact/components/tooltip.tsx +37 -13
- package/src/preact/mutationsOverTime/__mockData__/aggregated_byDay.json +38 -0
- package/src/preact/mutationsOverTime/__mockData__/aggregated_byWeek.json +122 -0
- package/src/preact/mutationsOverTime/__mockData__/aggregated_tooManyMutations.json +1470 -0
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_20_01_2024.json +6778 -0
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_21_01_2024.json +7129 -0
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_22_01_2024.json +4681 -0
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_23_01_2024.json +10738 -0
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_24_01_2024.json +11710 -0
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_25_01_2024.json +11557 -0
- package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_26_01_2024.json +8596 -0
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_tooManyMutations.json +16453 -0
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week3_2024.json +8812 -0
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week4_2024.json +9730 -0
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week5_2024.json +9865 -0
- package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week6_2024.json +11314 -0
- package/src/preact/mutationsOverTime/mutations-over-time-grid.tsx +62 -43
- package/src/preact/mutationsOverTime/mutations-over-time.stories.tsx +62 -8
- package/src/preact/mutationsOverTime/mutations-over-time.tsx +32 -8
- package/src/utils/temporal.spec.ts +3 -4
- package/src/utils/temporal.ts +9 -4
- package/src/web-components/visualization/gs-mutations-over-time.stories.ts +254 -2
- package/src/web-components/visualization/gs-mutations-over-time.tsx +11 -5
|
@@ -6,8 +6,7 @@ import {
|
|
|
6
6
|
} from '../../query/queryMutationsOverTime';
|
|
7
7
|
import { type Deletion, type Substitution } from '../../utils/mutations';
|
|
8
8
|
import { compareTemporal, type Temporal, YearMonthDay } from '../../utils/temporal';
|
|
9
|
-
import {
|
|
10
|
-
import Tooltip from '../components/tooltip';
|
|
9
|
+
import Tooltip, { type TooltipPosition } from '../components/tooltip';
|
|
11
10
|
import { singleGraphColorRGBByName } from '../shared/charts/colors';
|
|
12
11
|
import { formatProportion } from '../shared/table/formatProportion';
|
|
13
12
|
|
|
@@ -18,57 +17,77 @@ export interface MutationsOverTimeGridProps {
|
|
|
18
17
|
const MAX_NUMBER_OF_GRID_ROWS = 100;
|
|
19
18
|
|
|
20
19
|
const MutationsOverTimeGrid: FunctionComponent<MutationsOverTimeGridProps> = ({ data }) => {
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
throw new UserFacingError(
|
|
24
|
-
'Too many mutations',
|
|
25
|
-
`The dataset contains ${mutations.length} mutations. ` +
|
|
26
|
-
`Please adapt the filters to reduce the number to below ${MAX_NUMBER_OF_GRID_ROWS}.`,
|
|
27
|
-
);
|
|
28
|
-
}
|
|
20
|
+
const allMutations = data.getFirstAxisKeys();
|
|
21
|
+
const shownMutations = allMutations.slice(0, MAX_NUMBER_OF_GRID_ROWS);
|
|
29
22
|
|
|
30
23
|
const dates = data.getSecondAxisKeys().sort((a, b) => compareTemporal(a, b));
|
|
31
24
|
|
|
32
25
|
return (
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
{
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
26
|
+
<>
|
|
27
|
+
{allMutations.length > MAX_NUMBER_OF_GRID_ROWS && (
|
|
28
|
+
<div className='pl-2'>
|
|
29
|
+
Showing {MAX_NUMBER_OF_GRID_ROWS} of {allMutations.length} mutations. You can narrow the filter to
|
|
30
|
+
reduce the number of mutations.
|
|
31
|
+
</div>
|
|
32
|
+
)}
|
|
33
|
+
<div
|
|
34
|
+
style={{
|
|
35
|
+
display: 'grid',
|
|
36
|
+
gridTemplateRows: `repeat(${shownMutations.length}, 24px)`,
|
|
37
|
+
gridTemplateColumns: `8rem repeat(${dates.length}, minmax(1.5rem, 1fr))`,
|
|
38
|
+
}}
|
|
39
|
+
>
|
|
40
|
+
{shownMutations.map((mutation, rowIndex) => {
|
|
41
|
+
return (
|
|
42
|
+
<Fragment key={`fragment-${mutation.toString()}`}>
|
|
43
|
+
<div
|
|
44
|
+
key={`mutation-${mutation.toString()}`}
|
|
45
|
+
style={{ gridRowStart: rowIndex + 1, gridColumnStart: 1 }}
|
|
46
|
+
>
|
|
47
|
+
<MutationCell mutation={mutation} />
|
|
48
|
+
</div>
|
|
49
|
+
{dates.map((date, columnIndex) => {
|
|
50
|
+
const value = data.get(mutation, date) ?? { proportion: 0, count: 0 };
|
|
51
|
+
const tooltipPosition = getTooltipPosition(
|
|
52
|
+
rowIndex,
|
|
53
|
+
shownMutations.length,
|
|
54
|
+
columnIndex,
|
|
55
|
+
dates.length,
|
|
56
|
+
);
|
|
57
|
+
return (
|
|
58
|
+
<div
|
|
59
|
+
style={{ gridRowStart: rowIndex + 1, gridColumnStart: columnIndex + 2 }}
|
|
60
|
+
key={`${mutation.toString()}-${date.toString()}`}
|
|
61
|
+
>
|
|
62
|
+
<ProportionCell
|
|
63
|
+
value={value}
|
|
64
|
+
date={date}
|
|
65
|
+
mutation={mutation}
|
|
66
|
+
tooltipPosition={tooltipPosition}
|
|
67
|
+
/>
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
})}
|
|
71
|
+
</Fragment>
|
|
72
|
+
);
|
|
73
|
+
})}
|
|
74
|
+
</div>
|
|
75
|
+
</>
|
|
64
76
|
);
|
|
65
77
|
};
|
|
66
78
|
|
|
79
|
+
function getTooltipPosition(rowIndex: number, rows: number, columnIndex: number, columns: number) {
|
|
80
|
+
const tooltipX = rowIndex < rows / 2 ? 'bottom' : 'top';
|
|
81
|
+
const tooltipY = columnIndex < columns / 2 ? 'start' : 'end';
|
|
82
|
+
return `${tooltipX}-${tooltipY}` as const;
|
|
83
|
+
}
|
|
84
|
+
|
|
67
85
|
const ProportionCell: FunctionComponent<{
|
|
68
86
|
value: MutationOverTimeMutationValue;
|
|
69
87
|
date: Temporal;
|
|
70
88
|
mutation: Substitution | Deletion;
|
|
71
|
-
|
|
89
|
+
tooltipPosition: TooltipPosition;
|
|
90
|
+
}> = ({ value, mutation, date, tooltipPosition }) => {
|
|
72
91
|
const tooltipContent = (
|
|
73
92
|
<div>
|
|
74
93
|
<p>
|
|
@@ -83,7 +102,7 @@ const ProportionCell: FunctionComponent<{
|
|
|
83
102
|
return (
|
|
84
103
|
<>
|
|
85
104
|
<div className={'py-1'}>
|
|
86
|
-
<Tooltip content={tooltipContent}>
|
|
105
|
+
<Tooltip content={tooltipContent} position={tooltipPosition}>
|
|
87
106
|
<div
|
|
88
107
|
style={{
|
|
89
108
|
backgroundColor: backgroundColor(value.proportion),
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type Meta, type StoryObj } from '@storybook/preact';
|
|
2
|
+
import { expect, waitFor } from '@storybook/test';
|
|
2
3
|
|
|
3
4
|
import aggregated_date from './__mockData__/aggregated_date.json';
|
|
5
|
+
import aggregated_tooManyMutations from './__mockData__/aggregated_tooManyMutations.json';
|
|
4
6
|
import nucleotideMutation_01 from './__mockData__/nucleotideMutations_2024_01.json';
|
|
5
7
|
import nucleotideMutation_02 from './__mockData__/nucleotideMutations_2024_02.json';
|
|
6
8
|
import nucleotideMutation_03 from './__mockData__/nucleotideMutations_2024_03.json';
|
|
@@ -8,6 +10,7 @@ import nucleotideMutation_04 from './__mockData__/nucleotideMutations_2024_04.js
|
|
|
8
10
|
import nucleotideMutation_05 from './__mockData__/nucleotideMutations_2024_05.json';
|
|
9
11
|
import nucleotideMutation_06 from './__mockData__/nucleotideMutations_2024_06.json';
|
|
10
12
|
import nucleotideMutation_07 from './__mockData__/nucleotideMutations_2024_07.json';
|
|
13
|
+
import nucleotideMutation_tooManyMutations from './__mockData__/nucleotideMutations_tooManyMutations.json';
|
|
11
14
|
import { MutationsOverTime, type MutationsOverTimeProps } from './mutations-over-time';
|
|
12
15
|
import { AGGREGATED_ENDPOINT, LAPIS_URL, NUCLEOTIDE_MUTATIONS_ENDPOINT } from '../../constants';
|
|
13
16
|
import referenceGenome from '../../lapisApi/__mockData__/referenceGenome.json';
|
|
@@ -95,7 +98,7 @@ export const Default: StoryObj<MutationsOverTimeProps> = {
|
|
|
95
98
|
pangoLineage: 'JN.1*',
|
|
96
99
|
dateFrom: '2024-01-01',
|
|
97
100
|
dateTo: '2024-01-31',
|
|
98
|
-
minProportion: 0,
|
|
101
|
+
minProportion: 0.001,
|
|
99
102
|
},
|
|
100
103
|
},
|
|
101
104
|
response: {
|
|
@@ -111,7 +114,7 @@ export const Default: StoryObj<MutationsOverTimeProps> = {
|
|
|
111
114
|
pangoLineage: 'JN.1*',
|
|
112
115
|
dateFrom: '2024-02-01',
|
|
113
116
|
dateTo: '2024-02-29',
|
|
114
|
-
minProportion: 0,
|
|
117
|
+
minProportion: 0.001,
|
|
115
118
|
},
|
|
116
119
|
},
|
|
117
120
|
response: {
|
|
@@ -127,7 +130,7 @@ export const Default: StoryObj<MutationsOverTimeProps> = {
|
|
|
127
130
|
pangoLineage: 'JN.1*',
|
|
128
131
|
dateFrom: '2024-03-01',
|
|
129
132
|
dateTo: '2024-03-31',
|
|
130
|
-
minProportion: 0,
|
|
133
|
+
minProportion: 0.001,
|
|
131
134
|
},
|
|
132
135
|
response: {
|
|
133
136
|
status: 200,
|
|
@@ -143,7 +146,7 @@ export const Default: StoryObj<MutationsOverTimeProps> = {
|
|
|
143
146
|
pangoLineage: 'JN.1*',
|
|
144
147
|
dateFrom: '2024-04-01',
|
|
145
148
|
dateTo: '2024-04-30',
|
|
146
|
-
minProportion: 0,
|
|
149
|
+
minProportion: 0.001,
|
|
147
150
|
},
|
|
148
151
|
response: {
|
|
149
152
|
status: 200,
|
|
@@ -159,7 +162,7 @@ export const Default: StoryObj<MutationsOverTimeProps> = {
|
|
|
159
162
|
pangoLineage: 'JN.1*',
|
|
160
163
|
dateFrom: '2024-05-01',
|
|
161
164
|
dateTo: '2024-05-31',
|
|
162
|
-
minProportion: 0,
|
|
165
|
+
minProportion: 0.001,
|
|
163
166
|
},
|
|
164
167
|
response: {
|
|
165
168
|
status: 200,
|
|
@@ -175,7 +178,7 @@ export const Default: StoryObj<MutationsOverTimeProps> = {
|
|
|
175
178
|
pangoLineage: 'JN.1*',
|
|
176
179
|
dateFrom: '2024-06-01',
|
|
177
180
|
dateTo: '2024-06-30',
|
|
178
|
-
minProportion: 0,
|
|
181
|
+
minProportion: 0.001,
|
|
179
182
|
},
|
|
180
183
|
response: {
|
|
181
184
|
status: 200,
|
|
@@ -183,7 +186,6 @@ export const Default: StoryObj<MutationsOverTimeProps> = {
|
|
|
183
186
|
},
|
|
184
187
|
},
|
|
185
188
|
},
|
|
186
|
-
|
|
187
189
|
{
|
|
188
190
|
matcher: {
|
|
189
191
|
name: 'nucleotideMutations_07',
|
|
@@ -192,7 +194,7 @@ export const Default: StoryObj<MutationsOverTimeProps> = {
|
|
|
192
194
|
pangoLineage: 'JN.1*',
|
|
193
195
|
dateFrom: '2024-07-01',
|
|
194
196
|
dateTo: '2024-07-31',
|
|
195
|
-
minProportion: 0,
|
|
197
|
+
minProportion: 0.001,
|
|
196
198
|
},
|
|
197
199
|
response: {
|
|
198
200
|
status: 200,
|
|
@@ -204,3 +206,55 @@ export const Default: StoryObj<MutationsOverTimeProps> = {
|
|
|
204
206
|
},
|
|
205
207
|
},
|
|
206
208
|
};
|
|
209
|
+
|
|
210
|
+
export const ShowsMessageWhenTooManyMutations: StoryObj<MutationsOverTimeProps> = {
|
|
211
|
+
...Template,
|
|
212
|
+
args: {
|
|
213
|
+
lapisFilter: { dateFrom: '2023-01-01', dateTo: '2023-12-31' },
|
|
214
|
+
sequenceType: 'nucleotide',
|
|
215
|
+
views: ['grid'],
|
|
216
|
+
width: '100%',
|
|
217
|
+
height: '700px',
|
|
218
|
+
granularity: 'year',
|
|
219
|
+
lapisDateField: 'date',
|
|
220
|
+
},
|
|
221
|
+
parameters: {
|
|
222
|
+
fetchMock: {
|
|
223
|
+
mocks: [
|
|
224
|
+
{
|
|
225
|
+
matcher: {
|
|
226
|
+
name: 'aggregated',
|
|
227
|
+
url: AGGREGATED_ENDPOINT,
|
|
228
|
+
body: {
|
|
229
|
+
dateFrom: '2023-01-01',
|
|
230
|
+
dateTo: '2023-12-31',
|
|
231
|
+
fields: ['date'],
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
response: {
|
|
235
|
+
status: 200,
|
|
236
|
+
body: aggregated_tooManyMutations,
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
matcher: {
|
|
241
|
+
name: 'nucleotideMutations',
|
|
242
|
+
url: NUCLEOTIDE_MUTATIONS_ENDPOINT,
|
|
243
|
+
body: {
|
|
244
|
+
dateFrom: '2023-01-01',
|
|
245
|
+
dateTo: '2023-12-31',
|
|
246
|
+
minProportion: 0.001,
|
|
247
|
+
},
|
|
248
|
+
response: {
|
|
249
|
+
status: 200,
|
|
250
|
+
body: nucleotideMutation_tooManyMutations,
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
],
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
play: async ({ canvas }) => {
|
|
258
|
+
await waitFor(() => expect(canvas.getByText('Showing 100 of 137 mutations.', { exact: false })).toBeVisible());
|
|
259
|
+
},
|
|
260
|
+
};
|
|
@@ -8,8 +8,10 @@ import {
|
|
|
8
8
|
queryMutationsOverTimeData,
|
|
9
9
|
} from '../../query/queryMutationsOverTime';
|
|
10
10
|
import { type LapisFilter, type SequenceType, type TemporalGranularity } from '../../types';
|
|
11
|
+
import { compareTemporal } from '../../utils/temporal';
|
|
11
12
|
import { LapisUrlContext } from '../LapisUrlContext';
|
|
12
13
|
import { type DisplayedSegment, SegmentSelector, useDisplayedSegments } from '../components/SegmentSelector';
|
|
14
|
+
import { CsvDownloadButton } from '../components/csv-download-button';
|
|
13
15
|
import { ErrorBoundary } from '../components/error-boundary';
|
|
14
16
|
import { ErrorDisplay } from '../components/error-display';
|
|
15
17
|
import Info from '../components/info';
|
|
@@ -126,6 +128,7 @@ const MutationsOverTimeTabs: FunctionComponent<MutationOverTimeTabsProps> = ({
|
|
|
126
128
|
setDisplayedMutationTypes={setDisplayedMutationTypes}
|
|
127
129
|
proportionInterval={proportionInterval}
|
|
128
130
|
setProportionInterval={setProportionInterval}
|
|
131
|
+
filteredData={filteredData}
|
|
129
132
|
/>
|
|
130
133
|
);
|
|
131
134
|
|
|
@@ -139,6 +142,7 @@ type ToolbarProps = {
|
|
|
139
142
|
setDisplayedMutationTypes: (types: DisplayedMutationType[]) => void;
|
|
140
143
|
proportionInterval: ProportionInterval;
|
|
141
144
|
setProportionInterval: Dispatch<StateUpdater<ProportionInterval>>;
|
|
145
|
+
filteredData: MutationOverTimeDataGroupedByMutation;
|
|
142
146
|
};
|
|
143
147
|
|
|
144
148
|
const Toolbar: FunctionComponent<ToolbarProps> = ({
|
|
@@ -148,6 +152,7 @@ const Toolbar: FunctionComponent<ToolbarProps> = ({
|
|
|
148
152
|
setDisplayedMutationTypes,
|
|
149
153
|
proportionInterval,
|
|
150
154
|
setProportionInterval,
|
|
155
|
+
filteredData,
|
|
151
156
|
}) => {
|
|
152
157
|
return (
|
|
153
158
|
<>
|
|
@@ -156,15 +161,34 @@ const Toolbar: FunctionComponent<ToolbarProps> = ({
|
|
|
156
161
|
setDisplayedMutationTypes={setDisplayedMutationTypes}
|
|
157
162
|
displayedMutationTypes={displayedMutationTypes}
|
|
158
163
|
/>
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
164
|
+
<ProportionSelectorDropdown
|
|
165
|
+
proportionInterval={proportionInterval}
|
|
166
|
+
setMinProportion={(min) => setProportionInterval((prev) => ({ ...prev, min }))}
|
|
167
|
+
setMaxProportion={(max) => setProportionInterval((prev) => ({ ...prev, max }))}
|
|
168
|
+
/>
|
|
169
|
+
<CsvDownloadButton
|
|
170
|
+
className='mx-1 btn btn-xs'
|
|
171
|
+
getData={() => getDownloadData(filteredData)}
|
|
172
|
+
filename='mutations_over_time.csv'
|
|
173
|
+
/>
|
|
167
174
|
<Info height={'100px'}>Info for mutations over time</Info>
|
|
168
175
|
</>
|
|
169
176
|
);
|
|
170
177
|
};
|
|
178
|
+
|
|
179
|
+
function getDownloadData(filteredData: MutationOverTimeDataGroupedByMutation) {
|
|
180
|
+
const dates = filteredData.getSecondAxisKeys().sort((a, b) => compareTemporal(a, b));
|
|
181
|
+
|
|
182
|
+
return filteredData.getFirstAxisKeys().map((mutation) => {
|
|
183
|
+
return dates.reduce(
|
|
184
|
+
(accumulated, date) => {
|
|
185
|
+
const proportion = filteredData.get(mutation, date)?.proportion ?? 0;
|
|
186
|
+
return {
|
|
187
|
+
...accumulated,
|
|
188
|
+
[date.toString()]: proportion,
|
|
189
|
+
};
|
|
190
|
+
},
|
|
191
|
+
{ mutation: mutation.toString() },
|
|
192
|
+
);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
@@ -57,8 +57,7 @@ describe('YearMonthDay', () => {
|
|
|
57
57
|
expect(underTest.yearNumber).equal(2020);
|
|
58
58
|
expect(underTest.monthNumber).equal(1);
|
|
59
59
|
expect(underTest.dayNumber).equal(1);
|
|
60
|
-
|
|
61
|
-
expect(underTest.week.text).equal('2019-01');
|
|
60
|
+
expect(underTest.week.text).equal('2020-W01');
|
|
62
61
|
expect(underTest.text).equal('2020-01-01');
|
|
63
62
|
expect(underTest.firstDay.text).equal('2020-01-01');
|
|
64
63
|
expect(underTest.lastDay.text).equal('2020-01-01');
|
|
@@ -67,12 +66,12 @@ describe('YearMonthDay', () => {
|
|
|
67
66
|
|
|
68
67
|
describe('YearWeek', () => {
|
|
69
68
|
it('should parse from string', () => {
|
|
70
|
-
const underTest = YearWeek.parse('2020-
|
|
69
|
+
const underTest = YearWeek.parse('2020-W02', cache);
|
|
71
70
|
|
|
72
71
|
expect(underTest.isoYearNumber).equal(2020);
|
|
73
72
|
expect(underTest.isoWeekNumber).equal(2);
|
|
74
73
|
expect(underTest.firstDay.text).equal('2020-01-06');
|
|
75
|
-
expect(underTest.text).equal('2020-
|
|
74
|
+
expect(underTest.text).equal('2020-W02');
|
|
76
75
|
expect(underTest.lastDay.text).equal('2020-01-12');
|
|
77
76
|
});
|
|
78
77
|
});
|
package/src/utils/temporal.ts
CHANGED
|
@@ -7,6 +7,11 @@ import type { TemporalGranularity } from '../types';
|
|
|
7
7
|
dayjs.extend(isoWeek);
|
|
8
8
|
dayjs.extend(advancedFormat);
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* https://day.js.org/docs/en/plugin/advanced-format
|
|
12
|
+
*/
|
|
13
|
+
const FORMAT_ISO_WEEK_YEAR_WEEK = 'GGGG-[W]WW';
|
|
14
|
+
|
|
10
15
|
export class TemporalCache {
|
|
11
16
|
private yearMonthDayCache = new Map<string, YearMonthDay>();
|
|
12
17
|
private yearWeekCache = new Map<string, YearWeek>();
|
|
@@ -93,7 +98,7 @@ export class YearMonthDay {
|
|
|
93
98
|
}
|
|
94
99
|
|
|
95
100
|
get week(): YearWeek {
|
|
96
|
-
return this.cache.getYearWeek(this.dayjs.format(
|
|
101
|
+
return this.cache.getYearWeek(this.dayjs.format(FORMAT_ISO_WEEK_YEAR_WEEK));
|
|
97
102
|
}
|
|
98
103
|
|
|
99
104
|
addDays(days: number): YearMonthDay {
|
|
@@ -120,7 +125,7 @@ export class YearWeek {
|
|
|
120
125
|
) {}
|
|
121
126
|
|
|
122
127
|
get text(): string {
|
|
123
|
-
return this.firstDay.dayjs.format(
|
|
128
|
+
return this.firstDay.dayjs.format(FORMAT_ISO_WEEK_YEAR_WEEK);
|
|
124
129
|
}
|
|
125
130
|
|
|
126
131
|
toString(): string {
|
|
@@ -160,7 +165,7 @@ export class YearWeek {
|
|
|
160
165
|
|
|
161
166
|
addWeeks(weeks: number): YearWeek {
|
|
162
167
|
const date = this.firstDay.dayjs.add(weeks, 'week');
|
|
163
|
-
const s = date.format(
|
|
168
|
+
const s = date.format(FORMAT_ISO_WEEK_YEAR_WEEK);
|
|
164
169
|
return this.cache.getYearWeek(s);
|
|
165
170
|
}
|
|
166
171
|
|
|
@@ -169,7 +174,7 @@ export class YearWeek {
|
|
|
169
174
|
}
|
|
170
175
|
|
|
171
176
|
static parse(s: string, cache: TemporalCache): YearWeek {
|
|
172
|
-
const [year, week] = s.split('-').map((s) => parseInt(s, 10));
|
|
177
|
+
const [year, week] = s.split('-W').map((s) => parseInt(s, 10));
|
|
173
178
|
return new YearWeek(year, week, cache);
|
|
174
179
|
}
|
|
175
180
|
}
|