@dhis2-ui/organisation-unit-tree 10.16.1 → 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.
- package/package.json +8 -7
- package/src/__e2e__/children_as_child_nodes.js +23 -0
- package/src/__e2e__/common.js +70 -0
- package/src/__e2e__/controlled_expanded.js +89 -0
- package/src/__e2e__/displaying_loading_error.js +45 -0
- package/src/__e2e__/expanded.js +42 -0
- package/src/__e2e__/force_reload.js +66 -0
- package/src/__e2e__/get-organisation-unit-data.js +119 -0
- package/src/__e2e__/highlight.js +23 -0
- package/src/__e2e__/loading_state.js +37 -0
- package/src/__e2e__/multi_selection.js +24 -0
- package/src/__e2e__/namespace.js +1 -0
- package/src/__e2e__/no_selection.js +32 -0
- package/src/__e2e__/path_based_filtering.js +49 -0
- package/src/__e2e__/single_selection.js +46 -0
- package/src/__e2e__/sub_unit_as_root.js +28 -0
- package/src/__e2e__/tree_api.js +55 -0
- package/src/__stories__/collapsed.js +11 -0
- package/src/__stories__/custom-expanded-imperative-open.js +181 -0
- package/src/__stories__/custom-node-label.js +19 -0
- package/src/__stories__/development-stories.js +86 -0
- package/src/__stories__/expanded.js +12 -0
- package/src/__stories__/filtered-root.js +15 -0
- package/src/__stories__/filtered.js +13 -0
- package/src/__stories__/force-reload-all.js +46 -0
- package/src/__stories__/force-reload-one-unit.js +36 -0
- package/src/__stories__/highlighted.js +13 -0
- package/src/__stories__/indeterminate.js +13 -0
- package/src/__stories__/loading-error-grandchild.js +39 -0
- package/src/__stories__/loading.js +27 -0
- package/src/__stories__/multiple-roots.js +20 -0
- package/src/__stories__/no-selection.js +16 -0
- package/src/__stories__/replace-roots.js +28 -0
- package/src/__stories__/root-error.js +36 -0
- package/src/__stories__/root-loading.js +34 -0
- package/src/__stories__/rtl.js +14 -0
- package/src/__stories__/selected-multiple.js +18 -0
- package/src/__stories__/shared.js +192 -0
- package/src/__stories__/single-selection.js +16 -0
- package/src/features/children_as_child_nodes/index.js +29 -0
- package/src/features/children_as_child_nodes.feature +6 -0
- package/src/features/controlled_expanded/index.js +86 -0
- package/src/features/controlled_expanded.feature +11 -0
- package/src/features/displaying_loading_error/index.js +46 -0
- package/src/features/displaying_loading_error.feature +24 -0
- package/src/features/expanded/index.js +87 -0
- package/src/features/expanded.feature +27 -0
- package/src/features/force_reload/index.js +36 -0
- package/src/features/force_reload.feature +7 -0
- package/src/features/highlight/index.js +9 -0
- package/src/features/highlight.feature +5 -0
- package/src/features/loading_state/index.js +26 -0
- package/src/features/loading_state.feature +7 -0
- package/src/features/multi_selection/index.js +94 -0
- package/src/features/multi_selection.feature +31 -0
- package/src/features/no_selection/index.js +41 -0
- package/src/features/no_selection.feature +13 -0
- package/src/features/path_based_filtering/index.js +97 -0
- package/src/features/path_based_filtering.feature +24 -0
- package/src/features/single_selection/index.js +41 -0
- package/src/features/single_selection.feature +20 -0
- package/src/features/sub_unit_as_root/index.js +83 -0
- package/src/features/sub_unit_as_root.feature +34 -0
- package/src/features/tree_api/index.js +121 -0
- package/src/features/tree_api.feature +37 -0
- package/src/get-all-expanded-paths/get-all-expanded-paths.js +32 -0
- package/src/get-all-expanded-paths/get-all-expanded-paths.test.js +22 -0
- package/src/get-all-expanded-paths/index.js +1 -0
- package/src/helpers/index.js +3 -0
- package/src/helpers/is-path-included.js +15 -0
- package/src/helpers/left-trim-to-root-id.js +3 -0
- package/src/helpers/sort-node-children-alphabetically.js +5 -0
- package/src/index.js +6 -0
- package/src/locales/ar/translations.json +5 -0
- package/src/locales/cs/translations.json +5 -0
- package/src/locales/en/translations.json +5 -0
- package/src/locales/es/translations.json +5 -0
- package/src/locales/es_419/translations.json +5 -0
- package/src/locales/fr/translations.json +5 -0
- package/src/locales/index.js +50 -0
- package/src/locales/lo/translations.json +5 -0
- package/src/locales/nb/translations.json +5 -0
- package/src/locales/nl/translations.json +5 -0
- package/src/locales/pt/translations.json +5 -0
- package/src/locales/ru/translations.json +5 -0
- package/src/locales/uk/translations.json +5 -0
- package/src/locales/uz_Latn/translations.json +5 -0
- package/src/locales/uz_UZ_Cyrl/translations.json +5 -0
- package/src/locales/uz_UZ_Latn/translations.json +5 -0
- package/src/locales/vi/translations.json +5 -0
- package/src/locales/zh/translations.json +5 -0
- package/src/locales/zh_CN/translations.json +5 -0
- package/src/organisation-unit-node/compute-child-nodes.js +27 -0
- package/src/organisation-unit-node/compute-child-nodes.test.js +85 -0
- package/src/organisation-unit-node/error-message.js +23 -0
- package/src/organisation-unit-node/has-descendant-selected-paths.js +15 -0
- package/src/organisation-unit-node/has-descendant-selected-paths.test.js +30 -0
- package/src/organisation-unit-node/index.js +1 -0
- package/src/organisation-unit-node/label/disabled-selection-label.js +26 -0
- package/src/organisation-unit-node/label/icon-empty.js +31 -0
- package/src/organisation-unit-node/label/icon-folder-closed.js +38 -0
- package/src/organisation-unit-node/label/icon-folder-open.js +49 -0
- package/src/organisation-unit-node/label/icon-single.js +41 -0
- package/src/organisation-unit-node/label/icon.js +35 -0
- package/src/organisation-unit-node/label/iconized-checkbox.js +67 -0
- package/src/organisation-unit-node/label/index.js +1 -0
- package/src/organisation-unit-node/label/label-container.js +36 -0
- package/src/organisation-unit-node/label/label.js +146 -0
- package/src/organisation-unit-node/label/single-selection-label.js +60 -0
- package/src/organisation-unit-node/loading-spinner.js +22 -0
- package/src/organisation-unit-node/organisation-unit-node-children.js +123 -0
- package/src/organisation-unit-node/organisation-unit-node.js +190 -0
- package/src/organisation-unit-node/use-open-state.js +37 -0
- package/src/organisation-unit-node/use-open-state.test.js +111 -0
- package/src/organisation-unit-node/use-org-children.js +63 -0
- package/src/organisation-unit-node/use-org-children.test.js +314 -0
- package/src/organisation-unit-node/use-org-data/index.js +1 -0
- package/src/organisation-unit-node/use-org-data/use-org-data.js +40 -0
- package/src/organisation-unit-node/use-org-data/use-org-data.test.js +137 -0
- package/src/organisation-unit-tree/default-render-node-label/default-render-node-label.js +1 -0
- package/src/organisation-unit-tree/default-render-node-label/index.js +1 -0
- package/src/organisation-unit-tree/filter-root-ids.js +9 -0
- package/src/organisation-unit-tree/index.js +3 -0
- package/src/organisation-unit-tree/organisation-unit-tree-root-error.js +20 -0
- package/src/organisation-unit-tree/organisation-unit-tree-root-loading.js +22 -0
- package/src/organisation-unit-tree/organisation-unit-tree.js +253 -0
- package/src/organisation-unit-tree/organisation-unit-tree.test.js +77 -0
- package/src/organisation-unit-tree/use-expanded/create-expand-handlers.js +45 -0
- package/src/organisation-unit-tree/use-expanded/create-expand-handlers.test.js +54 -0
- package/src/organisation-unit-tree/use-expanded/index.js +1 -0
- package/src/organisation-unit-tree/use-expanded/use-expanded.js +42 -0
- package/src/organisation-unit-tree/use-expanded/use-expanded.test.js +73 -0
- package/src/organisation-unit-tree/use-force-reload.js +22 -0
- package/src/organisation-unit-tree/use-force-reload.test.js +43 -0
- package/src/organisation-unit-tree/use-root-org-data/index.js +1 -0
- package/src/organisation-unit-tree/use-root-org-data/patch-missing-display-name.js +20 -0
- package/src/organisation-unit-tree/use-root-org-data/patch-missing-display-name.test.js +24 -0
- package/src/organisation-unit-tree/use-root-org-data/use-root-org-data.js +60 -0
- package/src/organisation-unit-tree/use-root-org-data/use-root-org-unit.test.js +184 -0
- package/src/organisation-unit-tree.e2e.stories.js +28 -0
- package/src/organisation-unit-tree.prod.stories.js +70 -0
- 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'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
|
+
]
|