Skip to content

Commit

Permalink
Merge branch 'master' into category-combo-form
Browse files Browse the repository at this point in the history
  • Loading branch information
Birkbjo committed Oct 1, 2024
2 parents 9817869 + f53707e commit 8c93815
Show file tree
Hide file tree
Showing 11 changed files with 208 additions and 11 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
# [0.6.0](https://github.com/dhis2/maintenance-app-beta/compare/v0.5.0...v0.6.0) (2024-09-30)


### Features

* add details panel to org list ([8d3b87b](https://github.com/dhis2/maintenance-app-beta/commit/8d3b87b7c47399bac5a8c4b88a8c0046fd69ca74))

# [0.5.0](https://github.com/dhis2/maintenance-app-beta/compare/v0.4.0...v0.5.0) (2024-09-30)


### Features

* **catCombo:** add category combo form and list ([#410](https://github.com/dhis2/maintenance-app-beta/issues/410)) ([7687c13](https://github.com/dhis2/maintenance-app-beta/commit/7687c13d99335154880275e7631af9c221d0aceb))

# [0.4.0](https://github.com/dhis2/maintenance-app-beta/compare/v0.3.1...v0.4.0) (2024-09-28)


Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "maintenance-app",
"version": "0.4.0",
"version": "0.6.0",
"description": "",
"license": "BSD-3-Clause",
"private": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,15 @@ const DetailsContent = ({ data }: { data: DetailsResponse }) => {
)}
<DetailItem label={i18n.t('Code')}>{data.code}</DetailItem>
<DetailItem label={i18n.t('Created by')}>
{data.createdBy.displayName}
{data.createdBy?.displayName}
</DetailItem>
<DetailItem label={i18n.t('Created')}>
<ClientDateTime value={data.created} />
</DetailItem>
<DetailItem label={i18n.t('Last updated by')}>
{data.lastUpdatedBy
? data.lastUpdatedBy.displayName
: data.createdBy.displayName}
? data.lastUpdatedBy?.displayName
: data.createdBy?.displayName}
</DetailItem>
<DetailItem label={i18n.t('Last updated')}>
<ClientDateTime value={data.lastUpdated} />
Expand Down
2 changes: 1 addition & 1 deletion src/components/sectionList/detailsPanel/DetailsPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type DetailsPanelProps = {
export const DetailsPanel = ({ children, onClose }: DetailsPanelProps) => {
return (
<aside className={css.detailsPanel}>
<Card className={css.detailsPanelCard}>
<Card className={css.detailsPanelCard} dataTest="details-panel">
<div className={css.detailsPanelWrapper}>
<DetailsPanelHeader onClose={onClose} />
<ErrorBoundary FallbackComponent={DetailsPanelError}>
Expand Down
2 changes: 1 addition & 1 deletion src/components/sectionList/download/DownloadDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const DownloadDialog = ({
const section = useModelSectionHandleOrThrow()

return (
<Modal onClose={onClose}>
<Modal onClose={onClose} dataTest="download-modal">
<DownloadFormWrapper hasSelected={selectedModels.size > 0}>
<DownloadDialogContent
section={section}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export const DownloadDialogContent = ({
model: section.titlePlural,
})}
className={css.horizontalRadio}
dataTest="download-models-to-include"
>
<Field<string | undefined>
name="filterType"
Expand Down
137 changes: 136 additions & 1 deletion src/pages/organisationUnits/List.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ const renderList = async ({
path="/organisationUnits"
customData={{
organisationUnits: (type: any, params: any) => {
if (type === 'read' && params.id !== undefined) {
const foundOrgUnit = organisationUnits.find(
(ou) => ou.id === params.id
)
return foundOrgUnit
}
if (type === 'read') {
const regex = /:(\w+)$/
const orgUnitFilter =
Expand Down Expand Up @@ -358,7 +364,7 @@ describe('Org Unit List', () => {
).toHaveClass('disabled')
})

it('delete an org unit when possible', async () => {
it('deletes an org unit when possible', async () => {
const rootOrg = testOrgUnit({ level: 1, childCount: 2 })
const child1 = testOrgUnit({
level: 2,
Expand Down Expand Up @@ -488,4 +494,133 @@ describe('Org Unit List', () => {
`/organisationUnits/${child1.id}`
)
})

it('has show a detail panel', async () => {
const rootOrg = testOrgUnit({ level: 1, childCount: 2 })
const child1 = testOrgUnit({
level: 2,
ancestors: [rootOrg],
parentId: rootOrg.id,
childCount: 0,
access: testAccess({ deleteAccess: true }),
})
const child2 = testOrgUnit({
level: 2,
ancestors: [rootOrg],
parentId: rootOrg.id,
childCount: 0,
})

const screen = await renderList({
rootOrgUnits: [rootOrg],
otherOrgUnits: [child1, child2],
})

const tableRows = screen.getAllByTestId('dhis2-uicore-datatablerow')
expect(tableRows.length).toBe(4)

expect(tableRows[2]).toHaveTextContent(child1.displayName!)
const actionButton = within(tableRows[2]).getByTestId(
'row-actions-menu-button'
)
fireEvent.click(actionButton)
const actionsMenu = screen.getByTestId('row-actions-menu')
expect(actionsMenu).toBeVisible()
fireEvent.click(within(actionsMenu).getByText('Show details'))
const detailsPanel = await screen.findByTestId('details-panel')
expect(detailsPanel).toBeVisible()
expect(detailsPanel).toHaveTextContent(child1.displayName!)
expect(detailsPanel).toHaveTextContent(child1.code!)
expect(detailsPanel).toHaveTextContent(child1.id!)
expect(detailsPanel).toHaveTextContent(child1.createdBy!.displayName!)
expect(detailsPanel).toHaveTextContent(
child1.lastUpdatedBy!.displayName!
)
expect(
within(detailsPanel).getByText('API URL link').closest('a')
).toHaveAttribute('href', child1.href)
})

it('should open and close the multi select toolbar', async () => {
const rootOrg = testOrgUnit({ level: 1, childCount: 2 })
const child1 = testOrgUnit({
level: 2,
ancestors: [rootOrg],
parentId: rootOrg.id,
childCount: 0,
access: testAccess({ deleteAccess: true }),
})
const child2 = testOrgUnit({
level: 2,
ancestors: [rootOrg],
parentId: rootOrg.id,
childCount: 0,
})

const screen = await renderList({
rootOrgUnits: [rootOrg],
otherOrgUnits: [child1, child2],
})

const tableRows = screen.getAllByTestId('dhis2-uicore-datatablerow')
expect(tableRows.length).toBe(4)

const secondChildCheckBox = within(tableRows[3]).getByRole('checkbox')
fireEvent.click(secondChildCheckBox)

const toolbar = screen.getByTestId('dhis2-uicore-tabletoolbar')
expect(toolbar).toBeVisible()
expect(secondChildCheckBox).toBeChecked()

fireEvent.click(within(toolbar).getByText('Deselect all'))
expect(secondChildCheckBox).not.toBeChecked()
expect(toolbar).not.toBeVisible()
})

it('should download all selected rows', async () => {
const rootOrg = testOrgUnit({ level: 1, childCount: 2 })
const child1 = testOrgUnit({
level: 2,
ancestors: [rootOrg],
parentId: rootOrg.id,
childCount: 0,
access: testAccess({ deleteAccess: true }),
})
const child2 = testOrgUnit({
level: 2,
ancestors: [rootOrg],
parentId: rootOrg.id,
childCount: 0,
})

const screen = await renderList({
rootOrgUnits: [rootOrg],
otherOrgUnits: [child1, child2],
})

const tableRows = screen.getAllByTestId('dhis2-uicore-datatablerow')
expect(tableRows.length).toBe(4)

const rootRow = tableRows[1]
const secondChildRow = tableRows[3]
fireEvent.click(within(rootRow).getByRole('checkbox'))
fireEvent.click(within(secondChildRow).getByRole('checkbox'))

const toolbar = screen.getByTestId('dhis2-uicore-tabletoolbar')
fireEvent.click(within(toolbar).getByText('Download'))

const downloadModal = await screen.findByTestId('download-modal')
expect(downloadModal).toBeVisible()
const downloadModelsSelector = within(downloadModal).getByTestId(
'download-models-to-include'
)
const radios = within(downloadModelsSelector).getAllByRole('radio')
const selectedRadio = radios.find(
(radio) => (radio as HTMLInputElement).checked
)
expect(selectedRadio).not.toBeNull()
expect(selectedRadio!.closest('label')).toHaveTextContent(
'Only selected (2)'
)
})
})
32 changes: 31 additions & 1 deletion src/pages/organisationUnits/list/OrganisationUnitList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,20 @@ import {
} from '@tanstack/react-table'
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { IdentifiableFilter, SectionList } from '../../../components'
import {
DefaultDetailsPanelContent,
DetailsPanel,
} from '../../../components/sectionList/detailsPanel'
import { useModelListView } from '../../../components/sectionList/listView'
import { ModelValue } from '../../../components/sectionList/modelValue/ModelValue'
import { SectionListTitle } from '../../../components/sectionList/SectionListTitle'
import { Toolbar } from '../../../components/sectionList/toolbar'
import { SchemaName, useSchema, useSectionListFilter } from '../../../lib'
import {
BaseListModel,
SchemaName,
useSchema,
useSectionListFilter,
} from '../../../lib'
import { getFieldFilter } from '../../../lib/models/path'
import { useCurrentUserRootOrgUnits } from '../../../lib/user/currentUserStore'
import css from './OrganisationUnitList.module.css'
Expand Down Expand Up @@ -81,6 +90,17 @@ export const OrganisationUnitList = () => {
() => initialExpandedState
)

const [detailsId, setDetailsId] = useState<string | undefined>()

const handleDetailsClick = useCallback(
({ id }: BaseListModel) => {
setDetailsId((prevDetailsId) =>
prevDetailsId === id ? undefined : id
)
},
[setDetailsId]
)

const fieldFilters = columnDefinitions.map(
(column) => column.meta.fieldFilter
)
Expand Down Expand Up @@ -243,11 +263,21 @@ export const OrganisationUnitList = () => {
showAllActive={
parentIdsToLoad[row.original.id] === true
}
onShowDetailsClick={handleDetailsClick}
isFiltering={isFiltering}
fetchNextPage={fetchNextPage}
/>
))}
</SectionList>
{detailsId && (
<DetailsPanel
onClose={() => setDetailsId(undefined)}
// reset component state when modelId changes
key={detailsId}
>
<DefaultDetailsPanelContent modelId={detailsId} />
</DetailsPanel>
)}
</div>
</div>
)
Expand Down
17 changes: 15 additions & 2 deletions src/pages/organisationUnits/list/OrganisationUnitListActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
Button,
FlyoutMenu,
IconEdit16,
IconMore16,
IconMore24,
MenuItem,
Popover,
Expand All @@ -21,14 +22,14 @@ import { canDeleteModel } from '../../../lib/models/access'

type OrganisationUnitListActionProps = {
model: BaseListModel
onShowDetailsClick: (model: BaseListModel) => void
// onOpenTranslationClick: (model: BaseListModel) => void
// onDeleteSuccess: () => void
}

export const OrganisationUnitListActions = ({
model,
onShowDetailsClick,
}: // onOpenTranslationClick,
// onDeleteSuccess,
OrganisationUnitListActionProps) => {
const deletable = canDeleteModel(model)
const queryClient = useQueryClient()
Expand All @@ -47,6 +48,7 @@ OrganisationUnitListActionProps) => {
model={model}
// onTranslateClick={() => onOpenTranslationClick(model)}
onDeleteSuccess={handleDeleteSuccess}
onShowDetailsClick={onShowDetailsClick}
/>
</ListActions>
)
Expand All @@ -57,13 +59,15 @@ type OrganisationUnitActionMoreProps = {
model: BaseListModel
// onTranslateClick: () => void
onDeleteSuccess: () => void
onShowDetailsClick: (model: BaseListModel) => void
}

const OrganisationUnitActionMore = ({
deletable,
model,
// onTranslateClick,
onDeleteSuccess,
onShowDetailsClick,
}: OrganisationUnitActionMoreProps) => {
const [open, setOpen] = useState(false)
const ref = useRef(null)
Expand All @@ -89,6 +93,15 @@ const OrganisationUnitActionMore = ({
dataTest="row-actions-menu"
>
<FlyoutMenu>
<MenuItem
dense
label={i18n.t('Show details')}
icon={<IconMore16 />}
onClick={() => {
onShowDetailsClick(model)
setOpen(false)
}}
/>
<MenuItem
dense
label={i18n.t('Edit')}
Expand Down
4 changes: 4 additions & 0 deletions src/pages/organisationUnits/list/OrganisationUnitRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from '@dhis2/ui'
import { flexRender, Row } from '@tanstack/react-table'
import React from 'react'
import { BaseListModel } from '../../../lib'
import type { OrganisationUnitListItem } from './OrganisationUnitList'
import css from './OrganisationUnitList.module.css'
import { OrganisationUnitListActions } from './OrganisationUnitListActions'
Expand All @@ -21,12 +22,14 @@ export const OrganisationUnitRow = ({
showAllActive,
isFiltering,
fetchNextPage,
onShowDetailsClick,
}: {
row: Row<OrganisationUnitListItem>
toggleShowAll: (id: string) => void
showAllActive: boolean
isFiltering: boolean
fetchNextPage: (id: string) => void
onShowDetailsClick: (model: BaseListModel) => void
}) => {
const parentRow = row.getParentRow()

Expand Down Expand Up @@ -103,6 +106,7 @@ export const OrganisationUnitRow = ({
<DataTableCell>
<OrganisationUnitListActions
model={row.original}
onShowDetailsClick={onShowDetailsClick}
// onOpenTranslationClick={()=>{}}
/>
</DataTableCell>
Expand Down
2 changes: 1 addition & 1 deletion src/types/generated/utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export type GistParams = {
* A utility type that takes a Model (eg. DataElement)
* and returns a type with the properties that are references
* Note that in case of collections, the type of the property will be the type of the items in the collection
*
*
* Eg. GetReferencedModels<DataElement> will return:
* {
* categoryCombo: CategoryCombo;
Expand Down

0 comments on commit 8c93815

Please sign in to comment.