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

Typescript migrate #79

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
Draft
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
17 changes: 16 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { config } = require('@dhis2/cli-style')

module.exports = {
extends: [config.eslintReact],
extends: [
config.eslintReact,
'plugin:@typescript-eslint/recommended',
'plugin:import/typescript',
],
settings: {
'import/resolver': {
node: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
},
},
globals: {
cy: 'readonly',
Cypress: 'readonly',
},
rules: {
'react/prop-types': 'off',
'react/display-name': 'off',
'import/extensions': 'off',
'@typescript-eslint/no-explicit-any': 'off',
},
}
50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,53 @@ You can learn more about the platform in the [DHIS2 Application Platform Documen
You can learn more about the runtime in the [DHIS2 Application Runtime Documentation](https://runtime.dhis2.nu/).

To learn React, check out the [React documentation](https://reactjs.org/).


## Migrating to TS

- the simplest `tsconfig.json`

```json
{
"compilerOptions": {
"allowJs": true,
"target": "es5"
},
"include": ["./src/**/*"]
}
```
from: https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html#writing-a-configuration-file

- install `typescript`

```bash
yarn add --dev typescript
```

(optionally) add an alias to make testing easier in `package.json`, to run `yarn tsc --noEmit` for example.

:::note[TypeScript is a typed "superset" of JavaScript]

TypeScript is a language that is a superset of JavaScript: JS syntax is therefore legal TS.
:::

- Rename all files from `.js` to `.ts` (or `.jsx` to `.tsx`). You could use a script:

```bash
find ./src -depth -name "*.js" -exec sh -c 'mv "$1" "${1%.js}.tsx"' _ {} \;
```

- Remove all references to modules `.js` - get rid of extensions (if you want to keep extensions, you'd need to set `allowImportingTsExtensions` - not worth the hassle)

(this will cause eslint errors)

- Fix eslint config

install `yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser`

extend eslint config

- inferred types
- settings cast
- generics (DRY)
-
2 changes: 1 addition & 1 deletion d2.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const config = {
minDHIS2Version: '2.39',
coreApp: false,
entryPoints: {
app: './src/index.js',
app: './src/index.tsx',
},
}

Expand Down
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,22 @@
"cypress:open:live": "start-server-and-test 'yarn cypress:start' http://localhost:3000 'yarn cypress open --env networkMode=live'",
"cypress:run:live": "start-server-and-test 'yarn cypress:start' http://localhost:3000 'yarn cypress run --env networkMode=live'",
"cypress:run:capture": "start-server-and-test 'yarn cypress:start' http://localhost:3000 'yarn cypress run --env networkMode=capture'",
"cypress:run:stub": "start-server-and-test 'yarn cypress:start' http://localhost:3000 'yarn cypress run --env networkMode=stub'"
"cypress:run:stub": "start-server-and-test 'yarn cypress:start' http://localhost:3000 'yarn cypress run --env networkMode=stub'",
"tsc": "tsc"
},
"devDependencies": {
"@dhis2/cli-app-scripts": "^10.4.1",
"@dhis2/cli-style": "^10.4.1",
"@dhis2/cypress-commands": "^9.0.2",
"@dhis2/cypress-plugins": "^9.0.2",
"@typescript-eslint/eslint-plugin": "^7.11.0",
"@typescript-eslint/parser": "^7.11.0",
"cypress": "^9.7.0",
"cypress-cucumber-preprocessor": "^4.3.1",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.6",
"start-server-and-test": "^1.14.0"
"start-server-and-test": "^1.14.0",
"typescript": "^5.4.5"
},
"dependencies": {
"@dhis2/analytics": "999.9.9-outlier-table.alpha.1",
Expand Down
4 changes: 2 additions & 2 deletions src/app.js → src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import React from 'react'
import { HashRouter, Route, Routes } from 'react-router-dom'
import { QueryParamProvider } from 'use-query-params'
import { ReactRouter6Adapter } from 'use-query-params/adapters/react-router-6'
import { AppProvider, UserProvider } from './context/index.js'
import { DataPage, EditPage, EditItem, AddItem } from './pages/index.js'
import { AppProvider, UserProvider } from './context/index'
import { DataPage, EditPage, EditItem, AddItem } from './pages/index'

const App = ({ router: Router }) => (
<>
Expand Down
1 change: 0 additions & 1 deletion src/components/common/button-with-tooltip/index.js

This file was deleted.

1 change: 1 addition & 0 deletions src/components/common/button-with-tooltip/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ButtonWithTooltip } from './button-with-tooltip'
2 changes: 0 additions & 2 deletions src/components/common/index.js

This file was deleted.

2 changes: 2 additions & 0 deletions src/components/common/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './loader/index'
export * from './warning/index'
1 change: 0 additions & 1 deletion src/components/common/loader/index.js

This file was deleted.

1 change: 1 addition & 0 deletions src/components/common/loader/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Loader } from './loader'
10 changes: 0 additions & 10 deletions src/components/common/loader/loader.js

This file was deleted.

10 changes: 10 additions & 0 deletions src/components/common/loader/loader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Center, CircularLoader } from '@dhis2/ui'
import React from 'react'

const Loader = () => (
<Center>
<CircularLoader />
</Center>
)

export { Loader }
1 change: 0 additions & 1 deletion src/components/common/warning/index.js

This file was deleted.

1 change: 1 addition & 0 deletions src/components/common/warning/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Warning } from './warning'
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { OU_LEVEL_PREFIX } from '../shared/index.js'
import { OU_LEVEL_PREFIX } from '../shared/index'

const dimensionTypes = [
'CATEGORY',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ import {
import classnames from 'classnames'
import PropTypes from 'prop-types'
import React, { useMemo, useState } from 'react'
import { Warning } from '../../common/index.js'
import { Warning } from '../../common/index'
import {
SchemeSelector,
Subsection,
AdvancedSubsection,
AUTHENTICATION_TYPES,
EXCHANGE_TYPES,
} from '../shared/index.js'
} from '../shared/index'
import styles from './exchange-form-contents.module.css'
import { RequestsOverview } from './requests-overview.js'
import { RequestsOverview } from './requests-overview'

const { Field, useField } = ReactFinalForm

Expand Down Expand Up @@ -79,7 +79,13 @@ RadioDecorator.propTypes = {
label: PropTypes.string,
}

export const ExchangeFormContents = React.memo(
type ExchangeFormContentsType = {
requestsState: Array<any>
setRequestEditMode: (request: any, addModeRequest?: any) => void
deleteRequest: (request: any, addModeRequest?: any) => void
}

export const ExchangeFormContents = React.memo<ExchangeFormContentsType>(
({ requestsState, setRequestEditMode, deleteRequest }) => {
const { input: typeInput } = useField('type', {
subscription: { value: true },
Expand Down Expand Up @@ -321,8 +327,8 @@ export const ExchangeFormContents = React.memo(
}
)

ExchangeFormContents.propTypes = {
deleteRequest: PropTypes.func,
requestsState: PropTypes.array,
setRequestEditMode: PropTypes.func,
}
// ExchangeFormContents.propTypes = {
// deleteRequest: PropTypes.func,
// requestsState: PropTypes.array,
// setRequestEditMode: PropTypes.func,
// }
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import classNames from 'classnames'
import PropTypes from 'prop-types'
import React, { useCallback } from 'react'
import { useNavigate } from 'react-router-dom'
import { AttributeProvider, useAppContext } from '../../../context/index.js'
import { Loader } from '../../common/index.js'
import { RequestForm } from '../request-update/index.js'
import { EditItemFooter, EditTitle } from '../shared/index.js'
import { ExchangeFormContents } from './exchange-form-contents.js'
import { AttributeProvider, useAppContext } from '../../../context/index'
import { Loader } from '../../common/index'
import { RequestForm } from '../request-update/index'
import { EditItemFooter, EditTitle } from '../shared/index'
import { ExchangeFormContents } from './exchange-form-contents'
import styles from './exchange-form.module.css'
import { getInitialValuesFromExchange } from './getExchangeValues.js'
import { useRequests } from './useRequests.js'
import { useUpdateExchange } from './useUpdateExchange.js'
import { getInitialValuesFromExchange } from './getExchangeValues'
import { useRequests } from './useRequests'
import { useUpdateExchange } from './useUpdateExchange'

const { Form } = ReactFinalForm

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
SCHEME_TYPES,
EXCHANGE_TYPES,
AUTHENTICATION_TYPES,
} from '../shared/index.js'
} from '../shared/index'

export const getExchangeValuesFromForm = ({ values, requests }) => ({
name: values.name,
Expand All @@ -29,8 +29,23 @@ const getFormIdSchemeValues = ({ values }) => {
}, {})
}

type SchemesType =
| 'idScheme'
| 'dataElementIdScheme'
| 'orgUnitIdScheme'
| 'categoryOptionComboIdScheme'
type TargetDetailType = {
type: string
request: Partial<{
[key in SchemesType]: any
}>
api?: {
url: string
}
}

const getTargetDetails = ({ values }) => {
const target = {
const target: TargetDetailType = {
type: values.type,
request: {
...getFormIdSchemeValues({ values }),
Expand Down
2 changes: 0 additions & 2 deletions src/components/edit/exchange-update/index.js

This file was deleted.

2 changes: 2 additions & 0 deletions src/components/edit/exchange-update/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { ExchangeForm } from './exchange-form'
export { useFetchExchange } from './useFetchExchange'
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from '@dhis2/ui'
import PropTypes from 'prop-types'
import React from 'react'
import { OU_LEVEL_PREFIX, OU_GROUP_PREFIX } from '../shared/index.js'
import { OU_LEVEL_PREFIX, OU_GROUP_PREFIX } from '../shared/index'
import styles from './requests-overview.module.css'

const getOuText = ({ ouInfo }) => {
Expand Down Expand Up @@ -53,7 +53,7 @@ const getOuText = ({ ouInfo }) => {
}

const EmptyTableInfo = () => (
<DataTableCell colspan="6">
<DataTableCell colSpan="6">
<div className={styles.emptyTableWrapper}>
<p className={styles.emptyTableHeader}>{i18n.t('No requests')}</p>
<p className={styles.emptyTableText}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { useDataEngine } from '@dhis2/app-runtime'
import { useCallback, useState } from 'react'
import {
SCHEME_TYPES,
OU_GROUP_PREFIX,
OU_LEVEL_PREFIX,
} from '../shared/index.js'
AggregateDataExchange,
ModelCollectionResponse,
OrganisationUnit,
Visualization,
} from '../../../types/generated'
import { SCHEME_TYPES, OU_GROUP_PREFIX, OU_LEVEL_PREFIX } from '../shared/index'
import {
getMetadataWithCode,
getFilterCodeMap,
getOuLevelMap,
} from './codeDetailsHelpers.js'
} from './codeDetailsHelpers'

const EXCHANGE_QUERY = {
exchange: {
Expand Down Expand Up @@ -76,9 +78,9 @@ export const useFetchExchange = () => {
// set to loading
setLoading(true)
try {
const { exchange } = await engine.query(EXCHANGE_QUERY, {
const { exchange } = (await engine.query(EXCHANGE_QUERY, {
variables: { id },
})
})) as { exchange: AggregateDataExchange }

// get metadata information for dx, pe
const metadataRequests = exchange.source.requests.map(
Expand Down Expand Up @@ -136,9 +138,14 @@ export const useFetchExchange = () => {
)

const { organisationUnits: orgUnitDetails } =
await engine.query(ORG_UNITS_QUERY, {
(await engine.query(ORG_UNITS_QUERY, {
variables: { ids: [...ousToLookUp] },
})
})) as {
organisationUnits: ModelCollectionResponse<
OrganisationUnit,
'organisationUnits'
>
}

const ouMap = orgUnitDetails.organisationUnits.reduce(
(orgUnitsMap, orgUnit) => {
Expand All @@ -155,9 +162,14 @@ export const useFetchExchange = () => {
)
)
const { visualizations: visualizationsDetails } =
await engine.query(VISUALIZATIONS_QUERY, {
(await engine.query(VISUALIZATIONS_QUERY, {
variables: { ids: [...visualizationsToLookUp] },
})
})) as {
visualizations: ModelCollectionResponse<
Visualization,
'visualizations'
>
}
const visualizationsMap =
visualizationsDetails.visualizations.reduce(
(visMap, visualization) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useCallback, useReducer, useState } from 'react'
import { requestsReducer } from '../request-update/index.js'
import { requestsReducer } from '../request-update/index'

export const useRequests = ({ exchangeInfo }) => {
const [requestEditInfo, setRequestEditInfo] = useState({
Expand Down
Loading
Loading