@dhis2/analytics 26.4.0 → 26.5.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 (79) hide show
  1. package/build/cjs/__fixtures__/fixtures.js +1 -0
  2. package/build/cjs/__fixtures__/json/api/analytics/outlierDetection.json +213 -0
  3. package/build/cjs/api/analytics/AnalyticsAggregate.js +27 -1
  4. package/build/cjs/api/analytics/AnalyticsBase.js +8 -7
  5. package/build/cjs/api/analytics/AnalyticsRequestBase.js +9 -5
  6. package/build/cjs/api/analytics/AnalyticsResponse.js +42 -39
  7. package/build/cjs/api/analytics/__tests__/Analytics.spec.js +5 -0
  8. package/build/cjs/api/analytics/__tests__/AnalyticsAggregate.spec.js +29 -0
  9. package/build/cjs/api/analytics/__tests__/AnalyticsBase.spec.js +36 -2
  10. package/build/cjs/components/DataDimension/DataDimension.js +31 -7
  11. package/build/cjs/components/DataDimension/DataTypeSelector.js +29 -8
  12. package/build/cjs/components/DataDimension/GroupSelector.js +7 -7
  13. package/build/cjs/components/DataDimension/ItemSelector.js +79 -61
  14. package/build/cjs/components/Interpretations/InterpretationModal/InterpretationModal.js +13 -4
  15. package/build/cjs/components/Interpretations/InterpretationModal/InterpretationThread.js +3 -0
  16. package/build/cjs/components/Interpretations/InterpretationsUnit/InterpretationList.js +3 -0
  17. package/build/cjs/components/Interpretations/InterpretationsUnit/InterpretationsUnit.js +15 -4
  18. package/build/cjs/components/Interpretations/common/Interpretation/Interpretation.js +7 -2
  19. package/build/cjs/components/Interpretations/common/Interpretation/useLike.js +12 -2
  20. package/build/cjs/components/PeriodDimension/PeriodDimension.js +5 -2
  21. package/build/cjs/components/PeriodDimension/PeriodTransfer.js +64 -31
  22. package/build/cjs/components/PeriodDimension/__tests__/__snapshots__/PeriodDimension.spec.js.snap +1 -1
  23. package/build/cjs/components/PeriodDimension/__tests__/__snapshots__/PeriodSelector.spec.js.snap +1 -12
  24. package/build/cjs/components/VisTypeIcon.js +6 -1
  25. package/build/cjs/index.js +43 -1
  26. package/build/cjs/locales/en/translations.json +5 -1
  27. package/build/cjs/modules/__tests__/getAdaptedUiLayoutByType.spec.js +15 -0
  28. package/build/cjs/modules/axis.js +4 -0
  29. package/build/cjs/modules/getAdaptedUiLayoutByType.js +9 -0
  30. package/build/cjs/modules/layoutTypes.js +4 -2
  31. package/build/cjs/modules/layoutUiRules/__tests__/rules.spec.js +13 -1
  32. package/build/cjs/modules/layoutUiRules/index.js +12 -0
  33. package/build/cjs/modules/layoutUiRules/rules.js +22 -2
  34. package/build/cjs/modules/layoutUiRules/rulesHelper.js +4 -2
  35. package/build/cjs/modules/layoutUiRules/rulesUtils.js +7 -2
  36. package/build/cjs/modules/visTypeToLayoutType.js +2 -1
  37. package/build/cjs/modules/visTypes.js +9 -3
  38. package/build/cjs/visualizations/config/adapters/dhis_highcharts/subtitle/index.js +3 -2
  39. package/build/cjs/visualizations/config/adapters/dhis_highcharts/title/index.js +3 -2
  40. package/build/es/__fixtures__/fixtures.js +1 -0
  41. package/build/es/__fixtures__/json/api/analytics/outlierDetection.json +213 -0
  42. package/build/es/api/analytics/AnalyticsAggregate.js +27 -1
  43. package/build/es/api/analytics/AnalyticsBase.js +7 -7
  44. package/build/es/api/analytics/AnalyticsRequestBase.js +9 -5
  45. package/build/es/api/analytics/AnalyticsResponse.js +42 -39
  46. package/build/es/api/analytics/__tests__/Analytics.spec.js +5 -0
  47. package/build/es/api/analytics/__tests__/AnalyticsAggregate.spec.js +29 -0
  48. package/build/es/api/analytics/__tests__/AnalyticsBase.spec.js +34 -1
  49. package/build/es/components/DataDimension/DataDimension.js +27 -6
  50. package/build/es/components/DataDimension/DataTypeSelector.js +30 -9
  51. package/build/es/components/DataDimension/GroupSelector.js +7 -7
  52. package/build/es/components/DataDimension/ItemSelector.js +80 -62
  53. package/build/es/components/Interpretations/InterpretationModal/InterpretationModal.js +13 -4
  54. package/build/es/components/Interpretations/InterpretationModal/InterpretationThread.js +3 -0
  55. package/build/es/components/Interpretations/InterpretationsUnit/InterpretationList.js +3 -0
  56. package/build/es/components/Interpretations/InterpretationsUnit/InterpretationsUnit.js +15 -4
  57. package/build/es/components/Interpretations/common/Interpretation/Interpretation.js +7 -2
  58. package/build/es/components/Interpretations/common/Interpretation/useLike.js +12 -2
  59. package/build/es/components/PeriodDimension/PeriodDimension.js +5 -2
  60. package/build/es/components/PeriodDimension/PeriodTransfer.js +65 -32
  61. package/build/es/components/PeriodDimension/__tests__/__snapshots__/PeriodDimension.spec.js.snap +1 -1
  62. package/build/es/components/PeriodDimension/__tests__/__snapshots__/PeriodSelector.spec.js.snap +1 -12
  63. package/build/es/components/VisTypeIcon.js +8 -3
  64. package/build/es/index.js +4 -4
  65. package/build/es/locales/en/translations.json +5 -1
  66. package/build/es/modules/__tests__/getAdaptedUiLayoutByType.spec.js +16 -1
  67. package/build/es/modules/axis.js +5 -1
  68. package/build/es/modules/getAdaptedUiLayoutByType.js +10 -1
  69. package/build/es/modules/layoutTypes.js +2 -1
  70. package/build/es/modules/layoutUiRules/__tests__/rules.spec.js +14 -2
  71. package/build/es/modules/layoutUiRules/index.js +2 -2
  72. package/build/es/modules/layoutUiRules/rules.js +22 -3
  73. package/build/es/modules/layoutUiRules/rulesHelper.js +3 -2
  74. package/build/es/modules/layoutUiRules/rulesUtils.js +6 -2
  75. package/build/es/modules/visTypeToLayoutType.js +4 -3
  76. package/build/es/modules/visTypes.js +7 -3
  77. package/build/es/visualizations/config/adapters/dhis_highcharts/subtitle/index.js +3 -2
  78. package/build/es/visualizations/config/adapters/dhis_highcharts/title/index.js +3 -2
  79. package/package.json +6 -3
@@ -93,6 +93,7 @@ var _default = function x() {
93
93
  addFixture('/api/analytics/cluster', require('./json/api/analytics/cluster.json'));
94
94
  addFixture('/api/analytics/response', require('./json/api/analytics/response.json'));
95
95
  addFixture('/api/analytics/enrollments', require('./json/api/analytics/enrollments.json'));
96
+ addFixture('/api/analytics/outlierDetection', require('./json/api/analytics/outlierDetection.json'));
96
97
  return {
97
98
  get: getFixture,
98
99
  add: addFixture
@@ -0,0 +1,213 @@
1
+ {
2
+ "headers": [
3
+ {
4
+ "name": "dxname",
5
+ "column": "Data name",
6
+ "valueType": "TEXT",
7
+ "type": "java.lang.String",
8
+ "hidden": false,
9
+ "meta": false
10
+ },
11
+ {
12
+ "name": "ouname",
13
+ "column": "Organisation unit name",
14
+ "valueType": "TEXT",
15
+ "type": "java.lang.String",
16
+ "hidden": false,
17
+ "meta": false
18
+ },
19
+ {
20
+ "name": "value",
21
+ "column": "Value",
22
+ "valueType": "NUMBER",
23
+ "type": "java.lang.Double",
24
+ "hidden": false,
25
+ "meta": false
26
+ },
27
+ {
28
+ "name": "absdev",
29
+ "column": "Absolute deviation",
30
+ "valueType": "NUMBER",
31
+ "type": "java.lang.Double",
32
+ "hidden": false,
33
+ "meta": false
34
+ },
35
+ {
36
+ "name": "modifiedzscore",
37
+ "column": "Modified zScore",
38
+ "valueType": "NUMBER",
39
+ "type": "java.lang.Double",
40
+ "hidden": false,
41
+ "meta": false
42
+ },
43
+ {
44
+ "name": "median",
45
+ "column": "Median",
46
+ "valueType": "NUMBER",
47
+ "type": "java.lang.Double",
48
+ "hidden": false,
49
+ "meta": false
50
+ },
51
+ {
52
+ "name": "lowerbound",
53
+ "column": "Lower boundary",
54
+ "valueType": "NUMBER",
55
+ "type": "java.lang.Double",
56
+ "hidden": false,
57
+ "meta": false
58
+ },
59
+ {
60
+ "name": "upperbound",
61
+ "column": "Upper boundary",
62
+ "valueType": "NUMBER",
63
+ "type": "java.lang.Double",
64
+ "hidden": false,
65
+ "meta": false
66
+ }
67
+ ],
68
+ "metaData": {
69
+ "maxResults": 100,
70
+ "count": 13,
71
+ "orderBy": "mean_abs_dev",
72
+ "threshold": 3.0,
73
+ "algorithm": "MOD_Z_SCORE"
74
+ },
75
+ "rowContext": {
76
+
77
+ },
78
+ "rows": [
79
+ [
80
+ "ANC 2nd visit",
81
+ "UMC (Urban Centre) Hospital",
82
+ "1669.0",
83
+ "920.0",
84
+ "3.902767295597484",
85
+ "749.0",
86
+ "-290.93013894085743",
87
+ "1788.9301389408574"
88
+ ],
89
+ [
90
+ "ANC 1st visit",
91
+ "Charlotte CHP",
92
+ "49.0",
93
+ "39.0",
94
+ "7.515857142857143",
95
+ "10.0",
96
+ "-23.948490393535913",
97
+ "43.94849039353591"
98
+ ],
99
+ [
100
+ "ANC 2nd visit",
101
+ "Charlotte CHP",
102
+ "40.0",
103
+ "33.0",
104
+ "22.258499999999998",
105
+ "7.0",
106
+ "-30.86489139031037",
107
+ "44.86489139031037"
108
+ ],
109
+ [
110
+ "ANC 2nd visit",
111
+ "Wilberforce CHC",
112
+ "56.0",
113
+ "24.5",
114
+ "3.004590909090909",
115
+ "31.5",
116
+ "-1.3890179239210454",
117
+ "64.38901792392105"
118
+ ],
119
+ [
120
+ "ANC 1st visit",
121
+ "Deep Eye water MCHP",
122
+ "40.0",
123
+ "16.0",
124
+ "3.5973333333333333",
125
+ "24.0",
126
+ "4.850913859925324",
127
+ "43.14908614007467"
128
+ ],
129
+ [
130
+ "ANC 2nd visit",
131
+ "Lion for Lion Clinic",
132
+ "30.0",
133
+ "16.0",
134
+ "3.5973333333333333",
135
+ "14.0",
136
+ "-5.620896815302167",
137
+ "33.62089681530217"
138
+ ],
139
+ [
140
+ "ANC 2nd visit",
141
+ "Deep Eye water MCHP",
142
+ "33.0",
143
+ "14.5",
144
+ "3.9121",
145
+ "18.5",
146
+ "-3.4245866551686603",
147
+ "40.42458665516866"
148
+ ],
149
+ [
150
+ "ANC 2nd visit",
151
+ "Blessed Mokaka East Clinic",
152
+ "2.0",
153
+ "13.0",
154
+ "4.38425",
155
+ "15.0",
156
+ "-3.417043736713012",
157
+ "33.41704373671301"
158
+ ],
159
+ [
160
+ "ANC 2nd visit",
161
+ "Malambay CHP",
162
+ "15.0",
163
+ "12.0",
164
+ "5.396",
165
+ "3.0",
166
+ "-13.770509831248425",
167
+ "19.770509831248425"
168
+ ],
169
+ [
170
+ "ANC 2nd visit",
171
+ "Wellbody MCHP",
172
+ "20.0",
173
+ "10.0",
174
+ "3.3725",
175
+ "10.0",
176
+ "-10.999999999999996",
177
+ "30.999999999999996"
178
+ ],
179
+ [
180
+ "ANC 1st visit",
181
+ "Blessed Mokaka East Clinic",
182
+ "26.0",
183
+ "10.0",
184
+ "4.496666666666667",
185
+ "16.0",
186
+ "1.6734512181055958",
187
+ "30.326548781894402"
188
+ ],
189
+ [
190
+ "ANC 1st visit",
191
+ "Murray Town CHC",
192
+ "18.0",
193
+ "9.0",
194
+ "6.0705",
195
+ "9.0",
196
+ "-2.43571205496543",
197
+ "20.43571205496543"
198
+ ],
199
+ [
200
+ "ANC 2nd visit",
201
+ "Thompson Bay MCHP",
202
+ "11.0",
203
+ "6.0",
204
+ "4.047",
205
+ "5.0",
206
+ "-2.038266127580332",
207
+ "12.038266127580332"
208
+ ]
209
+ ],
210
+ "headerWidth": 8,
211
+ "width": 8,
212
+ "height": 13
213
+ }
@@ -74,12 +74,38 @@ class AnalyticsAggregate extends _AnalyticsBase.default {
74
74
  * .withStartDate('2017-10-01')
75
75
  * .withEndDate('2017-10-31');
76
76
  *
77
- * analytics.aggregate.getDebugSql(req);
77
+ * analytics.aggregate.getDebugSql(req)
78
78
  * .then(console.log);
79
79
  */
80
80
  getDebugSql(req) {
81
81
  return this.fetch(req.withPath('debug/sql'));
82
82
  }
83
+
84
+ /**
85
+ * @param {!AnalyticsRequest} req Request object
86
+ *
87
+ * @returns {Promise} Promise that resolves with the SQL statement used to query the database.
88
+ *
89
+ * @example
90
+ * const req = new analytics.request()
91
+ * .withParameters({
92
+ * dx: 'fbfJHSPpUQD,cYeuwXTCPkU',
93
+ * pe: 'THIS_YEAR',
94
+ * ou: 'USER_ORGUNIT,USER_ORGUNIT_CHILDREN',
95
+ * headers: 'dxname,pename,ouname,value,absdev,modifiedzscore,median,lowerbound,upperbound',
96
+ * algorithm: 'MODIFIED_Z_SCORE',
97
+ * maxResults: 100,
98
+ * threshold: 3,
99
+ orderBy: 'value',
100
+ sortOrder: 'desc',
101
+ * });
102
+ *
103
+ * analytics.aggregate.getOutliersData(req)
104
+ * .then(console.log);
105
+ */
106
+ getOutliersData(req) {
107
+ return this.fetch(req.withPath('outlierDetection'));
108
+ }
83
109
  }
84
110
  var _default = AnalyticsAggregate;
85
111
  exports.default = _default;
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.default = void 0;
6
+ exports.generateDimensionStrings = exports.default = void 0;
7
7
  var _sortBy = _interopRequireDefault(require("lodash/sortBy"));
8
8
  var _AnalyticsRequest = _interopRequireDefault(require("./AnalyticsRequest.js"));
9
9
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -23,8 +23,8 @@ const analyticsQuery = {
23
23
  parameters
24
24
  } = _ref2;
25
25
  return {
26
- dimension: dimensions,
27
- filter: filters,
26
+ dimension: dimensions.length ? dimensions : undefined,
27
+ filter: filters.length ? filters : undefined,
28
28
  ...parameters
29
29
  };
30
30
  }
@@ -45,8 +45,8 @@ const analyticsDataQuery = {
45
45
  parameters
46
46
  } = _ref4;
47
47
  return {
48
- dimension: dimensions,
49
- filter: filters,
48
+ dimension: dimensions.length ? dimensions : undefined,
49
+ filter: filters.length ? filters : undefined,
50
50
  ...parameters,
51
51
  skipMeta: true,
52
52
  skipData: false
@@ -69,8 +69,8 @@ const analyticsMetaDataQuery = {
69
69
  parameters
70
70
  } = _ref6;
71
71
  return {
72
- dimension: dimensions,
73
- filter: filters,
72
+ dimension: dimensions.length ? dimensions : undefined,
73
+ filter: filters.length ? filters : undefined,
74
74
  ...parameters,
75
75
  skipMeta: false,
76
76
  skipData: true,
@@ -110,6 +110,7 @@ const generateDimensionStrings = function () {
110
110
  * @memberof module:analytics
111
111
  * @abstract
112
112
  */
113
+ exports.generateDimensionStrings = generateDimensionStrings;
113
114
  class AnalyticsBase {
114
115
  constructor(dataEngine) {
115
116
  this.dataEngine = dataEngine;
@@ -53,7 +53,7 @@ class AnalyticsRequestBase {
53
53
  buildUrl(options) {
54
54
  // at least 1 dimension is required
55
55
  let dimensions = this.dimensions;
56
- if (options && options.sorted) {
56
+ if (dimensions.length && options !== null && options !== void 0 && options.sorted) {
57
57
  dimensions = (0, _sortBy.default)(dimensions, 'dimension');
58
58
  }
59
59
  const encodedDimensions = dimensions.map(_ref => {
@@ -63,7 +63,7 @@ class AnalyticsRequestBase {
63
63
  } = _ref;
64
64
  if (Array.isArray(items) && items.length) {
65
65
  const encodedItems = items.map(_utils.customEncodeURIComponent);
66
- if (options && options.sorted) {
66
+ if (options !== null && options !== void 0 && options.sorted) {
67
67
  encodedItems.sort();
68
68
  }
69
69
  return `${dimension}:${encodedItems.join(';')}`;
@@ -71,7 +71,11 @@ class AnalyticsRequestBase {
71
71
  return dimension;
72
72
  });
73
73
  const endPoint = [this.endPoint, this.path, this.program].filter(e => !!e).join('/');
74
- return `${endPoint}.${this.format}?dimension=${encodedDimensions.join('&dimension=')}`;
74
+ let url = `${endPoint}.${this.format}`;
75
+ if (encodedDimensions.length) {
76
+ url += `?dimension=${encodedDimensions.join('&dimension=')}`;
77
+ }
78
+ return url;
75
79
  }
76
80
 
77
81
  /**
@@ -89,7 +93,7 @@ class AnalyticsRequestBase {
89
93
  */
90
94
  buildQuery(options) {
91
95
  let filters = this.filters;
92
- if (options && options.sorted) {
96
+ if (filters.length && options !== null && options !== void 0 && options.sorted) {
93
97
  filters = (0, _sortBy.default)(filters, 'dimension');
94
98
  }
95
99
  const encodedFilters = filters.map(_ref2 => {
@@ -99,7 +103,7 @@ class AnalyticsRequestBase {
99
103
  } = _ref2;
100
104
  if (Array.isArray(items) && items.length) {
101
105
  const encodedItems = items.map(_utils.customEncodeURIComponent);
102
- if (options && options.sorted) {
106
+ if (options !== null && options !== void 0 && options.sorted) {
103
107
  encodedItems.sort();
104
108
  }
105
109
  return `${dimension}:${encodedItems.join(';')}`;
@@ -58,7 +58,8 @@ class AnalyticsResponse {
58
58
  }
59
59
  }
60
60
  extractHeaders() {
61
- const dimensions = this.response.metaData.dimensions;
61
+ // some endpoints (ie. outlierDetection) don't return dimensions in metaData
62
+ const dimensions = this.response.metaData.dimensions || {};
62
63
  const headers = this.response.headers || [];
63
64
  return headers.map((header, index) => new _AnalyticsResponseHeader.default(header, {
64
65
  isPrefix: isPrefixHeader(header, dimensions[header.name]),
@@ -94,48 +95,50 @@ class AnalyticsResponse {
94
95
  items
95
96
  } = metaData;
96
97
 
97
- // populate metaData dimensions and items
98
- this.headers.filter(header => !DEFAULT_COLLECT_IGNORE_HEADERS.includes(header.name)).forEach(header => {
99
- let ids;
98
+ // some endpoints (ie. outlierDetection) don't return dimensions or items
99
+ if (dimensions && items) {
100
+ this.headers.filter(header => !DEFAULT_COLLECT_IGNORE_HEADERS.includes(header.name)).forEach(header => {
101
+ let ids;
100
102
 
101
- // collect row values
102
- if (header.isCollect) {
103
- ids = this.getSortedUniqueRowIdStringsByHeader(header);
104
- dimensions[header.name] = ids;
105
- } else {
106
- ids = dimensions[header.name];
107
- }
108
- if (header.isPrefix) {
109
- // create prefixed dimensions array
110
- dimensions[header.name] = ids.map(id => getPrefixedId(id, header.name));
111
-
112
- // create items
113
- dimensions[header.name].forEach((prefixedId, index) => {
114
- const id = ids[index];
115
- const valueType = header.valueType;
116
- const name = getNameByIdsByValueType(id, valueType);
117
- items[prefixedId] = {
118
- name
119
- };
120
- });
121
- }
122
- });
103
+ // collect row values
104
+ if (header.isCollect) {
105
+ ids = this.getSortedUniqueRowIdStringsByHeader(header);
106
+ dimensions[header.name] = ids;
107
+ } else {
108
+ ids = dimensions[header.name];
109
+ }
110
+ if (header.isPrefix) {
111
+ // create prefixed dimensions array
112
+ dimensions[header.name] = ids.map(id => getPrefixedId(id, header.name));
123
113
 
124
- // for events, add items from 'ouname'
125
- if (this.hasHeader(OUNAME) && this.hasHeader(OU)) {
126
- const ouNameHeaderIndex = this.getHeader(OUNAME).getIndex();
127
- const ouHeaderIndex = this.getHeader(OU).getIndex();
128
- let ouId;
129
- let ouName;
130
- this.rows.forEach(row => {
131
- ouId = row[ouHeaderIndex];
132
- if (items[ouId] === undefined) {
133
- ouName = row[ouNameHeaderIndex];
134
- items[ouId] = {
135
- name: ouName
136
- };
114
+ // create items
115
+ dimensions[header.name].forEach((prefixedId, index) => {
116
+ const id = ids[index];
117
+ const valueType = header.valueType;
118
+ const name = getNameByIdsByValueType(id, valueType);
119
+ items[prefixedId] = {
120
+ name
121
+ };
122
+ });
137
123
  }
138
124
  });
125
+
126
+ // for events, add items from 'ouname'
127
+ if (this.hasHeader(OUNAME) && this.hasHeader(OU)) {
128
+ const ouNameHeaderIndex = this.getHeader(OUNAME).getIndex();
129
+ const ouHeaderIndex = this.getHeader(OU).getIndex();
130
+ let ouId;
131
+ let ouName;
132
+ this.rows.forEach(row => {
133
+ ouId = row[ouHeaderIndex];
134
+ if (items[ouId] === undefined) {
135
+ ouName = row[ouNameHeaderIndex];
136
+ items[ouId] = {
137
+ name: ouName
138
+ };
139
+ }
140
+ });
141
+ }
139
142
  }
140
143
  return metaData;
141
144
  }
@@ -2,6 +2,7 @@
2
2
 
3
3
  var _Analytics = _interopRequireDefault(require("../Analytics.js"));
4
4
  var _AnalyticsAggregate = _interopRequireDefault(require("../AnalyticsAggregate.js"));
5
+ var _AnalyticsEnrollments = _interopRequireDefault(require("../AnalyticsEnrollments.js"));
5
6
  var _AnalyticsEvents = _interopRequireDefault(require("../AnalyticsEvents.js"));
6
7
  var _AnalyticsRequest = _interopRequireDefault(require("../AnalyticsRequest.js"));
7
8
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -10,6 +11,7 @@ describe('Analytics', () => {
10
11
  beforeEach(() => {
11
12
  analytics = new _Analytics.default({
12
13
  aggregate: new _AnalyticsAggregate.default(),
14
+ enrollments: new _AnalyticsEnrollments.default(),
13
15
  events: new _AnalyticsEvents.default(),
14
16
  request: _AnalyticsRequest.default
15
17
  });
@@ -23,6 +25,9 @@ describe('Analytics', () => {
23
25
  it('should contain an instance of AnalyticsAggregate', () => {
24
26
  expect(analytics.aggregate).toBeInstanceOf(_AnalyticsAggregate.default);
25
27
  });
28
+ it('should contain an instance of AnalyticsEnrollments', () => {
29
+ expect(analytics.enrollments).toBeInstanceOf(_AnalyticsEnrollments.default);
30
+ });
26
31
  it('should contain an instance of AnalyticsEvents', () => {
27
32
  expect(analytics.events).toBeInstanceOf(_AnalyticsEvents.default);
28
33
  });
@@ -87,4 +87,33 @@ describe('Analytics.aggregate', () => {
87
87
  expect(data.height).toEqual(0);
88
88
  }));
89
89
  });
90
+ describe('.getOutliersData', () => {
91
+ beforeEach(() => {
92
+ aggregate = new _AnalyticsAggregate.default(new _DataEngine.default());
93
+ request = new _AnalyticsRequest.default();
94
+ request.withParameters({
95
+ dx: 'fbfJHSPpUQD,cYeuwXTCPkU',
96
+ pe: 'THIS_YEAR',
97
+ ou: 'at6UHUQatSo',
98
+ headers: 'dxname,pename,ouname,value,absdev,modifiedzscore,median,lowerbound,upperbound',
99
+ algorithm: 'MOD_Z_SCORE',
100
+ maxResults: 100,
101
+ threshold: 3
102
+ });
103
+ fixture = _fixtures.default.get('/api/analytics/outlierDetection');
104
+ dataEngineMock.query.mockReturnValue(Promise.resolve({
105
+ data: fixture
106
+ }));
107
+ });
108
+ it('should be a function', () => {
109
+ expect(aggregate.getOutliersData).toBeInstanceOf(Function);
110
+ });
111
+ it('should resolve a promise with data', () => aggregate.getOutliersData(request).then(data => {
112
+ expect(data.metaData.items).toEqual(fixture.metaData.items);
113
+ expect(data.metaData.dimensions).toEqual(fixture.metaData.dimensions);
114
+ expect(data.headers).toEqual(fixture.headers);
115
+ expect(data.width).toEqual(8);
116
+ expect(data.height).toEqual(13);
117
+ }));
118
+ });
90
119
  });
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
 
3
- var _AnalyticsBase = _interopRequireDefault(require("../AnalyticsBase.js"));
4
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
3
+ var _AnalyticsBase = _interopRequireWildcard(require("../AnalyticsBase.js"));
4
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
5
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
5
6
  let base;
6
7
  describe('constructor', () => {
7
8
  beforeEach(() => {
@@ -15,4 +16,37 @@ describe('constructor', () => {
15
16
  base = new _AnalyticsBase.default(dataEngineMock);
16
17
  expect(base.dataEngine).toBe(dataEngineMock);
17
18
  });
19
+ });
20
+ describe('generateDimensionString', () => {
21
+ const tests = [{
22
+ input: [{
23
+ dimension: 'dim2',
24
+ items: ['item2', 'item1']
25
+ }, {
26
+ dimension: 'dim1',
27
+ items: ['item1']
28
+ }],
29
+ output: ['dim2:item2;item1', 'dim1:item1'],
30
+ outputSorted: ['dim1:item1', 'dim2:item1;item2']
31
+ }];
32
+ it('should return dimension strings correctly formatted', () => {
33
+ tests.forEach(_ref => {
34
+ let {
35
+ input,
36
+ output
37
+ } = _ref;
38
+ expect((0, _AnalyticsBase.generateDimensionStrings)(input)).toEqual(output);
39
+ });
40
+ });
41
+ it('should return dimension strings correctly formatted and sorted', () => {
42
+ tests.forEach(_ref2 => {
43
+ let {
44
+ input,
45
+ outputSorted
46
+ } = _ref2;
47
+ expect((0, _AnalyticsBase.generateDimensionStrings)(input, {
48
+ sorted: true
49
+ })).toEqual(outputSorted);
50
+ });
51
+ });
18
52
  });
@@ -3,25 +3,40 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.default = void 0;
6
+ exports.useDataDimensionContext = exports.default = void 0;
7
7
  var _appRuntime = require("@dhis2/app-runtime");
8
8
  var _propTypes = _interopRequireDefault(require("prop-types"));
9
- var _react = _interopRequireDefault(require("react"));
9
+ var _react = _interopRequireWildcard(require("react"));
10
+ var _dataTypes = require("../../modules/dataTypes.js");
10
11
  var _predefinedDimensions = require("../../modules/predefinedDimensions.js");
11
12
  var _ItemSelector = _interopRequireDefault(require("./ItemSelector.js"));
13
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
14
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
12
15
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16
+ const DataDimensionCtx = /*#__PURE__*/(0, _react.createContext)({});
13
17
  const DataDimension = _ref => {
14
18
  let {
15
19
  onSelect,
16
20
  selectedDimensions,
17
21
  displayNameProp,
22
+ enabledDataTypes,
18
23
  infoBoxMessage,
19
- onCalculationSave
24
+ onCalculationSave,
25
+ visType
20
26
  } = _ref;
21
27
  const {
22
28
  serverVersion
23
29
  } = (0, _appRuntime.useConfig)();
24
- const supportsEDI = `${serverVersion.major}.${serverVersion.minor}.${serverVersion.patch || 0}` >= '2.40.0';
30
+ const filterDataTypesByVersion = (0, _react.useCallback)(dataTypes => dataTypes.filter(_ref2 => {
31
+ let {
32
+ id
33
+ } = _ref2;
34
+ return (
35
+ // Calculations only available from 2.40
36
+ id !== _dataTypes.DIMENSION_TYPE_EXPRESSION_DIMENSION_ITEM || serverVersion.minor >= 40
37
+ );
38
+ }), [serverVersion.minor]);
39
+ const [dataTypes, setDataTypes] = (0, _react.useState)(filterDataTypesByVersion(enabledDataTypes || Object.values(_dataTypes.dataTypeMap)));
25
40
  const onSelectItems = selectedItem => onSelect({
26
41
  dimensionId: _predefinedDimensions.DIMENSION_ID_DATA,
27
42
  items: selectedItem.map(item => ({
@@ -31,7 +46,12 @@ const DataDimension = _ref => {
31
46
  expression: item.expression
32
47
  }))
33
48
  });
34
- return /*#__PURE__*/_react.default.createElement(_ItemSelector.default, {
49
+ (0, _react.useEffect)(() => enabledDataTypes && setDataTypes(filterDataTypesByVersion(enabledDataTypes)), [enabledDataTypes, filterDataTypesByVersion]);
50
+ return /*#__PURE__*/_react.default.createElement(DataDimensionCtx.Provider, {
51
+ value: {
52
+ visType
53
+ }
54
+ }, /*#__PURE__*/_react.default.createElement(_ItemSelector.default, {
35
55
  selectedItems: selectedDimensions.map(item => ({
36
56
  value: item.id,
37
57
  label: item.name,
@@ -44,9 +64,9 @@ const DataDimension = _ref => {
44
64
  displayNameProp: displayNameProp,
45
65
  infoBoxMessage: infoBoxMessage,
46
66
  dataTest: 'data-dimension',
47
- supportsEDI: supportsEDI,
67
+ dataTypes: dataTypes,
48
68
  onEDISave: onCalculationSave
49
- });
69
+ }));
50
70
  };
51
71
  DataDimension.propTypes = {
52
72
  displayNameProp: _propTypes.default.string.isRequired,
@@ -58,12 +78,16 @@ DataDimension.propTypes = {
58
78
  type: _propTypes.default.string
59
79
  })).isRequired,
60
80
  onSelect: _propTypes.default.func.isRequired,
81
+ enabledDataTypes: _propTypes.default.array,
61
82
  infoBoxMessage: _propTypes.default.string,
83
+ visType: _propTypes.default.string,
62
84
  onCalculationSave: _propTypes.default.func
63
85
  };
64
86
  DataDimension.defaultProps = {
65
87
  selectedDimensions: [],
66
88
  onSelect: Function.prototype
67
89
  };
90
+ const useDataDimensionContext = () => (0, _react.useContext)(DataDimensionCtx);
91
+ exports.useDataDimensionContext = useDataDimensionContext;
68
92
  var _default = DataDimension;
69
93
  exports.default = _default;