@dhis2-ui/organisation-unit-tree 10.16.2 → 10.16.3-alpha.1

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 (142) hide show
  1. package/package.json +8 -7
  2. package/src/__e2e__/children_as_child_nodes.js +23 -0
  3. package/src/__e2e__/common.js +70 -0
  4. package/src/__e2e__/controlled_expanded.js +89 -0
  5. package/src/__e2e__/displaying_loading_error.js +45 -0
  6. package/src/__e2e__/expanded.js +42 -0
  7. package/src/__e2e__/force_reload.js +66 -0
  8. package/src/__e2e__/get-organisation-unit-data.js +119 -0
  9. package/src/__e2e__/highlight.js +23 -0
  10. package/src/__e2e__/loading_state.js +37 -0
  11. package/src/__e2e__/multi_selection.js +24 -0
  12. package/src/__e2e__/namespace.js +1 -0
  13. package/src/__e2e__/no_selection.js +32 -0
  14. package/src/__e2e__/path_based_filtering.js +49 -0
  15. package/src/__e2e__/single_selection.js +46 -0
  16. package/src/__e2e__/sub_unit_as_root.js +28 -0
  17. package/src/__e2e__/tree_api.js +55 -0
  18. package/src/__stories__/collapsed.js +11 -0
  19. package/src/__stories__/custom-expanded-imperative-open.js +181 -0
  20. package/src/__stories__/custom-node-label.js +19 -0
  21. package/src/__stories__/development-stories.js +86 -0
  22. package/src/__stories__/expanded.js +12 -0
  23. package/src/__stories__/filtered-root.js +15 -0
  24. package/src/__stories__/filtered.js +13 -0
  25. package/src/__stories__/force-reload-all.js +46 -0
  26. package/src/__stories__/force-reload-one-unit.js +36 -0
  27. package/src/__stories__/highlighted.js +13 -0
  28. package/src/__stories__/indeterminate.js +13 -0
  29. package/src/__stories__/loading-error-grandchild.js +39 -0
  30. package/src/__stories__/loading.js +27 -0
  31. package/src/__stories__/multiple-roots.js +20 -0
  32. package/src/__stories__/no-selection.js +16 -0
  33. package/src/__stories__/replace-roots.js +28 -0
  34. package/src/__stories__/root-error.js +36 -0
  35. package/src/__stories__/root-loading.js +34 -0
  36. package/src/__stories__/rtl.js +14 -0
  37. package/src/__stories__/selected-multiple.js +18 -0
  38. package/src/__stories__/shared.js +192 -0
  39. package/src/__stories__/single-selection.js +16 -0
  40. package/src/features/children_as_child_nodes/index.js +29 -0
  41. package/src/features/children_as_child_nodes.feature +6 -0
  42. package/src/features/controlled_expanded/index.js +86 -0
  43. package/src/features/controlled_expanded.feature +11 -0
  44. package/src/features/displaying_loading_error/index.js +46 -0
  45. package/src/features/displaying_loading_error.feature +24 -0
  46. package/src/features/expanded/index.js +87 -0
  47. package/src/features/expanded.feature +27 -0
  48. package/src/features/force_reload/index.js +36 -0
  49. package/src/features/force_reload.feature +7 -0
  50. package/src/features/highlight/index.js +9 -0
  51. package/src/features/highlight.feature +5 -0
  52. package/src/features/loading_state/index.js +26 -0
  53. package/src/features/loading_state.feature +7 -0
  54. package/src/features/multi_selection/index.js +94 -0
  55. package/src/features/multi_selection.feature +31 -0
  56. package/src/features/no_selection/index.js +41 -0
  57. package/src/features/no_selection.feature +13 -0
  58. package/src/features/path_based_filtering/index.js +97 -0
  59. package/src/features/path_based_filtering.feature +24 -0
  60. package/src/features/single_selection/index.js +41 -0
  61. package/src/features/single_selection.feature +20 -0
  62. package/src/features/sub_unit_as_root/index.js +83 -0
  63. package/src/features/sub_unit_as_root.feature +34 -0
  64. package/src/features/tree_api/index.js +121 -0
  65. package/src/features/tree_api.feature +37 -0
  66. package/src/get-all-expanded-paths/get-all-expanded-paths.js +32 -0
  67. package/src/get-all-expanded-paths/get-all-expanded-paths.test.js +22 -0
  68. package/src/get-all-expanded-paths/index.js +1 -0
  69. package/src/helpers/index.js +3 -0
  70. package/src/helpers/is-path-included.js +15 -0
  71. package/src/helpers/left-trim-to-root-id.js +3 -0
  72. package/src/helpers/sort-node-children-alphabetically.js +5 -0
  73. package/src/index.js +6 -0
  74. package/src/locales/ar/translations.json +5 -0
  75. package/src/locales/cs/translations.json +5 -0
  76. package/src/locales/en/translations.json +5 -0
  77. package/src/locales/es/translations.json +5 -0
  78. package/src/locales/es_419/translations.json +5 -0
  79. package/src/locales/fr/translations.json +5 -0
  80. package/src/locales/index.js +50 -0
  81. package/src/locales/lo/translations.json +5 -0
  82. package/src/locales/nb/translations.json +5 -0
  83. package/src/locales/nl/translations.json +5 -0
  84. package/src/locales/pt/translations.json +5 -0
  85. package/src/locales/ru/translations.json +5 -0
  86. package/src/locales/uk/translations.json +5 -0
  87. package/src/locales/uz_Latn/translations.json +5 -0
  88. package/src/locales/uz_UZ_Cyrl/translations.json +5 -0
  89. package/src/locales/uz_UZ_Latn/translations.json +5 -0
  90. package/src/locales/vi/translations.json +5 -0
  91. package/src/locales/zh/translations.json +5 -0
  92. package/src/locales/zh_CN/translations.json +5 -0
  93. package/src/organisation-unit-node/compute-child-nodes.js +27 -0
  94. package/src/organisation-unit-node/compute-child-nodes.test.js +85 -0
  95. package/src/organisation-unit-node/error-message.js +23 -0
  96. package/src/organisation-unit-node/has-descendant-selected-paths.js +15 -0
  97. package/src/organisation-unit-node/has-descendant-selected-paths.test.js +30 -0
  98. package/src/organisation-unit-node/index.js +1 -0
  99. package/src/organisation-unit-node/label/disabled-selection-label.js +26 -0
  100. package/src/organisation-unit-node/label/icon-empty.js +31 -0
  101. package/src/organisation-unit-node/label/icon-folder-closed.js +38 -0
  102. package/src/organisation-unit-node/label/icon-folder-open.js +49 -0
  103. package/src/organisation-unit-node/label/icon-single.js +41 -0
  104. package/src/organisation-unit-node/label/icon.js +35 -0
  105. package/src/organisation-unit-node/label/iconized-checkbox.js +67 -0
  106. package/src/organisation-unit-node/label/index.js +1 -0
  107. package/src/organisation-unit-node/label/label-container.js +36 -0
  108. package/src/organisation-unit-node/label/label.js +146 -0
  109. package/src/organisation-unit-node/label/single-selection-label.js +60 -0
  110. package/src/organisation-unit-node/loading-spinner.js +22 -0
  111. package/src/organisation-unit-node/organisation-unit-node-children.js +123 -0
  112. package/src/organisation-unit-node/organisation-unit-node.js +190 -0
  113. package/src/organisation-unit-node/use-open-state.js +37 -0
  114. package/src/organisation-unit-node/use-open-state.test.js +111 -0
  115. package/src/organisation-unit-node/use-org-children.js +63 -0
  116. package/src/organisation-unit-node/use-org-children.test.js +314 -0
  117. package/src/organisation-unit-node/use-org-data/index.js +1 -0
  118. package/src/organisation-unit-node/use-org-data/use-org-data.js +40 -0
  119. package/src/organisation-unit-node/use-org-data/use-org-data.test.js +137 -0
  120. package/src/organisation-unit-tree/default-render-node-label/default-render-node-label.js +1 -0
  121. package/src/organisation-unit-tree/default-render-node-label/index.js +1 -0
  122. package/src/organisation-unit-tree/filter-root-ids.js +9 -0
  123. package/src/organisation-unit-tree/index.js +3 -0
  124. package/src/organisation-unit-tree/organisation-unit-tree-root-error.js +20 -0
  125. package/src/organisation-unit-tree/organisation-unit-tree-root-loading.js +22 -0
  126. package/src/organisation-unit-tree/organisation-unit-tree.js +253 -0
  127. package/src/organisation-unit-tree/organisation-unit-tree.test.js +77 -0
  128. package/src/organisation-unit-tree/use-expanded/create-expand-handlers.js +45 -0
  129. package/src/organisation-unit-tree/use-expanded/create-expand-handlers.test.js +54 -0
  130. package/src/organisation-unit-tree/use-expanded/index.js +1 -0
  131. package/src/organisation-unit-tree/use-expanded/use-expanded.js +42 -0
  132. package/src/organisation-unit-tree/use-expanded/use-expanded.test.js +73 -0
  133. package/src/organisation-unit-tree/use-force-reload.js +22 -0
  134. package/src/organisation-unit-tree/use-force-reload.test.js +43 -0
  135. package/src/organisation-unit-tree/use-root-org-data/index.js +1 -0
  136. package/src/organisation-unit-tree/use-root-org-data/patch-missing-display-name.js +20 -0
  137. package/src/organisation-unit-tree/use-root-org-data/patch-missing-display-name.test.js +24 -0
  138. package/src/organisation-unit-tree/use-root-org-data/use-root-org-data.js +60 -0
  139. package/src/organisation-unit-tree/use-root-org-data/use-root-org-unit.test.js +184 -0
  140. package/src/organisation-unit-tree.e2e.stories.js +28 -0
  141. package/src/organisation-unit-tree.prod.stories.js +70 -0
  142. package/src/prop-types.js +33 -0
@@ -0,0 +1,46 @@
1
+ import { CustomDataProvider } from '@dhis2/app-runtime'
2
+ import React from 'react'
3
+ import { OrganisationUnitTree } from '../index.js'
4
+ import { StatefulMultiSelectionWrapper, dataProviderData } from './common.js'
5
+
6
+ const data = {
7
+ organisationUnits: (...args) => {
8
+ const [, { id }] = args
9
+
10
+ if (id === 'A0000000000') {
11
+ return dataProviderData
12
+ .organisationUnits(...args)
13
+ .then((response) => ({
14
+ ...response,
15
+ children: [],
16
+ }))
17
+ }
18
+
19
+ if (id === 'A0000000001') {
20
+ return dataProviderData
21
+ .organisationUnits(...args)
22
+ .then((response) => ({
23
+ ...response,
24
+ path: '/A0000000001',
25
+ children: [],
26
+ }))
27
+ }
28
+
29
+ return Promise.resolve({})
30
+ },
31
+ }
32
+
33
+ export const SingleSelection = () => (
34
+ <CustomDataProvider data={data}>
35
+ <StatefulMultiSelectionWrapper>
36
+ {({ selected, onChange }) => (
37
+ <OrganisationUnitTree
38
+ singleSelection
39
+ roots={['A0000000000', 'A0000000001']}
40
+ onChange={onChange}
41
+ selected={selected}
42
+ />
43
+ )}
44
+ </StatefulMultiSelectionWrapper>
45
+ </CustomDataProvider>
46
+ )
@@ -0,0 +1,28 @@
1
+ import React, { useState } from 'react'
2
+ import { OrganisationUnitTree } from '../index.js'
3
+ import {
4
+ createDecoratorCustomDataProvider,
5
+ createDecoratorStatefulMultiSelection,
6
+ } from './common.js'
7
+
8
+ export const MultipleRootSubAndOneMainOrgUnit = (_, { selected, onChange }) => {
9
+ const [filter, setFilter] = useState('')
10
+
11
+ return (
12
+ <>
13
+ <input type="input" onChange={(e) => setFilter(e.target.value)} />
14
+
15
+ <OrganisationUnitTree
16
+ filter={filter ? filter.split(',') : []}
17
+ onChange={onChange}
18
+ selected={selected}
19
+ roots={['A0000000000', 'A0000000001', 'A0000000002']}
20
+ />
21
+ </>
22
+ )
23
+ }
24
+
25
+ MultipleRootSubAndOneMainOrgUnit.decorators = [
26
+ createDecoratorStatefulMultiSelection(),
27
+ createDecoratorCustomDataProvider(),
28
+ ]
@@ -0,0 +1,55 @@
1
+ import { CustomDataProvider } from '@dhis2/app-runtime'
2
+ import React from 'react'
3
+ import { OrganisationUnitTree } from '../index.js'
4
+ import { StatefulMultiSelectionWrapper, dataProviderData } from './common.js'
5
+
6
+ const customizedDataProviderData = {
7
+ organisationUnits: (...args) => {
8
+ const [, { id, params }] = args
9
+ const { fields } = params
10
+
11
+ if (id === 'A0000000000') {
12
+ return dataProviderData.organisationUnits(...args).then((data) => ({
13
+ ...data,
14
+ children: fields.includes('children::size')
15
+ ? 1
16
+ : data.children?.slice(0, 1),
17
+ }))
18
+ }
19
+
20
+ if (id === 'A0000000001') {
21
+ return dataProviderData.organisationUnits(...args).then((data) => ({
22
+ ...data,
23
+ path: '/A0000000001',
24
+ children: fields.includes('children::size') ? 0 : [],
25
+ }))
26
+ }
27
+
28
+ return Promise.resolve({})
29
+ },
30
+ }
31
+
32
+ window.onChange = window.Cypress && window.Cypress.cy.stub()
33
+ window.onCollapse = window.Cypress && window.Cypress.cy.stub()
34
+ window.onExpand = window.Cypress && window.Cypress.cy.stub()
35
+ window.onChildrenLoaded = window.Cypress && window.Cypress.cy.stub()
36
+
37
+ export const Events = () => (
38
+ <CustomDataProvider data={customizedDataProviderData}>
39
+ <StatefulMultiSelectionWrapper>
40
+ {({ selected, onChange }) => (
41
+ <OrganisationUnitTree
42
+ roots="A0000000000"
43
+ selected={selected}
44
+ onChange={(...args) => {
45
+ onChange(...args)
46
+ window.onChange(...args)
47
+ }}
48
+ onExpand={window.onExpand}
49
+ onCollapse={window.onCollapse}
50
+ onChildrenLoaded={window.onChildrenLoaded}
51
+ />
52
+ )}
53
+ </StatefulMultiSelectionWrapper>
54
+ </CustomDataProvider>
55
+ )
@@ -0,0 +1,11 @@
1
+ import React from 'react'
2
+ import { OrganisationUnitTree } from '../index.js'
3
+ import { onChange } from './shared.js'
4
+
5
+ export const Collapsed = () => (
6
+ <OrganisationUnitTree
7
+ onChange={onChange}
8
+ name={'Root org unit'}
9
+ roots={['A0000000000']}
10
+ />
11
+ )
@@ -0,0 +1,181 @@
1
+ import { Button } from '@dhis2-ui/button'
2
+ import React, { useState } from 'react'
3
+ import { OrganisationUnitTree, getAllExpandedOrgUnitPaths } from '../index.js'
4
+ import { onChange } from './shared.js'
5
+
6
+ export const CustomExpandedImperativeOpen = () => {
7
+ const orgUnit2Path = '/A0000000000/A0000000001'
8
+ const initiallyExpanded = getAllExpandedOrgUnitPaths([])
9
+
10
+ const [expanded, setExpanded] = useState(initiallyExpanded)
11
+
12
+ const handleExpand = ({ path }) => {
13
+ if (!expanded.includes(path)) {
14
+ setExpanded([...expanded, path])
15
+ }
16
+ }
17
+
18
+ const handleCollapse = ({ path }) => {
19
+ const pathIndex = expanded.indexOf(path)
20
+
21
+ if (pathIndex !== -1) {
22
+ const updatedExpanded =
23
+ pathIndex === 0
24
+ ? expanded.slice(1)
25
+ : [
26
+ ...expanded.slice(0, pathIndex),
27
+ ...expanded.slice(pathIndex + 1),
28
+ ]
29
+
30
+ setExpanded(updatedExpanded)
31
+ }
32
+ }
33
+
34
+ const imperativeToggle = () => {
35
+ if (!expanded.includes('/A0000000000/A0000000001')) {
36
+ // Make sure that all required sub paths are included as well
37
+ const nextPaths = getAllExpandedOrgUnitPaths([
38
+ ...expanded,
39
+ orgUnit2Path,
40
+ ])
41
+
42
+ return setExpanded(nextPaths)
43
+ }
44
+
45
+ setExpanded(expanded.filter((v) => v !== '/A0000000000/A0000000001'))
46
+ }
47
+
48
+ return (
49
+ <>
50
+ <OrganisationUnitTree
51
+ onChange={onChange}
52
+ name="Root org unit"
53
+ roots={['A0000000000']}
54
+ expanded={expanded}
55
+ handleExpand={handleExpand}
56
+ handleCollapse={handleCollapse}
57
+ />
58
+ <br />
59
+ <Button onClick={imperativeToggle}>Toggle Org Unit 2</Button>
60
+ </>
61
+ )
62
+ }
63
+
64
+ // Do we need this story?
65
+ // export const CustomExpandedKeepUserExpanded = () => {
66
+ // /**
67
+ // * @param {string} path
68
+ // * @returns {string[]}
69
+ // */
70
+ // const extractAllPathsFromPath = path => {
71
+ // // remove leading slash and split by path delimiter/slashes
72
+ // const segments = path.replace(/^\//, '').split('/')
73
+ //
74
+ // const withSubPaths = segments.map((segment, index) => {
75
+ // // take all segments from 0 to index and join them with the delimiter
76
+ // return `/${segments.slice(0, index + 1).join('/')}`
77
+ // })
78
+ //
79
+ // return withSubPaths
80
+ // }
81
+ //
82
+ // /**
83
+ // * @param {string[]} initiallyExpanded
84
+ // * @returns {string[]}
85
+ // */
86
+ // const getInitiallyExpandedPaths = paths =>
87
+ // paths.reduce((all, curPath) => {
88
+ // const allPathsInCurPath = extractAllPathsFromPath(curPath)
89
+ // return [...all, ...allPathsInCurPath]
90
+ // }, [])
91
+ //
92
+ // const [useOriginal, setUseOriginal] = useState(true)
93
+ // const initiallyExpanded = getInitiallyExpandedPaths(
94
+ // ['/A0000000000/A0000000001']
95
+ // )
96
+ // const alternativeInitiallyExpanded = getInitiallyExpandedPaths(
97
+ // ['/A0000000000']
98
+ // )
99
+ //
100
+ // const [expandedConfig, setExpandedConfig] = useState(
101
+ // () => initiallyExpanded.map(path => ({
102
+ // userExpanded: false,
103
+ // path,
104
+ // }))
105
+ // )
106
+ //
107
+ // const expanded = useMemo(
108
+ // () => expandedConfig.map(({ path }) => path),
109
+ // [expandedConfig]
110
+ // )
111
+ //
112
+ // const switchAutomaticallyExpended = () => {
113
+ // // Necessary due to the nature of the async state setter of the hook
114
+ // const nextUseOriginal = !useOriginal
115
+ // const allUserExpandedPaths = getInitiallyExpandedPaths(
116
+ // expandedConfig
117
+ // .filter(({ userExpanded }) => userExpanded)
118
+ // .map(({ path }) => path)
119
+ // )
120
+ //
121
+ // const allUserExpanded = allUserExpandedPaths.map(path => ({
122
+ // userExpanded: true,
123
+ // path,
124
+ // }))
125
+ //
126
+ // const actualInitiallyExpended = nextUseOriginal ? initiallyExpanded : alternativeInitiallyExpanded
127
+ // const missingInitiallyExpanded = actualInitiallyExpended.filter(path => {
128
+ // return !allUserExpandedPaths.find(curPath => curPath.includes(path))
129
+ // })
130
+ //
131
+ // const nextExpandedConfig = [
132
+ // ...allUserExpanded,
133
+ // ...missingInitiallyExpanded.map(path => ({
134
+ // userExpanded: false,
135
+ // path,
136
+ // }))
137
+ // ]
138
+ //
139
+ // setExpandedConfig(nextExpandedConfig)
140
+ // setUseOriginal(nextUseOriginal)
141
+ // }
142
+ //
143
+ // const handleExpand = ({ path }) => {
144
+ // if (!expandedConfig.find(config => config.path === path)) {
145
+ // setExpandedConfig([...expandedConfig, { userExpanded: true, path }])
146
+ // }
147
+ // }
148
+ //
149
+ // const handleCollapse = ({ path }) => {
150
+ // const pathIndex = expandedConfig.findIndex(config => config.path === path)
151
+ //
152
+ // if (pathIndex !== -1) {
153
+ // const updatedExpandedConfig =
154
+ // pathIndex === 0
155
+ // ? expandedConfig.slice(1)
156
+ // : [
157
+ // ...expandedConfig.slice(0, pathIndex),
158
+ // ...expandedConfig.slice(pathIndex + 1),
159
+ // ]
160
+ //
161
+ // setExpandedConfig(updatedExpandedConfig)
162
+ // }
163
+ // }
164
+ //
165
+ // return (
166
+ // <>
167
+ // <OrganisationUnitTree
168
+ // onChange={onChange}
169
+ // name="Root org unit"
170
+ // roots={['A0000000000']}
171
+ // expanded={expanded}
172
+ // handleExpand={handleExpand}
173
+ // handleCollapse={handleCollapse}
174
+ // />
175
+ // <br />
176
+ // <Button onClick={switchAutomaticallyExpended}>
177
+ // Switch automatically expanded
178
+ // </Button>
179
+ // </>
180
+ // )
181
+ // }
@@ -0,0 +1,19 @@
1
+ import React from 'react'
2
+ import { OrganisationUnitTree } from '../index.js'
3
+ import { onChange } from './shared.js'
4
+
5
+ export const CustomNodeLabel = () => (
6
+ <OrganisationUnitTree
7
+ name="Root org unit"
8
+ roots="A0000000000"
9
+ initiallyExpanded={['/A0000000000/A0000000001']}
10
+ renderNodeLabel={({ label, node }) => {
11
+ if (node.path !== '/A0000000000/A0000000001') {
12
+ return label
13
+ }
14
+
15
+ return <span>--- {label}</span>
16
+ }}
17
+ onChange={onChange}
18
+ />
19
+ )
@@ -0,0 +1,86 @@
1
+ import { DataProvider } from '@dhis2/app-runtime'
2
+ import React, { useState } from 'react'
3
+ import { OrganisationUnitTree } from '../index.js'
4
+
5
+ const DX_onChange =
6
+ (selected, setSelected, singleSelection) =>
7
+ ({ id, path, checked }) => {
8
+ console.log('onChange', { path, id, checked })
9
+ const pathIndex = selected.indexOf(path)
10
+
11
+ let nextSelected
12
+
13
+ if (checked) {
14
+ nextSelected = singleSelection ? [path] : [...selected, path]
15
+ } else {
16
+ nextSelected = singleSelection
17
+ ? []
18
+ : [
19
+ ...selected.slice(0, pathIndex),
20
+ ...selected.slice(pathIndex + 1),
21
+ ]
22
+ }
23
+
24
+ console.log('> nextSelected', nextSelected)
25
+ setSelected(nextSelected)
26
+ }
27
+
28
+ const Wrapper = (props) => {
29
+ const [selected, setSelected] = useState([])
30
+
31
+ return (
32
+ <OrganisationUnitTree
33
+ name="Root org unit"
34
+ roots={['A0000000000']}
35
+ selected={selected}
36
+ onChange={DX_onChange(selected, setSelected, props.singleSelection)}
37
+ initiallyExpanded={['A0000000001/A0000000002']}
38
+ {...props}
39
+ />
40
+ )
41
+ }
42
+
43
+ export const DxMultiSelection = () => <Wrapper />
44
+ DxMultiSelection.storyName = 'DX: Multi selection'
45
+
46
+ export const DxSingleSelection = () => <Wrapper singleSelection />
47
+ DxSingleSelection.storyName = 'DX: Single selection'
48
+
49
+ export const DxNoSelection = () => <Wrapper disableSelection />
50
+ DxNoSelection.storyName = 'DX: No selection'
51
+
52
+ export const DxWithRealBackend = () => (
53
+ <div>
54
+ <div style={{ marginBottom: 20, lineHeight: '28px' }}>
55
+ <b>
56
+ This story doesn&apos;t work on netlify for some reason, just
57
+ run it locally.
58
+ </b>
59
+ <br />
60
+ You need to log in to{' '}
61
+ <a
62
+ href="https://debug.dhis2.org/dev"
63
+ target="_blank"
64
+ rel="noopener noreferrer"
65
+ >
66
+ https://debug.dhis2.org/dev
67
+ </a>
68
+ <br />
69
+ Make sure the{' '}
70
+ <code style={{ background: '#ccc' }}>localhost:[PORT]</code> is part
71
+ of the accepted list:{' '}
72
+ <a
73
+ href="https://debug.dhis2.org/dev/dhis-web-settings/#/access"
74
+ target="_blank"
75
+ rel="noopener noreferrer"
76
+ >
77
+ Settings app / Access
78
+ </a>
79
+ </div>
80
+ <DataProvider baseUrl="https://debug.dhis2.org/dev" apiVersion="">
81
+ <Wrapper roots={['ImspTQPwCqd', 'O6uvpzGd5pu', 'fdc6uOvgoji']} />
82
+ </DataProvider>
83
+ </div>
84
+ )
85
+
86
+ DxWithRealBackend.storyName = 'DX: With real backend'
@@ -0,0 +1,12 @@
1
+ import React from 'react'
2
+ import { OrganisationUnitTree } from '../index.js'
3
+ import { onChange } from './shared.js'
4
+
5
+ export const Expanded = () => (
6
+ <OrganisationUnitTree
7
+ onChange={onChange}
8
+ name="Root org unit"
9
+ roots={['A0000000000']}
10
+ initiallyExpanded={['/A0000000000/A0000000001']}
11
+ />
12
+ )
@@ -0,0 +1,15 @@
1
+ import React from 'react'
2
+ import { OrganisationUnitTree } from '../index.js'
3
+ import { onChange } from './shared.js'
4
+
5
+ export const FilteredRoot = () => (
6
+ <OrganisationUnitTree
7
+ onChange={onChange}
8
+ name="Root org unit"
9
+ roots={['A0000000000', 'A0000000001']}
10
+ initiallyExpanded={['/A0000000000/A0000000001']}
11
+ filter={['/A0000000000']}
12
+ />
13
+ )
14
+
15
+ FilteredRoot.storyName = 'Filtered (root)'
@@ -0,0 +1,13 @@
1
+ import React from 'react'
2
+ import { OrganisationUnitTree } from '../index.js'
3
+ import { onChange } from './shared.js'
4
+
5
+ export const Filtered = () => (
6
+ <OrganisationUnitTree
7
+ onChange={onChange}
8
+ name="Root org unit"
9
+ roots={['A0000000000']}
10
+ initiallyExpanded={['/A0000000000/A0000000001']}
11
+ filter={['/A0000000000/A0000000001']}
12
+ />
13
+ )
@@ -0,0 +1,46 @@
1
+ import { Button } from '@dhis2/ui'
2
+ import React, { useState } from 'react'
3
+ import { OrganisationUnitTree } from '../index.js'
4
+ import { onChange } from './shared.js'
5
+
6
+ export const ForceReloadAll = () => {
7
+ const [forceReload, _setForceReload] = useState(false)
8
+ const setForceReload = (v) =>
9
+ console.log('setForceReload', v) || _setForceReload(v)
10
+
11
+ return (
12
+ <>
13
+ <Button disabled={forceReload} onClick={() => setForceReload(true)}>
14
+ Reload org unit tree
15
+ </Button>{' '}
16
+ <span>(Force reload: {forceReload ? 'true' : 'false'})</span>
17
+ <div>
18
+ <OrganisationUnitTree
19
+ onChange={onChange}
20
+ forceReload={forceReload}
21
+ name="Root org unit"
22
+ roots={['A0000000000']}
23
+ initiallyExpanded={['/A0000000000/A0000000001']}
24
+ selected={['/A0000000000/A0000000001/A0000000003']}
25
+ onChildrenLoaded={(data) => {
26
+ const { id } = data
27
+ if (id === 'A0000000000') {
28
+ setForceReload(false)
29
+ }
30
+ }}
31
+ />
32
+ </div>
33
+ <style jsx>{`
34
+ div {
35
+ width: 400px;
36
+ border: 1px solid black;
37
+ margin-top: 32px;
38
+ padding: 16px;
39
+ min-height: 200px;
40
+ }
41
+ `}</style>
42
+ </>
43
+ )
44
+ }
45
+
46
+ ForceReloadAll.storyName = 'Force reload all'
@@ -0,0 +1,36 @@
1
+ import React from 'react'
2
+
3
+ export const ForceReloadOneUnit = () => {
4
+ return (
5
+ <p>
6
+ This is currently not working due to limitations of the data engine
7
+ in the app runtime.
8
+ </p>
9
+ )
10
+
11
+ //const [idsThatShouldBeReloaded, setIdsThatShouldBeReloaded] = useState([])
12
+
13
+ //useEffect(() => {
14
+ // setTimeout(() => setIdsThatShouldBeReloaded(['A0000000001']), delay)
15
+ //}, [])
16
+
17
+ //return (
18
+ // <OrganisationUnitTree
19
+ // onChange={onChange}
20
+ // idsThatShouldBeReloaded={idsThatShouldBeReloaded}
21
+ // name="Root org unit"
22
+ // roots={['A0000000000']}
23
+ // initiallyExpanded={['/A0000000000', '/A0000000000/A0000000001']}
24
+ // selected={['/A0000000000/A0000000001/A0000000003']}
25
+ // onChildrenLoaded={({ path, forced }) =>
26
+ // console.log(
27
+ // `Unit with path "${path}" loaded, was forced: ${
28
+ // forced ? 'yes' : 'no'
29
+ // }`
30
+ // )
31
+ // }
32
+ // />
33
+ //)
34
+ }
35
+
36
+ ForceReloadOneUnit.storyName = 'Force reload one unit'
@@ -0,0 +1,13 @@
1
+ import React from 'react'
2
+ import { OrganisationUnitTree } from '../index.js'
3
+ import { onChange } from './shared.js'
4
+
5
+ export const Highlighted = () => (
6
+ <OrganisationUnitTree
7
+ onChange={onChange}
8
+ highlighted={['/A0000000000/A0000000001']}
9
+ name="Root org unit"
10
+ roots={['A0000000000']}
11
+ initiallyExpanded={['/A0000000000']}
12
+ />
13
+ )
@@ -0,0 +1,13 @@
1
+ import React from 'react'
2
+ import { OrganisationUnitTree } from '../index.js'
3
+ import { onChange } from './shared.js'
4
+
5
+ export const Indeterminate = () => (
6
+ <OrganisationUnitTree
7
+ onChange={onChange}
8
+ name="Root org unit"
9
+ roots={['A0000000000']}
10
+ selected={['/A0000000000/A0000000001']}
11
+ initiallyExpanded={['/A0000000000']}
12
+ />
13
+ )
@@ -0,0 +1,39 @@
1
+ import { CustomDataProvider } from '@dhis2/app-runtime'
2
+ import React from 'react'
3
+ import { OrganisationUnitTree } from '../index.js'
4
+ import {
5
+ customData,
6
+ onChange,
7
+ onExpand,
8
+ onCollapse,
9
+ onChildrenLoaded,
10
+ } from './shared.js'
11
+
12
+ export const LoadingErrorGrandchild = () => (
13
+ <CustomDataProvider
14
+ data={{
15
+ ...customData,
16
+ organisationUnits: (...args) => {
17
+ const [, { id }] = args
18
+ if (id === 'A0000000003') {
19
+ return Promise.reject('Loading org unit 4 and 5 failed')
20
+ }
21
+
22
+ return customData.organisationUnits(...args)
23
+ },
24
+ }}
25
+ >
26
+ <OrganisationUnitTree
27
+ autoExpandLoadingError
28
+ name="Root org unit"
29
+ roots={['A0000000000']}
30
+ onChange={onChange}
31
+ onExpand={onExpand}
32
+ onCollapse={onCollapse}
33
+ onChildrenLoaded={onChildrenLoaded}
34
+ initiallyExpanded={['/A0000000000/A0000000001']}
35
+ />
36
+ </CustomDataProvider>
37
+ )
38
+
39
+ LoadingErrorGrandchild.storyName = 'Loading error grandchild'
@@ -0,0 +1,27 @@
1
+ import { CustomDataProvider } from '@dhis2/app-runtime'
2
+ import React from 'react'
3
+ import { OrganisationUnitTree } from '../index.js'
4
+ import { customData, onChange } from './shared.js'
5
+
6
+ export const Loading = () => (
7
+ <CustomDataProvider
8
+ data={{
9
+ ...customData,
10
+ organisationUnits: (...args) => {
11
+ const [, { id }] = args
12
+ if (id === 'A0000000001') {
13
+ return new Promise(() => null)
14
+ }
15
+
16
+ return customData.organisationUnits(...args)
17
+ },
18
+ }}
19
+ >
20
+ <OrganisationUnitTree
21
+ onChange={onChange}
22
+ name="Root org unit"
23
+ roots={['A0000000000']}
24
+ initiallyExpanded={['/A0000000000/A0000000001']}
25
+ />
26
+ </CustomDataProvider>
27
+ )
@@ -0,0 +1,20 @@
1
+ import React from 'react'
2
+ import { OrganisationUnitTree } from '../index.js'
3
+ import {
4
+ createDecoratorCustomDataProvider,
5
+ createDecoratorStatefulMultiSelection,
6
+ } from './shared.js'
7
+
8
+ export const MultipleRoots = (_, { onChange, selected }) => (
9
+ <OrganisationUnitTree
10
+ selected={selected}
11
+ onChange={onChange}
12
+ roots={['A0000000000', 'A0000000001']}
13
+ initiallyExpanded={['/A0000000000/A0000000001']}
14
+ />
15
+ )
16
+
17
+ MultipleRoots.decorators = [
18
+ createDecoratorStatefulMultiSelection(),
19
+ createDecoratorCustomDataProvider(),
20
+ ]