diff --git a/CHANGELOG.md b/CHANGELOG.md
index cecf7e271a..e90033b62c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,16 @@
+# [100.4.0](https://github.com/dhis2/data-visualizer-app/compare/v100.3.1...v100.4.0) (2023-12-14)
+
+
+### Bug Fixes
+
+* **translations:** sync translations from transifex (dev) ([65441f2](https://github.com/dhis2/data-visualizer-app/commit/65441f2b454a6e0f74567b8b7107cad63d594a04))
+* **translations:** sync translations from transifex (dev) ([005be59](https://github.com/dhis2/data-visualizer-app/commit/005be599f7dd4382f0086861d74064aedc49ac29))
+
+
+### Features
+
+* cumulative values in PT (DHIS2-5497) ([#2746](https://github.com/dhis2/data-visualizer-app/issues/2746)) ([bff69ab](https://github.com/dhis2/data-visualizer-app/commit/bff69ab9cec7685adad823197de8508e9ae83636)), closes [#1946](https://github.com/dhis2/data-visualizer-app/issues/1946)
+
## [100.3.1](https://github.com/dhis2/data-visualizer-app/compare/v100.3.0...v100.3.1) (2023-11-08)
diff --git a/cypress/elements/common.js b/cypress/elements/common.js
index 7b245a202f..2ff7ba0562 100644
--- a/cypress/elements/common.js
+++ b/cypress/elements/common.js
@@ -12,9 +12,16 @@ const loadingEl = 'dhis2-uicore-circularloader'
export const expectAppToNotBeLoading = () =>
cy.getBySel(loadingEl, { timeout: 15000 }).should('not.exist')
-export const clickCheckbox = (target) =>
+export const checkCheckbox = (target) =>
cy.getBySel(target).click().find('[type="checkbox"]').should('be.checked')
+export const uncheckCheckbox = (target) =>
+ cy
+ .getBySel(target)
+ .click()
+ .find('[type="checkbox"]')
+ .should('not.be.checked')
+
export const typeInput = (target, text) =>
cy.getBySel(target).find('input').type(text)
diff --git a/cypress/elements/optionsModal/index.js b/cypress/elements/optionsModal/index.js
index 1f8f7f6bdd..b1a74c55fa 100644
--- a/cypress/elements/optionsModal/index.js
+++ b/cypress/elements/optionsModal/index.js
@@ -51,19 +51,19 @@ export {
} from './axes.js'
export {
- clickTrendLineCheckbox,
+ checkTrendLineCheckbox,
selectTrendLineType,
- clickTargetLineCheckbox,
+ checkTargetLineCheckbox,
setTargetLineValue,
setTargetLineLabel,
- clickBaseLineCheckbox,
+ checkBaseLineCheckbox,
setBaseLineLabel,
setBaseLineValue,
} from './lines.js'
export { setCustomSubtitle } from './subtitle.js'
-export { clickOutliersCheckbox } from './outliers.js'
+export { checkOutliersCheckbox } from './outliers.js'
export { setItemToAxis, setItemToType } from './series.js'
diff --git a/cypress/elements/optionsModal/lines.js b/cypress/elements/optionsModal/lines.js
index d7368fa505..6402fa1534 100644
--- a/cypress/elements/optionsModal/lines.js
+++ b/cypress/elements/optionsModal/lines.js
@@ -1,4 +1,4 @@
-import { clickCheckbox, typeInput } from '../common.js'
+import { checkCheckbox, typeInput } from '../common.js'
const trendLineCheckboxEl = 'option-trend-line-checkbox'
const trendLineSelectEl = 'option-trend-line-select'
@@ -10,14 +10,14 @@ const baseLineCheckboxEl = 'option-base-line-checkbox'
const baseLineValueInputEl = 'option-base-line-value-input'
const baseLineLabelInputEl = 'option-base-line-label-input'
-export const clickTrendLineCheckbox = () => clickCheckbox(trendLineCheckboxEl)
+export const checkTrendLineCheckbox = () => checkCheckbox(trendLineCheckboxEl)
export const selectTrendLineType = (optionName) => {
cy.getBySel(trendLineSelectEl).findBySel('dhis2-uicore-select').click()
cy.getBySel(trendLineSelectOptionEl).contains(optionName).click()
}
-export const clickTargetLineCheckbox = () => clickCheckbox(targetLineCheckboxEl)
+export const checkTargetLineCheckbox = () => checkCheckbox(targetLineCheckboxEl)
export const setTargetLineValue = (text) =>
typeInput(targetLineValueInputEl, text)
@@ -25,7 +25,7 @@ export const setTargetLineValue = (text) =>
export const setTargetLineLabel = (text) =>
typeInput(targetLineLabelInputEl, text)
-export const clickBaseLineCheckbox = () => clickCheckbox(baseLineCheckboxEl)
+export const checkBaseLineCheckbox = () => checkCheckbox(baseLineCheckboxEl)
export const setBaseLineValue = (text) => typeInput(baseLineValueInputEl, text)
diff --git a/cypress/elements/optionsModal/outliers.js b/cypress/elements/optionsModal/outliers.js
index 93db0ea56b..678a4e2e18 100644
--- a/cypress/elements/optionsModal/outliers.js
+++ b/cypress/elements/optionsModal/outliers.js
@@ -1,5 +1,5 @@
-import { clickCheckbox } from '../common.js'
+import { checkCheckbox } from '../common.js'
const outliersCheckboxEl = 'option-outliers-enabled-checkbox'
-export const clickOutliersCheckbox = () => clickCheckbox(outliersCheckboxEl)
+export const checkOutliersCheckbox = () => checkCheckbox(outliersCheckboxEl)
diff --git a/cypress/elements/optionsModal/totals.js b/cypress/elements/optionsModal/totals.js
new file mode 100644
index 0000000000..bbe931be43
--- /dev/null
+++ b/cypress/elements/optionsModal/totals.js
@@ -0,0 +1,100 @@
+export const colTotalsOptionEl = 'option-col-totals'
+const colSubTotalsOptionEl = 'option-col-subtotals'
+const rowTotalsOptionEl = 'option-row-totals'
+const rowSubTotalsOptionEl = 'option-row-subtotals'
+
+export const expectColumnsTotalsToBeDisabled = () =>
+ cy
+ .getBySel(colTotalsOptionEl)
+ .find('[type="checkbox"]')
+ .should('be.disabled')
+
+export const expectColumnsTotalsToBeEnabled = () =>
+ cy
+ .getBySel(colTotalsOptionEl)
+ .find('[type="checkbox"]')
+ .should('not.be.disabled')
+
+export const expectColumnsTotalsToBeChecked = () =>
+ cy
+ .getBySel(colTotalsOptionEl)
+ .find('[type="checkbox"]')
+ .should('be.checked')
+
+export const expectColumnsTotalsToBeUnchecked = () =>
+ cy
+ .getBySel(colTotalsOptionEl)
+ .find('[type="checkbox"]')
+ .should('not.be.checked')
+
+export const expectColumnsSubTotalsToBeDisabled = () =>
+ cy
+ .getBySel(colSubTotalsOptionEl)
+ .find('[type="checkbox"]')
+ .should('be.disabled')
+
+export const expectColumnsSubTotalsToBeEnabled = () =>
+ cy
+ .getBySel(colSubTotalsOptionEl)
+ .find('[type="checkbox"]')
+ .should('be.enabled')
+
+export const expectColumnsSubTotalsToBeChecked = () =>
+ cy
+ .getBySel(colSubTotalsOptionEl)
+ .find('[type="checkbox"]')
+ .should('be.checked')
+
+export const expectColumnsSubTotalsToBeUnchecked = () =>
+ cy
+ .getBySel(colSubTotalsOptionEl)
+ .find('[type="checkbox"]')
+ .should('not.be.checked')
+
+export const expectRowsTotalsToBeDisabled = () =>
+ cy
+ .getBySel(rowTotalsOptionEl)
+ .find('[type="checkbox"]')
+ .should('be.disabled')
+
+export const expectRowsTotalsToBeEnabled = () =>
+ cy
+ .getBySel(rowTotalsOptionEl)
+ .find('[type="checkbox"]')
+ .should('be.enabled')
+
+export const expectRowsTotalsToBeChecked = () =>
+ cy
+ .getBySel(rowTotalsOptionEl)
+ .find('[type="checkbox"]')
+ .should('be.checked')
+
+export const expectRowsTotalsToBeUnchecked = () =>
+ cy
+ .getBySel(rowTotalsOptionEl)
+ .find('[type="checkbox"]')
+ .should('not.be.checked')
+
+export const expectRowsSubTotalsToBeDisabled = () =>
+ cy
+ .getBySel(rowSubTotalsOptionEl)
+ .find('[type="checkbox"]')
+ .should('be.disabled')
+
+export const expectRowsSubTotalsToBeEnabled = () =>
+ cy
+ .getBySel(rowSubTotalsOptionEl)
+ .find('[type="checkbox"]')
+ .should('be.enabled')
+
+export const expectRowsSubTotalsToBeChecked = () =>
+ cy
+ .getBySel(rowSubTotalsOptionEl)
+ .find('[type="checkbox"]')
+ .should('be.checked')
+
+export const expectRowsSubTotalsToBeUnchecked = () =>
+ cy
+ .getBySel(rowSubTotalsOptionEl)
+ .find('[type="checkbox"]')
+ .should('not.be.checked')
diff --git a/cypress/elements/pivotTable.js b/cypress/elements/pivotTable.js
index e92d64a714..3b41d3982d 100644
--- a/cypress/elements/pivotTable.js
+++ b/cypress/elements/pivotTable.js
@@ -1,7 +1,14 @@
const valueCellEl = 'visualization-value-cell'
+const headerCellEl = 'visualization-column-header'
export const clickTableValueCell = (index) =>
cy.getBySel(valueCellEl).eq(index).click()
export const expectTableValueCellsToHaveLength = (length) =>
cy.getBySel(valueCellEl).should('have.length', length)
+
+export const expectTableValueCellToContainValue = (index, value) =>
+ cy.getBySel(valueCellEl).eq(index).contains(value)
+
+export const clickTableHeaderCell = (name) =>
+ cy.getBySel(headerCellEl).contains(name).click()
diff --git a/cypress/integration/options/cumulativeValues.cy.js b/cypress/integration/options/cumulativeValues.cy.js
new file mode 100644
index 0000000000..0334f46e7e
--- /dev/null
+++ b/cypress/integration/options/cumulativeValues.cy.js
@@ -0,0 +1,221 @@
+import {
+ AXIS_ID_COLUMNS,
+ AXIS_ID_ROWS,
+ DIMENSION_ID_DATA,
+ DIMENSION_ID_PERIOD,
+ VIS_TYPE_PIVOT_TABLE,
+ visTypeDisplayNames,
+} from '@dhis2/analytics'
+import {
+ clickNewCalculationButton,
+ clickSaveButton,
+ inputCalculationLabel,
+ selectOperatorFromListByDoubleClick,
+ typeInNumberField,
+} from '../../elements/calculationsModal.js'
+import { checkCheckbox, uncheckCheckbox } from '../../elements/common.js'
+import {
+ clickDimensionModalHideButton,
+ clickDimensionModalUpdateButton,
+ selectDataElements,
+ selectFixedPeriods,
+ unselectAllItemsByButton,
+} from '../../elements/dimensionModal/index.js'
+import { openDimension } from '../../elements/dimensionsPanel.js'
+import { clickContextMenuMove, openContextMenu } from '../../elements/layout.js'
+import { openOptionsModal } from '../../elements/menuBar.js'
+import {
+ OPTIONS_TAB_DATA,
+ OPTIONS_TAB_LEGEND,
+ clickOptionsModalHideButton,
+ clickOptionsModalUpdateButton,
+ clickOptionsTab,
+} from '../../elements/optionsModal/index.js'
+import {
+ colTotalsOptionEl,
+ expectColumnsTotalsToBeChecked,
+ expectColumnsTotalsToBeDisabled,
+ expectColumnsSubTotalsToBeDisabled,
+ expectRowsTotalsToBeDisabled,
+ expectRowsSubTotalsToBeDisabled,
+ expectColumnsTotalsToBeEnabled,
+ expectColumnsSubTotalsToBeEnabled,
+ expectRowsTotalsToBeEnabled,
+ expectRowsSubTotalsToBeEnabled,
+} from '../../elements/optionsModal/totals.js'
+import {
+ expectTableValueCellToContainValue,
+ clickTableHeaderCell,
+} from '../../elements/pivotTable.js'
+import { goToStartPage } from '../../elements/startScreen.js'
+import { changeVisType } from '../../elements/visualizationTypeSelector.js'
+import { TEST_DATA_ELEMENTS } from '../../utils/data.js'
+
+const cumulativeValuesOptionEl = 'option-cumulative-values'
+
+describe('Options - Cumulative values', () => {
+ describe('Interaction with other options (only for PT)', () => {
+ beforeEach(() => {
+ goToStartPage()
+ changeVisType(visTypeDisplayNames[VIS_TYPE_PIVOT_TABLE])
+ })
+
+ it('disables/enables Totals, Number type and Legend options when cumulativeValues is checked/unchecked', () => {
+ openOptionsModal(OPTIONS_TAB_DATA)
+ checkCheckbox(cumulativeValuesOptionEl)
+
+ // Totals
+ expectColumnsTotalsToBeDisabled()
+ expectColumnsSubTotalsToBeDisabled()
+ expectRowsTotalsToBeDisabled()
+ expectRowsSubTotalsToBeDisabled()
+
+ // Number type
+ cy.getBySel('option-number-type-select')
+ .should('contain', 'Not supported when using cumulative values')
+ .find('[data-test="dhis2-uicore-select-input"]')
+ .should('have.class', 'disabled')
+
+ // Legend
+ clickOptionsTab(OPTIONS_TAB_LEGEND)
+ cy.getBySel('option-legend')
+ .should('contain', 'Not supported when using cumulative values')
+ .find('[type="checkbox"]')
+ .should('be.disabled')
+
+ clickOptionsTab(OPTIONS_TAB_DATA)
+ uncheckCheckbox(cumulativeValuesOptionEl)
+
+ // Totals
+ expectColumnsTotalsToBeEnabled()
+ expectColumnsSubTotalsToBeEnabled()
+ expectRowsTotalsToBeEnabled()
+ expectRowsSubTotalsToBeEnabled()
+
+ // Number type
+ cy.getBySel('option-number-type-select')
+ .should(
+ 'not.contain',
+ 'Not supported when using cumulative values'
+ )
+ .find('[data-test="dhis2-uicore-select-input"]')
+ .should('not.have.class', 'disabled')
+
+ // Legend
+ clickOptionsTab(OPTIONS_TAB_LEGEND)
+ cy.getBySel('option-legend')
+ .should(
+ 'not.contain',
+ 'Not supported when using cumulative values'
+ )
+ .find('[type="checkbox"]')
+ .should('not.be.disabled')
+
+ clickOptionsModalHideButton()
+ })
+
+ it('disables/enables a total option preserving its state', () => {
+ openOptionsModal(OPTIONS_TAB_DATA)
+ checkCheckbox(colTotalsOptionEl)
+
+ expectColumnsTotalsToBeChecked()
+
+ checkCheckbox(cumulativeValuesOptionEl)
+
+ expectColumnsTotalsToBeDisabled()
+ expectColumnsTotalsToBeChecked()
+
+ uncheckCheckbox(cumulativeValuesOptionEl)
+
+ expectColumnsTotalsToBeEnabled()
+ expectColumnsTotalsToBeChecked()
+
+ clickOptionsModalHideButton()
+ })
+ })
+
+ describe('Applying cumulativeValues: Pivot table', () => {
+ beforeEach(() => {
+ goToStartPage()
+ changeVisType(visTypeDisplayNames[VIS_TYPE_PIVOT_TABLE])
+ })
+
+ it('correctly shows the cumulative values', () => {
+ openContextMenu(DIMENSION_ID_DATA)
+ clickContextMenuMove(DIMENSION_ID_DATA, AXIS_ID_ROWS)
+ openContextMenu(DIMENSION_ID_PERIOD)
+ clickContextMenuMove(DIMENSION_ID_PERIOD, AXIS_ID_COLUMNS)
+
+ // create a calculation to facilitate testing the cumulative values
+ openDimension(DIMENSION_ID_DATA)
+ clickNewCalculationButton()
+ selectOperatorFromListByDoubleClick('Number')
+ typeInNumberField(1, 1)
+ inputCalculationLabel('test data for cumulativeValues')
+ clickSaveButton()
+
+ clickDimensionModalUpdateButton()
+
+ openOptionsModal(OPTIONS_TAB_DATA)
+ checkCheckbox(cumulativeValuesOptionEl)
+ clickOptionsModalUpdateButton()
+
+ Array.from({ length: 12 }, (_, i) => i).forEach((i) =>
+ expectTableValueCellToContainValue(i, i + 1)
+ )
+ })
+
+ it('correctly sort a column with cumulative values', () => {
+ openContextMenu(DIMENSION_ID_DATA)
+ clickContextMenuMove(DIMENSION_ID_DATA, AXIS_ID_ROWS)
+ openContextMenu(DIMENSION_ID_PERIOD)
+ clickContextMenuMove(DIMENSION_ID_PERIOD, AXIS_ID_COLUMNS)
+
+ const year = new Date().getFullYear().toString()
+
+ openDimension(DIMENSION_ID_PERIOD)
+ unselectAllItemsByButton()
+ selectFixedPeriods(
+ [`October ${year}`, `November ${year}`, `December ${year}`],
+ 'Monthly'
+ )
+ clickDimensionModalHideButton()
+
+ // create a calculation to facilitate testing the cumulative values
+ openDimension(DIMENSION_ID_DATA)
+ clickNewCalculationButton()
+ selectOperatorFromListByDoubleClick('Number')
+ typeInNumberField(1, 6000)
+ inputCalculationLabel(
+ 'test data for sorting cumulative values sorting'
+ )
+ clickSaveButton()
+
+ selectDataElements([TEST_DATA_ELEMENTS[4].name])
+
+ clickDimensionModalUpdateButton()
+
+ // sort before cumulative
+ expectTableValueCellToContainValue(2, '6 000')
+ expectTableValueCellToContainValue(5, '5 266')
+
+ clickTableHeaderCell(`December ${year}`)
+
+ expectTableValueCellToContainValue(2, '5 266')
+ expectTableValueCellToContainValue(5, '6 000')
+
+ // sort after cumulative
+ openOptionsModal(OPTIONS_TAB_DATA)
+ checkCheckbox(cumulativeValuesOptionEl)
+ clickOptionsModalUpdateButton()
+
+ expectTableValueCellToContainValue(2, '18 000')
+ expectTableValueCellToContainValue(5, '18 488')
+
+ clickTableHeaderCell(`December ${year}`)
+
+ expectTableValueCellToContainValue(2, '18 000')
+ expectTableValueCellToContainValue(5, '18 488')
+ })
+ })
+})
diff --git a/cypress/integration/options/fontStyles.cy.js b/cypress/integration/options/fontStyles.cy.js
index 15408d334f..2cbee29b55 100644
--- a/cypress/integration/options/fontStyles.cy.js
+++ b/cypress/integration/options/fontStyles.cy.js
@@ -20,10 +20,10 @@ import {
OPTIONS_TAB_STYLE,
OPTIONS_TAB_DATA,
OPTIONS_TAB_AXES,
- clickTargetLineCheckbox,
+ checkTargetLineCheckbox,
setTargetLineValue,
setTargetLineLabel,
- clickBaseLineCheckbox,
+ checkBaseLineCheckbox,
setBaseLineLabel,
setBaseLineValue,
setAxisTitleText,
@@ -221,7 +221,7 @@ describe('Options - Font styles', () => {
})
it('sets target line', () => {
cy.log(`Test value: ${TEST_VALUE}`)
- clickTargetLineCheckbox()
+ checkTargetLineCheckbox()
setTargetLineLabel(TEST_LABEL)
setTargetLineValue(TEST_VALUE)
})
@@ -280,7 +280,7 @@ describe('Options - Font styles', () => {
})
it('sets base line', () => {
cy.log(`Test value: ${TEST_VALUE}`)
- clickBaseLineCheckbox()
+ checkBaseLineCheckbox()
setBaseLineLabel(TEST_LABEL)
setBaseLineValue(TEST_VALUE)
})
diff --git a/cypress/integration/options/icon.cy.js b/cypress/integration/options/icon.cy.js
index 541e586eac..ea90015372 100644
--- a/cypress/integration/options/icon.cy.js
+++ b/cypress/integration/options/icon.cy.js
@@ -9,7 +9,7 @@ import {
visTypeDisplayNames,
} from '@dhis2/analytics'
import { expectVisualizationToBeVisible } from '../../elements/chart.js'
-import { clickCheckbox } from '../../elements/common.js'
+import { checkCheckbox } from '../../elements/common.js'
import {
expectSelectableDataItemsAmountToBeLeast,
switchDataTypeTo,
@@ -98,7 +98,7 @@ describe('Icon', () => {
it(`icon shows when option is enabled for ${type}`, () => {
// enable the icon
openOptionsModal(OPTIONS_TAB_STYLE)
- clickCheckbox('option-show-data-item-icon')
+ checkCheckbox('option-show-data-item-icon')
clickOptionsModalHideButton()
// find the data item
@@ -129,7 +129,7 @@ describe('Icon', () => {
it.skip('icon gets correct color when a legend is in use', () => {
// enable the icon
openOptionsModal(OPTIONS_TAB_STYLE)
- clickCheckbox('option-show-data-item-icon')
+ checkCheckbox('option-show-data-item-icon')
// enable the legend
clickOptionsTab(OPTIONS_TAB_LEGEND)
diff --git a/cypress/integration/options/lines.cy.js b/cypress/integration/options/lines.cy.js
index ea8fef0357..3a332aeb84 100644
--- a/cypress/integration/options/lines.cy.js
+++ b/cypress/integration/options/lines.cy.js
@@ -11,7 +11,7 @@ import { openDimension } from '../../elements/dimensionsPanel.js'
import { openOptionsModal } from '../../elements/menuBar.js'
import {
clickOptionsModalUpdateButton,
- clickTrendLineCheckbox,
+ checkTrendLineCheckbox,
OPTIONS_TAB_DATA,
selectTrendLineType,
} from '../../elements/optionsModal/index.js'
@@ -54,7 +54,7 @@ describe('Options - Lines', () => {
})
if (index === 0) {
it('enables trendline', () => {
- clickTrendLineCheckbox()
+ checkTrendLineCheckbox()
})
}
it('selects trendline type', () => {
diff --git a/cypress/integration/visTypes/scatter.cy.js b/cypress/integration/visTypes/scatter.cy.js
index 6fba12f094..d35eba4e66 100644
--- a/cypress/integration/visTypes/scatter.cy.js
+++ b/cypress/integration/visTypes/scatter.cy.js
@@ -41,7 +41,7 @@ import {
} from '../../elements/menuBar.js'
import {
clickOptionsModalUpdateButton,
- clickOutliersCheckbox,
+ checkOutliersCheckbox,
OPTIONS_TAB_AXES,
OPTIONS_TAB_OUTLIERS,
setAxisRangeMaxValue,
@@ -180,7 +180,7 @@ describe('using a Scatter chart', () => {
})
it('Options -> Outliers -> enables outliers', () => {
openOptionsModal(OPTIONS_TAB_OUTLIERS)
- clickOutliersCheckbox()
+ checkOutliersCheckbox()
// TODO: Set more outlier options
clickOptionsModalUpdateButton()
expectVisualizationToBeVisible(VIS_TYPE_SCATTER)
diff --git a/docs/data-visualizer.md b/docs/data-visualizer.md
index 2978d41418..3dc516c7a4 100644
--- a/docs/data-visualizer.md
+++ b/docs/data-visualizer.md
@@ -165,7 +165,7 @@ The display of a visualization can be changed by enabling/disabling and configur
| Base line | Displays a horizontal line at the given domain value. Useful for example when you want to visualize how your performance has evolved since the beginning of a process. |
| Column sub-totals | Displays sub-totals in a Pivot table for each dimension.
If you only select one dimension, sub-totals will be hidden for those columns. This is because the values will be equal to the sub-totals. |
| Column totals | Displays total values in a Pivot table for each column, as well as a total for all values in the table. |
-| Cumulative values | Displays cumulative values in Column, Stacked column, Bar, Stacked bar, Line and Area visualizations |
+| Cumulative values | Displays cumulative values in Column, Stacked column, Bar, Stacked bar, Line, Area and Pivot Table visualizations |
| Custom sort order | Controls the sort order of the values. |
| Dimension labels | Shows the dimension names as part of a Pivot table. |
| Hide empty categories | Hides the category items with no data from the visualization.
**Before first**: hides missing values only before the first value
**After last**: hides missing values only after the last value
**Before first and after last**: hides missing values only before the first value and after the last value
**All**: hides all missing values
This is useful for example when you create Column and Bar visualizations. |
diff --git a/i18n/en.pot b/i18n/en.pot
index 70faa64252..a591ac3402 100644
--- a/i18n/en.pot
+++ b/i18n/en.pot
@@ -375,6 +375,9 @@ msgstr "Include cumulative"
msgid "Cumulative values"
msgstr "Cumulative values"
+msgid "Accumulate cell values along rows"
+msgstr "Accumulate cell values along rows"
+
msgid "Show data item icon"
msgstr "Show data item icon"
@@ -706,6 +709,9 @@ msgstr "Open as Map"
msgid "Visually plot data on a world map. Data elements use separate map layers."
msgstr "Visually plot data on a world map. Data elements use separate map layers."
+msgid "Not supported when using cumulative values"
+msgstr "Not supported when using cumulative values"
+
msgid "No data available"
msgstr "No data available"
@@ -999,6 +1005,9 @@ msgstr "Lines"
msgid "Totals"
msgstr "Totals"
+msgid "Totals are not supported when using cumulative values"
+msgstr "Totals are not supported when using cumulative values"
+
msgid "Vertical (y) axis {{axisId}}"
msgstr "Vertical (y) axis {{axisId}}"
diff --git a/package.json b/package.json
index 1427db228d..93959761c3 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "data-visualizer-app",
- "version": "100.3.1",
+ "version": "100.4.0",
"description": "DHIS2 Data Visualizer",
"license": "BSD-3-Clause",
"private": true,
@@ -41,7 +41,7 @@
"start-server-and-test": "^2.0.0"
},
"dependencies": {
- "@dhis2/analytics": "^26.1.6",
+ "@dhis2/analytics": "^26.2.0",
"@dhis2/app-runtime": "^3.7.0",
"@dhis2/app-runtime-adapter-d2": "^1.1.0",
"@dhis2/app-service-datastore": "^1.0.0-beta.3",
diff --git a/src/actions/ui.js b/src/actions/ui.js
index fe3e3fcdfe..df704580f7 100644
--- a/src/actions/ui.js
+++ b/src/actions/ui.js
@@ -1,8 +1,10 @@
+import { getDisabledOptions } from '../modules/disabledOptions.js'
import {
SET_UI,
CLEAR_UI,
SET_UI_FROM_VISUALIZATION,
SET_UI_TYPE,
+ SET_UI_DISABLED_OPTIONS,
SET_UI_OPTIONS,
SET_UI_LAYOUT,
ADD_UI_LAYOUT_DIMENSIONS,
@@ -21,6 +23,8 @@ import {
UPDATE_UI_SERIES_ITEM,
SET_UI_OPTION,
SET_UI_OPTION_FONT_STYLE,
+ sGetUiType,
+ sGetUiOptions,
} from '../reducers/ui.js'
export const acSetUi = (value) => ({
@@ -43,6 +47,11 @@ export const acSetUiType = (value) => ({
value,
})
+export const acSetUiDisabledOptions = (value) => ({
+ type: SET_UI_DISABLED_OPTIONS,
+ value,
+})
+
export const acSetUiOptions = (value) => ({
type: SET_UI_OPTIONS,
value,
@@ -129,3 +138,15 @@ export const acSetUiRightSidebarOpen = () => ({
export const acClearSeriesType = () => ({
type: CLEAR_SERIES_TYPE,
})
+
+export const tSetUiOptionAndDisabledOptions =
+ (option) => (dispatch, getState) => {
+ dispatch(acSetUiOption(option))
+
+ const visType = sGetUiType(getState())
+ const options = sGetUiOptions(getState())
+
+ dispatch(
+ acSetUiDisabledOptions(getDisabledOptions({ visType, options }))
+ )
+ }
diff --git a/src/components/Visualization/Visualization.js b/src/components/Visualization/Visualization.js
index 2d67a2bef0..0b67d8a528 100644
--- a/src/components/Visualization/Visualization.js
+++ b/src/components/Visualization/Visualization.js
@@ -3,7 +3,6 @@ import debounce from 'lodash-es/debounce'
import PropTypes from 'prop-types'
import React, { Component, Fragment } from 'react'
import { connect } from 'react-redux'
-import { createSelector } from 'reselect'
import { acSetChart } from '../../actions/chart.js'
import { tSetCurrentFromUi } from '../../actions/current.js'
import { acSetLoadError, acSetPluginLoading } from '../../actions/loader.js'
@@ -183,7 +182,7 @@ export class UnconnectedVisualization extends Component {
render() {
const {
visualization,
- userSettings,
+ displayProperty,
error,
isLoading,
onLoadingComplete,
@@ -208,7 +207,7 @@ export class UnconnectedVisualization extends Component {
onError={this.onError}
onDrill={this.onDrill}
style={styles.chartCanvas}
- displayProperty={userSettings.displayProperty}
+ displayProperty={displayProperty}
/>
)
@@ -218,6 +217,7 @@ export class UnconnectedVisualization extends Component {
UnconnectedVisualization.propTypes = {
addMetadata: PropTypes.func,
addParentGraphMap: PropTypes.func,
+ displayProperty: PropTypes.string,
error: PropTypes.object,
isLoading: PropTypes.bool,
rightSidebarOpen: PropTypes.bool,
@@ -225,24 +225,16 @@ UnconnectedVisualization.propTypes = {
setCurrent: PropTypes.func,
setLoadError: PropTypes.func,
setUiItems: PropTypes.func,
- userSettings: PropTypes.object,
visualization: PropTypes.object,
onLoadingComplete: PropTypes.func,
}
-export const userSettingsSelector = createSelector(
- [sGetSettingsDisplayProperty],
- (displayProperty) => ({
- displayProperty,
- })
-)
-
const mapStateToProps = (state) => ({
visualization: sGetCurrent(state),
rightSidebarOpen: sGetUiRightSidebarOpen(state),
error: sGetLoadError(state),
isLoading: sGetIsPluginLoading(state),
- userSettings: userSettingsSelector(state),
+ displayProperty: sGetSettingsDisplayProperty(state),
})
const mapDispatchToProps = (dispatch) => ({
diff --git a/src/components/VisualizationOptions/Options/CheckboxBaseOption.js b/src/components/VisualizationOptions/Options/CheckboxBaseOption.js
index 829dcdf651..4e7ba0e712 100644
--- a/src/components/VisualizationOptions/Options/CheckboxBaseOption.js
+++ b/src/components/VisualizationOptions/Options/CheckboxBaseOption.js
@@ -2,8 +2,8 @@ import { CheckboxField } from '@dhis2/ui'
import PropTypes from 'prop-types'
import React from 'react'
import { connect } from 'react-redux'
-import { acSetUiOption } from '../../../actions/ui.js'
-import { sGetUiOption } from '../../../reducers/ui.js'
+import { tSetUiOptionAndDisabledOptions } from '../../../actions/ui.js'
+import { sGetUiOption, sGetUiDisabledOption } from '../../../reducers/ui.js'
import {
tabSectionOption,
tabSectionOptionToggleable,
@@ -19,6 +19,7 @@ export const UnconnectedCheckboxBaseOption = ({
inverted,
fontStyleKey,
dataTest,
+ disabled,
}) => (