@dhis2/analytics 26.4.1 → 26.6.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 (89) 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/Analytics.js +7 -0
  4. package/build/cjs/api/analytics/AnalyticsAggregate.js +27 -1
  5. package/build/cjs/api/analytics/AnalyticsBase.js +32 -13
  6. package/build/cjs/api/analytics/AnalyticsRequest.js +33 -10
  7. package/build/cjs/api/analytics/AnalyticsRequestBase.js +12 -6
  8. package/build/cjs/api/analytics/AnalyticsRequestPropertiesMixin.js +19 -0
  9. package/build/cjs/api/analytics/AnalyticsResponse.js +42 -39
  10. package/build/cjs/api/analytics/AnalyticsTrackedEntities.js +31 -0
  11. package/build/cjs/api/analytics/__tests__/Analytics.spec.js +5 -0
  12. package/build/cjs/api/analytics/__tests__/AnalyticsAggregate.spec.js +29 -0
  13. package/build/cjs/api/analytics/__tests__/AnalyticsBase.spec.js +36 -2
  14. package/build/cjs/api/analytics/utils.js +21 -2
  15. package/build/cjs/components/DataDimension/DataDimension.js +31 -7
  16. package/build/cjs/components/DataDimension/DataTypeSelector.js +29 -8
  17. package/build/cjs/components/DataDimension/GroupSelector.js +7 -7
  18. package/build/cjs/components/DataDimension/ItemSelector.js +79 -61
  19. package/build/cjs/components/PeriodDimension/PeriodDimension.js +5 -2
  20. package/build/cjs/components/PeriodDimension/PeriodTransfer.js +64 -31
  21. package/build/cjs/components/PeriodDimension/__tests__/__snapshots__/PeriodDimension.spec.js.snap +1 -1
  22. package/build/cjs/components/PeriodDimension/__tests__/__snapshots__/PeriodSelector.spec.js.snap +1 -12
  23. package/build/cjs/components/VisTypeIcon.js +6 -1
  24. package/build/cjs/index.js +43 -1
  25. package/build/cjs/locales/en/translations.json +5 -1
  26. package/build/cjs/modules/__tests__/getAdaptedUiLayoutByType.spec.js +15 -0
  27. package/build/cjs/modules/axis.js +4 -0
  28. package/build/cjs/modules/getAdaptedUiLayoutByType.js +9 -0
  29. package/build/cjs/modules/layout/axisGetDimensionIds.js +1 -1
  30. package/build/cjs/modules/layout/dimension.js +9 -2
  31. package/build/cjs/modules/layout/dimensionCreate.js +3 -0
  32. package/build/cjs/modules/layout/dimensionGetId.js +9 -3
  33. package/build/cjs/modules/layout/layoutFilterDimensions.js +1 -1
  34. package/build/cjs/modules/layout/layoutGetAxisIdDimensionIdsObject.js +1 -1
  35. package/build/cjs/modules/layout/layoutGetDimensionIdItemIdsObject.js +1 -1
  36. package/build/cjs/modules/layout/layoutHasDynamicDimension.js +1 -1
  37. package/build/cjs/modules/layoutTypes.js +4 -2
  38. package/build/cjs/modules/layoutUiRules/__tests__/rules.spec.js +13 -1
  39. package/build/cjs/modules/layoutUiRules/index.js +12 -0
  40. package/build/cjs/modules/layoutUiRules/rules.js +22 -2
  41. package/build/cjs/modules/layoutUiRules/rulesHelper.js +4 -2
  42. package/build/cjs/modules/layoutUiRules/rulesUtils.js +7 -2
  43. package/build/cjs/modules/visTypeToLayoutType.js +2 -1
  44. package/build/cjs/modules/visTypes.js +9 -3
  45. package/build/es/__fixtures__/fixtures.js +1 -0
  46. package/build/es/__fixtures__/json/api/analytics/outlierDetection.json +213 -0
  47. package/build/es/api/analytics/Analytics.js +7 -0
  48. package/build/es/api/analytics/AnalyticsAggregate.js +27 -1
  49. package/build/es/api/analytics/AnalyticsBase.js +31 -13
  50. package/build/es/api/analytics/AnalyticsRequest.js +33 -10
  51. package/build/es/api/analytics/AnalyticsRequestBase.js +12 -6
  52. package/build/es/api/analytics/AnalyticsRequestPropertiesMixin.js +19 -0
  53. package/build/es/api/analytics/AnalyticsResponse.js +42 -39
  54. package/build/es/api/analytics/AnalyticsTrackedEntities.js +24 -0
  55. package/build/es/api/analytics/__tests__/Analytics.spec.js +5 -0
  56. package/build/es/api/analytics/__tests__/AnalyticsAggregate.spec.js +29 -0
  57. package/build/es/api/analytics/__tests__/AnalyticsBase.spec.js +34 -1
  58. package/build/es/api/analytics/utils.js +18 -1
  59. package/build/es/components/DataDimension/DataDimension.js +27 -6
  60. package/build/es/components/DataDimension/DataTypeSelector.js +30 -9
  61. package/build/es/components/DataDimension/GroupSelector.js +7 -7
  62. package/build/es/components/DataDimension/ItemSelector.js +80 -62
  63. package/build/es/components/PeriodDimension/PeriodDimension.js +5 -2
  64. package/build/es/components/PeriodDimension/PeriodTransfer.js +65 -32
  65. package/build/es/components/PeriodDimension/__tests__/__snapshots__/PeriodDimension.spec.js.snap +1 -1
  66. package/build/es/components/PeriodDimension/__tests__/__snapshots__/PeriodSelector.spec.js.snap +1 -12
  67. package/build/es/components/VisTypeIcon.js +8 -3
  68. package/build/es/index.js +4 -4
  69. package/build/es/locales/en/translations.json +5 -1
  70. package/build/es/modules/__tests__/getAdaptedUiLayoutByType.spec.js +16 -1
  71. package/build/es/modules/axis.js +5 -1
  72. package/build/es/modules/getAdaptedUiLayoutByType.js +10 -1
  73. package/build/es/modules/layout/axisGetDimensionIds.js +1 -1
  74. package/build/es/modules/layout/dimension.js +7 -1
  75. package/build/es/modules/layout/dimensionCreate.js +4 -1
  76. package/build/es/modules/layout/dimensionGetId.js +10 -4
  77. package/build/es/modules/layout/layoutFilterDimensions.js +1 -1
  78. package/build/es/modules/layout/layoutGetAxisIdDimensionIdsObject.js +1 -1
  79. package/build/es/modules/layout/layoutGetDimensionIdItemIdsObject.js +1 -1
  80. package/build/es/modules/layout/layoutHasDynamicDimension.js +1 -1
  81. package/build/es/modules/layoutTypes.js +2 -1
  82. package/build/es/modules/layoutUiRules/__tests__/rules.spec.js +14 -2
  83. package/build/es/modules/layoutUiRules/index.js +2 -2
  84. package/build/es/modules/layoutUiRules/rules.js +22 -3
  85. package/build/es/modules/layoutUiRules/rulesHelper.js +3 -2
  86. package/build/es/modules/layoutUiRules/rulesUtils.js +6 -2
  87. package/build/es/modules/visTypeToLayoutType.js +4 -3
  88. package/build/es/modules/visTypes.js +7 -3
  89. package/package.json +6 -3
@@ -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
+ }
@@ -6,12 +6,15 @@ import AnalyticsEnrollments from './AnalyticsEnrollments.js';
6
6
  import AnalyticsEvents from './AnalyticsEvents.js';
7
7
  import AnalyticsRequest from './AnalyticsRequest.js';
8
8
  import AnalyticsResponse from './AnalyticsResponse.js';
9
+ import AnalyticsTrackedEntities from './AnalyticsTrackedEntities.js';
9
10
 
10
11
  /**
11
12
  * @description
12
13
  * Analytics class used to request analytics data from Web API.
13
14
  *
14
15
  * @requires analytics.AnalyticsAggregate
16
+ * @requires analytics.AnalyticsTrackedEntities
17
+ * @requires analytics.AnalyticsEnrollments
15
18
  * @requires analytics.AnalyticsEvents
16
19
  * @requires analytics.AnalyticsRequest
17
20
  * @requires analytics.AnalyticsResponse
@@ -31,6 +34,7 @@ import AnalyticsResponse from './AnalyticsResponse.js';
31
34
  class Analytics {
32
35
  /**
33
36
  * @param {!module:analytics.AnalyticsAggregate} analyticsAggregate The AnalyticsAggregate instance
37
+ * @param {!module:analytics.AnalyticsTrackedEntities} analyticsTrackedEntities The AnalyticsTrackedEntities instance
34
38
  * @param {!module:analytics.AnalyticsEnrollments} analyticsEnrollments The AnalyticsEnrollments instance
35
39
  * @param {!module:analytics.AnalyticsEvents} analyticsEvents The AnalyticsEvents instance
36
40
  * @param {!module:analytics.AnalyticsRequest} analyticsRequest The AnalyticsRequest class
@@ -39,12 +43,14 @@ class Analytics {
39
43
  constructor(_ref) {
40
44
  let {
41
45
  aggregate,
46
+ trackedEntities,
42
47
  enrollments,
43
48
  events,
44
49
  request,
45
50
  response
46
51
  } = _ref;
47
52
  this.aggregate = aggregate;
53
+ this.trackedEntities = trackedEntities;
48
54
  this.enrollments = enrollments;
49
55
  this.events = events;
50
56
  this.request = request;
@@ -67,6 +73,7 @@ class Analytics {
67
73
  if (!Analytics.getAnalytics.analytics) {
68
74
  Analytics.getAnalytics.analytics = new Analytics({
69
75
  aggregate: new AnalyticsAggregate(dataEngine),
76
+ trackedEntities: new AnalyticsTrackedEntities(dataEngine),
70
77
  enrollments: new AnalyticsEnrollments(dataEngine),
71
78
  events: new AnalyticsEvents(dataEngine),
72
79
  request: AnalyticsRequest,
@@ -68,11 +68,37 @@ class AnalyticsAggregate extends AnalyticsBase {
68
68
  * .withStartDate('2017-10-01')
69
69
  * .withEndDate('2017-10-31');
70
70
  *
71
- * analytics.aggregate.getDebugSql(req);
71
+ * analytics.aggregate.getDebugSql(req)
72
72
  * .then(console.log);
73
73
  */
74
74
  getDebugSql(req) {
75
75
  return this.fetch(req.withPath('debug/sql'));
76
76
  }
77
+
78
+ /**
79
+ * @param {!AnalyticsRequest} req Request object
80
+ *
81
+ * @returns {Promise} Promise that resolves with the SQL statement used to query the database.
82
+ *
83
+ * @example
84
+ * const req = new analytics.request()
85
+ * .withParameters({
86
+ * dx: 'fbfJHSPpUQD,cYeuwXTCPkU',
87
+ * pe: 'THIS_YEAR',
88
+ * ou: 'USER_ORGUNIT,USER_ORGUNIT_CHILDREN',
89
+ * headers: 'dxname,pename,ouname,value,absdev,modifiedzscore,median,lowerbound,upperbound',
90
+ * algorithm: 'MODIFIED_Z_SCORE',
91
+ * maxResults: 100,
92
+ * threshold: 3,
93
+ orderBy: 'value',
94
+ sortOrder: 'desc',
95
+ * });
96
+ *
97
+ * analytics.aggregate.getOutliersData(req)
98
+ * .then(console.log);
99
+ */
100
+ getOutliersData(req) {
101
+ return this.fetch(req.withPath('outlierDetection'));
102
+ }
77
103
  }
78
104
  export default AnalyticsAggregate;
@@ -1,13 +1,19 @@
1
1
  import sortBy from 'lodash/sortBy';
2
2
  import AnalyticsRequest from './AnalyticsRequest.js';
3
+ import { formatRequestPath } from './utils.js';
3
4
  const analyticsQuery = {
4
5
  resource: 'analytics',
5
6
  id: _ref => {
6
7
  let {
7
8
  path,
8
- program
9
+ program,
10
+ trackedEntityType
9
11
  } = _ref;
10
- return [path, program].filter(Boolean).join('/');
12
+ return formatRequestPath({
13
+ path,
14
+ program,
15
+ trackedEntityType
16
+ });
11
17
  },
12
18
  params: _ref2 => {
13
19
  let {
@@ -16,8 +22,8 @@ const analyticsQuery = {
16
22
  parameters
17
23
  } = _ref2;
18
24
  return {
19
- dimension: dimensions,
20
- filter: filters,
25
+ dimension: dimensions.length ? dimensions : undefined,
26
+ filter: filters.length ? filters : undefined,
21
27
  ...parameters
22
28
  };
23
29
  }
@@ -27,9 +33,14 @@ const analyticsDataQuery = {
27
33
  id: _ref3 => {
28
34
  let {
29
35
  path,
30
- program
36
+ program,
37
+ trackedEntityType
31
38
  } = _ref3;
32
- return [path, program].filter(Boolean).join('/');
39
+ return formatRequestPath({
40
+ path,
41
+ program,
42
+ trackedEntityType
43
+ });
33
44
  },
34
45
  params: _ref4 => {
35
46
  let {
@@ -38,8 +49,8 @@ const analyticsDataQuery = {
38
49
  parameters
39
50
  } = _ref4;
40
51
  return {
41
- dimension: dimensions,
42
- filter: filters,
52
+ dimension: dimensions.length ? dimensions : undefined,
53
+ filter: filters.length ? filters : undefined,
43
54
  ...parameters,
44
55
  skipMeta: true,
45
56
  skipData: false
@@ -51,9 +62,14 @@ const analyticsMetaDataQuery = {
51
62
  id: _ref5 => {
52
63
  let {
53
64
  path,
54
- program
65
+ program,
66
+ trackedEntityType
55
67
  } = _ref5;
56
- return [path, program].filter(Boolean).join('/');
68
+ return formatRequestPath({
69
+ path,
70
+ program,
71
+ trackedEntityType
72
+ });
57
73
  },
58
74
  params: _ref6 => {
59
75
  let {
@@ -62,8 +78,8 @@ const analyticsMetaDataQuery = {
62
78
  parameters
63
79
  } = _ref6;
64
80
  return {
65
- dimension: dimensions,
66
- filter: filters,
81
+ dimension: dimensions.length ? dimensions : undefined,
82
+ filter: filters.length ? filters : undefined,
67
83
  ...parameters,
68
84
  skipMeta: false,
69
85
  skipData: true,
@@ -71,7 +87,7 @@ const analyticsMetaDataQuery = {
71
87
  };
72
88
  }
73
89
  };
74
- const generateDimensionStrings = function () {
90
+ export const generateDimensionStrings = function () {
75
91
  let dimensions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
76
92
  let options = arguments.length > 1 ? arguments[1] : undefined;
77
93
  if (options && options.sorted) {
@@ -145,6 +161,7 @@ class AnalyticsBase {
145
161
  variables: {
146
162
  path: req.path,
147
163
  program: req.program,
164
+ trackedEntityType: req.trackedEntityType,
148
165
  dimensions: generateDimensionStrings(req.dimensions),
149
166
  filters: generateDimensionStrings(req.filters),
150
167
  parameters: req.parameters,
@@ -187,6 +204,7 @@ class AnalyticsBase {
187
204
  variables: {
188
205
  path: req.path,
189
206
  program: req.program,
207
+ trackedEntityType: req.trackedEntityType,
190
208
  dimensions: generateDimensionStrings(req.dimensions, options),
191
209
  filters: generateDimensionStrings(req.filters, options),
192
210
  parameters: req.parameters
@@ -4,6 +4,7 @@ import AnalyticsRequestBase from './AnalyticsRequestBase.js';
4
4
  import AnalyticsRequestDimensionsMixin from './AnalyticsRequestDimensionsMixin.js';
5
5
  import AnalyticsRequestFiltersMixin from './AnalyticsRequestFiltersMixin.js';
6
6
  import AnalyticsRequestPropertiesMixin from './AnalyticsRequestPropertiesMixin.js';
7
+ import { formatDimension } from './utils.js';
7
8
 
8
9
  /**
9
10
  * @description
@@ -41,6 +42,7 @@ class AnalyticsRequest extends AnalyticsRequestDimensionsMixin(AnalyticsRequestF
41
42
  fromVisualization(visualization) {
42
43
  let passFilterAsDimension = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
43
44
  let request = this;
45
+ const outputType = visualization.outputType;
44
46
 
45
47
  // extract dimensions from visualization
46
48
  const columns = visualization.columns || [];
@@ -51,19 +53,28 @@ class AnalyticsRequest extends AnalyticsRequestDimensionsMixin(AnalyticsRequestF
51
53
  if ((_d$legendSet = d.legendSet) !== null && _d$legendSet !== void 0 && _d$legendSet.id) {
52
54
  dimension += `-${d.legendSet.id}`;
53
55
  }
54
- if ((_d$programStage = d.programStage) !== null && _d$programStage !== void 0 && _d$programStage.id) {
55
- dimension = `${d.programStage.id}.${dimension}`;
56
- }
57
56
  if (d.filter) {
58
57
  dimension += `:${d.filter}`;
59
58
  }
59
+ const programStageId = (_d$programStage = d.programStage) === null || _d$programStage === void 0 ? void 0 : _d$programStage.id;
60
60
  if ((_d$repetition = d.repetition) !== null && _d$repetition !== void 0 && (_d$repetition$indexes = _d$repetition.indexes) !== null && _d$repetition$indexes !== void 0 && _d$repetition$indexes.length) {
61
61
  d.repetition.indexes.forEach(index => {
62
- request = request.addDimension(dimension.replace(/\./, `[${index}].`));
62
+ var _d$program;
63
+ request = request.addDimension(formatDimension({
64
+ programId: (_d$program = d.program) === null || _d$program === void 0 ? void 0 : _d$program.id,
65
+ programStageId: `${programStageId}[${index}]`,
66
+ dimension,
67
+ outputType
68
+ }));
63
69
  });
64
70
  } else {
65
- var _d$items;
66
- request = request.addDimension(dimension, (_d$items = d.items) === null || _d$items === void 0 ? void 0 : _d$items.map(item => item.id));
71
+ var _d$program2, _d$items;
72
+ request = request.addDimension(formatDimension({
73
+ programId: (_d$program2 = d.program) === null || _d$program2 === void 0 ? void 0 : _d$program2.id,
74
+ programStageId,
75
+ dimension,
76
+ outputType
77
+ }), (_d$items = d.items) === null || _d$items === void 0 ? void 0 : _d$items.map(item => item.id));
67
78
  }
68
79
  });
69
80
 
@@ -78,17 +89,29 @@ class AnalyticsRequest extends AnalyticsRequestDimensionsMixin(AnalyticsRequestF
78
89
  request = request.addDimension(f.dimension, (_f$items = f.items) === null || _f$items === void 0 ? void 0 : _f$items.map(item => item.id));
79
90
  } else {
80
91
  var _f$programStage, _f$repetition, _f$repetition$indexes;
81
- let filterString = (_f$programStage = f.programStage) !== null && _f$programStage !== void 0 && _f$programStage.id ? `${f.programStage.id}.${f.dimension}` : f.dimension;
92
+ let filterString = f.dimension;
82
93
  if (f.filter) {
83
94
  filterString += `:${f.filter}`;
84
95
  }
96
+ const programStageId = (_f$programStage = f.programStage) === null || _f$programStage === void 0 ? void 0 : _f$programStage.id;
85
97
  if ((_f$repetition = f.repetition) !== null && _f$repetition !== void 0 && (_f$repetition$indexes = _f$repetition.indexes) !== null && _f$repetition$indexes !== void 0 && _f$repetition$indexes.length) {
86
98
  f.repetition.indexes.forEach(index => {
87
- request = request.addFilter(filterString.replace(/\./, `[${index}].`));
99
+ var _f$program;
100
+ request = request.addFilter(formatDimension({
101
+ programId: (_f$program = f.program) === null || _f$program === void 0 ? void 0 : _f$program.id,
102
+ programStageId: `${programStageId}[${index}]`,
103
+ dimension: filterString,
104
+ outputType
105
+ }));
88
106
  });
89
107
  } else {
90
- var _f$items2;
91
- request = request.addFilter(filterString, (_f$items2 = f.items) === null || _f$items2 === void 0 ? void 0 : _f$items2.map(item => item.id));
108
+ var _f$program2, _f$items2;
109
+ request = request.addFilter(formatDimension({
110
+ programId: (_f$program2 = f.program) === null || _f$program2 === void 0 ? void 0 : _f$program2.id,
111
+ programStageId,
112
+ dimension: filterString,
113
+ outputType
114
+ }), (_f$items2 = f.items) === null || _f$items2 === void 0 ? void 0 : _f$items2.map(item => item.id));
92
115
  }
93
116
  }
94
117
  });
@@ -18,6 +18,7 @@ class AnalyticsRequestBase {
18
18
  format = 'json',
19
19
  path,
20
20
  program,
21
+ trackedEntityType,
21
22
  dimensions = [],
22
23
  filters = [],
23
24
  parameters = {}
@@ -26,6 +27,7 @@ class AnalyticsRequestBase {
26
27
  this.format = format.toLowerCase();
27
28
  this.path = path;
28
29
  this.program = program;
30
+ this.trackedEntityType = trackedEntityType;
29
31
  this.dimensions = dimensions;
30
32
  this.filters = filters;
31
33
  this.parameters = {
@@ -47,7 +49,7 @@ class AnalyticsRequestBase {
47
49
  buildUrl(options) {
48
50
  // at least 1 dimension is required
49
51
  let dimensions = this.dimensions;
50
- if (options && options.sorted) {
52
+ if (dimensions.length && options !== null && options !== void 0 && options.sorted) {
51
53
  dimensions = sortBy(dimensions, 'dimension');
52
54
  }
53
55
  const encodedDimensions = dimensions.map(_ref => {
@@ -57,15 +59,19 @@ class AnalyticsRequestBase {
57
59
  } = _ref;
58
60
  if (Array.isArray(items) && items.length) {
59
61
  const encodedItems = items.map(customEncodeURIComponent);
60
- if (options && options.sorted) {
62
+ if (options !== null && options !== void 0 && options.sorted) {
61
63
  encodedItems.sort();
62
64
  }
63
65
  return `${dimension}:${encodedItems.join(';')}`;
64
66
  }
65
67
  return dimension;
66
68
  });
67
- const endPoint = [this.endPoint, this.path, this.program].filter(e => !!e).join('/');
68
- return `${endPoint}.${this.format}?dimension=${encodedDimensions.join('&dimension=')}`;
69
+ const endPoint = [this.endPoint, this.path, this.program, this.trackedEntityType].filter(Boolean).join('/');
70
+ let url = `${endPoint}.${this.format}`;
71
+ if (encodedDimensions.length) {
72
+ url += `?dimension=${encodedDimensions.join('&dimension=')}`;
73
+ }
74
+ return url;
69
75
  }
70
76
 
71
77
  /**
@@ -83,7 +89,7 @@ class AnalyticsRequestBase {
83
89
  */
84
90
  buildQuery(options) {
85
91
  let filters = this.filters;
86
- if (options && options.sorted) {
92
+ if (filters.length && options !== null && options !== void 0 && options.sorted) {
87
93
  filters = sortBy(filters, 'dimension');
88
94
  }
89
95
  const encodedFilters = filters.map(_ref2 => {
@@ -93,7 +99,7 @@ class AnalyticsRequestBase {
93
99
  } = _ref2;
94
100
  if (Array.isArray(items) && items.length) {
95
101
  const encodedItems = items.map(customEncodeURIComponent);
96
- if (options && options.sorted) {
102
+ if (options !== null && options !== void 0 && options.sorted) {
97
103
  encodedItems.sort();
98
104
  }
99
105
  return `${dimension}:${encodedItems.join(';')}`;
@@ -491,6 +491,25 @@ class extends base {
491
491
  return new AnalyticsRequest(this);
492
492
  }
493
493
 
494
+ /**
495
+ * Sets the tracked entity type for the request.
496
+ * It appends the tracked entity type id to the request's path.
497
+ *
498
+ * @param {!String} trackedEntityType The tracked entity type id
499
+ *
500
+ * @returns {AnalyticsRequest} A new instance of the class for chaining purposes
501
+ *
502
+ * @example
503
+ * const req = new analytics.request()
504
+ * .withTrackedEntityType('nEenWmSyUEp');
505
+ */
506
+ withTrackedEntityType(trackedEntityType) {
507
+ if (trackedEntityType) {
508
+ this.trackedEntityType = trackedEntityType;
509
+ }
510
+ return new AnalyticsRequest(this);
511
+ }
512
+
494
513
  /**
495
514
  * Sets the program for the request.
496
515
  * It appends the program id to the request's path.
@@ -51,7 +51,8 @@ class AnalyticsResponse {
51
51
  }
52
52
  }
53
53
  extractHeaders() {
54
- const dimensions = this.response.metaData.dimensions;
54
+ // some endpoints (ie. outlierDetection) don't return dimensions in metaData
55
+ const dimensions = this.response.metaData.dimensions || {};
55
56
  const headers = this.response.headers || [];
56
57
  return headers.map((header, index) => new AnalyticsResponseHeader(header, {
57
58
  isPrefix: isPrefixHeader(header, dimensions[header.name]),
@@ -87,48 +88,50 @@ class AnalyticsResponse {
87
88
  items
88
89
  } = metaData;
89
90
 
90
- // populate metaData dimensions and items
91
- this.headers.filter(header => !DEFAULT_COLLECT_IGNORE_HEADERS.includes(header.name)).forEach(header => {
92
- let ids;
91
+ // some endpoints (ie. outlierDetection) don't return dimensions or items
92
+ if (dimensions && items) {
93
+ this.headers.filter(header => !DEFAULT_COLLECT_IGNORE_HEADERS.includes(header.name)).forEach(header => {
94
+ let ids;
93
95
 
94
- // collect row values
95
- if (header.isCollect) {
96
- ids = this.getSortedUniqueRowIdStringsByHeader(header);
97
- dimensions[header.name] = ids;
98
- } else {
99
- ids = dimensions[header.name];
100
- }
101
- if (header.isPrefix) {
102
- // create prefixed dimensions array
103
- dimensions[header.name] = ids.map(id => getPrefixedId(id, header.name));
104
-
105
- // create items
106
- dimensions[header.name].forEach((prefixedId, index) => {
107
- const id = ids[index];
108
- const valueType = header.valueType;
109
- const name = getNameByIdsByValueType(id, valueType);
110
- items[prefixedId] = {
111
- name
112
- };
113
- });
114
- }
115
- });
96
+ // collect row values
97
+ if (header.isCollect) {
98
+ ids = this.getSortedUniqueRowIdStringsByHeader(header);
99
+ dimensions[header.name] = ids;
100
+ } else {
101
+ ids = dimensions[header.name];
102
+ }
103
+ if (header.isPrefix) {
104
+ // create prefixed dimensions array
105
+ dimensions[header.name] = ids.map(id => getPrefixedId(id, header.name));
116
106
 
117
- // for events, add items from 'ouname'
118
- if (this.hasHeader(OUNAME) && this.hasHeader(OU)) {
119
- const ouNameHeaderIndex = this.getHeader(OUNAME).getIndex();
120
- const ouHeaderIndex = this.getHeader(OU).getIndex();
121
- let ouId;
122
- let ouName;
123
- this.rows.forEach(row => {
124
- ouId = row[ouHeaderIndex];
125
- if (items[ouId] === undefined) {
126
- ouName = row[ouNameHeaderIndex];
127
- items[ouId] = {
128
- name: ouName
129
- };
107
+ // create items
108
+ dimensions[header.name].forEach((prefixedId, index) => {
109
+ const id = ids[index];
110
+ const valueType = header.valueType;
111
+ const name = getNameByIdsByValueType(id, valueType);
112
+ items[prefixedId] = {
113
+ name
114
+ };
115
+ });
130
116
  }
131
117
  });
118
+
119
+ // for events, add items from 'ouname'
120
+ if (this.hasHeader(OUNAME) && this.hasHeader(OU)) {
121
+ const ouNameHeaderIndex = this.getHeader(OUNAME).getIndex();
122
+ const ouHeaderIndex = this.getHeader(OU).getIndex();
123
+ let ouId;
124
+ let ouName;
125
+ this.rows.forEach(row => {
126
+ ouId = row[ouHeaderIndex];
127
+ if (items[ouId] === undefined) {
128
+ ouName = row[ouNameHeaderIndex];
129
+ items[ouId] = {
130
+ name: ouName
131
+ };
132
+ }
133
+ });
134
+ }
132
135
  }
133
136
  return metaData;
134
137
  }