Skip to content

Commit

Permalink
feat: add status tag and workflow-context (#13)
Browse files Browse the repository at this point in the history
* feat: add status tag and workflow-context

* chore: fix broken import

* feat: add title bar

* refactor: pass data more granularly to title bar

Co-authored-by: Médi-Rémi Hashim <[email protected]>
Co-authored-by: Médi-Rémi Hashim <[email protected]>
  • Loading branch information
3 people authored Jul 6, 2021
1 parent 326a187 commit 500628d
Show file tree
Hide file tree
Showing 53 changed files with 482 additions and 136 deletions.
25 changes: 23 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: 2021-06-27T19:54:18.211Z\n"
"PO-Revision-Date: 2021-06-27T19:54:18.211Z\n"
"POT-Creation-Date: 2021-07-06T11:47:50.144Z\n"
"PO-Revision-Date: 2021-07-06T11:47:50.144Z\n"

msgid "Not authorized"
msgstr "Not authorized"
Expand All @@ -18,6 +18,24 @@ msgstr ""
"You don't have access to the Data Approval App. Contact a system "
"administrator to request access."

msgid "{{dataSetsCount}} data sets"
msgstr "{{dataSetsCount}} data sets"

msgid "Approved"
msgstr "Approved"

msgid "Ready for approval and accepted"
msgstr "Ready for approval and accepted"

msgid "Ready for approval"
msgstr "Ready for approval"

msgid "Waiting"
msgstr "Waiting"

msgid "Cannot approve"
msgstr "Cannot approve"

msgid "Clear selections"
msgstr "Clear selections"

Expand Down Expand Up @@ -143,3 +161,6 @@ msgstr "Workflow"

msgid "No workflows found. None may exist, or you may not have access to any."
msgstr "No workflows found. None may exist, or you may not have access to any."

msgid "Could not load approval data"
msgstr "Could not load approval data"
5 changes: 5 additions & 0 deletions src/app-data/app-data-context.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { createContext } from 'react'

const AppDataContext = createContext({})

export { AppDataContext }
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useDataQuery } from '@dhis2/app-runtime'
import { PropTypes } from '@dhis2/prop-types'
import { CircularLoader, Layer, CenteredContent } from '@dhis2/ui'
import { Layer } from '@dhis2/ui'
import React from 'react'
import { CurrentUserContext } from './current-user-context.js'
import { Loader } from '../shared/index.js'
import { AppDataContext } from './app-data-context.js'

const query = {
me: {
Expand All @@ -28,15 +29,13 @@ const query = {
},
}

const CurrentUserProvider = ({ children }) => {
const AppDataProvider = ({ children }) => {
const { data, loading, error } = useDataQuery(query)

if (loading) {
return (
<Layer>
<CenteredContent>
<CircularLoader />
</CenteredContent>
<Loader />
</Layer>
)
}
Expand All @@ -56,14 +55,14 @@ const CurrentUserProvider = ({ children }) => {
}

return (
<CurrentUserContext.Provider value={providerValue}>
<AppDataContext.Provider value={providerValue}>
{children}
</CurrentUserContext.Provider>
</AppDataContext.Provider>
)
}

CurrentUserProvider.propTypes = {
AppDataProvider.propTypes = {
children: PropTypes.node.isRequired,
}

export { CurrentUserProvider }
export { AppDataProvider }
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useDataQuery } from '@dhis2/app-runtime'
import { shallow, mount } from 'enzyme'
import React from 'react'
import { expectRenderError } from '../test-utils/expect-render-error.js'
import { CurrentUserProvider } from './current-user-provider.js'
import { AppDataProvider } from './app-data-provider.js'

jest.mock('@dhis2/app-runtime', () => ({
useDataQuery: jest.fn(),
Expand All @@ -12,11 +12,11 @@ afterEach(() => {
jest.resetAllMocks()
})

describe('<CurrentUserProvider>', () => {
describe('<AppDataProvider>', () => {
it('shows a spinner when loading', () => {
useDataQuery.mockImplementation(() => ({ loading: true }))

const wrapper = mount(<CurrentUserProvider>Child</CurrentUserProvider>)
const wrapper = mount(<AppDataProvider>Child</AppDataProvider>)
const loadingIndicator = wrapper.find({
'data-test': 'dhis2-uicore-circularloader',
})
Expand All @@ -34,7 +34,7 @@ describe('<CurrentUserProvider>', () => {
error,
}))

expectRenderError(<CurrentUserProvider {...props} />, message)
expectRenderError(<AppDataProvider {...props} />, message)
})

it('renders the children once data has been received', () => {
Expand All @@ -46,9 +46,7 @@ describe('<CurrentUserProvider>', () => {
},
}))

const wrapper = shallow(
<CurrentUserProvider>Child</CurrentUserProvider>
)
const wrapper = shallow(<AppDataProvider>Child</AppDataProvider>)

expect(wrapper.text()).toEqual(expect.stringContaining('Child'))
})
Expand Down
3 changes: 3 additions & 0 deletions src/app-data/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { AppDataContext } from './app-data-context.js'
export { AppDataProvider } from './app-data-provider.js'
export { useAppData } from './use-app-data.js'
4 changes: 4 additions & 0 deletions src/app-data/use-app-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { useContext } from 'react'
import { AppDataContext } from './app-data-context.js'

export const useAppData = () => useContext(AppDataContext)
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import { renderHook } from '@testing-library/react-hooks'
import React from 'react'
import { CurrentUserContext } from './current-user-context.js'
import { useCurrentUser } from './use-current-user.js'
import { AppDataContext } from './app-data-context.js'
import { useAppData } from './use-app-data.js'

describe('useCurrentUser', () => {
describe('useAppData', () => {
const value = {
authorities: ['dummy'],
}

const wrapper = ({ children }) => (
<CurrentUserContext.Provider value={value}>
<AppDataContext.Provider value={value}>
{children}
</CurrentUserContext.Provider>
</AppDataContext.Provider>
)

it('returns an object with current user properties', () => {
const { result } = renderHook(() => useCurrentUser(), { wrapper })
const { result } = renderHook(() => useAppData(), { wrapper })

expect(result.current).toEqual(value)
})
Expand Down
22 changes: 12 additions & 10 deletions src/app/app.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
import { CssVariables } from '@dhis2/ui'
import React from 'react'
import { AppDataProvider } from '../app-data/index.js'
import { AuthWall } from '../auth/index.js'
import { BottomBar } from '../bottom-bar/index.js'
import { CurrentUserProvider } from '../current-user/index.js'
import { DataWorkspace } from '../data-workspace/index.js'
import { TopBar } from '../top-bar/index.js'
import { WorkflowProvider } from '../workflow-context/index.js'
import { Layout } from './layout.js'

const App = () => (
<>
<CssVariables spacers colors theme />
<CurrentUserProvider>
<AppDataProvider>
<AuthWall>
<Layout.Container>
<Layout.Top>
<TopBar />
</Layout.Top>
<Layout.Content>
<DataWorkspace />
</Layout.Content>
<Layout.Bottom>
<BottomBar />
</Layout.Bottom>
<WorkflowProvider>
<Layout.Content>
<DataWorkspace />
</Layout.Content>
<Layout.Bottom>
<BottomBar />
</Layout.Bottom>
</WorkflowProvider>
</Layout.Container>
</AuthWall>
</CurrentUserProvider>
</AppDataProvider>
</>
)

Expand Down
15 changes: 6 additions & 9 deletions src/auth/auth-wall.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
import i18n from '@dhis2/d2-i18n'
import { NoticeBox } from '@dhis2/ui'
import PropTypes from 'prop-types'
import React from 'react'
import classes from './auth-wall.module.css'
import { ErrorMessage } from '../shared/index.js'
import { useIsAuthorized } from './use-is-authorized.js'

const AuthWall = ({ children }) => {
const isAuthorized = useIsAuthorized()

if (!isAuthorized) {
return (
<div className={classes.wrapper}>
<NoticeBox error title={i18n.t('Not authorized')}>
{i18n.t(
"You don't have access to the Data Approval App. Contact a system administrator to request access."
)}
</NoticeBox>
</div>
<ErrorMessage title={i18n.t('Not authorized')}>
{i18n.t(
"You don't have access to the Data Approval App. Contact a system administrator to request access."
)}
</ErrorMessage>
)
}

Expand Down
3 changes: 2 additions & 1 deletion src/auth/auth-wall.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { shallow } from 'enzyme'
import React from 'react'
import { ErrorMessage } from '../shared/index.js'
import { AuthWall } from './auth-wall.js'
import { useIsAuthorized } from './use-is-authorized.js'

Expand All @@ -17,7 +18,7 @@ describe('<AuthWall>', () => {

const wrapper = shallow(<AuthWall>Child</AuthWall>)

expect(wrapper.find('NoticeBox')).toHaveLength(1)
expect(wrapper.find(ErrorMessage)).toHaveLength(1)
})

it('renders the children for authorised users', () => {
Expand Down
4 changes: 2 additions & 2 deletions src/auth/use-is-authorized.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useCurrentUser } from '../current-user/index.js'
import { useAppData } from '../app-data/index.js'

export const useIsAuthorized = () => {
const { authorities } = useCurrentUser()
const { authorities } = useAppData()
return authorities.some(
authority => authority === 'ALL' || authority === 'M_dhis-web-approval'
)
Expand Down
14 changes: 7 additions & 7 deletions src/auth/use-is-authorized.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { renderHook } from '@testing-library/react-hooks'
import React from 'react'
import { CurrentUserContext } from '../current-user/index.js'
import { AppDataContext } from '../app-data/index.js'
import { useIsAuthorized } from './use-is-authorized.js'

describe('useIsAuthorized', () => {
Expand All @@ -10,9 +10,9 @@ describe('useIsAuthorized', () => {
}

const wrapper = ({ children }) => (
<CurrentUserContext.Provider value={value}>
<AppDataContext.Provider value={value}>
{children}
</CurrentUserContext.Provider>
</AppDataContext.Provider>
)

const { result } = renderHook(() => useIsAuthorized(), { wrapper })
Expand All @@ -26,9 +26,9 @@ describe('useIsAuthorized', () => {
}

const wrapper = ({ children }) => (
<CurrentUserContext.Provider value={value}>
<AppDataContext.Provider value={value}>
{children}
</CurrentUserContext.Provider>
</AppDataContext.Provider>
)

const { result } = renderHook(() => useIsAuthorized(), { wrapper })
Expand All @@ -42,9 +42,9 @@ describe('useIsAuthorized', () => {
}

const wrapper = ({ children }) => (
<CurrentUserContext.Provider value={value}>
<AppDataContext.Provider value={value}>
{children}
</CurrentUserContext.Provider>
</AppDataContext.Provider>
)

const { result } = renderHook(() => useIsAuthorized(), { wrapper })
Expand Down
12 changes: 11 additions & 1 deletion src/bottom-bar/bottom-bar.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import React from 'react'
import { StatusTag } from '../shared/index.js'
import { useWorkflowContext } from '../workflow-context/index.js'

const BottomBar = () => <pre>BottomBar placeholder</pre>
const BottomBar = () => {
const { approvalStatus } = useWorkflowContext()

return (
<>
<StatusTag approvalState={approvalStatus.state} />
</>
)
}

export { BottomBar }
5 changes: 0 additions & 5 deletions src/current-user/current-user-context.js

This file was deleted.

3 changes: 0 additions & 3 deletions src/current-user/index.js

This file was deleted.

4 changes: 0 additions & 4 deletions src/current-user/use-current-user.js

This file was deleted.

12 changes: 8 additions & 4 deletions src/data-workspace/data-workspace.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import React from 'react'
import { useQueryParams } from '../navigation/index.js'
import { useWorkflowContext } from '../workflow-context/index.js'
import { TitleBar } from './title-bar.js'

const DataWorkspace = () => {
const query = useQueryParams()
const workflow = useWorkflowContext()

return (
<>
<h1>Data workspace placeholder</h1>
<pre>{JSON.stringify(query, null, 4)}</pre>
<TitleBar
name={workflow.displayName}
dataSetsCount={workflow.dataSets.length}
approvalState={workflow.approvalStatus.state}
/>
</>
)
}
Expand Down
Loading

0 comments on commit 500628d

Please sign in to comment.