diff --git a/package.json b/package.json index a6e1e5f6e..ecbb9410f 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "@tanstack/react-query-persist-client": "4.24.10", "chart.js": "3.9.1", "classnames": "2.3.2", + "dompurify": "^3.0.9", "expr-eval": "2.0.2", "final-form": "4.20.9", "final-form-set-field-data": "1.0.2", diff --git a/src/data-workspace/section-form/section-description.js b/src/data-workspace/section-form/section-description.js new file mode 100644 index 000000000..a79951d5c --- /dev/null +++ b/src/data-workspace/section-form/section-description.js @@ -0,0 +1,24 @@ +import * as DOMPurify from 'dompurify' +import PropTypes from 'prop-types' +import React from 'react' +import styles from './section.module.css' + +export const SectionDescription = ({ children }) => { + if (!children) { + return null + } + const html = DOMPurify.sanitize(children, { + ALLOWED_TAGS: ['a', 'b', 'strong', 'underline'], + }) + + return ( +
+ ) +} + +SectionDescription.propTypes = { + children: PropTypes.node.isRequired, +} diff --git a/src/data-workspace/section-form/section.js b/src/data-workspace/section-form/section.js index 74affa175..1f66021f6 100644 --- a/src/data-workspace/section-form/section.js +++ b/src/data-workspace/section-form/section.js @@ -18,6 +18,7 @@ import { } from '../category-combo-table-body-pivoted/index.js' import { getFieldId } from '../get-field-id.js' import { IndicatorsTableBody } from '../indicators-table-body/indicators-table-body.js' +import { SectionDescription } from './section-description.js' import styles from './section.module.css' export function SectionFormSection({ section, dataSetId, globalFilterText }) { @@ -77,72 +78,86 @@ export function SectionFormSection({ section, dataSetId, globalFilterText }) { ? PivotedCategoryComboTableBody : CategoryComboTableBody + const { beforeSectionText, afterSectionText } = displayOptions + return ( - - - - -
-
- {section.displayName} -
- {section.description && ( -
- {section.description || - 'Placeholder section description'} -
- )} -
-
-
- - -
+ + + - - +
+ {section.displayName} +
+ {section.description && ( +
+ {section.description || + 'Placeholder section description'} +
)} - value={filterText} - onChange={({ target }) => - setFilterText(target.value) - } - className={styles.filterInput} - /> - -
-
-
- {groupedDataElements.map(({ categoryCombo, dataElements }, i) => ( - - ))} - {indicators.length > 0 && ( - - )} -
+ + + + + + + + + + {groupedDataElements.map( + ({ categoryCombo, dataElements }, i) => ( + + ) + )} + {indicators.length > 0 && ( + + )} + + {afterSectionText} + ) } diff --git a/src/data-workspace/section-form/section.module.css b/src/data-workspace/section-form/section.module.css index 11ca12ba3..cbcaea064 100644 --- a/src/data-workspace/section-form/section.module.css +++ b/src/data-workspace/section-form/section.module.css @@ -71,4 +71,18 @@ .hideForPrint { composes: hideForPrint from '../../app/app.css' } +} + +/* section description area */ +.sectionDescription { + margin: 12px 4px 8px; + font-size: 13px; + color: var(--colors-grey800) +} + +.sectionDescription :global(a):link, +.sectionDescription :global(a):visited, +.sectionDescription :global(a):hover, +.sectionDescription :global(a):active { + color: var(--colors-blue700) } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index bc807442c..9f71bafe6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6787,6 +6787,11 @@ domhandler@^5.0.1, domhandler@^5.0.2, domhandler@^5.0.3: dependencies: domelementtype "^2.3.0" +dompurify@^3.0.9: + version "3.0.9" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.0.9.tgz#b3f362f24b99f53498c75d43ecbd784b0b3ad65e" + integrity sha512-uyb4NDIvQ3hRn6NiC+SIFaP4mJ/MdXlvtunaqK9Bn6dD3RuB/1S/gasEjDHD8eiaqdSael2vBv+hOs7Y+jhYOQ== + domutils@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"