@dhis2/analytics 21.8.2 → 21.9.1
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/CHANGELOG.md +14 -0
- package/build/cjs/components/PeriodDimension/PeriodDimension.js +32 -1
- package/build/cjs/components/PeriodDimension/PeriodTransfer.js +20 -6
- package/build/cjs/components/PeriodDimension/__tests__/PeriodDimension.spec.js +13 -0
- package/build/cjs/components/PeriodDimension/__tests__/__snapshots__/PeriodDimension.spec.js.snap +6 -0
- package/build/cjs/components/PeriodDimension/utils/fixedPeriods.js +206 -478
- package/build/cjs/locales/en/translations.json +0 -14
- package/build/cjs/modules/pivotTable/PivotTableEngine.js +9 -28
- package/build/cjs/modules/pivotTable/__tests__/addToTotalIfNumber.js +72 -0
- package/build/cjs/modules/pivotTable/addToTotalIfNumber.js +10 -0
- package/build/es/components/PeriodDimension/PeriodDimension.js +30 -1
- package/build/es/components/PeriodDimension/PeriodTransfer.js +19 -6
- package/build/es/components/PeriodDimension/__tests__/PeriodDimension.spec.js +13 -0
- package/build/es/components/PeriodDimension/__tests__/__snapshots__/PeriodDimension.spec.js.snap +6 -0
- package/build/es/components/PeriodDimension/utils/fixedPeriods.js +204 -477
- package/build/es/locales/en/translations.json +0 -14
- package/build/es/modules/pivotTable/PivotTableEngine.js +8 -28
- package/build/es/modules/pivotTable/__tests__/addToTotalIfNumber.js +69 -0
- package/build/es/modules/pivotTable/addToTotalIfNumber.js +1 -0
- package/package.json +2 -1
|
@@ -147,20 +147,6 @@
|
|
|
147
147
|
"Fixed periods": "Fixed periods",
|
|
148
148
|
"Selected Periods": "Selected Periods",
|
|
149
149
|
"No periods selected": "No periods selected",
|
|
150
|
-
"January": "January",
|
|
151
|
-
"February": "February",
|
|
152
|
-
"March": "March",
|
|
153
|
-
"April": "April",
|
|
154
|
-
"May": "May",
|
|
155
|
-
"June": "June",
|
|
156
|
-
"July": "July",
|
|
157
|
-
"August": "August",
|
|
158
|
-
"September": "September",
|
|
159
|
-
"October": "October",
|
|
160
|
-
"November": "November",
|
|
161
|
-
"December": "December",
|
|
162
|
-
"Week {{weekNumber}}": "Week {{weekNumber}}",
|
|
163
|
-
"Bi-Week {{biWeekNumber}}": "Bi-Week {{biWeekNumber}}",
|
|
164
150
|
"Daily": "Daily",
|
|
165
151
|
"Weekly": "Weekly",
|
|
166
152
|
"Weekly (Start Wednesday)": "Weekly (Start Wednesday)",
|
|
@@ -11,6 +11,8 @@ var _predefinedDimensions = require("../predefinedDimensions.js");
|
|
|
11
11
|
|
|
12
12
|
var _AdaptiveClippingController = require("./AdaptiveClippingController.js");
|
|
13
13
|
|
|
14
|
+
var _addToTotalIfNumber = require("./addToTotalIfNumber.js");
|
|
15
|
+
|
|
14
16
|
var _parseValue = require("./parseValue.js");
|
|
15
17
|
|
|
16
18
|
var _pivotTableConstants = require("./pivotTableConstants.js");
|
|
@@ -611,10 +613,7 @@ class PivotTableEngine {
|
|
|
611
613
|
dataFields.forEach(field => {
|
|
612
614
|
const headerIndex = this.dimensionLookup.dataHeaders[field];
|
|
613
615
|
const value = (0, _parseValue.parseValue)(dataRow[headerIndex]);
|
|
614
|
-
|
|
615
|
-
if (value && !isNaN(value)) {
|
|
616
|
-
totalCell[field] = (totalCell[field] || 0) + value;
|
|
617
|
-
}
|
|
616
|
+
totalCell[field] = (0, _addToTotalIfNumber.addToTotalIfNumber)(value, totalCell[field]);
|
|
618
617
|
});
|
|
619
618
|
}
|
|
620
619
|
|
|
@@ -633,10 +632,7 @@ class PivotTableEngine {
|
|
|
633
632
|
dataFields.forEach(field => {
|
|
634
633
|
const headerIndex = this.dimensionLookup.dataHeaders[field];
|
|
635
634
|
const value = (0, _parseValue.parseValue)(dataRow[headerIndex]);
|
|
636
|
-
|
|
637
|
-
if (value && !isNaN(value)) {
|
|
638
|
-
percentageTotal[field] = (percentageTotal[field] || 0) + value;
|
|
639
|
-
}
|
|
635
|
+
percentageTotal[field] = (0, _addToTotalIfNumber.addToTotalIfNumber)(value, percentageTotal[field]);
|
|
640
636
|
});
|
|
641
637
|
|
|
642
638
|
if (totals.columnSubtotal) {
|
|
@@ -651,10 +647,7 @@ class PivotTableEngine {
|
|
|
651
647
|
dataFields.forEach(field => {
|
|
652
648
|
const headerIndex = this.dimensionLookup.dataHeaders[field];
|
|
653
649
|
const value = (0, _parseValue.parseValue)(dataRow[headerIndex]);
|
|
654
|
-
|
|
655
|
-
if (value && !isNaN(value)) {
|
|
656
|
-
percentageTotal[field] = (percentageTotal[field] || 0) + value;
|
|
657
|
-
}
|
|
650
|
+
percentageTotal[field] = (0, _addToTotalIfNumber.addToTotalIfNumber)(value, percentageTotal[field]);
|
|
658
651
|
});
|
|
659
652
|
}
|
|
660
653
|
|
|
@@ -670,10 +663,7 @@ class PivotTableEngine {
|
|
|
670
663
|
dataFields.forEach(field => {
|
|
671
664
|
const headerIndex = this.dimensionLookup.dataHeaders[field];
|
|
672
665
|
const value = (0, _parseValue.parseValue)(dataRow[headerIndex]);
|
|
673
|
-
|
|
674
|
-
if (value && !isNaN(value)) {
|
|
675
|
-
percentageTotal[field] = (percentageTotal[field] || 0) + value;
|
|
676
|
-
}
|
|
666
|
+
percentageTotal[field] = (0, _addToTotalIfNumber.addToTotalIfNumber)(value, percentageTotal[field]);
|
|
677
667
|
});
|
|
678
668
|
}
|
|
679
669
|
}
|
|
@@ -690,10 +680,7 @@ class PivotTableEngine {
|
|
|
690
680
|
dataFields.forEach(field => {
|
|
691
681
|
const headerIndex = this.dimensionLookup.dataHeaders[field];
|
|
692
682
|
const value = (0, _parseValue.parseValue)(dataRow[headerIndex]);
|
|
693
|
-
|
|
694
|
-
if (value && !isNaN(value)) {
|
|
695
|
-
percentageTotal[field] = (percentageTotal[field] || 0) + value;
|
|
696
|
-
}
|
|
683
|
+
percentageTotal[field] = (0, _addToTotalIfNumber.addToTotalIfNumber)(value, percentageTotal[field]);
|
|
697
684
|
});
|
|
698
685
|
|
|
699
686
|
if (totals.rowSubtotal) {
|
|
@@ -708,10 +695,7 @@ class PivotTableEngine {
|
|
|
708
695
|
dataFields.forEach(field => {
|
|
709
696
|
const headerIndex = this.dimensionLookup.dataHeaders[field];
|
|
710
697
|
const value = (0, _parseValue.parseValue)(dataRow[headerIndex]);
|
|
711
|
-
|
|
712
|
-
if (value && !isNaN(value)) {
|
|
713
|
-
percentageTotal[field] = (percentageTotal[field] || 0) + value;
|
|
714
|
-
}
|
|
698
|
+
percentageTotal[field] = (0, _addToTotalIfNumber.addToTotalIfNumber)(value, percentageTotal[field]);
|
|
715
699
|
});
|
|
716
700
|
}
|
|
717
701
|
|
|
@@ -727,10 +711,7 @@ class PivotTableEngine {
|
|
|
727
711
|
dataFields.forEach(field => {
|
|
728
712
|
const headerIndex = this.dimensionLookup.dataHeaders[field];
|
|
729
713
|
const value = (0, _parseValue.parseValue)(dataRow[headerIndex]);
|
|
730
|
-
|
|
731
|
-
if (value && !isNaN(value)) {
|
|
732
|
-
percentageTotal[field] = (percentageTotal[field] || 0) + value;
|
|
733
|
-
}
|
|
714
|
+
percentageTotal[field] = (0, _addToTotalIfNumber.addToTotalIfNumber)(value, percentageTotal[field]);
|
|
734
715
|
});
|
|
735
716
|
}
|
|
736
717
|
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _addToTotalIfNumber = require("../addToTotalIfNumber.js");
|
|
4
|
+
|
|
5
|
+
const tests = [{
|
|
6
|
+
testName: 'negative value',
|
|
7
|
+
value: -1,
|
|
8
|
+
total: undefined,
|
|
9
|
+
expected: -1
|
|
10
|
+
}, {
|
|
11
|
+
testName: 'zero value',
|
|
12
|
+
value: 0,
|
|
13
|
+
total: undefined,
|
|
14
|
+
expected: 0
|
|
15
|
+
}, {
|
|
16
|
+
testName: 'positive value',
|
|
17
|
+
value: 1,
|
|
18
|
+
total: undefined,
|
|
19
|
+
expected: 1
|
|
20
|
+
}, {
|
|
21
|
+
testName: 'null value',
|
|
22
|
+
value: null,
|
|
23
|
+
total: undefined,
|
|
24
|
+
expected: undefined
|
|
25
|
+
}, {
|
|
26
|
+
testName: 'undefined value',
|
|
27
|
+
value: undefined,
|
|
28
|
+
total: undefined,
|
|
29
|
+
expected: undefined
|
|
30
|
+
}, {
|
|
31
|
+
testName: 'string value',
|
|
32
|
+
value: 'string',
|
|
33
|
+
total: undefined,
|
|
34
|
+
expected: undefined
|
|
35
|
+
}, {
|
|
36
|
+
testName: 'negative value with existing total',
|
|
37
|
+
value: -1,
|
|
38
|
+
total: 100,
|
|
39
|
+
expected: 99
|
|
40
|
+
}, {
|
|
41
|
+
testName: 'zero value with existing total',
|
|
42
|
+
value: 0,
|
|
43
|
+
total: 100,
|
|
44
|
+
expected: 100
|
|
45
|
+
}, {
|
|
46
|
+
testName: 'positive value with existing total',
|
|
47
|
+
value: 1,
|
|
48
|
+
total: 100,
|
|
49
|
+
expected: 101
|
|
50
|
+
}, {
|
|
51
|
+
testName: 'null value with existing total',
|
|
52
|
+
value: null,
|
|
53
|
+
total: 100,
|
|
54
|
+
expected: 100
|
|
55
|
+
}, {
|
|
56
|
+
testName: 'undefined value with existing total',
|
|
57
|
+
value: undefined,
|
|
58
|
+
total: 100,
|
|
59
|
+
expected: 100
|
|
60
|
+
}, {
|
|
61
|
+
testName: 'string value with existing total',
|
|
62
|
+
value: 'string',
|
|
63
|
+
total: 100,
|
|
64
|
+
expected: 100
|
|
65
|
+
}];
|
|
66
|
+
describe('addToTotalIfNumber', () => {
|
|
67
|
+
tests.forEach(t => {
|
|
68
|
+
it(t.testName, () => {
|
|
69
|
+
expect((0, _addToTotalIfNumber.addToTotalIfNumber)(t.value, t.total)).toEqual(t.expected);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.addToTotalIfNumber = void 0;
|
|
7
|
+
|
|
8
|
+
const addToTotalIfNumber = (value, total) => typeof value === 'number' && Number.isFinite(value) ? (total !== null && total !== void 0 ? total : 0) + value : total;
|
|
9
|
+
|
|
10
|
+
exports.addToTotalIfNumber = addToTotalIfNumber;
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
+
import { useConfig, useDataQuery } from '@dhis2/app-runtime';
|
|
1
2
|
import PropTypes from 'prop-types';
|
|
2
3
|
import React from 'react';
|
|
3
4
|
import { DIMENSION_ID_PERIOD } from '../../modules/predefinedDimensions.js';
|
|
4
5
|
import PeriodTransfer from './PeriodTransfer.js';
|
|
6
|
+
const userSettingsQuery = {
|
|
7
|
+
userSettings: {
|
|
8
|
+
resource: 'userSettings',
|
|
9
|
+
params: {
|
|
10
|
+
key: ['keyUiLocale']
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
};
|
|
5
14
|
|
|
6
15
|
const PeriodDimension = ({
|
|
7
16
|
onSelect,
|
|
@@ -9,6 +18,25 @@ const PeriodDimension = ({
|
|
|
9
18
|
rightFooter,
|
|
10
19
|
excludedPeriodTypes
|
|
11
20
|
}) => {
|
|
21
|
+
const {
|
|
22
|
+
systemInfo
|
|
23
|
+
} = useConfig();
|
|
24
|
+
const result = useDataQuery(userSettingsQuery);
|
|
25
|
+
const {
|
|
26
|
+
calendar = 'gregory'
|
|
27
|
+
} = systemInfo;
|
|
28
|
+
const {
|
|
29
|
+
data: {
|
|
30
|
+
userSettings: {
|
|
31
|
+
keyUiLocale: locale
|
|
32
|
+
} = {}
|
|
33
|
+
} = {}
|
|
34
|
+
} = result;
|
|
35
|
+
const periodsSettings = {
|
|
36
|
+
calendar,
|
|
37
|
+
locale
|
|
38
|
+
};
|
|
39
|
+
|
|
12
40
|
const selectPeriods = periods => {
|
|
13
41
|
onSelect({
|
|
14
42
|
dimensionId: DIMENSION_ID_PERIOD,
|
|
@@ -21,7 +49,8 @@ const PeriodDimension = ({
|
|
|
21
49
|
initialSelectedPeriods: selectedPeriods,
|
|
22
50
|
rightFooter: rightFooter,
|
|
23
51
|
dataTest: 'period-dimension',
|
|
24
|
-
excludedPeriodTypes: excludedPeriodTypes
|
|
52
|
+
excludedPeriodTypes: excludedPeriodTypes,
|
|
53
|
+
periodsSettings: periodsSettings
|
|
25
54
|
});
|
|
26
55
|
};
|
|
27
56
|
|
|
@@ -2,6 +2,7 @@ import _JSXStyle from "styled-jsx/style";
|
|
|
2
2
|
|
|
3
3
|
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
4
4
|
|
|
5
|
+
import { getNowInCalendar } from '@dhis2/multi-calendar-dates';
|
|
5
6
|
import { TabBar, Tab, Transfer } from '@dhis2/ui';
|
|
6
7
|
import PropTypes from 'prop-types';
|
|
7
8
|
import React, { useState } from 'react';
|
|
@@ -22,11 +23,15 @@ const PeriodTransfer = ({
|
|
|
22
23
|
dataTest,
|
|
23
24
|
initialSelectedPeriods,
|
|
24
25
|
rightFooter,
|
|
25
|
-
excludedPeriodTypes
|
|
26
|
+
excludedPeriodTypes,
|
|
27
|
+
periodsSettings
|
|
26
28
|
}) => {
|
|
27
29
|
const defaultRelativePeriodType = excludedPeriodTypes.includes(MONTHLY) ? getRelativePeriodsOptionsById(QUARTERLY) : getRelativePeriodsOptionsById(MONTHLY);
|
|
28
|
-
const defaultFixedPeriodType = excludedPeriodTypes.includes(MONTHLY) ? getFixedPeriodsOptionsById(QUARTERLY) : getFixedPeriodsOptionsById(MONTHLY);
|
|
29
|
-
const
|
|
30
|
+
const defaultFixedPeriodType = excludedPeriodTypes.includes(MONTHLY) ? getFixedPeriodsOptionsById(QUARTERLY, periodsSettings) : getFixedPeriodsOptionsById(MONTHLY, periodsSettings);
|
|
31
|
+
const now = getNowInCalendar(periodsSettings.calendar); // use ".eraYear" rather than ".year" because in Ethiopian calendar, eraYear is what our users expect to see (for other calendars, it doesn't matter)
|
|
32
|
+
// there is still a pending decision in Temporal regarding which era to use by default: https://github.com/js-temporal/temporal-polyfill/blob/9350ee7dd0d29f329fc097debf923a517c32f813/lib/calendar.ts#L1964
|
|
33
|
+
|
|
34
|
+
const defaultFixedPeriodYear = now.eraYear || now.year;
|
|
30
35
|
|
|
31
36
|
const fixedPeriodConfig = year => ({
|
|
32
37
|
offset: year - defaultFixedPeriodYear,
|
|
@@ -48,7 +53,7 @@ const PeriodTransfer = ({
|
|
|
48
53
|
const onIsRelativeClick = state => {
|
|
49
54
|
if (state !== isRelative) {
|
|
50
55
|
setIsRelative(state);
|
|
51
|
-
setAllPeriods(state ? getRelativePeriodsOptionsById(relativeFilter.periodType).getPeriods() : getFixedPeriodsOptionsById(fixedFilter.periodType).getPeriods(fixedPeriodConfig(Number(fixedFilter.year))));
|
|
56
|
+
setAllPeriods(state ? getRelativePeriodsOptionsById(relativeFilter.periodType).getPeriods() : getFixedPeriodsOptionsById(fixedFilter.periodType, periodsSettings).getPeriods(fixedPeriodConfig(Number(fixedFilter.year))));
|
|
52
57
|
}
|
|
53
58
|
};
|
|
54
59
|
|
|
@@ -101,7 +106,7 @@ const PeriodTransfer = ({
|
|
|
101
106
|
|
|
102
107
|
const onSelectFixedPeriods = filter => {
|
|
103
108
|
setFixedFilter(filter);
|
|
104
|
-
setAllPeriods(getFixedPeriodsOptionsById(filter.periodType).getPeriods(fixedPeriodConfig(Number(filter.year))));
|
|
109
|
+
setAllPeriods(getFixedPeriodsOptionsById(filter.periodType, periodsSettings).getPeriods(fixedPeriodConfig(Number(filter.year)), periodsSettings));
|
|
105
110
|
};
|
|
106
111
|
|
|
107
112
|
const renderEmptySelection = () => /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("p", {
|
|
@@ -147,7 +152,11 @@ const PeriodTransfer = ({
|
|
|
147
152
|
|
|
148
153
|
PeriodTransfer.defaultProps = {
|
|
149
154
|
initialSelectedPeriods: [],
|
|
150
|
-
excludedPeriodTypes: []
|
|
155
|
+
excludedPeriodTypes: [],
|
|
156
|
+
periodsSettings: {
|
|
157
|
+
calendar: 'gregory',
|
|
158
|
+
locale: 'en'
|
|
159
|
+
}
|
|
151
160
|
};
|
|
152
161
|
PeriodTransfer.propTypes = {
|
|
153
162
|
onSelect: PropTypes.func.isRequired,
|
|
@@ -157,6 +166,10 @@ PeriodTransfer.propTypes = {
|
|
|
157
166
|
id: PropTypes.string,
|
|
158
167
|
name: PropTypes.string
|
|
159
168
|
})),
|
|
169
|
+
periodsSettings: PropTypes.shape({
|
|
170
|
+
calendar: PropTypes.string,
|
|
171
|
+
locale: PropTypes.string
|
|
172
|
+
}),
|
|
160
173
|
rightFooter: PropTypes.node
|
|
161
174
|
};
|
|
162
175
|
export default PeriodTransfer;
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import { shallow } from 'enzyme';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import PeriodDimension from '../PeriodDimension.js';
|
|
4
|
+
jest.mock('@dhis2/app-runtime', () => ({
|
|
5
|
+
useConfig: () => ({
|
|
6
|
+
systemInfo: {}
|
|
7
|
+
}),
|
|
8
|
+
useDataQuery: () => ({
|
|
9
|
+
data: {
|
|
10
|
+
userSettings: {
|
|
11
|
+
keyUiLocale: 'en'
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
})
|
|
15
|
+
}));
|
|
16
|
+
afterEach(jest.clearAllMocks);
|
|
4
17
|
describe('The Period Dimension component', () => {
|
|
5
18
|
let props;
|
|
6
19
|
let shallowPeriodDimension;
|
package/build/es/components/PeriodDimension/__tests__/__snapshots__/PeriodDimension.spec.js.snap
CHANGED
|
@@ -6,6 +6,12 @@ exports[`The Period Dimension component matches the snapshot 1`] = `
|
|
|
6
6
|
excludedPeriodTypes={Array []}
|
|
7
7
|
initialSelectedPeriods={Array []}
|
|
8
8
|
onSelect={[Function]}
|
|
9
|
+
periodsSettings={
|
|
10
|
+
Object {
|
|
11
|
+
"calendar": "gregory",
|
|
12
|
+
"locale": "en",
|
|
13
|
+
}
|
|
14
|
+
}
|
|
9
15
|
rightFooter={<React.Fragment />}
|
|
10
16
|
/>
|
|
11
17
|
`;
|