Skip to content

Commit

Permalink
fix: exclude data non-readable exchanges from dropdown [DHIS2-18010]
Browse files Browse the repository at this point in the history
  • Loading branch information
tomzemp committed Sep 6, 2024
1 parent e541f86 commit 3654c8c
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 28 deletions.
8 changes: 5 additions & 3 deletions src/components/view/data-workspace/data-workspace.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { RequestsNavigation } from './requests-navigation/index.js'
import { TitleBar } from './title-bar/title-bar.js'

const DataWorkspace = () => {
const { aggregateDataExchanges } = useAppContext()
const { readableExchangeOptions } = useAppContext()
const { exchange } = useExchangeContext()
const [exchangeId] = useExchangeId()
// memoize for stable reference?
Expand All @@ -33,10 +33,12 @@ const DataWorkspace = () => {
}
}, [exchangeId, requests, selectedRequest, setSelectedRequest])

if (aggregateDataExchanges.length === 0) {
if (readableExchangeOptions.length === 0) {
return (
<CenteredContent>
<span>{i18n.t('There are no exchanges available to you')}</span>
<span data-test="no-exchanges-screen-message">
{i18n.t('There are no exchanges available to you')}
</span>
</CenteredContent>
)
}
Expand Down
11 changes: 3 additions & 8 deletions src/components/view/top-bar/exchange-select/exchange-select.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,16 @@ import { useExchangeId } from '../../../../use-context-selection/use-context-sel
import { MenuSelect } from '../menu-select/index.js'

const ExchangeSelect = () => {
const { aggregateDataExchanges } = useAppContext()
const { readableExchangeOptions } = useAppContext()
const [exchangeId, setExchangeId] = useExchangeId()
const [exchangeSelectorOpen, setExchangeSelectorOpen] = useState(false)

const dataExchangeOptions = aggregateDataExchanges.map((exchange) => ({
value: exchange.id,
label: exchange.displayName,
}))

return (
<div data-test="data-exchange-selector">
<SelectorBarItem
label={i18n.t('Data exchange')}
value={
dataExchangeOptions.find(
readableExchangeOptions.find(
(dExchange) => dExchange.value === exchangeId
)?.label
}
Expand All @@ -30,7 +25,7 @@ const ExchangeSelect = () => {
>
<div data-test="data-exchange-selector-contents">
<MenuSelect
values={dataExchangeOptions}
values={readableExchangeOptions}
selected={exchangeId}
dataTest="exchange-selector-menu"
onChange={({ selected }) => {
Expand Down
11 changes: 11 additions & 0 deletions src/context/app-context/app-provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ const query = {
},
}

export const getReadableExchangeOptions = (aggregateDataExchanges) =>
aggregateDataExchanges
.filter((exchange) => exchange?.access?.data?.read !== false)
.map((exchange) => ({
value: exchange.id,
label: exchange.displayName,
}))

const AppProvider = ({ children }) => {
const {
data,
Expand Down Expand Up @@ -61,6 +69,9 @@ const AppProvider = ({ children }) => {

const providerValue = {
aggregateDataExchanges,
readableExchangeOptions: getReadableExchangeOptions(
aggregateDataExchanges
),
refetchExchanges,
}

Expand Down
96 changes: 85 additions & 11 deletions src/pages/data.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ReactRouter6Adapter } from 'use-query-params/adapters/react-router-6'
import { formatData } from '../components/view/data-workspace/requests-display/index.js'
import { getRelativeTimeDifference } from '../components/view/data-workspace/title-bar/index.js'
import { getReportText } from '../components/view/submit-modal/submit-modal.js'
import { getReadableExchangeOptions } from '../context/app-context/app-provider.js'
import { AppContext, UserContext } from '../context/index.js'
import {
addOnlyPermissionsUserContext,
Expand Down Expand Up @@ -48,7 +49,11 @@ jest.mock('@dhis2/app-runtime', () => ({
const setUp = (
ui,
{
aggregateDataExchanges = [testDataExchange(), testDataExchange()],
aggregateDataExchanges = [
testDataExchange({ readDataAccess: true }),
testDataExchange({ readDataAccess: true }),
testDataExchange({ readDataAccess: false }),
],
exchangeId = null,
exchangeData = [testDataExchangeSourceData()],
importSummaryResponse = { importSummaries: [testImportSummary()] },
Expand Down Expand Up @@ -82,6 +87,9 @@ const setUp = (
<AppContext.Provider
value={{
aggregateDataExchanges,
readableExchangeOptions: getReadableExchangeOptions(
aggregateDataExchanges
),
refetchExchanges: () => {},
}}
>
Expand All @@ -105,7 +113,48 @@ beforeEach(() => {

describe('<DataPage/>', () => {
it('should display a drop down to select an exchange', async () => {
const exchanges = [testDataExchange(), testDataExchange()]
const exchanges = [
testDataExchange({ readDataAccess: true }),
testDataExchange({ readDataAccess: true }),
]
const { screen } = setUp(<DataPage />, {
aggregateDataExchanges: exchanges,
})

screen.getByTestId('dhis2-ui-selectorbaritem').click()
const menuItems = await screen.findAllByTestId('dhis2-uicore-menuitem')
expect(menuItems).toHaveLength(2)
menuItems.map((menuItem, i) => {
expect(menuItem).toHaveTextContent(exchanges[i].displayName)
})
})

it('should only display data readable exchanges for selection', async () => {
const exchanges = [
testDataExchange({ readDataAccess: true }),
testDataExchange({ readDataAccess: false }),
testDataExchange({ readDataAccess: true }),
]
const readableExchanges = exchanges.filter(
(exchange) => exchange.access.data.read
)
const { screen } = setUp(<DataPage />, {
aggregateDataExchanges: exchanges,
})

screen.getByTestId('dhis2-ui-selectorbaritem').click()
const menuItems = await screen.findAllByTestId('dhis2-uicore-menuitem')
expect(menuItems).toHaveLength(2)
menuItems.map((menuItem, i) => {
expect(menuItem).toHaveTextContent(readableExchanges[i].displayName)
})
})

it('should include exchanges with undefined data access for selection', async () => {
const exchanges = [
testDataExchange({ includeDataAccess: false }),
testDataExchange({ includeDataAccess: false }),
]
const { screen } = setUp(<DataPage />, {
aggregateDataExchanges: exchanges,
})
Expand All @@ -124,6 +173,17 @@ describe('<DataPage/>', () => {
expect(screen.getByTestId('entry-screen-message')).toBeInTheDocument()
})

it('should display a message about no available exchanges if there are no data readable exchanges', async () => {
const exchanges = [testDataExchange({ readDataAccess: false })]
const { screen } = setUp(<DataPage />, {
aggregateDataExchanges: exchanges,
})

expect(
screen.getByTestId('no-exchanges-screen-message')
).toBeInTheDocument()
})

it('should show an edit configurations button when the user all permissions', async () => {
const { screen } = setUp(<DataPage />, {
userContext: allPermissionsUserContext(),
Expand Down Expand Up @@ -151,8 +211,11 @@ describe('<DataPage/>', () => {
})

it('should select and clear the selected exchange', async () => {
const anExchange = testDataExchange()
const exchanges = [anExchange, testDataExchange()]
const anExchange = testDataExchange({ readDataAccess: true })
const exchanges = [
anExchange,
testDataExchange({ readDataAccess: true }),
]
const { screen } = setUp(<DataPage />, {
aggregateDataExchanges: exchanges,
})
Expand All @@ -178,7 +241,7 @@ describe('<DataPage/>', () => {
})

it('should show a progress bar when loading content', async () => {
const anExchange = testDataExchange()
const anExchange = testDataExchange({ readDataAccess: true })
const exchanges = [anExchange]

const { screen } = setUp(<DataPage />, {
Expand All @@ -191,7 +254,10 @@ describe('<DataPage/>', () => {
})

it('should display a warning if there are no requests', async () => {
const anExchange = testDataExchange({ requests: null })
const anExchange = testDataExchange({
requests: null,
readDataAccess: true,
})
const exchanges = [anExchange, testDataExchange()]
const { screen } = setUp(<DataPage />, {
aggregateDataExchanges: exchanges,
Expand All @@ -204,7 +270,7 @@ describe('<DataPage/>', () => {
})

it('should display the correct exchange specified in url if the param is present', async () => {
const anExchange = testDataExchange()
const anExchange = testDataExchange({ readDataAccess: true })
const exchanges = [anExchange, testDataExchange()]
const { screen } = setUp(<DataPage />, {
aggregateDataExchanges: exchanges,
Expand All @@ -220,7 +286,7 @@ describe('<DataPage/>', () => {
})

it('should display a preview table once an exchange is selected', async () => {
const anExchange = testDataExchange()
const anExchange = testDataExchange({ readDataAccess: true })

const exchanges = [anExchange]
const exchangeData = testDataExchangeSourceData()
Expand Down Expand Up @@ -272,6 +338,7 @@ describe('<DataPage/>', () => {
it('can show the correct data once another tab is clicked on', async () => {
const anExchange = testDataExchange({
requests: [testRequest(), testRequest()],
readDataAccess: true,
})

const exchanges = [anExchange]
Expand Down Expand Up @@ -309,10 +376,11 @@ describe('<DataPage/>', () => {
})

it('should show a submit modal for internal exchange when the user clicks on the submit data button', async () => {
const anExchangeRequest = testRequest()
const anExchangeRequest = testRequest({ readDataAccess: true })
const anExchange = testDataExchange({
targetType: 'INTERNAL',
requests: [anExchangeRequest],
readDataAccess: true,
})

const exchanges = [anExchange]
Expand Down Expand Up @@ -343,11 +411,12 @@ describe('<DataPage/>', () => {

it('should show a submit modal for external exchange when the user clicks on the submit data button', async () => {
const externalURL = 'a/url'
const anExchangeRequest = testRequest()
const anExchangeRequest = testRequest({ readDataAccess: true })
const anExchange = testDataExchange({
targetType: 'EXTERNAL',
externalURL: externalURL,
requests: [anExchangeRequest],
readDataAccess: true,
})
const exchanges = [anExchange]
const exchangeData = testDataExchangeSourceData()
Expand Down Expand Up @@ -379,6 +448,7 @@ describe('<DataPage/>', () => {
const importSummaries = [testImportSummary(), testImportSummary()]
const anExchange = testDataExchange({
requests: [testRequest(), testRequest()],
readDataAccess: true,
})

const exchanges = [anExchange]
Expand Down Expand Up @@ -465,6 +535,7 @@ describe('<DataPage/>', () => {
]
const anExchange = testDataExchange({
requests: [testRequest(), testRequest()],
readDataAccess: true,
})

const exchanges = [anExchange]
Expand Down Expand Up @@ -502,7 +573,10 @@ describe('<DataPage/>', () => {
testImportSummary({ status: 'ERROR' }),
]
const anExchange = testDataExchange({
requests: [testRequest(), testRequest()],
requests: [
testRequest({ readDataAccess: true }),
testRequest({ readDataAccess: true }),
],
})

const exchanges = [anExchange]
Expand Down
18 changes: 12 additions & 6 deletions src/utils/builders.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ export const testDataExchange = ({
inputIdSchemes = { idScheme: 'UID' },
writeMetadataAccess = faker.datatype.boolean(),
readMetadataAccess = faker.datatype.boolean(),
writeDataAccess = faker.datatype.boolean(),
readDataAccess = faker.datatype.boolean(),
writeDataAccess = faker.datatype.boolean(),
created = faker.date.recent(),
externalURL = undefined,
includeDataAccess = true,
} = {}) => ({
id,
displayName: name,
Expand All @@ -36,11 +37,16 @@ export const testDataExchange = ({
api: { url: externalURL },
request: inputIdSchemes,
},
access: {
write: writeMetadataAccess,
read: readMetadataAccess,
data: { write: writeDataAccess, read: readDataAccess },
},
access: includeDataAccess
? {
write: writeMetadataAccess,
read: readMetadataAccess,
data: { write: writeDataAccess, read: readDataAccess },
}
: {
write: writeMetadataAccess,
read: readMetadataAccess,
},
created,
})

Expand Down

0 comments on commit 3654c8c

Please sign in to comment.