Skip to content

Commit

Permalink
feat(DHIS2-16132): add ability to transpose/pivot a section form (#367)
Browse files Browse the repository at this point in the history
* feat(DHIS2-16132): add ability to transpose/pivot a section form

feat: add ability to transpose/pivot a section form

refactor: change file structure to separate transposed from grouped

test: add missed tests

* refactor: apply code review comments
  • Loading branch information
kabaros authored Mar 5, 2024
1 parent 9b6bacf commit 1d841ab
Show file tree
Hide file tree
Showing 15 changed files with 24,298 additions and 502 deletions.
10 changes: 8 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-08-10T08:31:47.096Z\n"
"PO-Revision-Date: 2023-08-10T08:31:47.096Z\n"
"POT-Creation-Date: 2024-01-15T14:35:08.966Z\n"
"PO-Revision-Date: 2024-01-15T14:35:08.966Z\n"

msgid "Not authorized"
msgstr "Not authorized"
Expand Down Expand Up @@ -210,6 +210,9 @@ msgstr "Data item has a comment"
msgid "Invalid value, not saved"
msgstr "Invalid value, not saved"

msgid "Warning, saved"
msgstr "Warning, saved"

msgid "Locked, not editable"
msgstr "Locked, not editable"

Expand Down Expand Up @@ -588,3 +591,6 @@ msgstr "{{title}} (disabled)"

msgid "Close details sidebar"
msgstr "Close details sidebar"

msgid "Integer numbers have to be in the range from -2147483648 to 2147483647"
msgstr "Integer numbers have to be in the range from -2147483648 to 2147483647"
14 changes: 10 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"devDependencies": {
"@badeball/cypress-cucumber-preprocessor": "^16.0.0",
"@cypress/webpack-preprocessor": "^5.17.0",
"@dhis2/cli-app-scripts": "^10.2.3",
"@dhis2/cli-app-scripts": "^10.4.0",
"@dhis2/cli-style": "10.5.1",
"@dhis2/cypress-commands": "^10.0.1",
"@dhis2/cypress-plugins": "^10.0.1",
Expand All @@ -45,12 +45,13 @@
"enzyme-adapter-react-16": "1.15.7",
"eslint-plugin-cypress": "2.12.1",
"fake-indexeddb": "4.0.1",
"jest-extended": "^4.0.2",
"start-server-and-test": "1.15.4"
},
"dependencies": {
"@dhis2/app-runtime": "^3.8.0",
"@dhis2/multi-calendar-dates": "^1.0.0-alpha.22",
"@dhis2/ui": "^8.12.0",
"@dhis2/app-runtime": "^3.10.2",
"@dhis2/multi-calendar-dates": "^1.1.0",
"@dhis2/ui": "^9.2.0",
"@dhis2/ui-forms": "7.16.3",
"@tanstack/react-query": "4.24.10",
"@tanstack/react-query-devtools": "4.24.14",
Expand All @@ -77,5 +78,10 @@
},
"engines": {
"node": ">=14.0.0"
},
"resolutions": {
"@dhis2/multi-calendar-dates": "^1.1.0",
"@dhis2/ui": "^9.2.0",
"@dhis2/app-runtime": "^3.10.2"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import { TableRow, TableCell, TableCellHead } from '@dhis2/ui'
import classNames from 'classnames'
import PropTypes from 'prop-types'
import React from 'react'
import { useMetadata, selectors } from '../../shared/index.js'
import { DataEntryCell, DataEntryField } from '../data-entry-cell/index.js'
import { getFieldId } from '../get-field-id.js'
import styles from '../table-body.module.css'
import { generateFormMatrix } from './generate-form-matrix/index.js'

/**
* This component is based on the CategoryComboTableBody, and the two should be consolidate eventually.
* Some of the reasons for the separate component:
* - data elements are baked into CategoryComboTableBody as rows. With pivoting, we need flexibility in defining what's a row and what's a column that wasn't easy to implement there
* - This reliance on data elements extends to functionality such as search filters, which is disabled here as we don't have rows of data elements anymore in a pivoted table (they could be columns or rows)
* - row headers are more complicated in this structure as they can have categories and category options
*
* ToDo(pivot): The plan is that - after that pivoting core functionality is finalised - to have a look at both components and consolidate them.
* https://dhis2.atlassian.net/browse/LIBS-584
*
*/
export const PivotedCategoryComboTableBody = React.memo(
function PivotedCategoryComboTableBody({
categoryCombo,
dataElements,
greyedFields,
/*
filterText,
globalFilterText,
maxColumnsInSection,
renderRowTotals,
renderColumnTotals,*/
displayOptions,
}) {
const { data: metadata } = useMetadata()

const categories = selectors.getCategoriesByCategoryComboId(
metadata,
categoryCombo.id
)

const sortedCOCs = selectors.getSortedCoCsByCatComboId(
metadata,
categoryCombo.id
)

const categoryOptionsDetails = categories
.map((c) => {
const headerOptions = selectors.getCategoryOptionsByCategoryId(
metadata,
c.id
)
return [...headerOptions]
})
.flat()

const options = {
metadata,
categoryOptionsDetails,
sortedCOCs,
categories,
dataElements,
}

const rowsMatrix = generateFormMatrix(options, displayOptions)

return (
<>
{rowsMatrix.map((row, id /** todo: find suitable id */) => {
return (
<TableRow key={id}>
{row.map((fieldInRow) => {
if (
fieldInRow.type === 'columnHeader' ||
fieldInRow.type === 'rowHeader'
) {
return (
<TableCellHead
key={fieldInRow.id}
className={classNames(
[
styles.pivotedHeader,
styles.noWrap,
styles[
fieldInRow.metadataType
],
],
{
[styles.dataElementRowHeader]:
fieldInRow.metadataType ===
'dataElement',
}
)}
colSpan={fieldInRow.colSpan}
rowSpan={fieldInRow.rowSpan}
>
{fieldInRow.name !== 'default' &&
fieldInRow.displayFormName}
</TableCellHead>
)
}

if (fieldInRow.type === 'empty') {
return (
<TableCell
className={[
styles.categoryNameHeader,
styles.noWrap,
]}
key={fieldInRow.id}
colSpan={fieldInRow.colSpan}
rowSpan={fieldInRow.rowSpan}
/>
)
}

if (fieldInRow.type === 'de') {
return (
<DataEntryCell key={fieldInRow.id}>
<DataEntryField
dataElement={
fieldInRow.dataElement
}
categoryOptionCombo={
fieldInRow.coc
}
disabled={greyedFields?.has(
getFieldId(
fieldInRow.dataElement
.id,
fieldInRow.coc.id
)
)}
/>
</DataEntryCell>
)
}
// should never get here
return <>unsupported field</>
})}
</TableRow>
)
})}
</>
)
}
)

export const DisplayOptionsProps = PropTypes.shape({
pivotMode: PropTypes.oneOf(['move_categories', 'pivot']),
pivotedCategory: PropTypes.string,
textAfterSection: PropTypes.string,
textBeforeSection: PropTypes.string,
})

PivotedCategoryComboTableBody.propTypes = {
categoryCombo: PropTypes.shape({
id: PropTypes.string.isRequired,
}),
dataElements: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string.isRequired,
displayFormName: PropTypes.string,
headerCombo: PropTypes.shape({
id: PropTypes.string,
}),
valueType: PropTypes.string,
})
),
displayOptions: DisplayOptionsProps,
/** Greyed fields is a Set where .has(fieldId) is true if that field is greyed/disabled */
greyedFields: PropTypes.instanceOf(Set),
}
Loading

1 comment on commit 1d841ab

@dhis2-bot
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.