Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4084a6f
feat: preserve optionSet on event layer table headers
BRaimbault Jul 13, 2026
451557b
feat: compute columnOptions for categorical data table columns
BRaimbault Jul 13, 2026
4ce4b3f
feat: support array-valued (multi-select) filters in filterData
BRaimbault Jul 13, 2026
2d263fe
feat: add filterByGlobalSearch utility and thread globalSearch throug…
BRaimbault Jul 13, 2026
d040a58
feat: add multi-select dropdown filter to FilterInput
BRaimbault Jul 13, 2026
8c4a621
feat: add numeric filter syntax help tooltip
BRaimbault Jul 13, 2026
0cbfac0
feat: pass columnOptions and optionSet through DataTable to FilterInput
BRaimbault Jul 13, 2026
7edbeb0
feat: add global search box to data table toolbar
BRaimbault Jul 13, 2026
121a86d
feat: wire legend item clicks to pre-populate data table filter
BRaimbault Jul 13, 2026
5ad7cee
chore: fix lint/prettier issues in PR3 files
BRaimbault Jul 13, 2026
9b96a2a
fix: toolbar polish - clear filters button, search sizing, collapse i…
BRaimbault Jul 14, 2026
9c58d46
feat: round out data table filtering with reverse-selection, zoom-to-…
BRaimbault Jul 14, 2026
51feb4f
revert: remove legend-click-to-filter, deferred to a future PR
BRaimbault Jul 14, 2026
c0716a6
chore: sonarqube issues
BRaimbault Jul 14, 2026
26ded61
chore: sonarqube issues
BRaimbault Jul 14, 2026
b672eed
chore: sonarqube issue
BRaimbault Jul 14, 2026
f7cc6ee
fix: handle narrow columns and hide index column
BRaimbault Jul 14, 2026
e5ff457
fix: rollback merging range and color columns
BRaimbault Jul 16, 2026
e53ed3e
chore: PR clean-up
BRaimbault Jul 16, 2026
7bbc7fc
chore: sonarqube issues
BRaimbault Jul 16, 2026
eca0c3d
fix: properly format dropdown numeric values
BRaimbault Jul 16, 2026
feeabc1
chore: fix cypress tests
BRaimbault Jul 16, 2026
c3e0725
chore: cypress test fix
BRaimbault Jul 16, 2026
66d88d8
chore: cypress test fix
BRaimbault Jul 16, 2026
82c9bbf
chore: cypress test fix
BRaimbault Jul 17, 2026
e8e3f66
chore: create and use replica accounts in CI
BRaimbault Jul 19, 2026
09f29cc
chore: update e2eReplicaAccount.js
BRaimbault Jul 20, 2026
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
136 changes: 69 additions & 67 deletions cypress/integration/dataTable.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const checkTableCell = ({ row = 0, column = 0, expectedContent }) => {
}

describe('data table', () => {
it('opens data table and filters and sorts', () => {
it('opens data table for a Thematic layer and filters and sorts', () => {
const viewportHeight = Cypress.config('viewportHeight')
const expectedBottoms1 = [viewportHeight]
const expectedHeights1 = [
Expand All @@ -47,7 +47,7 @@ describe('data table', () => {
cy.visit(`/#/${map.id}`)
cy.get('canvas', EXTENDED_TIMEOUT).should('be.visible')

//check that the map resizes properly
// Check that the map resizes properly
assertMapPosition(expectedBottoms1, expectedHeights1)

cy.getByDataTest('moremenubutton').first().click()
Expand All @@ -62,10 +62,10 @@ describe('data table', () => {
.contains('Show data table')
.click()

//check that the bottom panel is present
// Check that the bottom panel is present
cy.getByDataTest('bottom-panel').should('be.visible')

//check that the map resizes properly
// Check that the map resizes properly
cy.getByDataTest('bottom-panel')
.invoke('height')
.then((height) => {
Expand All @@ -80,25 +80,25 @@ describe('data table', () => {
// Collapse the Layers Panel to give the table more width
cy.getByDataTest('layers-toggle-button').click()

// check number of columns
// Check number of columns
cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-datatablecellhead')
.should('have.length', 11)
.should('have.length', 10)

// Filter by name
cy.getByDataTest('data-table-column-filter-input-Name')
cy.getByDataTest('data-table-column-filter-search-Name')
.find('input')
.type('bar')
.type('bar{enter}')

// check that the filter returned the correct number of rows
// Check that the filter returned the correct number of rows
cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.findByDataTest('dhis2-uicore-datatablerow')
.should('have.length', 7)

// confirm that the sort order is initially ascending by Name
checkTableCell({ row: 0, column: 2, expectedContent: 'Bargbe' })
checkTableCell({ row: 6, column: 2, expectedContent: 'Upper Bambara' })
// Confirm that the sort order is initially ascending by Name
checkTableCell({ row: 0, column: 1, expectedContent: 'Bargbe' })
checkTableCell({ row: 6, column: 1, expectedContent: 'Upper Bambara' })

// Sort by name
cy.getByDataTest('data-table-column-sort-button-Name').click()
Expand All @@ -108,16 +108,16 @@ describe('data table', () => {
// so we reset to top before asserting on row indices below
cy.get('[data-testid="virtuoso-scroller"]').scrollTo('top')

// confirm that the rows are sorted by Name descending
checkTableCell({ row: 0, column: 2, expectedContent: 'Upper Bambara' })
checkTableCell({ row: 6, column: 2, expectedContent: 'Bargbe' })
// Confirm that the rows are sorted by Name descending
checkTableCell({ row: 0, column: 1, expectedContent: 'Upper Bambara' })
checkTableCell({ row: 6, column: 1, expectedContent: 'Bargbe' })

// filter by Value (numeric)
cy.getByDataTest('data-table-column-filter-input-Value')
// Filter by Value (numeric)
cy.getByDataTest('data-table-column-filter-search-Value')
.find('input')
.type('>26')
.type('>26{enter}')

// check that the (combined) filter returned the correct number of rows
// Check that the (combined) filter returned the correct number of rows
cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.findByDataTest('dhis2-uicore-datatablerow')
Expand All @@ -129,11 +129,11 @@ describe('data table', () => {
// Reset scroll position after sorting - see comment above
cy.get('[data-testid="virtuoso-scroller"]').scrollTo('top')

// check that the rows are sorted by Value ascending
checkTableCell({ row: 0, column: 4, expectedContent: '35' })
checkTableCell({ row: 4, column: 4, expectedContent: '76' })
// Check that the rows are sorted by Value ascending
checkTableCell({ row: 0, column: 3, expectedContent: '35' })
checkTableCell({ row: 4, column: 3, expectedContent: '76' })

// right-click a row and select "View profile"
// Right-click a row and select "View profile"
cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.findByDataTest('dhis2-uicore-datatablerow')
Expand All @@ -142,22 +142,22 @@ describe('data table', () => {

cy.getByDataTest('data-table-context-menu-view-profile').click()

// check that the org unit profile drawer is opened
// Check that the org unit profile drawer is opened
cy.getByDataTest('org-unit-profile').should('be.visible')

cy.getByDataTest('layers-toggle-button').click()

// close the datatable
// Close the datatable
cy.getByDataTest('moremenubutton').first().click()
cy.getByDataTest('more-menu')
.find('li')
.contains('Hide data table')
.click()

//check that the bottom panel is closed
// Check that the bottom panel is closed
cy.getByDataTest('bottom-panel').should('not.exist')

//check that the map resizes properly
// Check that the map resizes properly
assertMapPosition(expectedBottoms1, expectedHeights1)
})

Expand Down Expand Up @@ -192,56 +192,59 @@ describe('data table', () => {
// Collapse the Layers Panel to give the table more width
cy.getByDataTest('layers-toggle-button').click()

// check number of columns
// Check number of columns
cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-datatablecellhead')
.should('have.length', 11)
.should('have.length', 10)

cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-datatablecellhead')
.contains('Age in years', { matchCase: false })
.should('be.visible')

// filter by Org unit
// Filter by Org unit
const ouName = 'Moyowa'
cy.getByDataTest('data-table-column-filter-input-Org unit')
cy.getByDataTest('data-table-column-filter-search-Org unit')
.find('input')
.type(ouName)
.type(`${ouName}{enter}`)

// check that all the rows have Org unit Moyowa
checkTableCell({ row: 0, column: 2, expectedContent: ouName })
checkTableCell({ row: 2, column: 2, expectedContent: ouName })
// Check that all the rows have Org unit Moyowa
checkTableCell({ row: 0, column: 1, expectedContent: ouName })
checkTableCell({ row: 2, column: 1, expectedContent: ouName })

cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.findByDataTest('dhis2-uicore-datatablerow')
.should('have.length', 3)

// filter by Mode of Discharge
cy.getByDataTest('data-table-column-filter-input-Mode of Discharge')
// Filter by Mode of Discharge
cy.getByDataTest('data-table-column-filter-search-Mode of Discharge')
.find('input')
.type('Absconded')
cy.contains('label', 'Absconded').click()

cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.findByDataTest('dhis2-uicore-datatablerow')
.should('have.length', 1)

cy.getByDataTest('data-table-column-filter-input-Mode of Discharge')
.find('input')
.clear()
cy.get('.backdrop').last().click()

cy.getByDataTest('data-table-column-filter-search-Mode of Discharge')
.find('.clear-button')
.click()

cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.findByDataTest('dhis2-uicore-datatablerow')
.should('have.length', 3)

// filter by Age in years (numeric)
cy.getByDataTest('data-table-column-filter-input-Age in years')
// Filter by Age in years (numeric)
cy.getByDataTest('data-table-column-filter-search-Age in years')
.find('input')
.type('<51')
.type('<51{enter}')

// check that the filter returned the correct number of rows
// Check that the filter returned the correct number of rows
cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.findByDataTest('dhis2-uicore-datatablerow')
Expand All @@ -252,10 +255,10 @@ describe('data table', () => {

// Confirm that the rows are sorted by Age in years ascending
// (the first click on a new column always sorts ascending)
checkTableCell({ row: 0, column: 8, expectedContent: '6' })
checkTableCell({ row: 1, column: 8, expectedContent: '32' })
checkTableCell({ row: 0, column: 7, expectedContent: '6' })
checkTableCell({ row: 1, column: 7, expectedContent: '32' })

// right-click a row: Event layers have no profile to view
// Right-click a row: Event layers have no profile to view
cy.getByDataTest('bottom-panel')
.findByDataTest('dhis2-uicore-tablebody')
.findByDataTest('dhis2-uicore-datatablerow')
Expand All @@ -266,7 +269,7 @@ describe('data table', () => {
'not.exist'
)

// check that the org unit profile drawer is NOT opened
// Check that the org unit profile drawer is NOT opened
cy.getByDataTest('org-unit-profile').should('not.exist')
})

Expand Down Expand Up @@ -314,7 +317,7 @@ describe('data table', () => {
cy.getByDataTest('layers-toggle-button').click()

// Confirm that the sort order is initially ascending by Name
checkTableCell({ row: 0, column: 2, expectedContent: 'Bendu CHC' })
checkTableCell({ row: 0, column: 1, expectedContent: 'Bendu CHC' })

// First click on a new column always sorts ascending
cy.getByDataTest('data-table-column-sort-button-Value').click()
Expand All @@ -323,40 +326,39 @@ describe('data table', () => {
cy.get('[data-testid="virtuoso-scroller"]').scrollTo('top')

// Check that first row has Tihun CHC with value 28.63
checkTableCell({ row: 0, column: 2, expectedContent: 'Tihun CHC' })
checkTableCell({ row: 0, column: 4, expectedContent: '28.63' })
checkTableCell({ row: 0, column: 1, expectedContent: 'Tihun CHC' })
checkTableCell({ row: 0, column: 3, expectedContent: '28.63' })

// Check that row 5 has Gbamgbama CHC with value 117.98
checkTableCell({ row: 5, column: 2, expectedContent: 'Gbamgbama CHC' })
checkTableCell({ row: 5, column: 4, expectedContent: '117.98' })
checkTableCell({ row: 5, column: 1, expectedContent: 'Gbamgbama CHC' })
checkTableCell({ row: 5, column: 3, expectedContent: '117.98' })

// Check that row 6 has no value (undefined)
checkTableCell({ row: 6, column: 4, expectedContent: '' })
checkTableCell({ row: 6, column: 3, expectedContent: '' })

// Sort descending by Value
cy.getByDataTest('data-table-column-sort-button-Value').click()

// Reset scroll position after sorting - see comment above
cy.get('[data-testid="virtuoso-scroller"]').scrollTo('top')

checkTableCell({ row: 0, column: 2, expectedContent: 'Gbamgbama CHC' })
checkTableCell({ row: 0, column: 4, expectedContent: '117.98' })
checkTableCell({ row: 0, column: 1, expectedContent: 'Gbamgbama CHC' })
checkTableCell({ row: 0, column: 3, expectedContent: '117.98' })

checkTableCell({ row: 5, column: 2, expectedContent: 'Tihun CHC' })
checkTableCell({ row: 5, column: 4, expectedContent: '28.63' })
checkTableCell({ row: 5, column: 1, expectedContent: 'Tihun CHC' })
checkTableCell({ row: 5, column: 3, expectedContent: '28.63' })

checkTableCell({ row: 6, column: 4, expectedContent: '' })
checkTableCell({ row: 6, column: 3, expectedContent: '' })

// Sort by index (a new column, so ascending)
cy.getByDataTest('data-table-column-sort-button-Index').click()
// Third click on the same column cycles back to natural (unsorted)
// order - there's no dedicated Index column/button any more
cy.getByDataTest('data-table-column-sort-button-Value').click()

// Reset scroll position after sorting - see comment above
cy.get('[data-testid="virtuoso-scroller"]').scrollTo('top')

checkTableCell({ row: 0, column: 1, expectedContent: '0' })

// Check that row 0 range value is empty
checkTableCell({ row: 0, column: 6, expectedContent: '' })
checkTableCell({ row: 0, column: 5, expectedContent: '' })

// Sort by range, which is a string
cy.getByDataTest('data-table-column-sort-button-Range').click()
Expand All @@ -365,12 +367,12 @@ describe('data table', () => {
cy.get('[data-testid="virtuoso-scroller"]').scrollTo('top')

// Check that row 0 range value has value '0-40'
checkTableCell({ row: 0, column: 6, expectedContent: '0 – 40' })
checkTableCell({ row: 0, column: 5, expectedContent: '0 – 40' })

// Check that row 5 range value has value '90 - 120'
checkTableCell({ row: 5, column: 6, expectedContent: '90 – 120' })
checkTableCell({ row: 5, column: 5, expectedContent: '90 – 120' })

// Check that row 6 range value is empty
checkTableCell({ row: 6, column: 6, expectedContent: '' })
checkTableCell({ row: 6, column: 5, expectedContent: '' })
})
})
Loading
Loading