@dhis2/analytics 24.10.0 → 24.10.2
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/modules/pivotTable/PivotTableEngine.js +9 -28
- package/build/cjs/modules/pivotTable/__tests__/addToTotalIfNumber.spec.js +72 -0
- package/build/cjs/modules/pivotTable/addToTotalIfNumber.js +10 -0
- package/build/cjs/visualizations/config/generators/dhis/singleValue.js +2 -2
- package/build/es/modules/pivotTable/PivotTableEngine.js +8 -28
- package/build/es/modules/pivotTable/__tests__/addToTotalIfNumber.spec.js +69 -0
- package/build/es/modules/pivotTable/addToTotalIfNumber.js +1 -0
- package/build/es/visualizations/config/generators/dhis/singleValue.js +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [24.10.2](https://github.com/dhis2/analytics/compare/v24.10.1...v24.10.2) (2023-10-25)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* avoid undefined in totals DHIS2-14511 v39 ([#1587](https://github.com/dhis2/analytics/issues/1587)) ([9831c17](https://github.com/dhis2/analytics/commit/9831c17f696f763b4ef6125fef9a9999c520f5aa))
|
|
7
|
+
|
|
8
|
+
## [24.10.1](https://github.com/dhis2/analytics/compare/v24.10.0...v24.10.1) (2023-04-24)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* sv size when downloading is a small square (DHIS2-15178) ([245d799](https://github.com/dhis2/analytics/commit/245d799d9513e0407e4a6b6ba24c3da15754618d))
|
|
14
|
+
|
|
1
15
|
# [24.10.0](https://github.com/dhis2/analytics/compare/v24.9.3...v24.10.0) (2023-04-19)
|
|
2
16
|
|
|
3
17
|
|
|
@@ -17,6 +17,8 @@ var _valueTypes = require("../valueTypes.js");
|
|
|
17
17
|
|
|
18
18
|
var _AdaptiveClippingController = require("./AdaptiveClippingController.js");
|
|
19
19
|
|
|
20
|
+
var _addToTotalIfNumber = require("./addToTotalIfNumber.js");
|
|
21
|
+
|
|
20
22
|
var _parseValue = require("./parseValue.js");
|
|
21
23
|
|
|
22
24
|
var _pivotTableConstants = require("./pivotTableConstants.js");
|
|
@@ -626,10 +628,7 @@ class PivotTableEngine {
|
|
|
626
628
|
dataFields.forEach(field => {
|
|
627
629
|
const headerIndex = this.dimensionLookup.dataHeaders[field];
|
|
628
630
|
const value = (0, _parseValue.parseValue)(dataRow[headerIndex]);
|
|
629
|
-
|
|
630
|
-
if (value && !isNaN(value)) {
|
|
631
|
-
totalCell[field] = (totalCell[field] || 0) + value;
|
|
632
|
-
}
|
|
631
|
+
totalCell[field] = (0, _addToTotalIfNumber.addToTotalIfNumber)(value, totalCell[field]);
|
|
633
632
|
});
|
|
634
633
|
}
|
|
635
634
|
|
|
@@ -648,10 +647,7 @@ class PivotTableEngine {
|
|
|
648
647
|
dataFields.forEach(field => {
|
|
649
648
|
const headerIndex = this.dimensionLookup.dataHeaders[field];
|
|
650
649
|
const value = (0, _parseValue.parseValue)(dataRow[headerIndex]);
|
|
651
|
-
|
|
652
|
-
if (value && !isNaN(value)) {
|
|
653
|
-
percentageTotal[field] = (percentageTotal[field] || 0) + value;
|
|
654
|
-
}
|
|
650
|
+
percentageTotal[field] = (0, _addToTotalIfNumber.addToTotalIfNumber)(value, percentageTotal[field]);
|
|
655
651
|
});
|
|
656
652
|
|
|
657
653
|
if (totals.columnSubtotal) {
|
|
@@ -666,10 +662,7 @@ class PivotTableEngine {
|
|
|
666
662
|
dataFields.forEach(field => {
|
|
667
663
|
const headerIndex = this.dimensionLookup.dataHeaders[field];
|
|
668
664
|
const value = (0, _parseValue.parseValue)(dataRow[headerIndex]);
|
|
669
|
-
|
|
670
|
-
if (value && !isNaN(value)) {
|
|
671
|
-
percentageTotal[field] = (percentageTotal[field] || 0) + value;
|
|
672
|
-
}
|
|
665
|
+
percentageTotal[field] = (0, _addToTotalIfNumber.addToTotalIfNumber)(value, percentageTotal[field]);
|
|
673
666
|
});
|
|
674
667
|
}
|
|
675
668
|
|
|
@@ -685,10 +678,7 @@ class PivotTableEngine {
|
|
|
685
678
|
dataFields.forEach(field => {
|
|
686
679
|
const headerIndex = this.dimensionLookup.dataHeaders[field];
|
|
687
680
|
const value = (0, _parseValue.parseValue)(dataRow[headerIndex]);
|
|
688
|
-
|
|
689
|
-
if (value && !isNaN(value)) {
|
|
690
|
-
percentageTotal[field] = (percentageTotal[field] || 0) + value;
|
|
691
|
-
}
|
|
681
|
+
percentageTotal[field] = (0, _addToTotalIfNumber.addToTotalIfNumber)(value, percentageTotal[field]);
|
|
692
682
|
});
|
|
693
683
|
}
|
|
694
684
|
}
|
|
@@ -705,10 +695,7 @@ class PivotTableEngine {
|
|
|
705
695
|
dataFields.forEach(field => {
|
|
706
696
|
const headerIndex = this.dimensionLookup.dataHeaders[field];
|
|
707
697
|
const value = (0, _parseValue.parseValue)(dataRow[headerIndex]);
|
|
708
|
-
|
|
709
|
-
if (value && !isNaN(value)) {
|
|
710
|
-
percentageTotal[field] = (percentageTotal[field] || 0) + value;
|
|
711
|
-
}
|
|
698
|
+
percentageTotal[field] = (0, _addToTotalIfNumber.addToTotalIfNumber)(value, percentageTotal[field]);
|
|
712
699
|
});
|
|
713
700
|
|
|
714
701
|
if (totals.rowSubtotal) {
|
|
@@ -723,10 +710,7 @@ class PivotTableEngine {
|
|
|
723
710
|
dataFields.forEach(field => {
|
|
724
711
|
const headerIndex = this.dimensionLookup.dataHeaders[field];
|
|
725
712
|
const value = (0, _parseValue.parseValue)(dataRow[headerIndex]);
|
|
726
|
-
|
|
727
|
-
if (value && !isNaN(value)) {
|
|
728
|
-
percentageTotal[field] = (percentageTotal[field] || 0) + value;
|
|
729
|
-
}
|
|
713
|
+
percentageTotal[field] = (0, _addToTotalIfNumber.addToTotalIfNumber)(value, percentageTotal[field]);
|
|
730
714
|
});
|
|
731
715
|
}
|
|
732
716
|
|
|
@@ -742,10 +726,7 @@ class PivotTableEngine {
|
|
|
742
726
|
dataFields.forEach(field => {
|
|
743
727
|
const headerIndex = this.dimensionLookup.dataHeaders[field];
|
|
744
728
|
const value = (0, _parseValue.parseValue)(dataRow[headerIndex]);
|
|
745
|
-
|
|
746
|
-
if (value && !isNaN(value)) {
|
|
747
|
-
percentageTotal[field] = (percentageTotal[field] || 0) + value;
|
|
748
|
-
}
|
|
729
|
+
percentageTotal[field] = (0, _addToTotalIfNumber.addToTotalIfNumber)(value, percentageTotal[field]);
|
|
749
730
|
});
|
|
750
731
|
}
|
|
751
732
|
}
|
|
@@ -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;
|
|
@@ -151,8 +151,8 @@ const generateDVItem = (config, _ref3) => {
|
|
|
151
151
|
const svg = document.createElementNS(svgNS, 'svg');
|
|
152
152
|
svg.setAttribute('xmlns', svgNS);
|
|
153
153
|
svg.setAttribute('viewBox', "0 0 ".concat(width, " ").concat(height));
|
|
154
|
-
svg.setAttribute('width',
|
|
155
|
-
svg.setAttribute('height',
|
|
154
|
+
svg.setAttribute('width', width);
|
|
155
|
+
svg.setAttribute('height', height);
|
|
156
156
|
svg.setAttribute('data-test', 'visualization-container');
|
|
157
157
|
|
|
158
158
|
if (backgroundColor) {
|
|
@@ -6,6 +6,7 @@ import { DIMENSION_ID_ORGUNIT } from '../predefinedDimensions.js';
|
|
|
6
6
|
import { renderValue } from '../renderValue.js';
|
|
7
7
|
import { VALUE_TYPE_NUMBER, VALUE_TYPE_TEXT } from '../valueTypes.js';
|
|
8
8
|
import { AdaptiveClippingController } from './AdaptiveClippingController.js';
|
|
9
|
+
import { addToTotalIfNumber } from './addToTotalIfNumber.js';
|
|
9
10
|
import { parseValue } from './parseValue.js';
|
|
10
11
|
import { AGGREGATE_TYPE_NA, AGGREGATE_TYPE_AVERAGE, AGGREGATE_TYPE_SUM, CELL_TYPE_VALUE, CELL_TYPE_TOTAL, CELL_TYPE_SUBTOTAL, SORT_ORDER_ASCENDING, SORT_ORDER_DESCENDING, DISPLAY_DENSITY_PADDING_COMPACT, DISPLAY_DENSITY_PADDING_COMFORTABLE, DISPLAY_DENSITY_OPTION_COMFORTABLE, DISPLAY_DENSITY_OPTION_COMPACT, DISPLAY_DENSITY_OPTION_NORMAL, DISPLAY_DENSITY_PADDING_NORMAL, FONT_SIZE_OPTION_SMALL, FONT_SIZE_SMALL, FONT_SIZE_OPTION_LARGE, FONT_SIZE_LARGE, FONT_SIZE_OPTION_NORMAL, FONT_SIZE_NORMAL, NUMBER_TYPE_COLUMN_PERCENTAGE, NUMBER_TYPE_ROW_PERCENTAGE, NUMBER_TYPE_VALUE } from './pivotTableConstants.js';
|
|
11
12
|
const dataFields = ['value', 'numerator', 'denominator', 'factor', 'multiplier', 'divisor'];
|
|
@@ -609,10 +610,7 @@ export class PivotTableEngine {
|
|
|
609
610
|
dataFields.forEach(field => {
|
|
610
611
|
const headerIndex = this.dimensionLookup.dataHeaders[field];
|
|
611
612
|
const value = parseValue(dataRow[headerIndex]);
|
|
612
|
-
|
|
613
|
-
if (value && !isNaN(value)) {
|
|
614
|
-
totalCell[field] = (totalCell[field] || 0) + value;
|
|
615
|
-
}
|
|
613
|
+
totalCell[field] = addToTotalIfNumber(value, totalCell[field]);
|
|
616
614
|
});
|
|
617
615
|
}
|
|
618
616
|
|
|
@@ -631,10 +629,7 @@ export class PivotTableEngine {
|
|
|
631
629
|
dataFields.forEach(field => {
|
|
632
630
|
const headerIndex = this.dimensionLookup.dataHeaders[field];
|
|
633
631
|
const value = parseValue(dataRow[headerIndex]);
|
|
634
|
-
|
|
635
|
-
if (value && !isNaN(value)) {
|
|
636
|
-
percentageTotal[field] = (percentageTotal[field] || 0) + value;
|
|
637
|
-
}
|
|
632
|
+
percentageTotal[field] = addToTotalIfNumber(value, percentageTotal[field]);
|
|
638
633
|
});
|
|
639
634
|
|
|
640
635
|
if (totals.columnSubtotal) {
|
|
@@ -649,10 +644,7 @@ export class PivotTableEngine {
|
|
|
649
644
|
dataFields.forEach(field => {
|
|
650
645
|
const headerIndex = this.dimensionLookup.dataHeaders[field];
|
|
651
646
|
const value = parseValue(dataRow[headerIndex]);
|
|
652
|
-
|
|
653
|
-
if (value && !isNaN(value)) {
|
|
654
|
-
percentageTotal[field] = (percentageTotal[field] || 0) + value;
|
|
655
|
-
}
|
|
647
|
+
percentageTotal[field] = addToTotalIfNumber(value, percentageTotal[field]);
|
|
656
648
|
});
|
|
657
649
|
}
|
|
658
650
|
|
|
@@ -668,10 +660,7 @@ export class PivotTableEngine {
|
|
|
668
660
|
dataFields.forEach(field => {
|
|
669
661
|
const headerIndex = this.dimensionLookup.dataHeaders[field];
|
|
670
662
|
const value = parseValue(dataRow[headerIndex]);
|
|
671
|
-
|
|
672
|
-
if (value && !isNaN(value)) {
|
|
673
|
-
percentageTotal[field] = (percentageTotal[field] || 0) + value;
|
|
674
|
-
}
|
|
663
|
+
percentageTotal[field] = addToTotalIfNumber(value, percentageTotal[field]);
|
|
675
664
|
});
|
|
676
665
|
}
|
|
677
666
|
}
|
|
@@ -688,10 +677,7 @@ export class PivotTableEngine {
|
|
|
688
677
|
dataFields.forEach(field => {
|
|
689
678
|
const headerIndex = this.dimensionLookup.dataHeaders[field];
|
|
690
679
|
const value = parseValue(dataRow[headerIndex]);
|
|
691
|
-
|
|
692
|
-
if (value && !isNaN(value)) {
|
|
693
|
-
percentageTotal[field] = (percentageTotal[field] || 0) + value;
|
|
694
|
-
}
|
|
680
|
+
percentageTotal[field] = addToTotalIfNumber(value, percentageTotal[field]);
|
|
695
681
|
});
|
|
696
682
|
|
|
697
683
|
if (totals.rowSubtotal) {
|
|
@@ -706,10 +692,7 @@ export class PivotTableEngine {
|
|
|
706
692
|
dataFields.forEach(field => {
|
|
707
693
|
const headerIndex = this.dimensionLookup.dataHeaders[field];
|
|
708
694
|
const value = parseValue(dataRow[headerIndex]);
|
|
709
|
-
|
|
710
|
-
if (value && !isNaN(value)) {
|
|
711
|
-
percentageTotal[field] = (percentageTotal[field] || 0) + value;
|
|
712
|
-
}
|
|
695
|
+
percentageTotal[field] = addToTotalIfNumber(value, percentageTotal[field]);
|
|
713
696
|
});
|
|
714
697
|
}
|
|
715
698
|
|
|
@@ -725,10 +708,7 @@ export class PivotTableEngine {
|
|
|
725
708
|
dataFields.forEach(field => {
|
|
726
709
|
const headerIndex = this.dimensionLookup.dataHeaders[field];
|
|
727
710
|
const value = parseValue(dataRow[headerIndex]);
|
|
728
|
-
|
|
729
|
-
if (value && !isNaN(value)) {
|
|
730
|
-
percentageTotal[field] = (percentageTotal[field] || 0) + value;
|
|
731
|
-
}
|
|
711
|
+
percentageTotal[field] = addToTotalIfNumber(value, percentageTotal[field]);
|
|
732
712
|
});
|
|
733
713
|
}
|
|
734
714
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { addToTotalIfNumber } from '../addToTotalIfNumber.js';
|
|
2
|
+
const tests = [{
|
|
3
|
+
testName: 'negative value',
|
|
4
|
+
value: -1,
|
|
5
|
+
total: undefined,
|
|
6
|
+
expected: -1
|
|
7
|
+
}, {
|
|
8
|
+
testName: 'zero value',
|
|
9
|
+
value: 0,
|
|
10
|
+
total: undefined,
|
|
11
|
+
expected: 0
|
|
12
|
+
}, {
|
|
13
|
+
testName: 'positive value',
|
|
14
|
+
value: 1,
|
|
15
|
+
total: undefined,
|
|
16
|
+
expected: 1
|
|
17
|
+
}, {
|
|
18
|
+
testName: 'null value',
|
|
19
|
+
value: null,
|
|
20
|
+
total: undefined,
|
|
21
|
+
expected: undefined
|
|
22
|
+
}, {
|
|
23
|
+
testName: 'undefined value',
|
|
24
|
+
value: undefined,
|
|
25
|
+
total: undefined,
|
|
26
|
+
expected: undefined
|
|
27
|
+
}, {
|
|
28
|
+
testName: 'string value',
|
|
29
|
+
value: 'string',
|
|
30
|
+
total: undefined,
|
|
31
|
+
expected: undefined
|
|
32
|
+
}, {
|
|
33
|
+
testName: 'negative value with existing total',
|
|
34
|
+
value: -1,
|
|
35
|
+
total: 100,
|
|
36
|
+
expected: 99
|
|
37
|
+
}, {
|
|
38
|
+
testName: 'zero value with existing total',
|
|
39
|
+
value: 0,
|
|
40
|
+
total: 100,
|
|
41
|
+
expected: 100
|
|
42
|
+
}, {
|
|
43
|
+
testName: 'positive value with existing total',
|
|
44
|
+
value: 1,
|
|
45
|
+
total: 100,
|
|
46
|
+
expected: 101
|
|
47
|
+
}, {
|
|
48
|
+
testName: 'null value with existing total',
|
|
49
|
+
value: null,
|
|
50
|
+
total: 100,
|
|
51
|
+
expected: 100
|
|
52
|
+
}, {
|
|
53
|
+
testName: 'undefined value with existing total',
|
|
54
|
+
value: undefined,
|
|
55
|
+
total: 100,
|
|
56
|
+
expected: 100
|
|
57
|
+
}, {
|
|
58
|
+
testName: 'string value with existing total',
|
|
59
|
+
value: 'string',
|
|
60
|
+
total: 100,
|
|
61
|
+
expected: 100
|
|
62
|
+
}];
|
|
63
|
+
describe('addToTotalIfNumber', () => {
|
|
64
|
+
tests.forEach(t => {
|
|
65
|
+
it(t.testName, () => {
|
|
66
|
+
expect(addToTotalIfNumber(t.value, t.total)).toEqual(t.expected);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const addToTotalIfNumber = (value, total) => typeof value === 'number' && Number.isFinite(value) ? (total !== null && total !== void 0 ? total : 0) + value : total;
|
|
@@ -141,8 +141,8 @@ const generateDVItem = (config, _ref3) => {
|
|
|
141
141
|
const svg = document.createElementNS(svgNS, 'svg');
|
|
142
142
|
svg.setAttribute('xmlns', svgNS);
|
|
143
143
|
svg.setAttribute('viewBox', "0 0 ".concat(width, " ").concat(height));
|
|
144
|
-
svg.setAttribute('width',
|
|
145
|
-
svg.setAttribute('height',
|
|
144
|
+
svg.setAttribute('width', width);
|
|
145
|
+
svg.setAttribute('height', height);
|
|
146
146
|
svg.setAttribute('data-test', 'visualization-container');
|
|
147
147
|
|
|
148
148
|
if (backgroundColor) {
|