Skip to content

Commit

Permalink
feat: distinguish non-existent repetitions from empty values in line …
Browse files Browse the repository at this point in the history
…lists (DHIS2-15767) (#427)

* fix: add custom styling to undefined cells

* fix: update color according to spec change

* fix: add tooltip to undefined cells

* chore: update PR template

* test: add tests for undefined values

* test: change test cell to match test.e2e data

* refactor: apply changes / suggestions from recent review

* chore: update PR template

* fix: remove background color for undefined cell

* fix: change background image for undefined cell

* fix: return empty value for undefined boolean cells

* fix: always display 'no event' for enrollment

* test: change tooltip label

---------

Co-authored-by: Jan Henrik Øverland <[email protected]>
  • Loading branch information
martinkrulltott and janhenrikoverland authored Nov 30, 2023
1 parent 2f6e1b3 commit 675118d
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 62 deletions.
2 changes: 1 addition & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ _text_

- [ ] Cypress tests
- [ ] Update docs
- [ ] KFMT
- [ ] Manual testing
- [ ] _task_

---
Expand Down
39 changes: 39 additions & 0 deletions cypress/integration/repeatedEvents.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ import {
getTableHeaderCells,
expectTableToBeVisible,
getTableDataCells,
getTableRows,
} from '../helpers/table.js'
import { EXTENDED_TIMEOUT } from '../support/util.js'

const getRepeatedEventsTab = () =>
cy.getBySel('conditions-modal-content').contains('Repeated events')
Expand Down Expand Up @@ -228,4 +230,41 @@ describe('repeated events', () => {

getRepeatedEventsTab().should('not.have.class', 'disabled')
})
it('undefined values display properly for a repeated event', () => {
const TEST_CELL = {
row: 6,
column: 3,
}
goToAO('WrIV7ZoYECj')

cy.getBySel('titlebar', EXTENDED_TIMEOUT)
.should('be.visible')
.and('contain', 'E2E: Enrollment - Hemoglobin (repeated)')

getTableRows()
.eq(TEST_CELL.row)
.find('td')
.eq(TEST_CELL.column)
.invoke('text')
.invoke('trim')
.should('equal', '')

getTableRows()
.eq(TEST_CELL.row)
.find('td')
.eq(TEST_CELL.column)
.should(($td) => {
const className = $td[0].className

expect(className).to.match(/Visualization_undefinedCell*/)
})

getTableRows()
.eq(TEST_CELL.row)
.find('td')
.eq(TEST_CELL.column)
.trigger('mouseover')

cy.getBySelLike('tooltip-content').contains('No event')
})
})
7 changes: 5 additions & 2 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"POT-Creation-Date: 2023-09-27T14:21:34.503Z\n"
"PO-Revision-Date: 2023-09-27T14:21:34.503Z\n"
"POT-Creation-Date: 2023-11-29T10:50:15.561Z\n"
"PO-Revision-Date: 2023-11-29T10:50:15.561Z\n"

msgid "Add to {{axisName}}"
msgstr "Add to {{axisName}}"
Expand Down Expand Up @@ -383,6 +383,9 @@ msgstr ""
msgid "Sort by {{column}}"
msgstr "Sort by {{column}}"

msgid "No event"
msgstr "No event"

msgid "Rows per page"
msgstr "Rows per page"

Expand Down
123 changes: 71 additions & 52 deletions src/components/Visualization/Visualization.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import {
} from '../../modules/visualization.js'
import styles from './styles/Visualization.module.css'
import {
cellIsUndefined,
getAdaptedVisualization,
useAnalyticsData,
} from './useAnalyticsData.js'
Expand Down Expand Up @@ -366,6 +367,50 @@ export const Visualization = ({
</div>
)

const renderCellContent = ({ columnIndex, value, isUndefined, props }) => (
<DataTableCell
{...props}
key={columnIndex}
className={cx(
styles.cell,
fontSizeClass,
sizeClass,
{
[styles.emptyCell]: !value,
[styles.nowrap]: cellValueShouldNotWrap(
data.headers[columnIndex]
),
[styles.undefinedCell]: isUndefined,
},
'bordered'
)}
backgroundColor={
visualization.legend?.style === LEGEND_DISPLAY_STYLE_FILL
? getColorByValueFromLegendSet(
data.headers[columnIndex].legendSet,
value
)
: undefined
}
dataTest={'table-cell'}
>
<div
style={
visualization.legend?.style === LEGEND_DISPLAY_STYLE_TEXT
? {
color: getColorByValueFromLegendSet(
data.headers[columnIndex].legendSet,
value
),
}
: {}
}
>
{formatCellValue(value, data.headers[columnIndex])}
</div>
</DataTableCell>
)

return (
<div className={styles.pluginContainer} ref={containerCallbackRef}>
<div
Expand Down Expand Up @@ -459,62 +504,36 @@ export const Visualization = ({
</DataTableHead>
{/* https://jira.dhis2.org/browse/LIBS-278 */}
<DataTableBody dataTest={'table-body'}>
{data.rows.map((row, index) => (
{data.rows.map((row, rowIndex) => (
<DataTableRow
key={index}
key={rowIndex}
dataTest={'table-row'}
>
{row.map((value, index) => (
<DataTableCell
key={index}
className={cx(
styles.cell,
fontSizeClass,
sizeClass,
{
[styles.emptyCell]: !value,
[styles.nowrap]:
cellValueShouldNotWrap(
data.headers[index]
),
},
'bordered'
)}
backgroundColor={
visualization.legend?.style ===
LEGEND_DISPLAY_STYLE_FILL
? getColorByValueFromLegendSet(
data.headers[index]
.legendSet,
value
)
: undefined
}
dataTest={'table-cell'}
>
<div
style={
visualization.legend
?.style ===
LEGEND_DISPLAY_STYLE_TEXT
? {
color: getColorByValueFromLegendSet(
data.headers[
index
].legendSet,
value
),
}
: {}
}
{row.map((value, columnIndex) =>
cellIsUndefined(
data.rowContext,
rowIndex,
columnIndex
) ? (
<Tooltip
content={i18n.t('No event')}
>
{formatCellValue(
value,
data.headers[index]
)}
</div>
</DataTableCell>
))}
{(props) =>
renderCellContent({
columnIndex,
value,
isUndefined: true,
props,
})
}
</Tooltip>
) : (
renderCellContent({
columnIndex,
value,
})
)
)}
</DataTableRow>
))}
</DataTableBody>
Expand Down
11 changes: 11 additions & 0 deletions src/components/Visualization/styles/Visualization.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,17 @@
white-space: nowrap;
}

.dataTable .undefinedCell {
background-image: repeating-linear-gradient(
45deg,
var(--colors-grey300) 0,
var(--colors-grey300) 0.8px,
transparent 0,
transparent 50%
);
background-size: 8px 8px;
}

/* Sizes for the table footer */
.dataTable .stickyNavigation.sizeComfortable {
padding: 14px 12px;
Expand Down
30 changes: 23 additions & 7 deletions src/components/Visualization/useAnalyticsData.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,18 @@ const lookupOptionSetOptionMetadata = (optionSetId, code, metaDataItems) => {

return undefined
}
const NOT_DEFINED_VALUE = 'ND'

const formatRowValue = (rowValue, header, metaDataItems) => {
export const cellIsUndefined = (rowContext = {}, rowIndex, columnIndex) =>
(rowContext[rowIndex] || {})[columnIndex]?.valueStatus === NOT_DEFINED_VALUE

const formatRowValue = ({ rowValue, header, metaDataItems, isUndefined }) => {
switch (header.valueType) {
case VALUE_TYPE_BOOLEAN:
case VALUE_TYPE_TRUE_ONLY:
return getBooleanValues()[rowValue || NULL_VALUE]
return !isUndefined
? getBooleanValues()[rowValue || NULL_VALUE]
: ''
default: {
if (!rowValue) {
return rowValue
Expand Down Expand Up @@ -166,6 +172,9 @@ const fetchAnalyticsData = async ({
.withParameters({
headers,
totalPages: false,
...(visualization.outputType !== OUTPUT_TYPE_EVENT
? { rowContext: true }
: {}),
...parameters,
})
.withProgram(visualization.program.id)
Expand Down Expand Up @@ -271,15 +280,19 @@ const extractRows = (analyticsResponse, headers) => {
headerIndex++
) {
const header = headers[headerIndex]

const rowValue = row[header.index]

filteredRow.push(
formatRowValue(
formatRowValue({
rowValue,
header,
analyticsResponse.metaData.items
)
metaDataItems: analyticsResponse.metaData.items,
isUndefined: cellIsUndefined(
analyticsResponse.rowContext,
rowIndex,
headerIndex
),
})
)
}

Expand All @@ -289,6 +302,8 @@ const extractRows = (analyticsResponse, headers) => {
return filteredRows
}

const extractRowContext = (analyticsResponse) => analyticsResponse.rowContext

const valueTypeIsNumeric = (valueType) =>
[
VALUE_TYPE_NUMBER,
Expand Down Expand Up @@ -334,6 +349,7 @@ const useAnalyticsData = ({
})
const headers = extractHeaders(analyticsResponse)
const rows = extractRows(analyticsResponse, headers)
const rowContext = extractRowContext(analyticsResponse)
const pager = analyticsResponse.metaData.pager
const legendSetIds = []
const headerLegendSetMap = headers.reduce(
Expand Down Expand Up @@ -386,7 +402,7 @@ const useAnalyticsData = ({
}

mounted.current && setError(undefined)
mounted.current && setData({ headers, rows, pager })
mounted.current && setData({ headers, rows, pager, rowContext })
onResponsesReceived(analyticsResponse)
} catch (error) {
mounted.current && setError(error)
Expand Down

0 comments on commit 675118d

Please sign in to comment.