-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(app-platform): upgrade platform tools to use vite and react 18
- Loading branch information
Showing
139 changed files
with
7,458 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
![React 18](https://img.shields.io/badge/react-18-blue) | ||
# Scheduler | ||
|
||
## Cypress env settings | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,63 +1,63 @@ | ||
{ | ||
"name": "scheduler-app", | ||
"private": true, | ||
"scripts": { | ||
"build": "d2-app-scripts build", | ||
"start": "d2-app-scripts start", | ||
"start:nobrowser": "BROWSER=none d2-app-scripts start", | ||
"test": "d2-app-scripts test --coverage", | ||
"test:watch": "d2-app-scripts test --watch", | ||
"lint": "d2-style check", | ||
"format": "d2-style apply", | ||
"cypress": "start-server-and-test 'yarn start:nobrowser' 3000 'yarn exec cypress open'" | ||
}, | ||
"dependencies": { | ||
"@dhis2/app-runtime": "^3.8.0", | ||
"@dhis2/d2-i18n": "^1.1.0", | ||
"@dhis2/prop-types": "2.0.3", | ||
"@dhis2/ui": "^9.11.8", | ||
"@testing-library/react": "^16.0.1", | ||
"classnames": "^2.3.1", | ||
"cronstrue": "^1.114.0", | ||
"history": "^4.9.0", | ||
"moment": "^2.29.1", | ||
"package.json": "^2.0.1", | ||
"prop-types": "^15.8.1", | ||
"react-router": "^5.0.1", | ||
"react-router-dom": "^5.2.0", | ||
"styled-jsx": "^4.0.1" | ||
}, | ||
"devDependencies": { | ||
"@badeball/cypress-cucumber-preprocessor": "^20.0.3", | ||
"@cfaester/enzyme-adapter-react-18": "^0.8.0", | ||
"@cypress/webpack-preprocessor": "^6.0.1", | ||
"@dhis2/cli-app-scripts": "^12.0.0-alpha.19", | ||
"@dhis2/cli-style": "^10.7.4", | ||
"@testing-library/cypress": "^10.0.1", | ||
"cypress": "^13.7.2", | ||
"enzyme": "^3.10.0", | ||
"eslint-plugin-compat": "^3.9.0", | ||
"eslint-plugin-i18next": "^5.1.1", | ||
"eslint-plugin-import": "^2.23.4", | ||
"eslint-plugin-jsx-a11y": "^6.4.1", | ||
"identity-obj-proxy": "^3.0.0", | ||
"start-server-and-test": "^2.0.3" | ||
}, | ||
"jest": { | ||
"setupFilesAfterEnv": [ | ||
"<rootDir>/src/setupTests.js" | ||
], | ||
"collectCoverageFrom": [ | ||
"src/**/*.{js,jsx}", | ||
"!src/{index.js,serviceWorker.js,setupTests.js}" | ||
], | ||
"coveragePathIgnorePatterns": [ | ||
"/node_modules/", | ||
"/src/locales/" | ||
], | ||
"moduleNameMapper": { | ||
"\\.css$": "identity-obj-proxy" | ||
} | ||
}, | ||
"version": "101.6.12" | ||
"name": "scheduler-app", | ||
"private": true, | ||
"scripts": { | ||
"build": "d2-app-scripts build", | ||
"start": "d2-app-scripts start", | ||
"start:nobrowser": "BROWSER=none d2-app-scripts start", | ||
"test": "d2-app-scripts test --coverage", | ||
"test:watch": "d2-app-scripts test --watch", | ||
"lint": "d2-style check", | ||
"format": "d2-style apply", | ||
"cypress": "start-server-and-test 'yarn start:nobrowser' 3000 'yarn exec cypress open'" | ||
}, | ||
"dependencies": { | ||
"@dhis2/app-runtime": "^3.8.0", | ||
"@dhis2/d2-i18n": "^1.1.0", | ||
"@dhis2/prop-types": "2.0.3", | ||
"@dhis2/ui": "^9.11.8", | ||
"@testing-library/react": "^16.0.1", | ||
"classnames": "^2.3.1", | ||
"cronstrue": "^1.114.0", | ||
"history": "^4.9.0", | ||
"moment": "^2.29.1", | ||
"package.json": "^2.0.1", | ||
"prop-types": "^15.8.1", | ||
"react-router": "^5.0.1", | ||
"react-router-dom": "^5.2.0", | ||
"styled-jsx": "^4.0.1" | ||
}, | ||
"devDependencies": { | ||
"@badeball/cypress-cucumber-preprocessor": "^20.0.3", | ||
"@cfaester/enzyme-adapter-react-18": "^0.8.0", | ||
"@cypress/webpack-preprocessor": "^6.0.1", | ||
"@dhis2/cli-app-scripts": "^12.0.0-alpha.19", | ||
"@dhis2/cli-style": "^10.7.4", | ||
"@testing-library/cypress": "^10.0.1", | ||
"cypress": "^13.7.2", | ||
"enzyme": "^3.10.0", | ||
"eslint-plugin-compat": "^3.9.0", | ||
"eslint-plugin-i18next": "^5.1.1", | ||
"eslint-plugin-import": "^2.23.4", | ||
"eslint-plugin-jsx-a11y": "^6.4.1", | ||
"identity-obj-proxy": "^3.0.0", | ||
"start-server-and-test": "^2.0.3" | ||
}, | ||
"jest": { | ||
"setupFilesAfterEnv": [ | ||
"<rootDir>/src/setupTests.js" | ||
], | ||
"collectCoverageFrom": [ | ||
"src/**/*.{js,jsx}", | ||
"!src/{index.js,serviceWorker.js,setupTests.js}" | ||
], | ||
"coveragePathIgnorePatterns": [ | ||
"/node_modules/", | ||
"/src/locales/" | ||
], | ||
"moduleNameMapper": { | ||
"\\.css$": "identity-obj-proxy" | ||
} | ||
}, | ||
"version": "101.6.12" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import React from 'react' | ||
import { CssVariables } from '@dhis2/ui' | ||
import { Routes } from '../Routes' | ||
import { AuthWall } from '../AuthWall' | ||
import { Store } from '../Store' | ||
import { PageWrapper } from '../PageWrapper' | ||
import './App.css' | ||
|
||
/* eslint-disable-next-line import/no-unassigned-import -- Necessary for translations to work */ | ||
import '../../locales' | ||
|
||
const App = () => ( | ||
<React.Fragment> | ||
<CssVariables spacers colors theme /> | ||
<PageWrapper> | ||
<AuthWall> | ||
<Store> | ||
<Routes /> | ||
</Store> | ||
</AuthWall> | ||
</PageWrapper> | ||
</React.Fragment> | ||
) | ||
|
||
export default App |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import React from 'react' | ||
import { shallow } from 'enzyme' | ||
import App from './App.jsx' | ||
|
||
describe('<App>', () => { | ||
it('renders without errors', () => { | ||
shallow(<App />) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import React from 'react' | ||
import PropTypes from 'prop-types' | ||
import { NoticeBox } from '@dhis2/ui' | ||
import i18n from '@dhis2/d2-i18n' | ||
import { useDataQuery } from '@dhis2/app-runtime' | ||
import { Spinner } from '../Spinner' | ||
import { getAuthorized } from './selectors' | ||
import styles from './AuthWall.module.css' | ||
|
||
const query = { | ||
me: { | ||
resource: 'me', | ||
}, | ||
} | ||
|
||
const AuthWall = ({ children }) => { | ||
const { loading, error, data } = useDataQuery(query) | ||
|
||
if (loading) { | ||
return <Spinner /> | ||
} | ||
|
||
if (error) { | ||
return ( | ||
<div className={styles.noticeBoxWrapper}> | ||
<NoticeBox error title={i18n.t('Something went wrong')}> | ||
{i18n.t( | ||
'Something went wrong whilst retrieving user permissions.' | ||
)} | ||
</NoticeBox> | ||
</div> | ||
) | ||
} | ||
|
||
const isAuthorized = getAuthorized(data.me) | ||
|
||
if (!isAuthorized) { | ||
return ( | ||
<div className={styles.noticeBoxWrapper}> | ||
<NoticeBox error title={i18n.t('Not authorized')}> | ||
{i18n.t( | ||
"You don't have access to the Job Scheduler. Contact a system administrator to request access." | ||
)} | ||
</NoticeBox> | ||
</div> | ||
) | ||
} | ||
|
||
return <React.Fragment>{children}</React.Fragment> | ||
} | ||
|
||
const { node } = PropTypes | ||
|
||
AuthWall.propTypes = { | ||
children: node.isRequired, | ||
} | ||
|
||
export default AuthWall |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import React from 'react' | ||
import { shallow, mount } from 'enzyme' | ||
import { useDataQuery } from '@dhis2/app-runtime' | ||
import { getAuthorized } from './selectors' | ||
import AuthWall from './AuthWall.jsx' | ||
|
||
jest.mock('@dhis2/app-runtime', () => ({ | ||
useDataQuery: jest.fn(), | ||
})) | ||
|
||
jest.mock('./selectors', () => ({ | ||
getAuthorized: jest.fn(), | ||
})) | ||
|
||
afterEach(() => { | ||
jest.resetAllMocks() | ||
}) | ||
|
||
describe('<AuthWall>', () => { | ||
it('shows a spinner when loading', () => { | ||
useDataQuery.mockImplementation(() => ({ loading: true })) | ||
|
||
const wrapper = mount(<AuthWall>Child</AuthWall>) | ||
const loadingIndicator = wrapper.find({ | ||
'data-test': 'dhis2-uicore-circularloader', | ||
}) | ||
|
||
expect(loadingIndicator).toHaveLength(1) | ||
}) | ||
|
||
it('shows a noticebox for fetching errors', () => { | ||
const message = 'Something went wrong' | ||
const error = new Error(message) | ||
|
||
useDataQuery.mockImplementation(() => ({ | ||
loading: false, | ||
error, | ||
})) | ||
|
||
const wrapper = shallow(<AuthWall>Child</AuthWall>) | ||
const noticebox = wrapper.find('NoticeBox') | ||
|
||
expect(noticebox).toHaveLength(1) | ||
}) | ||
|
||
it('shows a noticebox for unauthorized users', () => { | ||
useDataQuery.mockImplementation(() => ({ | ||
loading: false, | ||
error: undefined, | ||
data: {}, | ||
})) | ||
getAuthorized.mockImplementation(() => false) | ||
|
||
const wrapper = shallow(<AuthWall>Child</AuthWall>) | ||
const noticebox = wrapper.find('NoticeBox') | ||
|
||
expect(noticebox).toHaveLength(1) | ||
}) | ||
|
||
it('renders the children for users that are authorized', () => { | ||
useDataQuery.mockImplementation(() => ({ | ||
loading: false, | ||
error: undefined, | ||
data: {}, | ||
})) | ||
getAuthorized.mockImplementation(() => true) | ||
|
||
const wrapper = shallow(<AuthWall>Child</AuthWall>) | ||
|
||
expect(wrapper.text()).toEqual(expect.stringContaining('Child')) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import React, { useState } from 'react' | ||
import PropTypes from 'prop-types' | ||
import { Button } from '@dhis2/ui' | ||
import i18n from '@dhis2/d2-i18n' | ||
import { CronPresetModal } from '../Modal' | ||
|
||
const CronPresetButton = ({ setCron, small }) => { | ||
const [showModal, setShowModal] = useState(false) | ||
|
||
return ( | ||
<React.Fragment> | ||
<Button onClick={() => setShowModal(true)} small={small}> | ||
{i18n.t('Choose from preset times')} | ||
</Button> | ||
{showModal && ( | ||
<CronPresetModal | ||
hideModal={ | ||
/* istanbul ignore next */ | ||
() => setShowModal(false) | ||
} | ||
setCron={setCron} | ||
/> | ||
)} | ||
</React.Fragment> | ||
) | ||
} | ||
|
||
CronPresetButton.defaultProps = { | ||
small: false, | ||
} | ||
|
||
const { func, bool } = PropTypes | ||
|
||
CronPresetButton.propTypes = { | ||
setCron: func.isRequired, | ||
small: bool, | ||
} | ||
|
||
export default CronPresetButton |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import React from 'react' | ||
import { shallow, mount } from 'enzyme' | ||
import CronPresetButton from './CronPresetButton.jsx' | ||
|
||
describe('<CronPresetButton>', () => { | ||
it('renders without errors', () => { | ||
shallow(<CronPresetButton setCron={() => {}} />) | ||
}) | ||
|
||
it('renders without errors when small', () => { | ||
shallow(<CronPresetButton setCron={() => {}} small />) | ||
}) | ||
|
||
it('shows the modal when button is clicked', () => { | ||
const wrapper = mount(<CronPresetButton setCron={() => {}} />) | ||
|
||
expect(wrapper.find('CronPresetModal')).toHaveLength(0) | ||
|
||
wrapper.find('button').simulate('click') | ||
|
||
expect(wrapper.find('CronPresetModal')).toHaveLength(1) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import React, { useState } from 'react' | ||
import PropTypes from 'prop-types' | ||
import { Button } from '@dhis2/ui' | ||
import i18n from '@dhis2/d2-i18n' | ||
import { DeleteJobModal } from '../Modal' | ||
|
||
const DeleteJobButton = ({ id, onSuccess }) => { | ||
const [showModal, setShowModal] = useState(false) | ||
|
||
return ( | ||
<React.Fragment> | ||
<Button destructive onClick={() => setShowModal(true)}> | ||
{i18n.t('Delete job')} | ||
</Button> | ||
{showModal && ( | ||
<DeleteJobModal | ||
id={id} | ||
hideModal={ | ||
/* istanbul ignore next */ | ||
() => setShowModal(false) | ||
} | ||
onSuccess={onSuccess} | ||
/> | ||
)} | ||
</React.Fragment> | ||
) | ||
} | ||
|
||
const { string, func } = PropTypes | ||
|
||
DeleteJobButton.propTypes = { | ||
id: string.isRequired, | ||
onSuccess: func.isRequired, | ||
} | ||
|
||
export default DeleteJobButton |
Oops, something went wrong.