Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions cypress/integration/manageLayerSources.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ describe('Manage Layer Sources', () => {
// Make sure authority request response is not comming from cache
cy.intercept(
'GET',
'**/me?fields=id%2Cusername%2CdisplayName~rename(name)%2Cauthorities%2Csettings%5BkeyAnalysisDisplayProperty%2CkeyUiLocale%5D',
`**/me?fields=${encodeURIComponent(
'id,username,displayName~rename(name),authorities,organisationUnits[id,children[id,children[id]]],settings[keyAnalysisDisplayProperty,keyUiLocale]'
)}`,
(request) => {
delete request.headers['if-none-match']
}
Expand Down Expand Up @@ -172,7 +174,9 @@ describe('Manage Layer Sources', () => {
// Remove admin authority
cy.intercept(
'GET',
'**/me?fields=id%2Cusername%2CdisplayName~rename(name)%2Cauthorities%2Csettings%5BkeyAnalysisDisplayProperty%2CkeyUiLocale%5D',
`**/me?fields=${encodeURIComponent(
'id,username,displayName~rename(name),authorities,organisationUnits[id,children[id,children[id]]],settings[keyAnalysisDisplayProperty,keyUiLocale]'
)}`,
(request) => {
delete request.headers['if-none-match']
request.continue((response) => {
Expand Down
2 changes: 1 addition & 1 deletion cypress/integration/usersettings.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const interceptRequests = (param) => {
{
method: 'GET',
url: `**/me?fields=${encodeURIComponent(
'id,username,displayName~rename(name),authorities,settings[keyAnalysisDisplayProperty,keyUiLocale]'
'id,username,displayName~rename(name),authorities,organisationUnits[id,children[id,children[id]]],settings[keyAnalysisDisplayProperty,keyUiLocale]'
)}`,
},
param,
Expand Down
2 changes: 1 addition & 1 deletion cypress/support/requests.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const requests = {
},
getCachedDataProvider_Me: {
method: 'GET',
url: '**/me?fields=id%2Cusername%2CdisplayName~rename(name)%2Cauthorities%2Csettings%5BkeyAnalysisDisplayProperty%2CkeyUiLocale%5D',
url: '**/me?fields=id%2Cusername%2CdisplayName~rename(name)%2Cauthorities%2CorganisationUnits%5Bid%2Cchildren%5Bid%2Cchildren%5Bid%5D%5D%5D%2Csettings%5BkeyAnalysisDisplayProperty%2CkeyUiLocale%5D',
},
getCachedDataProvider_SystemSettings: {
method: 'GET',
Expand Down
35 changes: 9 additions & 26 deletions d2.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
const fs = require('node:fs')

const omitPatterns = [
// User info
'me/authorization',
Expand Down Expand Up @@ -49,30 +47,6 @@ const config = {
},

viteConfigExtensions: {
plugins: [
{
// Wraps the CJS Google EE API bundle as ESM so Vite doesn't
// flag it as an unoptimised dep and trigger a full-reload when
// the EE worker first imports it.
name: 'ee-api-js-worker-esm',
apply: 'serve',
load(id) {
if (
id.endsWith('/ee_api_js_worker.js') &&
!id.includes('?')
) {
const content = fs.readFileSync(id, 'utf-8')
return {
code:
'const module={exports:{}};const exports=module.exports;\n' +
content +
'\nexport default module.exports;',
map: null,
}
}
},
},
],
optimizeDeps: {
// Excluded so Vite serves maps-gl via /@fs/... with its full
// transform pipeline, which lets the EE worker URL resolve to the
Expand All @@ -86,11 +60,20 @@ const config = {
'fetch-jsonp',
'lodash.throttle',
'@mapbox/sphericalmercator',
'@turf/area',
'@turf/bbox',
'@turf/buffer',
'@turf/center-of-mass',
'@turf/centroid',
'@turf/circle',
'@turf/jsts',
'@turf/length',
'comlink',
'concaveman',
'polylabel',
'pretty-bytes',
'suggestions',
'uuid',
],
esbuildOptions: {
target: 'es2022',
Expand Down
11 changes: 11 additions & 0 deletions docs/maps.md
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,17 @@ layer configuration dialog.
**Data quality** section of the legend. They also appear in the data table. These events may or
may not have data.

- **Filter and count events outside org unit boundaries**: Events falling outside the boundaries
of the selected org units are excluded from the map, and counted in the **Data quality** section
of the legend, which also flags when some or all of the selected org units lack boundary data.
These events remain in the data table, but can be identified by their empty **Org unit
boundary** column value. Events inside a boundary are tagged with the name of their containing
org unit in that same column.

- **Tooltip field**: Select a data element or attribute to show as a tooltip when hovering over an
event. Selecting **Labels** makes the tooltip persistent on the map. Font size, weight, style
and color can also be modified.

- Select **Style by data item** (data element or attribute) to colorize the events according to a
data value. If events are grouped, clusters are displayed as small donut charts showing the
distribution of the data values. The available options vary for different data types:
Expand Down
Binary file modified docs/resources/images/maps_event_layer_dialog_STYLE.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions docs/src/05-event-layer.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,17 @@ layer configuration dialog.
**Data quality** section of the legend. They also appear in the data table. These events may or
may not have data.

- **Filter and count events outside org unit boundaries**: Events falling outside the boundaries
of the selected org units are excluded from the map, and counted in the **Data quality** section
of the legend, which also flags when some or all of the selected org units lack boundary data.
These events remain in the data table, but can be identified by their empty **Org unit
boundary** column value. Events inside a boundary are tagged with the name of their containing
org unit in that same column.

- **Tooltip field**: Select a data element or attribute to show as a tooltip when hovering over an
event. Selecting **Labels** makes the tooltip persistent on the map. Font size, weight, style
and color can also be modified.

- Select **Style by data item** (data element or attribute) to colorize the events according to a
data value. If events are grouped, clusters are displayed as small donut charts showing the
distribution of the data values. The available options vary for different data types:
Expand Down
65 changes: 48 additions & 17 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"POT-Creation-Date: 2026-06-30T11:26:45.998Z\n"
"PO-Revision-Date: 2026-06-30T11:26:45.998Z\n"
"POT-Creation-Date: 2026-07-09T08:38:38.049Z\n"
"PO-Revision-Date: 2026-07-09T08:38:38.049Z\n"

msgid "2020"
msgstr "2020"
Expand Down Expand Up @@ -131,9 +131,6 @@ msgstr "Previously selected value not available in list: {{id}}"
msgid "Style by data item"
msgstr "Style by data item"

msgid "Filtering is available after selecting a program stage."
msgstr "Filtering is available after selecting a program stage."

msgid "Add filter"
msgstr "Add filter"

Expand Down Expand Up @@ -210,6 +207,9 @@ msgstr "Range"
msgid "Org unit"
msgstr "Org unit"

msgid "Org unit boundary"
msgstr "Org unit boundary"

msgid "Event time"
msgstr "Event time"

Expand Down Expand Up @@ -416,6 +416,9 @@ msgstr "Org Units"
msgid "Filter"
msgstr "Filter"

msgid "Filtering is available after selecting a program stage."
msgstr "Filtering is available after selecting a program stage."

msgid "Group events"
msgstr "Group events"

Expand All @@ -428,6 +431,9 @@ msgstr "Radius"
msgid "Count events without coordinates"
msgstr "Count events without coordinates"

msgid "Filter and count events outside org unit boundaries"
msgstr "Filter and count events outside org unit boundaries"

msgid "You can style events by data element after selecting a program."
msgstr "You can style events by data element after selecting a program."

Expand Down Expand Up @@ -698,6 +704,24 @@ msgstr "Duplicate layer"
msgid "Remove layer"
msgstr "Remove layer"

msgid "Filters"
msgstr "Filters"

msgid "Failed to load layer"
msgstr "Failed to load layer"

msgid "No data found"
msgstr "No data found"

msgid "All events outside org unit boundaries"
msgstr "All events outside org unit boundaries"

msgid "No coordinates found"
msgstr "No coordinates found"

msgid "Could not check org unit boundaries"
msgstr "Could not check org unit boundaries"

msgid "Data quality"
msgstr "Data quality"

Expand All @@ -709,6 +733,25 @@ msgid_plural "{{n}} event without coordinates"
msgstr[0] "{{n}} event without coordinates"
msgstr[1] "{{n}} events without coordinates"

msgid "All events within org unit boundaries"
msgstr "All events within org unit boundaries"

msgid "{{n}} event outside org unit boundaries"
msgid_plural "{{n}} event outside org unit boundaries"
msgstr[0] "{{n}} event outside org unit boundaries"
msgstr[1] "{{n}} events outside org unit boundaries"

msgid "{{n}} of {{total}} org unit without boundaries"
msgid_plural "{{n}} of {{total}} org unit without boundaries"
msgstr[0] "{{n}} of {{total}} org unit without boundaries"
msgstr[1] "{{n}} of {{total}} org units without boundaries"

msgid "Boundary check skipped"
msgstr "Boundary check skipped"

msgid "All org units without boundaries"
msgstr "All org units without boundaries"

msgid "All org units have a point location"
msgstr "All org units have a point location"

Expand All @@ -725,18 +768,6 @@ msgid_plural "{{n}} org unit without coordinates"
msgstr[0] "{{n}} org unit without coordinates"
msgstr[1] "{{n}} org units without coordinates"

msgid "Filters"
msgstr "Filters"

msgid "Failed to load layer"
msgstr "Failed to load layer"

msgid "No data found"
msgstr "No data found"

msgid "No coordinates found"
msgstr "No coordinates found"

msgid "Selected org units: No coordinates found"
msgstr "Selected org units: No coordinates found"

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@
"@dhis2/analytics": "^29.5.5",
"@dhis2/app-runtime": "^3.17.3",
"@dhis2/app-service-datastore": "^1.0.0-beta.3",
"@dhis2/maps-gl": "^4.2.8",
"@dhis2/maps-gl": "^4.3.1",
"@dhis2/ui": "^10.16.3",
"@turf/boolean-point-in-polygon": "^7.3.5",
"@turf/centroid": "^7.3.5",
"abortcontroller-polyfill": "^1.7.8",
"array-move": "^4.0.0",
Expand Down
12 changes: 12 additions & 0 deletions src/actions/layerEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,12 @@ export const setCountFeaturesWithoutCoordinates = (checked) => ({
checked,
})

// Set if events outside selected org units should be filtered and counted
export const setCountEventsOutsideOrgUnits = (checked) => ({
type: types.LAYER_EDIT_COUNT_EVENTS_OUTSIDE_OU_SET,
checked,
})

// Set event point radius (event layer)
export const setEventPointRadius = (radius) => ({
type: types.LAYER_EDIT_EVENT_POINT_RADIUS_SET,
Expand Down Expand Up @@ -384,3 +390,9 @@ export const setFeatureStyle = (payload) => ({
type: types.LAYER_EDIT_FEATURE_STYLE_SET,
payload,
})

// Set label data item
export const setLabelDataItem = (item) => ({
type: types.LAYER_EDIT_LABEL_DATA_ITEM_ID_SET,
item,
})
7 changes: 2 additions & 5 deletions src/components/classification/LegendSetSelect.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import React, { useEffect } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { setLegendSet } from '../../actions/layerEdit.js'
import { SelectField } from '../core/index.js'
import styles from './styles/LegendSetSelect.module.css'

// Load all legend sets
const LEGEND_SETS_QUERY = {
Expand All @@ -17,10 +18,6 @@ const LEGEND_SETS_QUERY = {
},
}

const style = {
width: '100%',
}

const LegendSetSelect = ({ defaultLegendSet, legendSetError }) => {
const legendSet = useSelector((state) => state.layerEdit.legendSet)
const dispatch = useDispatch()
Expand All @@ -45,7 +42,7 @@ const LegendSetSelect = ({ defaultLegendSet, legendSetError }) => {
value={legendSet ? legendSet.id : null}
errorText={error?.message || legendSetError}
onChange={(legendSet) => dispatch(setLegendSet(legendSet))}
style={style}
className={styles.legendSetSelect}
/>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
display: flex;
gap: var(--spacers-dp16);
align-items: flex-end;
margin-bottom: var(--spacers-dp12);
margin-bottom: var(--spacers-dp24);
}

.singleColorField {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.legendSetSelect {
margin-bottom: var(--spacers-dp8);
}
2 changes: 1 addition & 1 deletion src/components/core/styles/FontStyle.module.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
.fontStyle {
display: flex;
align-items: flex-end;
margin-bottom: var(--spacers-dp8);
padding-left: var(--spacers-dp24);
margin-bottom: var(--spacers-dp8);
}

.fontStyle > * {
Expand Down
4 changes: 4 additions & 0 deletions src/components/core/styles/Spacer.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.spacer {
height: var(--spacers-dp16);
width: var(--spacers-dp4);
}
7 changes: 2 additions & 5 deletions src/components/dataItem/BooleanStyle.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ import { useDispatch } from 'react-redux'
import { setBooleanStyle } from '../../actions/layerEdit.js'
import { qualitativeColors } from '../../constants/colors.js'
import OptionStyle from '../optionSet/OptionStyle.jsx'

const style = {
marginTop: 20,
}
import styles from './styles/BooleanStyle.module.css'

const BooleanStyle = ({ valueType, values }) => {
const dispatch = useDispatch()
Expand All @@ -28,7 +25,7 @@ const BooleanStyle = ({ valueType, values }) => {
}

return (
<div style={style}>
<div className={styles.booleanStyle}>
<OptionStyle
name={i18n.t('Yes')}
color={values.true}
Expand Down
8 changes: 2 additions & 6 deletions src/components/dataItem/CoordinateField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import {
EVENT_COORDINATE_CASCADING,
NONE,
} from '../../constants/layers.js'
import { useEventDataItems } from '../../hooks/useEventDataItems.js'
import { SelectField } from '../core/index.js'
import { useEventDataItems } from './EventDataItemsProvider.jsx'

const CoordinateField = ({
value,
Expand Down Expand Up @@ -42,11 +42,7 @@ const CoordinateField = ({
eventDataItems,
trackedEntityType,
loading: itemsLoading,
} = useEventDataItems({
programId: program?.id,
programStageId: programStage?.id,
includeTypes,
})
} = useEventDataItems({ includeTypes })

const defaultValue = eventCoordinateField ? NONE : EVENT_COORDINATE_DEFAULT

Expand Down
Loading
Loading