@dhis2/analytics 29.4.2 → 29.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.
- package/build/cjs/__demo__/AboutAOUnit.stories.js +142 -0
- package/build/cjs/__demo__/PivotTable.event.stories.js +67 -2
- package/build/cjs/__demo__/data/event/eventou.data.json +123 -0
- package/build/cjs/__demo__/data/event/eventou.visualization.json +139 -0
- package/build/cjs/__demo__/data/event/eventstatus.data.hidena.json +122 -0
- package/build/cjs/__demo__/data/event/eventstatus.data.json +132 -0
- package/build/cjs/__demo__/data/event/eventstatus.data.org.json +117 -0
- package/build/cjs/__demo__/data/event/eventstatus.visualization.json +154 -0
- package/build/cjs/__demo__/data/event/integer.data.json +225 -39
- package/build/cjs/__demo__/data/event/integer.visualization.json +3 -1
- package/build/cjs/components/AboutAOUnit/AboutAOUnit.js +15 -8
- package/build/cjs/components/AboutAOUnit/styles/AboutAOUnit.style.js +2 -2
- package/build/cjs/index.js +8 -0
- package/build/cjs/locales/en/translations.json +16 -0
- package/build/cjs/modules/dimensions.js +68 -0
- package/build/cjs/modules/eventVisualization/__tests__/eventVisualization.spec.js +42 -0
- package/build/cjs/modules/eventVisualization/eventVisualization.js +31 -0
- package/build/cjs/modules/response/event/__tests__/response.spec.js +23 -0
- package/build/cjs/modules/response/event/response.js +25 -3
- package/build/es/__demo__/AboutAOUnit.stories.js +132 -0
- package/build/es/__demo__/PivotTable.event.stories.js +63 -1
- package/build/es/__demo__/data/event/eventou.data.json +123 -0
- package/build/es/__demo__/data/event/eventou.visualization.json +139 -0
- package/build/es/__demo__/data/event/eventstatus.data.hidena.json +122 -0
- package/build/es/__demo__/data/event/eventstatus.data.json +132 -0
- package/build/es/__demo__/data/event/eventstatus.data.org.json +117 -0
- package/build/es/__demo__/data/event/eventstatus.visualization.json +154 -0
- package/build/es/__demo__/data/event/integer.data.json +225 -39
- package/build/es/__demo__/data/event/integer.visualization.json +3 -1
- package/build/es/components/AboutAOUnit/AboutAOUnit.js +16 -9
- package/build/es/components/AboutAOUnit/styles/AboutAOUnit.style.js +2 -2
- package/build/es/index.js +4 -0
- package/build/es/locales/en/translations.json +16 -0
- package/build/es/modules/dimensions.js +61 -0
- package/build/es/modules/eventVisualization/__tests__/eventVisualization.spec.js +40 -0
- package/build/es/modules/eventVisualization/eventVisualization.js +25 -0
- package/build/es/modules/response/event/__tests__/response.spec.js +24 -1
- package/build/es/modules/response/event/response.js +23 -2
- package/package.json +9 -7
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { transformEventVisualization } from '../eventVisualization.js';
|
|
2
|
+
const testDim1 = {
|
|
3
|
+
dimension: 'eventDate',
|
|
4
|
+
programStage: {
|
|
5
|
+
id: 'A03MvHHogjR'
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
const testDim2 = {
|
|
9
|
+
dimension: 'enrollmentDate',
|
|
10
|
+
program: {
|
|
11
|
+
id: 'IpHINAT79UW'
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const testDim3 = {
|
|
15
|
+
dimension: 'created'
|
|
16
|
+
};
|
|
17
|
+
const testAxis = [testDim1];
|
|
18
|
+
const testVis = {
|
|
19
|
+
columns: testAxis,
|
|
20
|
+
rows: [testDim2],
|
|
21
|
+
filters: [testDim3]
|
|
22
|
+
};
|
|
23
|
+
describe('eventVisualization', () => {
|
|
24
|
+
describe('transformEventVisualization', () => {
|
|
25
|
+
it('does not modify dimension, axis or vis', () => {
|
|
26
|
+
const newVis = transformEventVisualization(testVis);
|
|
27
|
+
expect(newVis).not.toBe(testVis);
|
|
28
|
+
expect(newVis.columns).not.toBe(testAxis);
|
|
29
|
+
expect(newVis.columns[0]).not.toBe(testDim1);
|
|
30
|
+
});
|
|
31
|
+
it('applies program stage to id', () => {
|
|
32
|
+
const newVis = transformEventVisualization(testVis);
|
|
33
|
+
expect(newVis.columns[0].dimension).toBe('A03MvHHogjR.eventdate');
|
|
34
|
+
});
|
|
35
|
+
it('applies program to id', () => {
|
|
36
|
+
const newVis = transformEventVisualization(testVis);
|
|
37
|
+
expect(newVis.rows[0].dimension).toBe('IpHINAT79UW.enrollmentdate');
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { getHeaderByVis } from '../dimensions.js';
|
|
2
|
+
import { layoutGetAllDimensions } from '../layout/layoutGetAllDimensions.js';
|
|
3
|
+
|
|
4
|
+
// Dimensions saved with program or program stage in an EventVisualization need
|
|
5
|
+
// transformation before we can pass them to the pivot table engine
|
|
6
|
+
|
|
7
|
+
const cloneAxis = axis => axis === null || axis === void 0 ? void 0 : axis.map(dim => ({
|
|
8
|
+
...dim
|
|
9
|
+
}));
|
|
10
|
+
export const transformEventVisualization = vis => {
|
|
11
|
+
// Do not modify the original visualization
|
|
12
|
+
const transformedVis = {
|
|
13
|
+
...vis,
|
|
14
|
+
columns: cloneAxis(vis.columns),
|
|
15
|
+
rows: cloneAxis(vis.rows),
|
|
16
|
+
filters: cloneAxis(vis.filters)
|
|
17
|
+
};
|
|
18
|
+
layoutGetAllDimensions(transformedVis).forEach(dim => {
|
|
19
|
+
var _dim$program$id, _dim$program, _dim$programStage;
|
|
20
|
+
const headerName = getHeaderByVis(dim.dimension);
|
|
21
|
+
const prefix = (_dim$program$id = (_dim$program = dim.program) === null || _dim$program === void 0 ? void 0 : _dim$program.id) !== null && _dim$program$id !== void 0 ? _dim$program$id : (_dim$programStage = dim.programStage) === null || _dim$programStage === void 0 ? void 0 : _dim$programStage.id;
|
|
22
|
+
dim.dimension = prefix ? `${prefix}.${headerName}` : headerName;
|
|
23
|
+
});
|
|
24
|
+
return transformedVis;
|
|
25
|
+
};
|
|
@@ -10,6 +10,9 @@ import responseDatetimeOrg from '../../../../__demo__/data/event/datetime.data.o
|
|
|
10
10
|
import responseTextHideNa from '../../../../__demo__/data/event/email.data.hidena.json';
|
|
11
11
|
import responseText from '../../../../__demo__/data/event/email.data.json';
|
|
12
12
|
import responseTextOrg from '../../../../__demo__/data/event/email.data.org.json';
|
|
13
|
+
import responseEventstatusHideNa from '../../../../__demo__/data/event/eventstatus.data.hidena.json';
|
|
14
|
+
import responseEventstatus from '../../../../__demo__/data/event/eventstatus.data.json';
|
|
15
|
+
import responseEventstatusOrg from '../../../../__demo__/data/event/eventstatus.data.org.json';
|
|
13
16
|
import responseNumericHideNa from '../../../../__demo__/data/event/integer.data.hidena.json';
|
|
14
17
|
import responseNumeric from '../../../../__demo__/data/event/integer.data.json';
|
|
15
18
|
import responseNumericOrg from '../../../../__demo__/data/event/integer.data.org.json';
|
|
@@ -23,8 +26,18 @@ import responseYesOnlyHideNa from '../../../../__demo__/data/event/yesonly.data.
|
|
|
23
26
|
import responseYesOnly from '../../../../__demo__/data/event/yesonly.data.json';
|
|
24
27
|
import responseYesOnlyOrg from '../../../../__demo__/data/event/yesonly.data.org.json';
|
|
25
28
|
import { VALUE_TYPE_AGE, VALUE_TYPE_BOOLEAN, VALUE_TYPE_DATE, VALUE_TYPE_DATETIME, VALUE_TYPE_PERCENTAGE, VALUE_TYPE_TRUE_ONLY } from '../../../valueTypes.js';
|
|
26
|
-
import { getItemFormatterByValueType, transformResponse } from '../response.js';
|
|
29
|
+
import { getItemFormatterByHeaderName, getItemFormatterByValueType, transformResponse } from '../response.js';
|
|
27
30
|
describe('response', () => {
|
|
31
|
+
describe('getItemFormatterByHeaderName', () => {
|
|
32
|
+
it('should return the correct formatter and format correctly', () => {
|
|
33
|
+
expect(getItemFormatterByHeaderName('eventstatus')('ACTIVE')).toBe('Active');
|
|
34
|
+
expect(getItemFormatterByHeaderName('eventstatus')('COMPLETED')).toBe('Completed');
|
|
35
|
+
expect(getItemFormatterByHeaderName('eventstatus')('SCHEDULE')).toBe('Scheduled');
|
|
36
|
+
expect(getItemFormatterByHeaderName('programstatus')('ACTIVE')).toBe('Active');
|
|
37
|
+
expect(getItemFormatterByHeaderName('programstatus')('COMPLETED')).toBe('Completed');
|
|
38
|
+
expect(getItemFormatterByHeaderName('programstatus')('CANCELLED')).toBe('Cancelled');
|
|
39
|
+
});
|
|
40
|
+
});
|
|
28
41
|
describe('getItemFormatterByValueType', () => {
|
|
29
42
|
it('should return the correct formatter and format correctly', () => {
|
|
30
43
|
expect(getItemFormatterByValueType(VALUE_TYPE_BOOLEAN)('1')).toBe('Yes');
|
|
@@ -118,5 +131,15 @@ describe('response', () => {
|
|
|
118
131
|
})).toEqual(responseYesOnlyHideNa);
|
|
119
132
|
});
|
|
120
133
|
});
|
|
134
|
+
describe('eventstatus', () => {
|
|
135
|
+
it('transforms response', () => {
|
|
136
|
+
expect(transformResponse(responseEventstatusOrg)).toEqual(responseEventstatus);
|
|
137
|
+
});
|
|
138
|
+
it('transforms response and hides N/A data', () => {
|
|
139
|
+
expect(transformResponse(responseEventstatusOrg, {
|
|
140
|
+
hideNaData: true
|
|
141
|
+
})).toEqual(responseEventstatusHideNa);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
121
144
|
});
|
|
122
145
|
});
|
|
@@ -3,6 +3,12 @@ import { DIMENSION_ID_ORGUNIT, DIMENSION_ID_PERIOD } from '../../predefinedDimen
|
|
|
3
3
|
import { VALUE_TYPE_AGE, VALUE_TYPE_BOOLEAN, VALUE_TYPE_COORDINATE, VALUE_TYPE_DATE, VALUE_TYPE_DATETIME, VALUE_TYPE_FILE_RESOURCE, VALUE_TYPE_GEOJSON, VALUE_TYPE_IMAGE, VALUE_TYPE_MULTI_TEXT, VALUE_TYPE_PERCENTAGE, VALUE_TYPE_REFERENCE, VALUE_TYPE_TRUE_ONLY } from '../../valueTypes.js';
|
|
4
4
|
import { applyDefaultHandler } from './default.js';
|
|
5
5
|
import { applyOptionSetHandler } from './optionSet.js';
|
|
6
|
+
|
|
7
|
+
// Responses coming from these endpoints need transformation
|
|
8
|
+
// before we can pass it to the pivot table engine:
|
|
9
|
+
// - analytics/events/aggregate
|
|
10
|
+
// - analytics/enrollments/aggregate
|
|
11
|
+
|
|
6
12
|
export const PREFIX_SEPARATOR = '_';
|
|
7
13
|
export const NA_VALUE = '';
|
|
8
14
|
export const NA_VALUE_ITEM = {
|
|
@@ -15,6 +21,18 @@ export const NA_VALUE_ITEM = {
|
|
|
15
21
|
}
|
|
16
22
|
};
|
|
17
23
|
export const UNSUPPORTED_VALUE_TYPES = [VALUE_TYPE_COORDINATE, VALUE_TYPE_GEOJSON, VALUE_TYPE_FILE_RESOURCE, VALUE_TYPE_IMAGE, VALUE_TYPE_MULTI_TEXT, VALUE_TYPE_REFERENCE];
|
|
24
|
+
const STATUSES = {
|
|
25
|
+
ACTIVE: i18n.t('Active'),
|
|
26
|
+
COMPLETED: i18n.t('Completed'),
|
|
27
|
+
SCHEDULE: i18n.t('Scheduled'),
|
|
28
|
+
CANCELLED: i18n.t('Cancelled')
|
|
29
|
+
};
|
|
30
|
+
const formatStatus = value => STATUSES[value] || value;
|
|
31
|
+
export const getItemFormatter = ({
|
|
32
|
+
name,
|
|
33
|
+
valueType
|
|
34
|
+
}) => getItemFormatterByHeaderName(name) || getItemFormatterByValueType(valueType);
|
|
35
|
+
export const getItemFormatterByHeaderName = name => name.endsWith('eventstatus') || name.endsWith('programstatus') ? formatStatus : undefined;
|
|
18
36
|
export const getItemFormatterByValueType = valueType => {
|
|
19
37
|
switch (valueType) {
|
|
20
38
|
case VALUE_TYPE_AGE:
|
|
@@ -31,6 +49,9 @@ export const getItemFormatterByValueType = valueType => {
|
|
|
31
49
|
return undefined;
|
|
32
50
|
}
|
|
33
51
|
};
|
|
52
|
+
const EXCLUDED_HEADER_NAMES = new Set([DIMENSION_ID_PERIOD, DIMENSION_ID_ORGUNIT, 'lastupdated', 'created', 'completed']);
|
|
53
|
+
const EXCLUDED_HEADER_SUFFIXES = ['.eventdate', '.enrollmentdate', '.scheduleddate', '.incidentdate', '.ou'];
|
|
54
|
+
const isIncludedHeader = header => Boolean(header.meta) && !EXCLUDED_HEADER_NAMES.has(header.name) && !EXCLUDED_HEADER_SUFFIXES.some(suffix => header.name.endsWith(suffix));
|
|
34
55
|
export const transformResponse = (response, {
|
|
35
56
|
hideNaData = false
|
|
36
57
|
} = {}) => {
|
|
@@ -54,7 +75,7 @@ export const transformResponse = (response, {
|
|
|
54
75
|
const metaHeaders = response.headers.map((header, index) => ({
|
|
55
76
|
...header,
|
|
56
77
|
index
|
|
57
|
-
})).filter(
|
|
78
|
+
})).filter(isIncludedHeader);
|
|
58
79
|
|
|
59
80
|
// Legendsets use uids and do not need transformation
|
|
60
81
|
// Skip unsupported value types
|
|
@@ -66,7 +87,7 @@ export const transformResponse = (response, {
|
|
|
66
87
|
transformedResponse = applyOptionSetHandler(transformedResponse, header.index);
|
|
67
88
|
} else {
|
|
68
89
|
transformedResponse = applyDefaultHandler(transformedResponse, header.index, {
|
|
69
|
-
itemFormatter:
|
|
90
|
+
itemFormatter: getItemFormatter(header)
|
|
70
91
|
});
|
|
71
92
|
}
|
|
72
93
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dhis2/analytics",
|
|
3
|
-
"version": "29.
|
|
3
|
+
"version": "29.5.0",
|
|
4
4
|
"main": "./build/cjs/index.js",
|
|
5
5
|
"module": "./build/es/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -35,10 +35,8 @@
|
|
|
35
35
|
"@dhis2/cli-style": "^10.7.9",
|
|
36
36
|
"@dhis2/d2-i18n": "^1.1.0",
|
|
37
37
|
"@dhis2/ui": "^10.12.7",
|
|
38
|
-
"@
|
|
39
|
-
"@storybook/
|
|
40
|
-
"@storybook/react": "^8.3.6",
|
|
41
|
-
"@storybook/react-webpack5": "^8.3.6",
|
|
38
|
+
"@storybook/preset-create-react-app": "^10.3.4",
|
|
39
|
+
"@storybook/react-webpack5": "^10.3.4",
|
|
42
40
|
"@testing-library/dom": "^10.4.0",
|
|
43
41
|
"@testing-library/jest-dom": "^6.6.3",
|
|
44
42
|
"@testing-library/react": "^16.3.0",
|
|
@@ -48,8 +46,9 @@
|
|
|
48
46
|
"react": "^18.3.1",
|
|
49
47
|
"react-dom": "^18.3.1",
|
|
50
48
|
"react-scripts": "^5.0.1",
|
|
51
|
-
"storybook": "^
|
|
52
|
-
"styled-jsx": "^4.0.1"
|
|
49
|
+
"storybook": "^10.3.4",
|
|
50
|
+
"styled-jsx": "^4.0.1",
|
|
51
|
+
"eslint-plugin-storybook": "10.3.4"
|
|
53
52
|
},
|
|
54
53
|
"peerDependencies": {
|
|
55
54
|
"@dhis2/app-runtime": "^3",
|
|
@@ -80,5 +79,8 @@
|
|
|
80
79
|
"files": [
|
|
81
80
|
"build"
|
|
82
81
|
],
|
|
82
|
+
"resolutions": {
|
|
83
|
+
"i18next": "^23.0.0"
|
|
84
|
+
},
|
|
83
85
|
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
|
84
86
|
}
|