@dhis2/create-app 5.3.0-alpha.1 → 5.3.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/package.json +1 -2
  2. package/src/index.js +46 -37
  3. package/src/utils/getPackageManager.js +15 -0
  4. package/templates/template-ts-dataelements/.prettierrc.mjs +10 -0
  5. package/templates/template-ts-dataelements/README.md +45 -0
  6. package/templates/template-ts-dataelements/d2.config.js +12 -0
  7. package/templates/template-ts-dataelements/eslint.config.mjs +13 -0
  8. package/templates/template-ts-dataelements/i18n/en.pot +42 -0
  9. package/templates/template-ts-dataelements/package.json +35 -0
  10. package/templates/template-ts-dataelements/pnpm-lock.yaml +12950 -0
  11. package/templates/template-ts-dataelements/pnpm-workspace.yaml +17 -0
  12. package/templates/template-ts-dataelements/src/App.module.css +22 -0
  13. package/templates/template-ts-dataelements/src/App.test.tsx +21 -0
  14. package/templates/template-ts-dataelements/src/App.tsx +95 -0
  15. package/templates/template-ts-dataelements/src/components/DataElementsList.module.css +9 -0
  16. package/templates/template-ts-dataelements/src/components/DataElementsList.tsx +132 -0
  17. package/templates/template-ts-dataelements/tsconfig.json +17 -0
  18. package/templates/template-ts-dataelements/types/global.d.ts +8 -0
  19. package/templates/template-ts-dataelements/types/modules.d.ts +4 -0
  20. package/templates/template-ts-dataelements/viteConfigExtensions.mts +15 -0
  21. package/templates/template-ts-dataelements-react-router/.prettierrc.mjs +10 -0
  22. package/templates/template-ts-dataelements-react-router/README.md +45 -0
  23. package/templates/template-ts-dataelements-react-router/d2.config.js +12 -0
  24. package/templates/template-ts-dataelements-react-router/eslint.config.mjs +13 -0
  25. package/templates/template-ts-dataelements-react-router/i18n/en.pot +39 -0
  26. package/templates/template-ts-dataelements-react-router/package.json +36 -0
  27. package/templates/template-ts-dataelements-react-router/pnpm-lock.yaml +12982 -0
  28. package/templates/template-ts-dataelements-react-router/pnpm-workspace.yaml +17 -0
  29. package/templates/template-ts-dataelements-react-router/src/App.module.css +61 -0
  30. package/templates/template-ts-dataelements-react-router/src/App.test.tsx +21 -0
  31. package/templates/template-ts-dataelements-react-router/src/App.tsx +94 -0
  32. package/templates/template-ts-dataelements-react-router/src/AppWrapper.tsx +31 -0
  33. package/templates/template-ts-dataelements-react-router/src/components/About.tsx +15 -0
  34. package/templates/template-ts-dataelements-react-router/src/components/AppMenu.tsx +31 -0
  35. package/templates/template-ts-dataelements-react-router/src/components/DataElementsList.module.css +9 -0
  36. package/templates/template-ts-dataelements-react-router/src/components/DataElementsList.tsx +132 -0
  37. package/templates/template-ts-dataelements-react-router/tsconfig.json +17 -0
  38. package/templates/template-ts-dataelements-react-router/types/global.d.ts +8 -0
  39. package/templates/template-ts-dataelements-react-router/types/modules.d.ts +4 -0
  40. package/templates/template-ts-dataelements-react-router/viteConfigExtensions.mts +15 -0
  41. package/templates/template-ts-dataelements-react-router.zip +0 -0
  42. package/templates/template-ts-dataelements.zip +0 -0
@@ -0,0 +1,17 @@
1
+ # These hoists are needed for @dhis2/app-shell since it uses directly some libraries that were hoisted by yarn 1
2
+ # This is a better alternative than pnpm's shamefullyHoist https://pnpm.io/settings#shamefullyhoist until we update the way that @dhis2/app-shell works
3
+ publicHoistPattern:
4
+ - '@dhis2/ui'
5
+ - 'typeface-roboto'
6
+ - '@dhis2/app-adapter'
7
+ - 'prop-types'
8
+ - '@dhis2/d2-i18n'
9
+ - 'post-robot'
10
+ - 'styled-jsx'
11
+ - '@dhis2/app-adapter'
12
+ - '@dhis2/pwa'
13
+
14
+ onlyBuiltDependencies:
15
+ - '@dhis2/cli-helpers-engine'
16
+ - core-js-pure
17
+ - esbuild
@@ -0,0 +1,61 @@
1
+ .appWrapper {
2
+ display: grid;
3
+ grid-template-areas: 'sidebar' 'main' 'footer';
4
+ font-size: 14px;
5
+ grid-template-columns: auto;
6
+ grid-template-rows: auto 1fr auto;
7
+ overflow: auto;
8
+ }
9
+
10
+ .sidebar {
11
+ grid-area: sidebar;
12
+ }
13
+
14
+ .footer {
15
+ grid-area: footer;
16
+ width: 100%;
17
+ }
18
+
19
+ .main {
20
+ grid-area: main;
21
+ width: 100%;
22
+ padding-inline-start: 10px;
23
+ /*height: 100%;
24
+ display: flex;
25
+ flex-direction: column;
26
+ font-size: 1rem;
27
+ max-width: 1020px;
28
+ margin: 0px auto;
29
+ padding-top: 8px; */
30
+ }
31
+
32
+ .noticeContainer {
33
+ /* width: 768px; */
34
+ max-width: 340px;
35
+
36
+ margin: 16px 0;
37
+ align-self: center;
38
+ }
39
+
40
+ @media (min-width: 768px) {
41
+ .appWrapper {
42
+ display: grid;
43
+ grid-template-areas: 'sidebar main' 'footer footer';
44
+ font-size: 14px;
45
+ height: 100%;
46
+ grid-template-columns: 250px 1fr;
47
+ grid-template-rows: 1fr auto;
48
+ overflow: auto;
49
+ min-height: 1000px;
50
+ }
51
+
52
+ .noticeContainer {
53
+ max-width: 768px;
54
+ }
55
+ }
56
+
57
+ :global(h2),
58
+ :global(h3) {
59
+ margin: 8px;
60
+ margin-inline-start: 0;
61
+ }
@@ -0,0 +1,21 @@
1
+ import { CustomDataProvider } from '@dhis2/app-runtime'
2
+ import React from 'react'
3
+ import { createRoot } from 'react-dom/client'
4
+ import App from './App'
5
+
6
+ it('renders without crashing', () => {
7
+ const container = document.createElement('div')
8
+
9
+ const data = {
10
+ resource: 'test',
11
+ }
12
+
13
+ const root = createRoot(container)
14
+ root.render(
15
+ <CustomDataProvider data={data}>
16
+ <App />
17
+ </CustomDataProvider>
18
+ )
19
+
20
+ root.unmount()
21
+ })
@@ -0,0 +1,94 @@
1
+ import { useDataQuery } from '@dhis2/app-runtime'
2
+ import i18n from '@dhis2/d2-i18n'
3
+ import { NoticeBox } from '@dhis2/ui'
4
+ import React, { FC } from 'react'
5
+ import classes from '@/App.module.css'
6
+ import DataElementsList from '@/components/DataElementsList'
7
+
8
+ interface QueryResults {
9
+ me: {
10
+ name: string
11
+ }
12
+ }
13
+
14
+ const query = {
15
+ me: {
16
+ resource: 'me',
17
+ },
18
+ }
19
+
20
+ const MyApp: FC = () => {
21
+ const { error, loading, data } = useDataQuery<QueryResults>(query)
22
+
23
+ if (error) {
24
+ return <span>{i18n.t('ERROR')}</span>
25
+ }
26
+
27
+ if (loading) {
28
+ return <span>{i18n.t('Loading...')}</span>
29
+ }
30
+
31
+ return (
32
+ <div>
33
+ <h2>{i18n.t('Hello {{name}}', { name: data?.me?.name })}</h2>
34
+ <div className={classes.noticeContainer}>
35
+ <NoticeBox title="DHIS2 Web application">
36
+ This application was scaffolded using DHIS2 app platform
37
+ (with <code>npm create @dhis2/app</code>).
38
+ <br />
39
+ For more information, you can check the DHIS2 documentation:
40
+ <ul>
41
+ <li>
42
+ <a
43
+ target="_blank"
44
+ href="https://developers.dhis2.org/docs/guides"
45
+ rel="noreferrer"
46
+ >
47
+ Web development guides
48
+ </a>
49
+ </li>
50
+ <li>
51
+ <a
52
+ target="_blank"
53
+ href="https://docs.dhis2.org/en/develop/using-the-api/dhis-core-version-master/metadata.html"
54
+ rel="noreferrer"
55
+ >
56
+ Documentation for the API{' '}
57
+ </a>
58
+ </li>
59
+ <li>
60
+ <a
61
+ target="_blank"
62
+ href="https://developers.dhis2.org/docs/tutorials/app-runtime-query/"
63
+ rel="noreferrer"
64
+ >
65
+ AppRuntime and useDataQuery hook
66
+ </a>
67
+ </li>
68
+ <li>
69
+ <a
70
+ target="_blank"
71
+ href="https://developers.dhis2.org/docs/ui/webcomponents"
72
+ rel="noreferrer"
73
+ >
74
+ UI Library
75
+ </a>
76
+ </li>
77
+ <li>
78
+ <a
79
+ target="_blank"
80
+ href="https://developers.dhis2.org/demo/"
81
+ rel="noreferrer"
82
+ >
83
+ UI library demo
84
+ </a>
85
+ </li>
86
+ </ul>
87
+ </NoticeBox>
88
+ </div>
89
+ <DataElementsList />
90
+ </div>
91
+ )
92
+ }
93
+
94
+ export default MyApp
@@ -0,0 +1,31 @@
1
+ import React from 'react'
2
+ import { HashRouter, Route, Routes } from 'react-router'
3
+ import App from '@/App'
4
+ import classes from '@/App.module.css'
5
+ import AboutPage from '@/components/About'
6
+ import AppMenu from '@/components/AppMenu'
7
+
8
+ const AppWrapper = () => {
9
+ return (
10
+ <div className={classes.appWrapper}>
11
+ {/*
12
+ For the client-side routing to work on a DHIS2 server, it needs to use HashRouter
13
+ otherwise it will interfer with the server-side routing
14
+ */}
15
+ <HashRouter>
16
+ <div className={classes.sidebar}>
17
+ <AppMenu />
18
+ </div>
19
+ <div className={classes.main}>
20
+ <Routes>
21
+ <Route path="/" element={<App />} />
22
+ <Route path="/about" element={<AboutPage />} />
23
+ </Routes>
24
+ </div>
25
+ <div className={classes.footer}>Our App</div>
26
+ </HashRouter>
27
+ </div>
28
+ )
29
+ }
30
+
31
+ export default AppWrapper
@@ -0,0 +1,15 @@
1
+ import * as React from 'react'
2
+
3
+ const AboutPage = () => {
4
+ return (
5
+ <div>
6
+ <h2>About the app</h2>
7
+ <div>
8
+ A placeholder for an About page showing under a separate
9
+ client-side route
10
+ </div>
11
+ </div>
12
+ )
13
+ }
14
+
15
+ export default AboutPage
@@ -0,0 +1,31 @@
1
+ import { Menu, MenuItem } from '@dhis2/ui'
2
+ import * as React from 'react'
3
+ import { useNavigate, useLocation } from 'react-router'
4
+
5
+ const AppMenu = () => {
6
+ const navigate = useNavigate()
7
+ const location = useLocation()
8
+
9
+ return (
10
+ <div>
11
+ <Menu>
12
+ <MenuItem
13
+ active={location.pathname === '/'}
14
+ onClick={() => {
15
+ navigate(`/`)
16
+ }}
17
+ label="Home"
18
+ />
19
+ <MenuItem
20
+ active={location.pathname == '/about'}
21
+ onClick={() => {
22
+ navigate(`/about`)
23
+ }}
24
+ label="About"
25
+ />
26
+ </Menu>
27
+ </div>
28
+ )
29
+ }
30
+
31
+ export default AppMenu
@@ -0,0 +1,9 @@
1
+ .tableContainer {
2
+ max-width: 168px;
3
+ }
4
+
5
+ @media (min-width: 768px) {
6
+ .tableContainer {
7
+ max-width: 90%;
8
+ }
9
+ }
@@ -0,0 +1,132 @@
1
+ import { useDataQuery } from '@dhis2/app-runtime'
2
+ import i18n from '@dhis2/d2-i18n'
3
+ import {
4
+ Center,
5
+ CircularLoader,
6
+ DataTable,
7
+ DataTableCell,
8
+ DataTableColumnHeader,
9
+ DataTableRow,
10
+ NoticeBox,
11
+ TableBody,
12
+ TableHead,
13
+ } from '@dhis2/ui'
14
+ import * as React from 'react'
15
+ import classes from './DataElementsList.module.css'
16
+ interface QueryResults {
17
+ dataElements: Array<{
18
+ id: string
19
+ name: string
20
+ displayName: string
21
+ domainType: string
22
+ valueType: string
23
+ createdBy: {
24
+ id: string
25
+ name: string
26
+ }
27
+ }>
28
+ }
29
+
30
+ /**
31
+ * Documentation for the API: https://docs.dhis2.org/en/develop/using-the-api/dhis-core-version-master/metadata.html
32
+ * Documentation for useDataQuery hook: https://developers.dhis2.org/docs/tutorials/app-runtime-query/
33
+ * UI Library: https://developers.dhis2.org/docs/ui/webcomponents
34
+ */
35
+ const PAGE_SIZE = 25
36
+ const query = {
37
+ dataElements: {
38
+ resource: 'dataElements',
39
+ params: {
40
+ pageSize: PAGE_SIZE,
41
+ fields: [
42
+ 'id,name,displayName,domainType,valueType,categoryCombo[id,name],createdBy',
43
+ ],
44
+ order: 'created:desc',
45
+ },
46
+ },
47
+ }
48
+ const DataElementsList = () => {
49
+ const { error, loading, data } = useDataQuery<{
50
+ dataElements: QueryResults
51
+ }>(query)
52
+
53
+ if (error) {
54
+ return (
55
+ <NoticeBox error title={i18n.t('Error')}>
56
+ {i18n.t('Error loading the data elements')}
57
+ </NoticeBox>
58
+ )
59
+ }
60
+
61
+ return (
62
+ <div>
63
+ <h2>{i18n.t('Last {{n}} Data Elements:', { n: PAGE_SIZE })}</h2>
64
+ <div className={classes.tableContainer}>
65
+ <DataTable>
66
+ <TableHead>
67
+ <DataTableRow>
68
+ <DataTableColumnHeader large>
69
+ {i18n.t('ID')}
70
+ </DataTableColumnHeader>
71
+ <DataTableColumnHeader large>
72
+ {i18n.t('Name')}
73
+ </DataTableColumnHeader>
74
+ <DataTableColumnHeader large>
75
+ {i18n.t('Domain')}
76
+ </DataTableColumnHeader>
77
+ <DataTableColumnHeader
78
+ width="180px"
79
+ align="center"
80
+ large
81
+ >
82
+ {i18n.t('Value Type')}
83
+ </DataTableColumnHeader>
84
+ <DataTableColumnHeader large>
85
+ {i18n.t('Created by')}{' '}
86
+ </DataTableColumnHeader>
87
+ </DataTableRow>
88
+ </TableHead>
89
+ <TableBody>
90
+ {loading && (
91
+ <DataTableRow>
92
+ <DataTableCell colSpan="100%">
93
+ <Center>
94
+ <CircularLoader large />
95
+ </Center>
96
+ </DataTableCell>
97
+ </DataTableRow>
98
+ )}
99
+ {data?.dataElements?.dataElements?.map(
100
+ (dataElement) => {
101
+ return (
102
+ <DataTableRow key={dataElement.id}>
103
+ <DataTableCell large>
104
+ {dataElement.id}
105
+ </DataTableCell>
106
+ <DataTableCell large>
107
+ {dataElement.displayName}
108
+ </DataTableCell>
109
+ <DataTableCell large>
110
+ {dataElement.domainType}
111
+ </DataTableCell>
112
+ <DataTableCell large>
113
+ {dataElement.valueType?.replaceAll(
114
+ '_',
115
+ ' '
116
+ )}
117
+ </DataTableCell>
118
+ <DataTableCell large>
119
+ {dataElement.createdBy.name}
120
+ </DataTableCell>
121
+ </DataTableRow>
122
+ )
123
+ }
124
+ )}
125
+ </TableBody>
126
+ </DataTable>
127
+ </div>
128
+ </div>
129
+ )
130
+ }
131
+
132
+ export default DataElementsList
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "noEmit": true,
4
+ "skipLibCheck": true,
5
+ "allowJs": true,
6
+ "jsx": "react",
7
+ "esModuleInterop": true,
8
+ "target": "ESNext",
9
+ "module": "esnext",
10
+ "moduleResolution": "node",
11
+ "baseUrl": ".",
12
+ "paths": {
13
+ "@/*": ["src/*"]
14
+ }
15
+ },
16
+ "include": ["src", "types"]
17
+ }
@@ -0,0 +1,8 @@
1
+ import 'react'
2
+
3
+ declare module 'react' {
4
+ interface StyleHTMLAttributes<T> extends React.HTMLAttributes<T> {
5
+ jsx?: boolean
6
+ global?: boolean
7
+ }
8
+ }
@@ -0,0 +1,4 @@
1
+ declare module '*.module.css' {
2
+ const classes: { [key: string]: string }
3
+ export default classes
4
+ }
@@ -0,0 +1,15 @@
1
+ import path from 'path'
2
+ import { defineConfig, ConfigEnv } from 'vite'
3
+
4
+ const viteConfig = defineConfig(async (configEnv: ConfigEnv) => {
5
+ const { mode } = configEnv
6
+ return {
7
+ // In dev environments, don't clear the terminal after files update
8
+ clearScreen: mode !== 'development',
9
+ // Use an import alias: import from '@/' anywhere instead of 'src/'
10
+ resolve: { alias: { '@': path.resolve(__dirname, 'src') } },
11
+ // ...other config options here
12
+ }
13
+ })
14
+
15
+ export default viteConfig