@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.
Files changed (39) hide show
  1. package/build/cjs/__demo__/AboutAOUnit.stories.js +142 -0
  2. package/build/cjs/__demo__/PivotTable.event.stories.js +67 -2
  3. package/build/cjs/__demo__/data/event/eventou.data.json +123 -0
  4. package/build/cjs/__demo__/data/event/eventou.visualization.json +139 -0
  5. package/build/cjs/__demo__/data/event/eventstatus.data.hidena.json +122 -0
  6. package/build/cjs/__demo__/data/event/eventstatus.data.json +132 -0
  7. package/build/cjs/__demo__/data/event/eventstatus.data.org.json +117 -0
  8. package/build/cjs/__demo__/data/event/eventstatus.visualization.json +154 -0
  9. package/build/cjs/__demo__/data/event/integer.data.json +225 -39
  10. package/build/cjs/__demo__/data/event/integer.visualization.json +3 -1
  11. package/build/cjs/components/AboutAOUnit/AboutAOUnit.js +15 -8
  12. package/build/cjs/components/AboutAOUnit/styles/AboutAOUnit.style.js +2 -2
  13. package/build/cjs/index.js +8 -0
  14. package/build/cjs/locales/en/translations.json +16 -0
  15. package/build/cjs/modules/dimensions.js +68 -0
  16. package/build/cjs/modules/eventVisualization/__tests__/eventVisualization.spec.js +42 -0
  17. package/build/cjs/modules/eventVisualization/eventVisualization.js +31 -0
  18. package/build/cjs/modules/response/event/__tests__/response.spec.js +23 -0
  19. package/build/cjs/modules/response/event/response.js +25 -3
  20. package/build/es/__demo__/AboutAOUnit.stories.js +132 -0
  21. package/build/es/__demo__/PivotTable.event.stories.js +63 -1
  22. package/build/es/__demo__/data/event/eventou.data.json +123 -0
  23. package/build/es/__demo__/data/event/eventou.visualization.json +139 -0
  24. package/build/es/__demo__/data/event/eventstatus.data.hidena.json +122 -0
  25. package/build/es/__demo__/data/event/eventstatus.data.json +132 -0
  26. package/build/es/__demo__/data/event/eventstatus.data.org.json +117 -0
  27. package/build/es/__demo__/data/event/eventstatus.visualization.json +154 -0
  28. package/build/es/__demo__/data/event/integer.data.json +225 -39
  29. package/build/es/__demo__/data/event/integer.visualization.json +3 -1
  30. package/build/es/components/AboutAOUnit/AboutAOUnit.js +16 -9
  31. package/build/es/components/AboutAOUnit/styles/AboutAOUnit.style.js +2 -2
  32. package/build/es/index.js +4 -0
  33. package/build/es/locales/en/translations.json +16 -0
  34. package/build/es/modules/dimensions.js +61 -0
  35. package/build/es/modules/eventVisualization/__tests__/eventVisualization.spec.js +40 -0
  36. package/build/es/modules/eventVisualization/eventVisualization.js +25 -0
  37. package/build/es/modules/response/event/__tests__/response.spec.js +24 -1
  38. package/build/es/modules/response/event/response.js +23 -2
  39. 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(header => Boolean(header.meta) && ![DIMENSION_ID_PERIOD, DIMENSION_ID_ORGUNIT].includes(header.name));
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: getItemFormatterByValueType(header.valueType)
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.4.2",
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
- "@mihkeleidast/storybook-addon-source": "^1.0.1",
39
- "@storybook/preset-create-react-app": "^8.3.6",
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": "^8.3.6",
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
  }