Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: make data sets sections collapsable #390

Merged
merged 6 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@ export const PivotedCategoryComboTableBody = React.memo(
categoryCombo,
dataElements,
greyedFields,
/*
/*
filterText,
globalFilterText,
maxColumnsInSection,
renderRowTotals,
renderColumnTotals,*/
displayOptions,
collapsed,
}) {
const { data: metadata } = useMetadata()

Expand Down Expand Up @@ -68,7 +69,12 @@ export const PivotedCategoryComboTableBody = React.memo(
<>
{rowsMatrix.map((row, id /** todo: find suitable id */) => {
return (
<TableRow key={id}>
<TableRow
key={id}
className={classNames({
[styles.sectionRowCollapsed]: collapsed,
})}
>
{row.map((fieldInRow) => {
if (
fieldInRow.type === 'columnHeader' ||
Expand Down Expand Up @@ -150,6 +156,7 @@ PivotedCategoryComboTableBody.propTypes = {
categoryCombo: PropTypes.shape({
id: PropTypes.string.isRequired,
}),
collapsed: PropTypes.bool,
dataElements: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string.isRequired,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { TableBody, TableRow, TableCell } from '@dhis2/ui'
import { TableBody, TableCell, TableRow } from '@dhis2/ui'
import cx from 'classnames'
import PropTypes from 'prop-types'
import React, { useCallback } from 'react'
import { useMetadata, selectors } from '../../shared/index.js'
import { selectors, useMetadata } from '../../shared/index.js'
import { DataEntryCell, DataEntryField } from '../data-entry-cell/index.js'
import { getFieldId } from '../get-field-id.js'
import { TableBodyHiddenByFiltersRow } from '../table-body-hidden-by-filter-row.js'
Expand All @@ -21,6 +21,7 @@ export const CategoryComboTableBody = React.memo(
maxColumnsInSection,
renderRowTotals,
renderColumnTotals,
collapsed,
}) {
const { data: metadata } = useMetadata()

Expand Down Expand Up @@ -59,7 +60,11 @@ export const CategoryComboTableBody = React.memo(
const hiddenItemsCount = filteredDeIds.size

return (
<TableBody>
<TableBody
className={cx({
[styles.sectionRowCollapsed]: collapsed,
})}
>
<CategoryComboTableBodyHeader
categoryOptionCombos={sortedCOCs}
categories={categories}
Expand Down Expand Up @@ -128,6 +133,7 @@ CategoryComboTableBody.propTypes = {
categoryCombo: PropTypes.shape({
id: PropTypes.string.isRequired,
}),
collapsed: PropTypes.bool,
dataElements: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string.isRequired,
Expand Down
1 change: 0 additions & 1 deletion src/data-workspace/section-form/displayOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export const getDisplayOptions = (section) => {

try {
const { displayOptions: displayOptionString } = section

return JSON.parse(displayOptionString)
} catch (e) {
console.error(
Expand Down
5 changes: 2 additions & 3 deletions src/data-workspace/section-form/section-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const SectionForm = ({ dataSet, globalFilterText }) => {
dataSetId={dataSet.id}
key={s.id}
globalFilterText={globalFilterText}
collapsible
/>
))}
</>
Expand All @@ -51,9 +52,7 @@ export const SectionForm = ({ dataSet, globalFilterText }) => {

SectionForm.propTypes = {
dataSet: PropTypes.shape({
displayOptions: PropTypes.shape({
tabsDirection: PropTypes.oneOf(['vertical', 'horizontal']),
}),
displayOptions: PropTypes.string,
Copy link
Member

Choose a reason for hiding this comment

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

not related to this ticket, but it looks like we also have some logic for parsing display options here (

export const getDisplayOptions = (section) => {
), so we could probably just have one function for this parsing, and do it at the level. It looks like that getDisplayOptions gets used in the SectionFormSection child component.

id: PropTypes.string,
renderAsTabs: PropTypes.bool,
sections: PropTypes.arrayOf(
Expand Down
109 changes: 75 additions & 34 deletions src/data-workspace/section-form/section.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import i18n from '@dhis2/d2-i18n'
import {
colors,
IconChevronDown16,
IconChevronUp16,
IconFilter16,
Table,
TableCellHead,
Expand All @@ -19,9 +21,16 @@ import { getDisplayOptions } from './displayOptions.js'
import { SectionDescription } from './section-description.js'
import styles from './section.module.css'

export function SectionFormSection({ section, dataSetId, globalFilterText }) {
export function SectionFormSection({
section,
dataSetId,
globalFilterText,
collapsible,
}) {
// Could potentially build table via props instead of rendering children
const [filterText, setFilterText] = useState('')
const [showSectionContent, setShowSectionContent] = useState(true)

const { data } = useMetadata()

const dataElements = selectors.getDataElementsBySection(
Expand Down Expand Up @@ -77,6 +86,15 @@ export function SectionFormSection({ section, dataSetId, globalFilterText }) {

const { beforeSectionText, afterSectionText } = displayOptions

const onSectionHeadClicked = () => {
collapsible &&
setShowSectionContent((displayingContent) => !displayingContent)
}

const onSectionHeadEntered = (e) => {
e.key === 'Enter' && onSectionHeadClicked()
}

return (
<div>
<SectionDescription>{beforeSectionText}</SectionDescription>
Expand All @@ -88,44 +106,61 @@ export function SectionFormSection({ section, dataSetId, globalFilterText }) {
className={styles.headerCell}
>
<div className={styles.labelWrapper}>
<div className={styles.title}>
{section.displayName}
<div
className={styles.collapseIcon}
tabIndex={collapsible ? 0 : -1}
onClick={onSectionHeadClicked}
onKeyDown={onSectionHeadEntered}
>
{collapsible &&
(showSectionContent ? (
<IconChevronUp16 color="var(--colors-white)" />
) : (
<IconChevronDown16 color="var(--colors-white)" />
))}
</div>
{section.description && (
<div className={styles.description}>
{section.description ||
'Placeholder section description'}
<div>
<div className={styles.title}>
{section.displayName}
</div>
)}
{section.description && (
<div className={styles.description}>
{section.description ||
'Placeholder section description'}
</div>
)}
</div>
</div>
</TableCellHead>
</TableRowHead>
<TableRowHead>
<TableCellHead
colSpan="100%"
className={headerCellStyles}
>
<label
htmlFor={filterInputId}
className={styles.filterWrapper}
{showSectionContent && (
<TableRowHead>
<TableCellHead
colSpan="100%"
className={headerCellStyles}
>
<IconFilter16 color={colors.grey600} />
<input
name={filterInputId}
id={filterInputId}
type="text"
placeholder={i18n.t(
'Type here to filter in this section'
)}
value={filterText}
onChange={({ target }) =>
setFilterText(target.value)
}
className={styles.filterInput}
/>
</label>
</TableCellHead>
</TableRowHead>
<label
htmlFor={filterInputId}
className={styles.filterWrapper}
>
<IconFilter16 color={colors.grey600} />
<input
name={filterInputId}
id={filterInputId}
type="text"
placeholder={i18n.t(
'Type here to filter in this section'
)}
value={filterText}
onChange={({ target }) =>
setFilterText(target.value)
}
className={styles.filterInput}
/>
</label>
</TableCellHead>
</TableRowHead>
)}
</TableHead>
{groupedDataElements.map(
({ categoryCombo, dataElements }, i) => (
Expand All @@ -140,10 +175,11 @@ export function SectionFormSection({ section, dataSetId, globalFilterText }) {
renderColumnTotals={section.showColumnTotals}
greyedFields={greyedFields}
displayOptions={displayOptions}
collapsed={!showSectionContent}
/>
)
)}
{indicators.length > 0 && (
{indicators.length > 0 && showSectionContent && (
<IndicatorsTableBody
indicators={indicators}
renderRowTotals={section.showRowTotals}
Expand All @@ -159,6 +195,7 @@ export function SectionFormSection({ section, dataSetId, globalFilterText }) {
}

SectionFormSection.propTypes = {
collapsible: PropTypes.bool,
dataSetId: PropTypes.string,
globalFilterText: PropTypes.string,
section: PropTypes.shape({
Expand All @@ -175,3 +212,7 @@ SectionFormSection.propTypes = {
showRowTotals: PropTypes.bool,
}),
}

SectionFormSection.defaultProps = {
collapsible: false,
}
45 changes: 36 additions & 9 deletions src/data-workspace/section-form/section.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
.labelWrapper {
background-color: transparent !important;
}
.title, .description {
.title,
.description {
color: black !important;
}
}
Expand All @@ -23,7 +24,34 @@
background-color: var(--colors-grey800);
line-height: 20px;
padding: 4px 8px;
display: flex;
align-items: center;
gap: 4px;
}

.collapseIcon {
margin-inline-start: -4px;
padding: var(--spacers-dp4);
height: 24px;
width: 24px;
align-self: flex-start;
border-radius: 3px;
cursor: pointer;
}

.collapseIcon:hover {
background-color: var(--colors-grey900);
}

.collapseIcon:focus {
outline: 3px solid var(--theme-focus);
}

/* Prevent focus styles when mouse clicking */
.collapseIcon:focus:not(:focus-visible) {
outline: none;
}

.title {
color: var(--colors-grey050);
font-weight: 400;
Expand Down Expand Up @@ -65,43 +93,42 @@

.sectionTab {
margin-bottom: 8px;

}

.verticalSectionTabWrapper .sectionTab div{
.verticalSectionTabWrapper .sectionTab div {
flex-direction: column;
}

.sectionTab button{
.sectionTab button {
align-self: stretch;
}

.sectionTabWrapper{
.sectionTabWrapper {
display: flex;
gap: 6px;
flex-direction: column;
}

.verticalSectionTabWrapper{
.verticalSectionTabWrapper {
flex-direction: row;
}

@media print {
.hideForPrint {
composes: hideForPrint from '../../app/app.css'
composes: hideForPrint from '../../app/app.css';
}
}

/* section description area */
.sectionDescription {
margin: 12px 4px 8px;
font-size: 13px;
color: var(--colors-grey800)
color: var(--colors-grey800);
}

.sectionDescription :global(a):link,
.sectionDescription :global(a):visited,
.sectionDescription :global(a):hover,
.sectionDescription :global(a):active {
color: var(--colors-blue700)
color: var(--colors-blue700);
}
8 changes: 6 additions & 2 deletions src/data-workspace/table-body.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
padding: 8px !important;
height: auto !important;
font-size: 13px !important;
line-height: 15px !important;
line-height: 15px !important;
}

.tableHeader {
Expand All @@ -12,6 +12,10 @@
font-weight: 500;
}

.sectionRowCollapsed{
visibility: collapse;
}

.categoryNameHeader {
composes: tableHeader;
font-weight: 300;
Expand Down Expand Up @@ -99,4 +103,4 @@
}
.category {
font-weight: 300;
}
}
Loading