diff --git a/src/__demo__/PivotTable.event.stories.js b/src/__demo__/PivotTable.event.stories.js
index e0fdd1e85..4ff446efb 100644
--- a/src/__demo__/PivotTable.event.stories.js
+++ b/src/__demo__/PivotTable.event.stories.js
@@ -13,6 +13,11 @@ import datetimeVisualization from './data/event/datetime.visualization.json'
import emailDataHideNa from './data/event/email.data.hidena.json'
import emailData from './data/event/email.data.json'
import emailVisualization from './data/event/email.visualization.json'
+import eventouData from './data/event/eventou.data.json'
+import eventouVisualization from './data/event/eventou.visualization.json'
+import eventstatusDataHideNa from './data/event/eventstatus.data.hidena.json'
+import eventstatusData from './data/event/eventstatus.data.json'
+import eventstatusVisualization from './data/event/eventstatus.visualization.json'
import integerDataHideNa from './data/event/integer.data.hidena.json'
import integerData from './data/event/integer.data.json'
import integerVisualization from './data/event/integer.visualization.json'
@@ -385,3 +390,54 @@ export const Yesonly = (_, { pivotTableOptions }) => {
}
Yesonly.storyName = 'Yesonly'
+
+export const EventstatusNA = (_, { pivotTableOptions }) => {
+ const visualization = {
+ ...eventstatusVisualization,
+ ...visualizationReset,
+ ...pivotTableOptions,
+ }
+
+ return (
+
+ )
+}
+
+EventstatusNA.storyName = 'Eventstatus N/A'
+
+export const Eventstatus = (_, { pivotTableOptions }) => {
+ const visualization = {
+ ...eventstatusVisualization,
+ ...visualizationReset,
+ ...pivotTableOptions,
+ }
+
+ return (
+
+ )
+}
+
+Eventstatus.storyName = 'Eventstatus'
+
+export const Eventou = (_, { pivotTableOptions }) => {
+ const visualization = {
+ ...eventouVisualization,
+ ...visualizationReset,
+ ...pivotTableOptions,
+ }
+
+ return (
+
+ )
+}
+
+Eventou.storyName = 'Event orgunit'
diff --git a/src/__demo__/data/event/eventou.data.json b/src/__demo__/data/event/eventou.data.json
new file mode 100644
index 000000000..b91914b4e
--- /dev/null
+++ b/src/__demo__/data/event/eventou.data.json
@@ -0,0 +1,123 @@
+{
+ "headers": [
+ {
+ "name": "A03MvHHogjR.ou",
+ "column": "Organisation unit",
+ "valueType": "ORGANISATION_UNIT",
+ "type": "org.hisp.dhis.organisationunit.OrganisationUnit",
+ "hidden": false,
+ "meta": true
+ },
+ {
+ "name": "A03MvHHogjR.eventdate",
+ "column": "Report date",
+ "valueType": "DATE",
+ "type": "java.time.LocalDate",
+ "hidden": false,
+ "meta": true
+ },
+ {
+ "name": "value",
+ "column": "Value",
+ "valueType": "NUMBER",
+ "type": "java.lang.Double",
+ "hidden": false,
+ "meta": false
+ }
+ ],
+ "metaData": {
+ "items": {
+ "202510": {
+ "name": "202510"
+ },
+ "202511": {
+ "name": "202511"
+ },
+ "202512": {
+ "name": "202512"
+ },
+ "202601": {
+ "name": "202601"
+ },
+ "202602": {
+ "name": "202602"
+ },
+ "202603": {
+ "name": "202603"
+ },
+ "IpHINAT79UW": {
+ "name": "Child Programme"
+ },
+ "ZzYYXq4fJie": {
+ "name": "Baby Postnatal"
+ },
+ "USER_ORGUNIT": {
+ "organisationUnits": [
+ "ImspTQPwCqd"
+ ]
+ },
+ "A03MvHHogjR.ou": {
+ "name": "Organisation unit"
+ },
+ "ImspTQPwCqd": {
+ "name": "Sierra Leone"
+ },
+ "A03MvHHogjR.eventdate": {
+ "name": "Report date"
+ },
+ "A03MvHHogjR": {
+ "name": "Birth"
+ }
+ },
+ "dimensions": {
+ "A03MvHHogjR.eventdate": [
+ "202510",
+ "202511",
+ "202512",
+ "202601",
+ "202602",
+ "202603"
+ ],
+ "pe": [],
+ "A03MvHHogjR.ou": [
+ "ImspTQPwCqd"
+ ]
+ }
+ },
+ "rowContext": {},
+ "width": 3,
+ "rows": [
+ [
+ "ImspTQPwCqd",
+ "202510",
+ "973"
+ ],
+ [
+ "ImspTQPwCqd",
+ "202511",
+ "932"
+ ],
+ [
+ "ImspTQPwCqd",
+ "202512",
+ "858"
+ ],
+ [
+ "ImspTQPwCqd",
+ "202601",
+ "694"
+ ],
+ [
+ "ImspTQPwCqd",
+ "202602",
+ "629"
+ ],
+ [
+ "ImspTQPwCqd",
+ "202603",
+ "694"
+ ]
+ ],
+ "headerWidth": 3,
+ "height": 6
+}
\ No newline at end of file
diff --git a/src/__demo__/data/event/eventou.visualization.json b/src/__demo__/data/event/eventou.visualization.json
new file mode 100644
index 000000000..b75aad7d6
--- /dev/null
+++ b/src/__demo__/data/event/eventou.visualization.json
@@ -0,0 +1,139 @@
+{
+ "name": "Event orgunit",
+ "created": "2025-07-02T10:27:50.483",
+ "lastUpdated": "2025-07-02T10:27:50.483",
+ "translations": [],
+ "createdBy": {
+ "id": "xE7jOejl9FI",
+ "code": null,
+ "name": "John Traore",
+ "displayName": "John Traore",
+ "username": "admin"
+ },
+ "favorites": [],
+ "lastUpdatedBy": {
+ "id": "xE7jOejl9FI",
+ "code": null,
+ "name": "John Traore",
+ "displayName": "John Traore",
+ "username": "admin"
+ },
+ "sharing": {
+ "owner": "xE7jOejl9FI",
+ "external": false,
+ "users": {},
+ "userGroups": {},
+ "public": "rw------"
+ },
+ "regressionType": "NONE",
+ "displayDensity": "NORMAL",
+ "fontSize": "NORMAL",
+ "sortOrder": 0,
+ "topLimit": 0,
+ "hideEmptyRows": false,
+ "showHierarchy": false,
+ "completedOnly": false,
+ "skipRounding": false,
+ "dataDimensionItems": [],
+ "dataElementGroupSetDimensions": [],
+ "organisationUnitGroupSetDimensions": [],
+ "categoryDimensions": [],
+ "categoryOptionGroupSetDimensions": [],
+ "attributeDimensions": [],
+ "programIndicatorDimensions": [],
+ "subscribers": [],
+ "digitGroupSeparator": "SPACE",
+ "hideEmptyRowItems": "NONE",
+ "hideLegend": false,
+ "noSpaceBetweenColumns": false,
+ "cumulativeValues": false,
+ "percentStackedValues": false,
+ "showData": false,
+ "colTotals": true,
+ "rowTotals": true,
+ "rowSubTotals": true,
+ "colSubTotals": true,
+ "hideTitle": false,
+ "hideSubtitle": false,
+ "showDimensionLabels": true,
+ "interpretations": [],
+ "program": {
+ "enrollmentDateLabel": "Date of enrollment",
+ "incidentDateLabel": "Date of birth",
+ "id": "IpHINAT79UW",
+ "name": "Child Programme"
+ },
+ "programStage": {
+ "executionDateLabel": "Report date",
+ "id": "A03MvHHogjR",
+ "name": "Birth"
+ },
+ "dataType": "AGGREGATED_VALUES",
+ "outputType": "EVENT",
+ "collapseDataDimensions": false,
+ "hideNaData": false,
+ "simpleDimensions": [
+ {
+ "parent": "COLUMN",
+ "dimension": "ou",
+ "values": [
+ "ImspTQPwCqd"
+ ]
+ }
+ ],
+ "legacy": true,
+ "type": "PIVOT_TABLE",
+ "filters": [],
+ "parentGraphMap": {
+ "ImspTQPwCqd": ""
+ },
+ "columns": [
+ {
+ "items": [
+ {
+ "name": "Sierra Leone",
+ "id": "ImspTQPwCqd"
+ }
+ ],
+ "dimension": "A03MvHHogjR.ou",
+ "programStage": {
+ "id": "A03MvHHogjR"
+ }
+ }
+ ],
+ "rows": [
+ {
+ "items": [
+ {
+ "dimensionItemType": "PERIOD",
+ "id": "LAST_6_MONTHS"
+ }
+ ],
+ "dimension": "A03MvHHogjR.eventdate",
+ "programStage": {
+ "id": "A03MvHHogjR"
+ }
+ }
+ ],
+ "displayName": "Event orgunit",
+ "access": {
+ "manage": true,
+ "externalize": true,
+ "write": true,
+ "read": true,
+ "update": true,
+ "delete": true
+ },
+ "user": {
+ "id": "xE7jOejl9FI",
+ "code": null,
+ "name": "John Traore",
+ "displayName": "John Traore",
+ "username": "admin"
+ },
+ "favorite": false,
+ "subscribed": false,
+ "displayFormName": "Event orgunit",
+ "id": "xLPn5T11Vd4",
+ "attributeValues": []
+}
\ No newline at end of file
diff --git a/src/__demo__/data/event/eventstatus.data.hidena.json b/src/__demo__/data/event/eventstatus.data.hidena.json
new file mode 100644
index 000000000..3c5631b0e
--- /dev/null
+++ b/src/__demo__/data/event/eventstatus.data.hidena.json
@@ -0,0 +1,122 @@
+{
+ "headers": [
+ {
+ "name": "A03MvHHogjR.ou",
+ "column": "Organisation unit",
+ "valueType": "ORGANISATION_UNIT",
+ "type": "org.hisp.dhis.organisationunit.OrganisationUnit",
+ "hidden": false,
+ "meta": true
+ },
+ {
+ "name": "A03MvHHogjR.eventdate",
+ "column": "Report date",
+ "valueType": "DATE",
+ "type": "java.time.LocalDate",
+ "hidden": false,
+ "meta": true
+ },
+ {
+ "name": "A03MvHHogjR.eventstatus",
+ "column": "Event status",
+ "valueType": "TEXT",
+ "type": "java.lang.String",
+ "hidden": false,
+ "meta": true
+ },
+ {
+ "name": "value",
+ "column": "Value",
+ "valueType": "NUMBER",
+ "type": "java.lang.Double",
+ "hidden": false,
+ "meta": false
+ }
+ ],
+ "metaData": {
+ "items": {
+ "202511": {
+ "name": "202511"
+ },
+ "202512": {
+ "name": "202512"
+ },
+ "202601": {
+ "name": "202601"
+ },
+ "ImspTQPwCqd": {
+ "name": "Sierra Leone"
+ },
+ "A03MvHHogjR.eventdate": {
+ "name": "Report date"
+ },
+ "A03MvHHogjR.eventstatus": {
+ "name": "Event status"
+ },
+ "A03MvHHogjR.eventstatus_ACTIVE": {
+ "name": "Active"
+ },
+ "IpHINAT79UW": {
+ "name": "Child Programme"
+ },
+ "ZzYYXq4fJie": {
+ "name": "Baby Postnatal"
+ },
+ "USER_ORGUNIT": {
+ "organisationUnits": [
+ "ImspTQPwCqd"
+ ]
+ },
+ "A03MvHHogjR": {
+ "name": "Birth"
+ },
+ "A03MvHHogjR.ou": {
+ "name": "Organisation unit"
+ }
+ },
+ "dimensions": {
+ "A03MvHHogjR.eventdate": [
+ "202511",
+ "202512",
+ "202601"
+ ],
+ "A03MvHHogjR.eventstatus": [
+ "A03MvHHogjR.eventstatus_ACTIVE"
+ ],
+ "pe": [],
+ "A03MvHHogjR.ou": [
+ "ImspTQPwCqd"
+ ]
+ }
+ },
+ "rowContext": {},
+ "width": 4,
+ "headerWidth": 4,
+ "height": 3,
+ "rows": [
+ [
+ "ImspTQPwCqd",
+ "202511",
+ "A03MvHHogjR.eventstatus_ACTIVE",
+ "925"
+ ],
+ [
+ "ImspTQPwCqd",
+ "202512",
+ "A03MvHHogjR.eventstatus_ACTIVE",
+ "858"
+ ],
+ [
+ "ImspTQPwCqd",
+ "202601",
+ "A03MvHHogjR.eventstatus_ACTIVE",
+ "690"
+ ],
+ [
+ "ImspTQPwCqd",
+ "202511",
+ "",
+ "12"
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/src/__demo__/data/event/eventstatus.data.json b/src/__demo__/data/event/eventstatus.data.json
new file mode 100644
index 000000000..21e306b6c
--- /dev/null
+++ b/src/__demo__/data/event/eventstatus.data.json
@@ -0,0 +1,132 @@
+{
+ "headers": [
+ {
+ "name": "A03MvHHogjR.ou",
+ "column": "Organisation unit",
+ "valueType": "ORGANISATION_UNIT",
+ "type": "org.hisp.dhis.organisationunit.OrganisationUnit",
+ "hidden": false,
+ "meta": true
+ },
+ {
+ "name": "A03MvHHogjR.eventdate",
+ "column": "Report date",
+ "valueType": "DATE",
+ "type": "java.time.LocalDate",
+ "hidden": false,
+ "meta": true
+ },
+ {
+ "name": "A03MvHHogjR.eventstatus",
+ "column": "Event status",
+ "valueType": "TEXT",
+ "type": "java.lang.String",
+ "hidden": false,
+ "meta": true
+ },
+ {
+ "name": "value",
+ "column": "Value",
+ "valueType": "NUMBER",
+ "type": "java.lang.Double",
+ "hidden": false,
+ "meta": false
+ }
+ ],
+ "metaData": {
+ "items": {
+ "202511": {
+ "name": "202511"
+ },
+ "202512": {
+ "name": "202512"
+ },
+ "202601": {
+ "name": "202601"
+ },
+ "ImspTQPwCqd": {
+ "name": "Sierra Leone"
+ },
+ "A03MvHHogjR.eventdate": {
+ "name": "Report date"
+ },
+ "A03MvHHogjR.eventstatus": {
+ "name": "Event status"
+ },
+ "A03MvHHogjR.eventstatus_ACTIVE": {
+ "name": "Active"
+ },
+ "IpHINAT79UW": {
+ "name": "Child Programme"
+ },
+ "ZzYYXq4fJie": {
+ "name": "Baby Postnatal"
+ },
+ "USER_ORGUNIT": {
+ "organisationUnits": [
+ "ImspTQPwCqd"
+ ]
+ },
+ "A03MvHHogjR": {
+ "name": "Birth"
+ },
+ "A03MvHHogjR.ou": {
+ "name": "Organisation unit"
+ },
+ "": {
+ "name": "No value",
+ "style": {
+ "fontStyle": "italic",
+ "color": "#6C7787",
+ "fontFamily": "monospace",
+ "letterSpacing": "-0.3px"
+ }
+ }
+ },
+ "dimensions": {
+ "A03MvHHogjR.eventdate": [
+ "202511",
+ "202512",
+ "202601"
+ ],
+ "A03MvHHogjR.eventstatus": [
+ "A03MvHHogjR.eventstatus_ACTIVE",
+ ""
+ ],
+ "pe": [],
+ "A03MvHHogjR.ou": [
+ "ImspTQPwCqd"
+ ]
+ }
+ },
+ "rowContext": {},
+ "width": 4,
+ "headerWidth": 4,
+ "height": 3,
+ "rows": [
+ [
+ "ImspTQPwCqd",
+ "202511",
+ "A03MvHHogjR.eventstatus_ACTIVE",
+ "925"
+ ],
+ [
+ "ImspTQPwCqd",
+ "202512",
+ "A03MvHHogjR.eventstatus_ACTIVE",
+ "858"
+ ],
+ [
+ "ImspTQPwCqd",
+ "202601",
+ "A03MvHHogjR.eventstatus_ACTIVE",
+ "690"
+ ],
+ [
+ "ImspTQPwCqd",
+ "202511",
+ "",
+ "12"
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/src/__demo__/data/event/eventstatus.data.org.json b/src/__demo__/data/event/eventstatus.data.org.json
new file mode 100644
index 000000000..23823ef9a
--- /dev/null
+++ b/src/__demo__/data/event/eventstatus.data.org.json
@@ -0,0 +1,117 @@
+{
+ "headers": [
+ {
+ "name": "A03MvHHogjR.ou",
+ "column": "Organisation unit",
+ "valueType": "ORGANISATION_UNIT",
+ "type": "org.hisp.dhis.organisationunit.OrganisationUnit",
+ "hidden": false,
+ "meta": true
+ },
+ {
+ "name": "A03MvHHogjR.eventdate",
+ "column": "Report date",
+ "valueType": "DATE",
+ "type": "java.time.LocalDate",
+ "hidden": false,
+ "meta": true
+ },
+ {
+ "name": "A03MvHHogjR.eventstatus",
+ "column": "Event status",
+ "valueType": "TEXT",
+ "type": "java.lang.String",
+ "hidden": false,
+ "meta": true
+ },
+ {
+ "name": "value",
+ "column": "Value",
+ "valueType": "NUMBER",
+ "type": "java.lang.Double",
+ "hidden": false,
+ "meta": false
+ }
+ ],
+ "metaData": {
+ "items": {
+ "202511": {
+ "name": "202511"
+ },
+ "202512": {
+ "name": "202512"
+ },
+ "202601": {
+ "name": "202601"
+ },
+ "ImspTQPwCqd": {
+ "name": "Sierra Leone"
+ },
+ "A03MvHHogjR.eventdate": {
+ "name": "Report date"
+ },
+ "A03MvHHogjR.eventstatus": {
+ "name": "Event status"
+ },
+ "IpHINAT79UW": {
+ "name": "Child Programme"
+ },
+ "ZzYYXq4fJie": {
+ "name": "Baby Postnatal"
+ },
+ "USER_ORGUNIT": {
+ "organisationUnits": [
+ "ImspTQPwCqd"
+ ]
+ },
+ "A03MvHHogjR": {
+ "name": "Birth"
+ },
+ "A03MvHHogjR.ou": {
+ "name": "Organisation unit"
+ }
+ },
+ "dimensions": {
+ "A03MvHHogjR.eventdate": [
+ "202511",
+ "202512",
+ "202601"
+ ],
+ "A03MvHHogjR.eventstatus": [],
+ "pe": [],
+ "A03MvHHogjR.ou": [
+ "ImspTQPwCqd"
+ ]
+ }
+ },
+ "rowContext": {},
+ "width": 4,
+ "headerWidth": 4,
+ "height": 3,
+ "rows": [
+ [
+ "ImspTQPwCqd",
+ "202511",
+ "ACTIVE",
+ "925"
+ ],
+ [
+ "ImspTQPwCqd",
+ "202512",
+ "ACTIVE",
+ "858"
+ ],
+ [
+ "ImspTQPwCqd",
+ "202601",
+ "ACTIVE",
+ "690"
+ ],
+ [
+ "ImspTQPwCqd",
+ "202511",
+ "",
+ "12"
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/src/__demo__/data/event/eventstatus.visualization.json b/src/__demo__/data/event/eventstatus.visualization.json
new file mode 100644
index 000000000..04dd512b6
--- /dev/null
+++ b/src/__demo__/data/event/eventstatus.visualization.json
@@ -0,0 +1,154 @@
+{
+ "name": "Event status",
+ "created": "2025-07-02T10:27:50.483",
+ "lastUpdated": "2025-07-02T10:27:50.483",
+ "translations": [],
+ "createdBy": {
+ "id": "xE7jOejl9FI",
+ "code": null,
+ "name": "John Traore",
+ "displayName": "John Traore",
+ "username": "admin"
+ },
+ "favorites": [],
+ "lastUpdatedBy": {
+ "id": "xE7jOejl9FI",
+ "code": null,
+ "name": "John Traore",
+ "displayName": "John Traore",
+ "username": "admin"
+ },
+ "sharing": {
+ "owner": "xE7jOejl9FI",
+ "external": false,
+ "users": {},
+ "userGroups": {},
+ "public": "rw------"
+ },
+ "regressionType": "NONE",
+ "displayDensity": "NORMAL",
+ "fontSize": "NORMAL",
+ "sortOrder": 0,
+ "topLimit": 0,
+ "hideEmptyRows": false,
+ "showHierarchy": false,
+ "completedOnly": false,
+ "skipRounding": false,
+ "dataDimensionItems": [],
+ "dataElementGroupSetDimensions": [],
+ "organisationUnitGroupSetDimensions": [],
+ "categoryDimensions": [],
+ "categoryOptionGroupSetDimensions": [],
+ "attributeDimensions": [],
+ "programIndicatorDimensions": [],
+ "subscribers": [],
+ "digitGroupSeparator": "SPACE",
+ "hideEmptyRowItems": "NONE",
+ "hideLegend": false,
+ "noSpaceBetweenColumns": false,
+ "cumulativeValues": false,
+ "percentStackedValues": false,
+ "showData": false,
+ "colTotals": true,
+ "rowTotals": true,
+ "rowSubTotals": true,
+ "colSubTotals": true,
+ "hideTitle": false,
+ "hideSubtitle": false,
+ "showDimensionLabels": true,
+ "interpretations": [],
+ "program": {
+ "enrollmentDateLabel": "Date of enrollment",
+ "incidentDateLabel": "Date of birth",
+ "id": "IpHINAT79UW",
+ "name": "Child Programme"
+ },
+ "programStage": {
+ "executionDateLabel": "Report date",
+ "id": "A03MvHHogjR",
+ "name": "Birth"
+ },
+ "dataType": "AGGREGATED_VALUES",
+ "outputType": "EVENT",
+ "collapseDataDimensions": false,
+ "hideNaData": false,
+ "simpleDimensions": [
+ {
+ "parent": "COLUMN",
+ "dimension": "ou",
+ "values": [
+ "ImspTQPwCqd"
+ ]
+ }
+ ],
+ "legacy": true,
+ "type": "PIVOT_TABLE",
+ "filters": [],
+ "parentGraphMap": {
+ "ImspTQPwCqd": ""
+ },
+ "columns": [
+ {
+ "items": [
+ {
+ "name": "Sierra Leone",
+ "id": "ImspTQPwCqd"
+ }
+ ],
+ "dimension": "A03MvHHogjR.ou",
+ "programStage": {
+ "id": "A03MvHHogjR"
+ }
+ },
+ {
+ "items": [],
+ "programStage": {
+ "id": "A03MvHHogjR"
+ },
+ "dimension": "A03MvHHogjR.eventstatus"
+ }
+ ],
+ "rows": [
+ {
+ "items": [
+ {
+ "dimensionItemType": "PERIOD",
+ "id": "202512"
+ },
+ {
+ "dimensionItemType": "PERIOD",
+ "id": "202511"
+ },
+ {
+ "dimensionItemType": "PERIOD",
+ "id": "202510"
+ }
+ ],
+ "dimension": "A03MvHHogjR.eventdate",
+ "programStage": {
+ "id": "A03MvHHogjR"
+ }
+ }
+ ],
+ "displayName": "Email",
+ "access": {
+ "manage": true,
+ "externalize": true,
+ "write": true,
+ "read": true,
+ "update": true,
+ "delete": true
+ },
+ "user": {
+ "id": "xE7jOejl9FI",
+ "code": null,
+ "name": "John Traore",
+ "displayName": "John Traore",
+ "username": "admin"
+ },
+ "favorite": false,
+ "subscribed": false,
+ "displayFormName": "Email",
+ "id": "xLPn5T11Vd4",
+ "attributeValues": []
+}
\ No newline at end of file
diff --git a/src/__demo__/data/event/integer.data.json b/src/__demo__/data/event/integer.data.json
index fc8d9f0e6..1a45381e8 100644
--- a/src/__demo__/data/event/integer.data.json
+++ b/src/__demo__/data/event/integer.data.json
@@ -112,7 +112,11 @@
}
},
"dimensions": {
- "pe": ["202503", "202504", "202505"],
+ "pe": [
+ "202503",
+ "202504",
+ "202505"
+ ],
"Zj7UnCAulEk.qrur9Dvnyt5": [
"Zj7UnCAulEk.qrur9Dvnyt5_0",
"Zj7UnCAulEk.qrur9Dvnyt5_1",
@@ -127,49 +131,231 @@
"Zj7UnCAulEk.qrur9Dvnyt5_10",
""
],
- "ou": ["ImspTQPwCqd"]
+ "ou": [
+ "ImspTQPwCqd"
+ ]
}
},
"rowContext": {},
"width": 4,
"rows": [
- ["Zj7UnCAulEk.qrur9Dvnyt5_8", "ImspTQPwCqd", "202503", "47"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_3", "ImspTQPwCqd", "202505", "67"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_0", "ImspTQPwCqd", "202503", "55"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_5", "ImspTQPwCqd", "202503", "70"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_10", "ImspTQPwCqd", "202505", "61"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_7", "ImspTQPwCqd", "202505", "52"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_9", "ImspTQPwCqd", "202504", "54"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_6", "ImspTQPwCqd", "202505", "65"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_9", "ImspTQPwCqd", "202505", "54"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_6", "ImspTQPwCqd", "202503", "53"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_2", "ImspTQPwCqd", "202504", "45"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_10", "ImspTQPwCqd", "202503", "51"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_2", "ImspTQPwCqd", "202505", "51"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_3", "ImspTQPwCqd", "202504", "38"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_2", "ImspTQPwCqd", "202503", "41"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_8", "ImspTQPwCqd", "202504", "44"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_7", "ImspTQPwCqd", "202504", "40"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_4", "ImspTQPwCqd", "202505", "41"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_4", "ImspTQPwCqd", "202504", "42"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_9", "ImspTQPwCqd", "202503", "52"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_0", "ImspTQPwCqd", "202504", "55"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_8", "ImspTQPwCqd", "202505", "43"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_5", "ImspTQPwCqd", "202504", "63"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_6", "ImspTQPwCqd", "202504", "53"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_4", "ImspTQPwCqd", "202503", "54"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_10", "ImspTQPwCqd", "202504", "46"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_1", "ImspTQPwCqd", "202503", "44"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_7", "ImspTQPwCqd", "202503", "47"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_5", "ImspTQPwCqd", "202505", "46"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_0", "ImspTQPwCqd", "202505", "50"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_1", "ImspTQPwCqd", "202504", "48"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_1", "ImspTQPwCqd", "202505", "53"],
- ["Zj7UnCAulEk.qrur9Dvnyt5_3", "ImspTQPwCqd", "202503", "56"],
- ["", "ImspTQPwCqd", "202505", "5"],
- ["", "ImspTQPwCqd", "202504", "12"],
- ["", "ImspTQPwCqd", "202503", "10"]
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_8",
+ "ImspTQPwCqd",
+ "202503",
+ "47"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_3",
+ "ImspTQPwCqd",
+ "202505",
+ "67"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_0",
+ "ImspTQPwCqd",
+ "202503",
+ "55"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_5",
+ "ImspTQPwCqd",
+ "202503",
+ "70"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_10",
+ "ImspTQPwCqd",
+ "202505",
+ "61"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_7",
+ "ImspTQPwCqd",
+ "202505",
+ "52"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_9",
+ "ImspTQPwCqd",
+ "202504",
+ "54"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_6",
+ "ImspTQPwCqd",
+ "202505",
+ "65"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_9",
+ "ImspTQPwCqd",
+ "202505",
+ "54"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_6",
+ "ImspTQPwCqd",
+ "202503",
+ "53"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_2",
+ "ImspTQPwCqd",
+ "202504",
+ "45"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_10",
+ "ImspTQPwCqd",
+ "202503",
+ "51"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_2",
+ "ImspTQPwCqd",
+ "202505",
+ "51"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_3",
+ "ImspTQPwCqd",
+ "202504",
+ "38"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_2",
+ "ImspTQPwCqd",
+ "202503",
+ "41"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_8",
+ "ImspTQPwCqd",
+ "202504",
+ "44"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_7",
+ "ImspTQPwCqd",
+ "202504",
+ "40"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_4",
+ "ImspTQPwCqd",
+ "202505",
+ "41"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_4",
+ "ImspTQPwCqd",
+ "202504",
+ "42"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_9",
+ "ImspTQPwCqd",
+ "202503",
+ "52"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_0",
+ "ImspTQPwCqd",
+ "202504",
+ "55"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_8",
+ "ImspTQPwCqd",
+ "202505",
+ "43"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_5",
+ "ImspTQPwCqd",
+ "202504",
+ "63"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_6",
+ "ImspTQPwCqd",
+ "202504",
+ "53"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_4",
+ "ImspTQPwCqd",
+ "202503",
+ "54"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_10",
+ "ImspTQPwCqd",
+ "202504",
+ "46"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_1",
+ "ImspTQPwCqd",
+ "202503",
+ "44"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_7",
+ "ImspTQPwCqd",
+ "202503",
+ "47"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_5",
+ "ImspTQPwCqd",
+ "202505",
+ "46"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_0",
+ "ImspTQPwCqd",
+ "202505",
+ "50"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_1",
+ "ImspTQPwCqd",
+ "202504",
+ "48"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_1",
+ "ImspTQPwCqd",
+ "202505",
+ "53"
+ ],
+ [
+ "Zj7UnCAulEk.qrur9Dvnyt5_3",
+ "ImspTQPwCqd",
+ "202503",
+ "56"
+ ],
+ [
+ "",
+ "ImspTQPwCqd",
+ "202505",
+ "5"
+ ],
+ [
+ "",
+ "ImspTQPwCqd",
+ "202504",
+ "12"
+ ],
+ [
+ "",
+ "ImspTQPwCqd",
+ "202503",
+ "10"
+ ]
],
"height": 267,
"headerWidth": 4
-}
+}
\ No newline at end of file
diff --git a/src/__demo__/data/event/integer.visualization.json b/src/__demo__/data/event/integer.visualization.json
index 9f2d66272..3b127ab9f 100644
--- a/src/__demo__/data/event/integer.visualization.json
+++ b/src/__demo__/data/event/integer.visualization.json
@@ -87,7 +87,9 @@
{
"parent": "COLUMN",
"dimension": "ou",
- "values": ["ImspTQPwCqd"]
+ "values": [
+ "ImspTQPwCqd"
+ ]
}
],
"legacy": true,
diff --git a/src/index.js b/src/index.js
index 976210f68..eabb4c277 100644
--- a/src/index.js
+++ b/src/index.js
@@ -334,6 +334,10 @@ export { renderValue as formatValue } from './modules/renderValue.js'
export { transformResponse as transformEventAggregateResponse } from './modules/response/event/response.js'
+// Modules: eventVisualization
+
+export { transformEventVisualization } from './modules/eventVisualization/eventVisualization.js'
+
// Utils: colorSets
export {
COLOR_SET_DEFAULT,
diff --git a/src/modules/dimensions.js b/src/modules/dimensions.js
new file mode 100644
index 000000000..71e62ce06
--- /dev/null
+++ b/src/modules/dimensions.js
@@ -0,0 +1,74 @@
+// vis: 'dimension' in EventVisualization columns/rows/filters
+// dim: tracker analytics api dimension/filter id
+// header: tracker analytics api header name (query endpoints)
+
+const EVENT_DIMENSIONS = [
+ {
+ vis: 'ou',
+ dim: 'ou',
+ header: 'ouname',
+ },
+ {
+ vis: 'eventDate',
+ dim: 'EVENT_DATE',
+ header: 'eventdate',
+ },
+ {
+ vis: 'enrollmentDate',
+ dim: 'ENROLLMENT_DATE',
+ header: 'enrollmentdate',
+ },
+ {
+ vis: 'scheduledDate',
+ dim: 'SCHEDULED_DATE',
+ header: 'scheduleddate',
+ },
+ {
+ vis: 'incidentDate',
+ dim: 'INCIDENT_DATE',
+ header: 'incidentdate',
+ },
+ {
+ vis: 'lastUpdated',
+ dim: 'LAST_UPDATED',
+ header: 'lastupdated',
+ },
+ {
+ vis: 'created',
+ dim: 'CREATED',
+ header: 'created',
+ },
+ {
+ vis: 'completed',
+ dim: 'COMPLETED',
+ header: 'completed',
+ },
+ {
+ vis: 'eventStatus',
+ dim: 'EVENT_STATUS',
+ header: 'eventstatus',
+ },
+ {
+ vis: 'programStatus',
+ dim: 'PROGRAM_STATUS',
+ header: 'programstatus',
+ },
+ {
+ vis: 'enrollmentOu',
+ dim: 'ENROLLMENT_OU',
+ header: 'enrollmentouname',
+ },
+ {
+ vis: 'createdBy',
+ dim: '',
+ header: 'createdbydisplayname',
+ },
+ {
+ vis: 'lastUpdatedBy',
+ dim: '',
+ header: 'lastupdatedbydisplayname',
+ },
+]
+
+export const getHeaderByVis = (vis) =>
+ EVENT_DIMENSIONS.find((d) => d.vis === vis)?.header
diff --git a/src/modules/eventVisualization/__tests__/eventVisualization.spec.js b/src/modules/eventVisualization/__tests__/eventVisualization.spec.js
new file mode 100644
index 000000000..8fb07d9d8
--- /dev/null
+++ b/src/modules/eventVisualization/__tests__/eventVisualization.spec.js
@@ -0,0 +1,48 @@
+import { transformEventVisualization } from '../eventVisualization.js'
+
+const testDim1 = {
+ dimension: 'eventDate',
+ programStage: {
+ id: 'A03MvHHogjR',
+ },
+}
+
+const testDim2 = {
+ dimension: 'enrollmentDate',
+ program: {
+ id: 'IpHINAT79UW',
+ },
+}
+
+const testDim3 = {
+ dimension: 'created',
+}
+
+const testAxis = [testDim1]
+
+const testVis = {
+ columns: testAxis,
+ rows: [testDim2],
+ filters: [testDim3],
+}
+
+describe('eventVisualization', () => {
+ describe('transformEventVisualization', () => {
+ it('does not modify dimension, axis or vis', () => {
+ const newVis = transformEventVisualization(testVis)
+ expect(newVis).not.toBe(testVis)
+ expect(newVis.columns).not.toBe(testAxis)
+ expect(newVis.columns[0]).not.toBe(testDim1)
+ })
+
+ it('applies program stage to id', () => {
+ const newVis = transformEventVisualization(testVis)
+ expect(newVis.columns[0].dimension).toBe('A03MvHHogjR.eventdate')
+ })
+
+ it('applies program to id', () => {
+ const newVis = transformEventVisualization(testVis)
+ expect(newVis.rows[0].dimension).toBe('IpHINAT79UW.enrollmentdate')
+ })
+ })
+})
diff --git a/src/modules/eventVisualization/eventVisualization.js b/src/modules/eventVisualization/eventVisualization.js
new file mode 100644
index 000000000..520fd3ba8
--- /dev/null
+++ b/src/modules/eventVisualization/eventVisualization.js
@@ -0,0 +1,26 @@
+import { getHeaderByVis } from '../dimensions.js'
+import { layoutGetAllDimensions } from '../layout/layoutGetAllDimensions.js'
+
+// Dimensions saved with program or program stage in an EventVisualization need
+// transformation before we can pass them to the pivot table engine
+
+const cloneAxis = (axis) => axis?.map((dim) => ({ ...dim }))
+
+export const transformEventVisualization = (vis) => {
+ // Do not modify the original visualization
+ const transformedVis = {
+ ...vis,
+ columns: cloneAxis(vis.columns),
+ rows: cloneAxis(vis.rows),
+ filters: cloneAxis(vis.filters),
+ }
+
+ layoutGetAllDimensions(transformedVis).forEach((dim) => {
+ const headerName = getHeaderByVis(dim.dimension)
+ const prefix = dim.program?.id ?? dim.programStage?.id
+
+ dim.dimension = prefix ? `${prefix}.${headerName}` : headerName
+ })
+
+ return transformedVis
+}
diff --git a/src/modules/response/event/__tests__/response.spec.js b/src/modules/response/event/__tests__/response.spec.js
index 8566ef653..452391d05 100644
--- a/src/modules/response/event/__tests__/response.spec.js
+++ b/src/modules/response/event/__tests__/response.spec.js
@@ -10,6 +10,9 @@ import responseDatetimeOrg from '../../../../__demo__/data/event/datetime.data.o
import responseTextHideNa from '../../../../__demo__/data/event/email.data.hidena.json'
import responseText from '../../../../__demo__/data/event/email.data.json'
import responseTextOrg from '../../../../__demo__/data/event/email.data.org.json'
+import responseEventstatusHideNa from '../../../../__demo__/data/event/eventstatus.data.hidena.json'
+import responseEventstatus from '../../../../__demo__/data/event/eventstatus.data.json'
+import responseEventstatusOrg from '../../../../__demo__/data/event/eventstatus.data.org.json'
import responseNumericHideNa from '../../../../__demo__/data/event/integer.data.hidena.json'
import responseNumeric from '../../../../__demo__/data/event/integer.data.json'
import responseNumericOrg from '../../../../__demo__/data/event/integer.data.org.json'
@@ -30,9 +33,36 @@ import {
VALUE_TYPE_PERCENTAGE,
VALUE_TYPE_TRUE_ONLY,
} from '../../../valueTypes.js'
-import { getItemFormatterByValueType, transformResponse } from '../response.js'
+import {
+ getItemFormatterByHeaderName,
+ getItemFormatterByValueType,
+ transformResponse,
+} from '../response.js'
describe('response', () => {
+ describe('getItemFormatterByHeaderName', () => {
+ it('should return the correct formatter and format correctly', () => {
+ expect(getItemFormatterByHeaderName('eventstatus')('ACTIVE')).toBe(
+ 'Active'
+ )
+ expect(
+ getItemFormatterByHeaderName('eventstatus')('COMPLETED')
+ ).toBe('Completed')
+ expect(
+ getItemFormatterByHeaderName('eventstatus')('SCHEDULE')
+ ).toBe('Scheduled')
+ expect(
+ getItemFormatterByHeaderName('programstatus')('ACTIVE')
+ ).toBe('Active')
+ expect(
+ getItemFormatterByHeaderName('programstatus')('COMPLETED')
+ ).toBe('Completed')
+ expect(
+ getItemFormatterByHeaderName('programstatus')('CANCELLED')
+ ).toBe('Cancelled')
+ })
+ })
+
describe('getItemFormatterByValueType', () => {
it('should return the correct formatter and format correctly', () => {
expect(getItemFormatterByValueType(VALUE_TYPE_BOOLEAN)('1')).toBe(
@@ -178,5 +208,21 @@ describe('response', () => {
).toEqual(responseYesOnlyHideNa)
})
})
+
+ describe('eventstatus', () => {
+ it('transforms response', () => {
+ expect(transformResponse(responseEventstatusOrg)).toEqual(
+ responseEventstatus
+ )
+ })
+
+ it('transforms response and hides N/A data', () => {
+ expect(
+ transformResponse(responseEventstatusOrg, {
+ hideNaData: true,
+ })
+ ).toEqual(responseEventstatusHideNa)
+ })
+ })
})
})
diff --git a/src/modules/response/event/response.js b/src/modules/response/event/response.js
index b25f8ad7b..35c62eeb3 100644
--- a/src/modules/response/event/response.js
+++ b/src/modules/response/event/response.js
@@ -20,6 +20,11 @@ import {
import { applyDefaultHandler } from './default.js'
import { applyOptionSetHandler } from './optionSet.js'
+// Responses coming from these endpoints need transformation
+// before we can pass it to the pivot table engine:
+// - analytics/events/aggregate
+// - analytics/enrollments/aggregate
+
export const PREFIX_SEPARATOR = '_'
export const NA_VALUE = ''
export const NA_VALUE_ITEM = {
@@ -41,6 +46,23 @@ export const UNSUPPORTED_VALUE_TYPES = [
VALUE_TYPE_REFERENCE,
]
+const STATUSES = {
+ ACTIVE: i18n.t('Active'),
+ COMPLETED: i18n.t('Completed'),
+ SCHEDULE: i18n.t('Scheduled'),
+ CANCELLED: i18n.t('Cancelled'),
+}
+
+const formatStatus = (value) => STATUSES[value] || value
+
+export const getItemFormatter = ({ name, valueType }) =>
+ getItemFormatterByHeaderName(name) || getItemFormatterByValueType(valueType)
+
+export const getItemFormatterByHeaderName = (name) =>
+ name.endsWith('eventstatus') || name.endsWith('programstatus')
+ ? formatStatus
+ : undefined
+
export const getItemFormatterByValueType = (valueType) => {
switch (valueType) {
case VALUE_TYPE_AGE:
@@ -58,6 +80,27 @@ export const getItemFormatterByValueType = (valueType) => {
}
}
+const EXCLUDED_HEADER_NAMES = new Set([
+ DIMENSION_ID_PERIOD,
+ DIMENSION_ID_ORGUNIT,
+ 'lastupdated',
+ 'created',
+ 'completed',
+])
+
+const EXCLUDED_HEADER_SUFFIXES = [
+ '.eventdate',
+ '.enrollmentdate',
+ '.scheduleddate',
+ '.incidentdate',
+ '.ou',
+]
+
+const isIncludedHeader = (header) =>
+ Boolean(header.meta) &&
+ !EXCLUDED_HEADER_NAMES.has(header.name) &&
+ !EXCLUDED_HEADER_SUFFIXES.some((suffix) => header.name.endsWith(suffix))
+
export const transformResponse = (response, { hideNaData = false } = {}) => {
// Do not modify the original response
// Rows is mapped by the handlers
@@ -81,13 +124,7 @@ export const transformResponse = (response, { hideNaData = false } = {}) => {
...header,
index,
}))
- .filter(
- (header) =>
- Boolean(header.meta) &&
- ![DIMENSION_ID_PERIOD, DIMENSION_ID_ORGUNIT].includes(
- header.name
- )
- )
+ .filter(isIncludedHeader)
// Legendsets use uids and do not need transformation
// Skip unsupported value types
@@ -110,9 +147,7 @@ export const transformResponse = (response, { hideNaData = false } = {}) => {
transformedResponse,
header.index,
{
- itemFormatter: getItemFormatterByValueType(
- header.valueType
- ),
+ itemFormatter: getItemFormatter(header),
}
)
}