Skip to content

Commit fdf69f4

Browse files
authored
Merge branch 'master' into feat/datatable-pr1-toolbar
2 parents e3a0fd7 + 4cbdffe commit fdf69f4

17 files changed

Lines changed: 243 additions & 422 deletions

File tree

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# [101.14.0](https://github.com/dhis2/maps-app/compare/v101.13.5...v101.14.0) (2026-07-02)
2+
3+
4+
### Features
5+
6+
* add custom scale toggle for heat stress layers [DHIS2-20564] ([#3708](https://github.com/dhis2/maps-app/issues/3708)) ([ad788ac](https://github.com/dhis2/maps-app/commit/ad788acfa1dee904b83b7e7f1811d873b4faa00c))
7+
8+
## [101.13.5](https://github.com/dhis2/maps-app/compare/v101.13.4...v101.13.5) (2026-06-30)
9+
10+
11+
### Bug Fixes
12+
13+
* stop flooding logs with warnings when opening the Data dimension panel [DHIS2-20499] ([#3709](https://github.com/dhis2/maps-app/issues/3709)) ([95fbdda](https://github.com/dhis2/maps-app/commit/95fbdda4206916c5785749f94f3ecdb6213100e4))
14+
115
## [101.13.4](https://github.com/dhis2/maps-app/compare/v101.13.3...v101.13.4) (2026-06-29)
216

317

cypress/integration/dataTable.cy.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ describe('data table', () => {
316316

317317
// Sort by index and scroll to the top
318318
cy.get('button[title="Sort by Index"]').click()
319-
cy.get('[data-test-id="virtuoso-scroller"]').scrollTo('top')
319+
cy.get('[data-testid="virtuoso-scroller"]').scrollTo('top')
320320

321321
checkTableCell({ row: 0, column: 0, expectedContent: '28' })
322322

i18n/en.pot

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,9 @@ msgstr "Max value is required"
407407
msgid "Valid classes are {{minSteps}} to {{maxSteps}}"
408408
msgstr "Valid classes are {{minSteps}} to {{maxSteps}}"
409409

410+
msgid "Use custom legend"
411+
msgstr "Use custom legend"
412+
410413
msgid "Facility buffer"
411414
msgstr "Facility buffer"
412415

@@ -1911,3 +1914,11 @@ msgstr "End date is invalid"
19111914

19121915
msgid "End date cannot be earlier than start date"
19131916
msgstr "End date cannot be earlier than start date"
1917+
1918+
msgctxt "Application title"
1919+
msgid "__MANIFEST_APP_TITLE"
1920+
msgstr "Maps"
1921+
1922+
msgctxt "Application description"
1923+
msgid "__MANIFEST_APP_DESCRIPTION"
1924+
msgstr "DHIS2 Maps"

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "maps-app",
3-
"version": "101.13.4",
3+
"version": "101.14.0",
44
"description": "DHIS2 Maps",
55
"license": "BSD-3-Clause",
66
"author": "Bjørn Sandvik",
@@ -44,8 +44,8 @@
4444
"start-server-and-test": "^2.1.3"
4545
},
4646
"dependencies": {
47-
"@dhis2/analytics": "^29.5.4",
48-
"@dhis2/app-runtime": "^3.14.4",
47+
"@dhis2/analytics": "^29.5.5",
48+
"@dhis2/app-runtime": "^3.17.3",
4949
"@dhis2/app-service-datastore": "^1.0.0-beta.3",
5050
"@dhis2/maps-gl": "^4.2.8",
5151
"@dhis2/ui": "^10.16.3",
@@ -71,11 +71,11 @@
7171
"react-redux": "^9.3.0",
7272
"react-sortable-hoc": "^2.0.0",
7373
"react-virtualized": "^9.22.6",
74-
"react-virtuoso": "^4.6.2",
74+
"react-virtuoso": "^4.18.10",
7575
"redux": "^4.2.1",
7676
"redux-logger": "^3.0.6",
7777
"redux-thunk": "^2.4.2",
78-
"simple-statistics": "^7.9.1",
78+
"simple-statistics": "^7.9.3",
7979
"styled-jsx": "^4.0.1",
8080
"url-polyfill": "^1.1.14"
8181
},

src/components/core/styles/Checkbox.module.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.checkbox {
2-
margin: var(--spacers-dp12) 0 var(--spacers-dp8);
2+
margin: var(--spacers-dp16) 0 var(--spacers-dp8);
33
display: flex;
44
align-items: center;
55
}

src/components/edit/earthEngine/EarthEngineDialog.jsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ const EarthEngineDialog = (props) => {
6969
() => getLayerSourceGrouping(layerId, managedLayerSources),
7070
[layerId, managedLayerSources]
7171
)
72+
const layerConfig = useMemo(() => getEarthEngineLayer(layerId), [layerId])
73+
const defaultStyle = layerConfig?.style
74+
const customColorScaleName = layerConfig?.customColorScaleName
7275

7376
const hasAggregations = !!(aggregations || defaultAggregations)
7477
const hasMultipleAggregations = !aggregations || aggregations.length > 1
@@ -354,6 +357,8 @@ const EarthEngineDialog = (props) => {
354357
<StyleTab
355358
unit={unit}
356359
style={style}
360+
defaultStyle={defaultStyle}
361+
customColorScaleName={customColorScaleName}
357362
showBelowMin={!maskOperator}
358363
hasOrgUnitField={hasOrgUnitField}
359364
/>

src/components/edit/earthEngine/StyleSelect.jsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export const getStyleSelectError = ({ min, max, steps, palette, ranges }) => {
3030
return undefined
3131
}
3232

33-
const StyleSelect = ({ unit, style, setStyle }) => {
33+
const StyleSelect = ({ style, setStyle }) => {
3434
const { min, max, palette } = style
3535
const [steps, setSteps] = useState(palette.length)
3636

@@ -58,9 +58,6 @@ const StyleSelect = ({ unit, style, setStyle }) => {
5858

5959
return (
6060
<div>
61-
<p>
62-
{i18n.t('Unit')}: {unit}
63-
</p>
6461
<div key="minmax" className={styles.flexInnerColumnFlow}>
6562
<NumberField
6663
label={i18n.t('Min')}
@@ -97,7 +94,6 @@ const StyleSelect = ({ unit, style, setStyle }) => {
9794

9895
StyleSelect.propTypes = {
9996
setStyle: PropTypes.func.isRequired,
100-
unit: PropTypes.string.isRequired,
10197
style: PropTypes.shape({
10298
max: PropTypes.number.isRequired,
10399
min: PropTypes.number.isRequired,

src/components/edit/earthEngine/StyleTab.jsx

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,31 @@
11
import i18n from '@dhis2/d2-i18n'
22
import PropTypes from 'prop-types'
3-
import React from 'react'
3+
import React, { useCallback } from 'react'
44
import { useDispatch, useSelector } from 'react-redux'
5-
import { setCountFeaturesWithoutCoordinates } from '../../../actions/layerEdit.js'
5+
import {
6+
setCountFeaturesWithoutCoordinates,
7+
setStyle,
8+
} from '../../../actions/layerEdit.js'
69
import { EE_BUFFER } from '../../../constants/layers.js'
10+
import {
11+
getColorPalette,
12+
defaultColorScaleName,
13+
defaultClasses,
14+
} from '../../../util/colors.js'
715
import { Checkbox } from '../../core/index.js'
816
import BufferRadius from '../shared/BufferRadius.jsx'
917
import styles from '../styles/LayerDialog.module.css'
1018
import LegendPreview from './LegendPreview.jsx'
1119
import StyleSelect from './StyleSelect.jsx'
1220

13-
const StyleTab = ({ unit, style, showBelowMin, hasOrgUnitField }) => {
21+
const StyleTab = ({
22+
unit,
23+
style,
24+
defaultStyle,
25+
customColorScaleName,
26+
showBelowMin,
27+
hasOrgUnitField,
28+
}) => {
1429
const dispatch = useDispatch()
1530
const countFeaturesWithoutCoordinates = useSelector(
1631
(state) => state.layerEdit.countFeaturesWithoutCoordinates
@@ -22,10 +37,47 @@ const StyleTab = ({ unit, style, showBelowMin, hasOrgUnitField }) => {
2237
palette !== undefined &&
2338
palette.length < 10
2439

40+
const hasReferenceScale = !!defaultStyle?.ranges?.length
41+
const useCustomScale = hasReferenceScale && !style?.ranges?.length
42+
43+
const handleScaleToggle = useCallback(
44+
(checked) => {
45+
if (checked) {
46+
const { min, max } = defaultStyle ?? {}
47+
dispatch(
48+
setStyle({
49+
min,
50+
max,
51+
palette: getColorPalette(
52+
customColorScaleName ?? defaultColorScaleName,
53+
defaultClasses
54+
),
55+
ranges: null,
56+
})
57+
)
58+
} else {
59+
dispatch(setStyle(defaultStyle))
60+
}
61+
},
62+
[customColorScaleName, defaultStyle, dispatch]
63+
)
64+
2565
return (
2666
<div className={styles.flexColumnFlow}>
2767
<div className={styles.flexColumn}>
28-
{isClassStyle && <StyleSelect unit={unit} style={style} />}
68+
{unit && (
69+
<p>
70+
{i18n.t('Unit')}: {unit}
71+
</p>
72+
)}
73+
{hasReferenceScale && (
74+
<Checkbox
75+
label={i18n.t('Use custom legend')}
76+
checked={useCustomScale}
77+
onChange={handleScaleToggle}
78+
/>
79+
)}
80+
{isClassStyle && <StyleSelect style={style} />}
2981
<BufferRadius
3082
label={i18n.t('Facility buffer')}
3183
defaultRadius={EE_BUFFER}
@@ -40,7 +92,7 @@ const StyleTab = ({ unit, style, showBelowMin, hasOrgUnitField }) => {
4092
}
4193
/>
4294
</div>
43-
{isClassStyle && (
95+
{(isClassStyle || (hasReferenceScale && !useCustomScale)) && (
4496
<LegendPreview style={style} showBelowMin={showBelowMin} />
4597
)}
4698
</div>
@@ -49,6 +101,13 @@ const StyleTab = ({ unit, style, showBelowMin, hasOrgUnitField }) => {
49101

50102
StyleTab.propTypes = {
51103
hasOrgUnitField: PropTypes.bool.isRequired,
104+
customColorScaleName: PropTypes.string,
105+
defaultStyle: PropTypes.shape({
106+
max: PropTypes.number,
107+
min: PropTypes.number,
108+
palette: PropTypes.array,
109+
ranges: PropTypes.array,
110+
}),
52111
showBelowMin: PropTypes.bool,
53112
style: PropTypes.oneOfType([
54113
PropTypes.array,

src/components/edit/shared/styles/BufferRadius.module.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.buffer {
2-
margin-top: var(--spacers-dp8);
2+
margin-top: var(--spacers-dp16);
33
clear: both;
44
align-items: center;
55
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import colorbrewer from '../colorbrewer.js'
2+
3+
const baseNames = Object.keys(colorbrewer).filter(
4+
(name) => !name.endsWith('_reverse')
5+
)
6+
7+
describe('colorbrewer', () => {
8+
test('every base scale has a corresponding _reverse entry', () => {
9+
for (const name of baseNames) {
10+
expect(colorbrewer[`${name}_reverse`]).toBeDefined()
11+
}
12+
})
13+
14+
test('_reverse entries are the mirror of their base scale', () => {
15+
for (const name of baseNames) {
16+
const base = colorbrewer[name]
17+
const reversed = colorbrewer[`${name}_reverse`]
18+
for (const bins of Object.keys(base)) {
19+
expect(reversed[bins]).toEqual([...base[bins]].reverse())
20+
}
21+
}
22+
})
23+
24+
test('_reverse entries do not mutate the base scale arrays', () => {
25+
for (const name of baseNames) {
26+
const base = colorbrewer[name]
27+
const reversed = colorbrewer[`${name}_reverse`]
28+
for (const bins of Object.keys(base)) {
29+
expect(reversed[bins]).not.toBe(base[bins])
30+
}
31+
}
32+
})
33+
})

0 commit comments

Comments
 (0)