Skip to content

Commit

Permalink
Merge pull request #2699 from dhis2/dev
Browse files Browse the repository at this point in the history
fix: merge to master

Fixes included in this release:

DHIS2-14544 avoid crash when filtering on ou levels or groups when dashboard has an app widget
  • Loading branch information
jenniferarnesen authored Sep 13, 2023
2 parents 4e6110e + 35877e1 commit 4d40998
Show file tree
Hide file tree
Showing 11 changed files with 754 additions and 549 deletions.
39 changes: 28 additions & 11 deletions cypress/integration/common/view/add_a_FILTERTYPE_filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,35 @@ const FACILITY_TYPE = 'Clinic'
When('I add a {string} filter', (dimensionType) => {
cy.contains('Add filter').click()

// open the dimensions modal
cy.get(filterDimensionsPanelSel).contains(dimensionType).click()

// select an item in the modal
if (dimensionType === 'Period') {
cy.get(unselectedItemsSel).contains(PERIOD).dblclick()
} else if (dimensionType === 'Organisation unit') {
cy.get(orgUnitTreeSel, EXTENDED_TIMEOUT)
.find('[type="checkbox"]', EXTENDED_TIMEOUT)
.check(OU_ID)
} else {
cy.get(unselectedItemsSel).contains(FACILITY_TYPE).dblclick()
switch (dimensionType) {
case 'Period':
cy.get(filterDimensionsPanelSel).contains(dimensionType).click()
cy.get(unselectedItemsSel).contains(PERIOD).dblclick()
break
case 'Organisation unit':
cy.get(filterDimensionsPanelSel).contains(dimensionType).click()
cy.get(orgUnitTreeSel, EXTENDED_TIMEOUT)
.find('[type="checkbox"]', EXTENDED_TIMEOUT)
.check(OU_ID)
break
case 'Org unit group':
cy.get(filterDimensionsPanelSel)
.contains('Organisation unit')
.click()
cy.getByDataTest('org-unit-group-select').click()
cy.getByDataTest('dhis2-uicore-select-menu-menuwrapper')
.contains('District')
.click()
// close the popup
cy.getByDataTest('dhis2-uicore-select-menu-menuwrapper')
.closest('[data-test="dhis2-uicore-layer"]')
.click('topLeft')
break

default:
cy.get(filterDimensionsPanelSel).contains(dimensionType).click()
cy.get(unselectedItemsSel).contains(FACILITY_TYPE).dblclick()
}

// confirm to apply the filter
Expand Down
8 changes: 7 additions & 1 deletion cypress/integration/view/dashboard_filter.feature
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Feature: Dashboard filter

Scenario: I add a Period filter
When I start a new dashboard
And I add a MAP and a CHART and save
And I add items and save
Then the dashboard displays in view mode
When I add a "Period" filter
Then the Period filter is applied to the dashboard
Expand All @@ -19,6 +19,12 @@ Feature: Dashboard filter
When I add a "Facility Type" filter
Then the Facility Type filter is applied to the dashboard

Scenario: I add a Org unit group filter
Given I open existing dashboard
Then the dashboard displays in view mode
When I add a "Org unit group" filter
Then the Org unit group filter is applied to the dashboard

Scenario: I can access the dimensions modal from the filter badge
Given I open existing dashboard
When I add a "Period" filter
Expand Down
88 changes: 60 additions & 28 deletions cypress/integration/view/dashboard_filter/create_dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,49 +9,78 @@ import {
dashboardChipSel,
dashboardTitleSel,
} from '../../../elements/viewDashboard.js'
import { getApiBaseUrl } from '../../../support/server/utils.js'
import {
EXTENDED_TIMEOUT,
createDashboardTitle,
} from '../../../support/utils.js'

const TEST_DASHBOARD_TITLE = createDashboardTitle('af')

When('I add a MAP and a CHART and save', () => {
//add the title
cy.get('[data-test="dashboard-title-input"]').type(TEST_DASHBOARD_TITLE)
const customApp = {
name: 'Users-Role-Monitor-Widget',
id: '5e43908a-3105-4baa-9a00-87a94ebdc034',
}

// add items
cy.get('[data-test="item-search"]').click()
cy.get('[data-test="item-search"]')
.find('input')
.type('Inpatient', { force: true })
When('I add items and save', () => {
// first install a custom app
cy.request('POST', `${getApiBaseUrl()}/api/appHub/${customApp.id}`).then(
(response) => {
expect(response.status).to.eq(204)

//chart
cy.get(
'[data-test="menu-item-Inpatient: BMI this year by districts"]'
).click()
//add the dashboard title
cy.get('[data-test="dashboard-title-input"]').type(
TEST_DASHBOARD_TITLE
)

cy.get('[data-test="dhis2-uicore-layer"]').click('topLeft')
// open item selector
cy.get('[data-test="item-search"]').click()
cy.get('[data-test="item-search"]')
.find('input')
.type('Inpatient', { force: true })

cy.get('[data-test="item-search"]').click()
cy.get('[data-test="item-search"]')
.find('input')
.type('ipt 2', { force: true })
//CHART
cy.get(
'[data-test="menu-item-Inpatient: BMI this year by districts"]'
).click()

//map
cy.get('[data-test="menu-item-ANC: IPT 2 Coverage this year"]').click()
cy.get('[data-test="dhis2-uicore-layer"]').click('topLeft')

cy.get('[data-test="dhis2-uicore-layer"]').click('topLeft')
cy.get('[data-test="item-search"]').click()
cy.get('[data-test="item-search"]')
.find('input')
.type('ipt 2', { force: true })

//move things so the dashboard is more compact
// eslint-disable-next-line cypress/unsafe-to-chain-command
cy.get(`${gridItemSel}.MAP`)
.trigger('mousedown')
.trigger('mousemove', { clientX: 650 })
.trigger('mouseup')
//MAP
cy.get(
'[data-test="menu-item-ANC: IPT 2 Coverage this year"]'
).click()

//save
cy.get('button').contains('Save changes', EXTENDED_TIMEOUT).click()
// close the item selector
cy.get('[data-test="dhis2-uicore-layer"]').click('topLeft')

//add a custom app item
cy.get('[data-test="item-search"]').click()
cy.get('[data-test="item-search"]')
.find('input')
.type('Role Monitor', { force: true })

cy.contains('Role Monitor Widget').click()

// close the item selector
cy.get('[data-test="dhis2-uicore-layer"]').click('topLeft')

//move things so the dashboard is more compact
// eslint-disable-next-line cypress/unsafe-to-chain-command
cy.get(`${gridItemSel}.MAP`)
.trigger('mousedown')
.trigger('mousemove', { clientX: 650 })
.trigger('mouseup')

//save
cy.get('button').contains('Save changes', EXTENDED_TIMEOUT).click()
}
)
})

Given('I open existing dashboard', () => {
Expand Down Expand Up @@ -84,4 +113,7 @@ Then('different dashboard displays in view mode', () => {
cy.get(dashboardTitleSel)
.should('be.visible')
.and('not.contain', TEST_DASHBOARD_TITLE)

// remove the custom app
cy.request('DELETE', `${getApiBaseUrl()}/api/apps/${customApp.name}`)
})
17 changes: 17 additions & 0 deletions cypress/integration/view/dashboard_filter/dashboard_filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,23 @@ Then('the Facility Type filter is applied to the dashboard', () => {
// .should('be.visible')
})

Then('the Org unit group filter is applied to the dashboard', () => {
// check that the filter badge is correct
cy.get(filterBadgeSel)
.contains('Organisation unit: District')
.should('be.visible')

// check that the custom app is loaded (see ticket DHIS2-14544)
cy.get('iframe')
.invoke('attr', 'title')
.contains('Role Monitor Widget')
.scrollIntoView()
cy.get('iframe')
.invoke('attr', 'title')
.contains('Role Monitor Widget')
.should('be.visible')
})

Then('the filter modal is opened', () => {
cy.get(dimensionsModalSel, EXTENDED_TIMEOUT).should('be.visible')
})
25 changes: 25 additions & 0 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Cypress.Commands.add('getByDataTest', (selector, ...args) =>
cy.get(`[data-test=${selector}]`, ...args)
)
Cypress.Commands.add(
'findByDataTest',
{
prevSubject: true,
},
(subject, selector, ...args) =>
cy.wrap(subject).find(`[data-test="${selector}"]`, ...args)
)

Cypress.Commands.add(
'containsExact',
{
prevSubject: 'optional',
},
(subject, selector) =>
cy.wrap(subject).contains(
new RegExp(
`^${selector.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')}$`, //eslint-disable-line no-useless-escape
'gm'
)
)
)
1 change: 1 addition & 0 deletions cypress/support/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { enableAutoLogin } from '@dhis2/cypress-commands'
import { enableNetworkShim } from './server/index.js'
import { getDefaultMode, isStubMode } from './server/utils.js'
import './commands.js'

enableNetworkShim()

Expand Down
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
"private": true,
"license": "BSD-3-Clause",
"dependencies": {
"@dhis2/analytics": "^25.1.15",
"@dhis2/app-runtime": "^3.9.3",
"@dhis2/analytics": "^26.0.17",
"@dhis2/app-runtime": "^3.9.4",
"@dhis2/app-runtime-adapter-d2": "^1.1.0",
"@dhis2/d2-i18n": "^1.1.1",
"@dhis2/d2-ui-core": "^7.4.3",
"@dhis2/d2-ui-interpretations": "^7.4.3",
"@dhis2/d2-ui-mentions-wrapper": "^7.4.3",
"@dhis2/d2-ui-rich-text": "^7.4.3",
"@dhis2/ui": "^8.13.11",
"@dhis2/ui": "^8.14.0",
"@krakenjs/post-robot": "^11.0.0",
"classnames": "^2.3.2",
"d2": "^31.10.0",
Expand Down Expand Up @@ -50,14 +50,14 @@
"cy:capture": "cypress_dhis2_api_stub_mode=CAPTURE yarn d2-utils-cypress run --appStart 'yarn cypress:start'"
},
"devDependencies": {
"@dhis2/cli-app-scripts": "^10.3.9",
"@dhis2/cli-app-scripts": "^10.3.10",
"@dhis2/cli-style": "^10.5.1",
"@dhis2/cli-utils-cypress": "^7.0.1",
"@dhis2/cypress-commands": "^7.0.1",
"@testing-library/jest-dom": "^6.1.2",
"@testing-library/react": "^12.0.0",
"@testing-library/react": "^12",
"d2-manifest": "^1.0.0",
"eslint-plugin-cypress": "^2.11.3",
"eslint-plugin-cypress": "^2.14.0",
"immutability-helper": "^3.1.1",
"patch-package": "^7",
"postinstall-postinstall": "^2.1.0",
Expand Down
16 changes: 1 addition & 15 deletions src/components/Item/AppItem/Item.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,13 @@ import { Divider, colors, spacers, IconQuestion24 } from '@dhis2/ui'
import PropTypes from 'prop-types'
import React from 'react'
import { connect } from 'react-redux'
import { FILTER_ORG_UNIT } from '../../../actions/itemFilters.js'
import { EDIT, isEditMode } from '../../../modules/dashboardModes.js'
import {
sGetItemFiltersRoot,
DEFAULT_STATE_ITEM_FILTERS,
} from '../../../reducers/itemFilters.js'
import ItemHeader from '../ItemHeader/ItemHeader.js'

const getIframeSrc = (appDetails, item, itemFilters) => {
let iframeSrc = `${appDetails.launchUrl}?dashboardItemId=${item.id}`

if (itemFilters[FILTER_ORG_UNIT] && itemFilters[FILTER_ORG_UNIT].length) {
const ouIds = itemFilters[FILTER_ORG_UNIT].map(
(ouFilter) => ouFilter.path.split('/').slice(-1)[0]
)

iframeSrc += `&userOrgUnit=${ouIds.join(',')}`
}

return iframeSrc
}
import { getIframeSrc } from './getIframeSrc.js'

const AppItem = ({ dashboardMode, item, itemFilters }) => {
const { d2 } = useD2()
Expand Down
Loading

0 comments on commit 4d40998

Please sign in to comment.