diff --git a/cypress/integration/customErrors/visualizationError.cy.js b/cypress/integration/customErrors/visualizationError.cy.js new file mode 100644 index 0000000000..f6dfb97301 --- /dev/null +++ b/cypress/integration/customErrors/visualizationError.cy.js @@ -0,0 +1,81 @@ +import { + DIMENSION_ID_DATA, + DIMENSION_ID_PERIOD, + visTypeDisplayNames, + VIS_TYPE_COLUMN, + VIS_TYPE_PIVOT_TABLE, +} from '@dhis2/analytics' +import { expectVisualizationToBeVisible } from '../../elements/chart.js' +import { + selectDataElements, + clickDimensionModalUpdateButton, + inputSearchTerm, + unselectAllItemsByButton, + selectRelativePeriods, + unselectItemByDoubleClick, +} from '../../elements/dimensionModal/index.js' +import { openDimension } from '../../elements/dimensionsPanel.js' +import { + expectErrorToContainTitle, + goToStartPage, +} from '../../elements/startScreen.js' +import { changeVisType } from '../../elements/visualizationTypeSelector.js' + +const NARRATIVE_ITEM = { + name: 'Cholera (Deaths < 5 yrs) Narrative', + content: + 'Cholera is an infection of the small intestine caused by the bacterium Vibrio cholerae.', +} + +const REGULAR_ITEM = { + name: 'All other follow-ups', + content: '53 666', +} + +describe('Visualization error', () => { + it('navigates to the start page and changes vis type to PT', () => { + goToStartPage() + changeVisType(visTypeDisplayNames[VIS_TYPE_PIVOT_TABLE]) + }) + it("selects period 'This year'", () => { + openDimension(DIMENSION_ID_PERIOD) + unselectAllItemsByButton() + selectRelativePeriods(['This year'], 'Years') + clickDimensionModalUpdateButton() + }) + it('selects a narrative item', () => { + openDimension(DIMENSION_ID_DATA) + inputSearchTerm('narrative') + selectDataElements([NARRATIVE_ITEM.name]) + clickDimensionModalUpdateButton() + expectVisualizationToBeVisible(VIS_TYPE_PIVOT_TABLE) + }) + it('narrative item is displayed correctly', () => { + cy.contains(NARRATIVE_ITEM.content) + }) + it('selects a regular item', () => { + openDimension(DIMENSION_ID_DATA) + selectDataElements([REGULAR_ITEM.name]) + clickDimensionModalUpdateButton() + expectVisualizationToBeVisible(VIS_TYPE_PIVOT_TABLE) + }) + it('both items are displayed correctly', () => { + cy.contains(NARRATIVE_ITEM.content) + cy.contains(REGULAR_ITEM.content) + }) + + it('changes vis type to Column', () => { + changeVisType(visTypeDisplayNames[VIS_TYPE_COLUMN]) + }) + it('regular item is displayed correctly', () => { + cy.contains(REGULAR_ITEM.content) + }) + it('removes the regular item', () => { + openDimension(DIMENSION_ID_DATA) + unselectItemByDoubleClick(REGULAR_ITEM.name) + clickDimensionModalUpdateButton() + }) + it('error is shown', () => { + expectErrorToContainTitle('Invalid data type') + }) +}) diff --git a/packages/app/i18n/en.pot b/packages/app/i18n/en.pot index 21c7263ae7..babf8bcfa9 100644 --- a/packages/app/i18n/en.pot +++ b/packages/app/i18n/en.pot @@ -832,6 +832,16 @@ msgstr "No organization units found" msgid "The level or group selections didn't return any organization units." msgstr "The level or group selections didn't return any organization units." +msgid "Invalid data type" +msgstr "Invalid data type" + +msgid "" +"The selected data dimensions didn't return any valid data. This " +"visualization type can only display numerical data." +msgstr "" +"The selected data dimensions didn't return any valid data. This " +"visualization type can only display numerical data." + msgid "Something went wrong" msgstr "Something went wrong" diff --git a/packages/app/src/components/Visualization/Visualization.js b/packages/app/src/components/Visualization/Visualization.js index d510148cc9..d0c252f59d 100644 --- a/packages/app/src/components/Visualization/Visualization.js +++ b/packages/app/src/components/Visualization/Visualization.js @@ -1,3 +1,4 @@ +import { DIMENSION_ID_DATA, VIS_TYPE_PIVOT_TABLE } from '@dhis2/analytics' import VisualizationPlugin from '@dhis2/data-visualizer-plugin' import debounce from 'lodash-es/debounce' import PropTypes from 'prop-types' @@ -19,6 +20,7 @@ import { CombinationDEGSRRError, NoOrgUnitResponseError, NoDataError, + ValueTypeError, } from '../../modules/error.js' import { removeLastPathSegment } from '../../modules/orgUnit.js' import { sGetCurrent } from '../../reducers/current.js' @@ -86,7 +88,19 @@ export class UnconnectedVisualization extends Component { onResponsesReceived = (responses) => { const forMetadata = {} + responses.forEach((response) => { + if ( + (response?.metaData?.dimensions || {})[ + DIMENSION_ID_DATA + ]?.every( + (dim) => response.metaData.items[dim]?.valueType === 'TEXT' + ) && + this.props.visualization.type !== VIS_TYPE_PIVOT_TABLE + ) { + throw new ValueTypeError() + } + Object.entries(response.metaData.items).forEach(([id, item]) => { forMetadata[id] = { id, diff --git a/packages/app/src/modules/error.js b/packages/app/src/modules/error.js index 20c2e626a5..334a2c3247 100644 --- a/packages/app/src/modules/error.js +++ b/packages/app/src/modules/error.js @@ -323,6 +323,18 @@ export class NoOrgUnitResponseError extends VisualizationError { } } +export class ValueTypeError extends VisualizationError { + constructor() { + super( + DataError, + i18n.t('Invalid data type'), + i18n.t( + "The selected data dimensions didn't return any valid data. This visualization type can only display numerical data." + ) + ) + } +} + export const genericErrorTitle = i18n.t('Something went wrong') const getAvailableAxesDescription = (visType) => {