@dhis2-ui/organisation-unit-tree 7.2.8 → 7.4.2
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/build/cjs/__e2e__/common.js +134 -92
- package/build/cjs/__e2e__/controlled_expanded.stories.e2e.js +90 -0
- package/build/cjs/__e2e__/path_based_filtering.stories.e2e.js +0 -1
- package/build/cjs/__e2e__/single_selection.stories.e2e.js +4 -4
- package/build/cjs/__e2e__/tree_api.stories.e2e.js +6 -8
- package/build/cjs/__stories__/collapsed.js +22 -0
- package/build/cjs/__stories__/custom-expanded-imperative-open.js +184 -0
- package/build/cjs/__stories__/custom-node-label.js +33 -0
- package/build/cjs/__stories__/development-stories.js +96 -0
- package/build/cjs/__stories__/expanded.js +23 -0
- package/build/cjs/__stories__/filtered-root.js +25 -0
- package/build/cjs/__stories__/filtered.js +24 -0
- package/build/cjs/__stories__/force-reload-all.js +58 -0
- package/build/cjs/__stories__/force-reload-one-unit.js +37 -0
- package/build/cjs/__stories__/highlighted.js +24 -0
- package/build/cjs/__stories__/indeterminate.js +24 -0
- package/build/cjs/__stories__/loading-error-grandchild.js +44 -0
- package/build/cjs/__stories__/loading.js +39 -0
- package/build/cjs/__stories__/multiple-roots.js +24 -0
- package/build/cjs/__stories__/no-selection.js +26 -0
- package/build/cjs/__stories__/replace-roots.js +28 -0
- package/build/cjs/__stories__/root-error.js +48 -0
- package/build/cjs/__stories__/root-loading.js +48 -0
- package/build/cjs/__stories__/selected-multiple.js +25 -0
- package/build/cjs/__stories__/shared.js +140 -0
- package/build/cjs/__stories__/single-selection.js +26 -0
- package/build/cjs/features/controlled_expanded/index.js +60 -0
- package/build/cjs/features/controlled_expanded.feature +11 -0
- package/build/cjs/features/tree_api/index.js +1 -3
- package/build/cjs/get-all-expanded-paths/get-all-expanded-paths.js +40 -0
- package/build/cjs/get-all-expanded-paths/get-all-expanded-paths.test.js +17 -0
- package/build/cjs/get-all-expanded-paths/index.js +13 -0
- package/build/cjs/index.js +9 -1
- package/build/cjs/organisation-unit-node/use-open-state.js +11 -16
- package/build/cjs/organisation-unit-node/use-open-state.test.js +59 -101
- package/build/cjs/organisation-unit-tree/organisation-unit-tree.js +35 -20
- package/build/cjs/organisation-unit-tree/organisation-unit-tree.test.js +63 -0
- package/build/cjs/organisation-unit-tree/use-expanded/{helpers.js → create-expand-handlers.js} +1 -30
- package/build/cjs/organisation-unit-tree/use-expanded/{helpers.test.js → create-expand-handlers.test.js} +5 -18
- package/build/cjs/organisation-unit-tree/use-expanded/use-expanded.js +23 -4
- package/build/cjs/organisation-unit-tree/use-expanded/use-expanded.test.js +42 -8
- package/build/cjs/organisation-unit-tree.stories.js +191 -534
- package/build/es/__e2e__/common.js +121 -90
- package/build/es/__e2e__/controlled_expanded.stories.e2e.js +68 -0
- package/build/es/__e2e__/path_based_filtering.stories.e2e.js +0 -1
- package/build/es/__e2e__/single_selection.stories.e2e.js +4 -4
- package/build/es/__e2e__/tree_api.stories.e2e.js +6 -7
- package/build/es/__stories__/collapsed.js +8 -0
- package/build/es/__stories__/custom-expanded-imperative-open.js +166 -0
- package/build/es/__stories__/custom-node-label.js +19 -0
- package/build/es/__stories__/development-stories.js +73 -0
- package/build/es/__stories__/expanded.js +9 -0
- package/build/es/__stories__/filtered-root.js +11 -0
- package/build/es/__stories__/filtered.js +10 -0
- package/build/es/__stories__/force-reload-all.js +38 -0
- package/build/es/__stories__/force-reload-one-unit.js +25 -0
- package/build/es/__stories__/highlighted.js +10 -0
- package/build/es/__stories__/indeterminate.js +10 -0
- package/build/es/__stories__/loading-error-grandchild.js +29 -0
- package/build/es/__stories__/loading.js +24 -0
- package/build/es/__stories__/multiple-roots.js +10 -0
- package/build/es/__stories__/no-selection.js +12 -0
- package/build/es/__stories__/replace-roots.js +16 -0
- package/build/es/__stories__/root-error.js +33 -0
- package/build/es/__stories__/root-loading.js +33 -0
- package/build/es/__stories__/selected-multiple.js +11 -0
- package/build/es/__stories__/shared.js +120 -0
- package/build/es/__stories__/single-selection.js +12 -0
- package/build/es/features/controlled_expanded/index.js +57 -0
- package/build/es/features/controlled_expanded.feature +11 -0
- package/build/es/features/tree_api/index.js +1 -3
- package/build/es/get-all-expanded-paths/get-all-expanded-paths.js +31 -0
- package/build/es/get-all-expanded-paths/get-all-expanded-paths.test.js +14 -0
- package/build/es/get-all-expanded-paths/index.js +1 -0
- package/build/es/index.js +2 -1
- package/build/es/organisation-unit-node/use-open-state.js +11 -16
- package/build/es/organisation-unit-node/use-open-state.test.js +59 -94
- package/build/es/organisation-unit-tree/organisation-unit-tree.js +15 -1
- package/build/es/organisation-unit-tree/organisation-unit-tree.test.js +55 -0
- package/build/es/organisation-unit-tree/use-expanded/{helpers.js → create-expand-handlers.js} +0 -23
- package/build/es/organisation-unit-tree/use-expanded/{helpers.test.js → create-expand-handlers.test.js} +1 -14
- package/build/es/organisation-unit-tree/use-expanded/use-expanded.js +21 -3
- package/build/es/organisation-unit-tree/use-expanded/use-expanded.test.js +40 -7
- package/build/es/organisation-unit-tree.stories.js +23 -465
- package/package.json +5 -5
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { OrganisationUnitTree } from '../index.js';
|
|
3
|
+
import { onChange } from './shared.js';
|
|
4
|
+
export const Filtered = () => /*#__PURE__*/React.createElement(OrganisationUnitTree, {
|
|
5
|
+
onChange: onChange,
|
|
6
|
+
name: "Root org unit",
|
|
7
|
+
roots: ['A0000000000'],
|
|
8
|
+
initiallyExpanded: ['/A0000000000/A0000000001'],
|
|
9
|
+
filter: ['/A0000000000/A0000000001']
|
|
10
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import _JSXStyle from "styled-jsx/style";
|
|
2
|
+
import { Button } from '@dhis2/ui';
|
|
3
|
+
import React, { useState } from 'react';
|
|
4
|
+
import { OrganisationUnitTree } from '../index.js';
|
|
5
|
+
import { onChange } from './shared.js';
|
|
6
|
+
export const ForceReloadAll = () => {
|
|
7
|
+
const [forceReload, _setForceReload] = useState(false);
|
|
8
|
+
|
|
9
|
+
const setForceReload = v => console.log('setForceReload', v) || _setForceReload(v);
|
|
10
|
+
|
|
11
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Button, {
|
|
12
|
+
disabled: forceReload,
|
|
13
|
+
onClick: () => setForceReload(true)
|
|
14
|
+
}, "Reload org unit tree"), ' ', /*#__PURE__*/React.createElement("span", {
|
|
15
|
+
className: "jsx-2109967648"
|
|
16
|
+
}, "(Force reload: ", forceReload ? 'true' : 'false', ")"), /*#__PURE__*/React.createElement("div", {
|
|
17
|
+
className: "jsx-2109967648"
|
|
18
|
+
}, /*#__PURE__*/React.createElement(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 {
|
|
27
|
+
id
|
|
28
|
+
} = data;
|
|
29
|
+
|
|
30
|
+
if (id === 'A0000000000') {
|
|
31
|
+
setForceReload(false);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
})), /*#__PURE__*/React.createElement(_JSXStyle, {
|
|
35
|
+
id: "2109967648"
|
|
36
|
+
}, ["div.jsx-2109967648{width:400px;border:1px solid black;margin-top:32px;padding:16px;min-height:200px;}"]));
|
|
37
|
+
};
|
|
38
|
+
ForceReloadAll.storyName = 'Force reload all';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export const ForceReloadOneUnit = () => {
|
|
3
|
+
return /*#__PURE__*/React.createElement("p", null, "This is currently not working due to limitations of the data engine in the app runtime."); //const [idsThatShouldBeReloaded, setIdsThatShouldBeReloaded] = useState([])
|
|
4
|
+
//useEffect(() => {
|
|
5
|
+
// setTimeout(() => setIdsThatShouldBeReloaded(['A0000000001']), delay)
|
|
6
|
+
//}, [])
|
|
7
|
+
//return (
|
|
8
|
+
// <OrganisationUnitTree
|
|
9
|
+
// onChange={onChange}
|
|
10
|
+
// idsThatShouldBeReloaded={idsThatShouldBeReloaded}
|
|
11
|
+
// name="Root org unit"
|
|
12
|
+
// roots={['A0000000000']}
|
|
13
|
+
// initiallyExpanded={['/A0000000000', '/A0000000000/A0000000001']}
|
|
14
|
+
// selected={['/A0000000000/A0000000001/A0000000003']}
|
|
15
|
+
// onChildrenLoaded={({ path, forced }) =>
|
|
16
|
+
// console.log(
|
|
17
|
+
// `Unit with path "${path}" loaded, was forced: ${
|
|
18
|
+
// forced ? 'yes' : 'no'
|
|
19
|
+
// }`
|
|
20
|
+
// )
|
|
21
|
+
// }
|
|
22
|
+
// />
|
|
23
|
+
//)
|
|
24
|
+
};
|
|
25
|
+
ForceReloadOneUnit.storyName = 'Force reload one unit';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { OrganisationUnitTree } from '../index.js';
|
|
3
|
+
import { onChange } from './shared.js';
|
|
4
|
+
export const Highlighted = () => /*#__PURE__*/React.createElement(OrganisationUnitTree, {
|
|
5
|
+
onChange: onChange,
|
|
6
|
+
highlighted: ['/A0000000000/A0000000001'],
|
|
7
|
+
name: "Root org unit",
|
|
8
|
+
roots: ['A0000000000'],
|
|
9
|
+
initiallyExpanded: ['/A0000000000']
|
|
10
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { OrganisationUnitTree } from '../index.js';
|
|
3
|
+
import { onChange } from './shared.js';
|
|
4
|
+
export const Indeterminate = () => /*#__PURE__*/React.createElement(OrganisationUnitTree, {
|
|
5
|
+
onChange: onChange,
|
|
6
|
+
name: "Root org unit",
|
|
7
|
+
roots: ['A0000000000'],
|
|
8
|
+
selected: ['/A0000000000/A0000000001'],
|
|
9
|
+
initiallyExpanded: ['/A0000000000']
|
|
10
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { CustomDataProvider } from '@dhis2/app-runtime';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { OrganisationUnitTree } from '../index.js';
|
|
4
|
+
import { customData, onChange, onExpand, onCollapse, onChildrenLoaded } from './shared.js';
|
|
5
|
+
export const LoadingErrorGrandchild = () => /*#__PURE__*/React.createElement(CustomDataProvider, {
|
|
6
|
+
data: { ...customData,
|
|
7
|
+
organisationUnits: (...args) => {
|
|
8
|
+
const [, {
|
|
9
|
+
id
|
|
10
|
+
}] = args;
|
|
11
|
+
|
|
12
|
+
if (id === 'A0000000003') {
|
|
13
|
+
return Promise.reject('Loading org unit 4 and 5 failed');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return customData.organisationUnits(...args);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}, /*#__PURE__*/React.createElement(OrganisationUnitTree, {
|
|
20
|
+
autoExpandLoadingError: true,
|
|
21
|
+
name: "Root org unit",
|
|
22
|
+
roots: ['A0000000000'],
|
|
23
|
+
onChange: onChange,
|
|
24
|
+
onExpand: onExpand,
|
|
25
|
+
onCollapse: onCollapse,
|
|
26
|
+
onChildrenLoaded: onChildrenLoaded,
|
|
27
|
+
initiallyExpanded: ['/A0000000000/A0000000001']
|
|
28
|
+
}));
|
|
29
|
+
LoadingErrorGrandchild.storyName = 'Loading error grandchild';
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
export const Loading = () => /*#__PURE__*/React.createElement(CustomDataProvider, {
|
|
6
|
+
data: { ...customData,
|
|
7
|
+
organisationUnits: (...args) => {
|
|
8
|
+
const [, {
|
|
9
|
+
id
|
|
10
|
+
}] = args;
|
|
11
|
+
|
|
12
|
+
if (id === 'A0000000001') {
|
|
13
|
+
return new Promise(() => null);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return customData.organisationUnits(...args);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}, /*#__PURE__*/React.createElement(OrganisationUnitTree, {
|
|
20
|
+
onChange: onChange,
|
|
21
|
+
name: "Root org unit",
|
|
22
|
+
roots: ['A0000000000'],
|
|
23
|
+
initiallyExpanded: ['/A0000000000/A0000000001']
|
|
24
|
+
}));
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { OrganisationUnitTree } from '../index.js';
|
|
3
|
+
import { onChange } from './shared.js';
|
|
4
|
+
export const MultipleRoots = () => /*#__PURE__*/React.createElement(OrganisationUnitTree, {
|
|
5
|
+
onChange: onChange,
|
|
6
|
+
name: "Root org unit",
|
|
7
|
+
roots: ['A0000000000', 'A0000000001'],
|
|
8
|
+
initiallyExpanded: ['/A0000000000/A0000000001']
|
|
9
|
+
});
|
|
10
|
+
MultipleRoots.storyName = 'Multiple roots';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { OrganisationUnitTree } from '../index.js';
|
|
3
|
+
import { onChange } from './shared.js';
|
|
4
|
+
export const NoSelection = () => /*#__PURE__*/React.createElement(OrganisationUnitTree, {
|
|
5
|
+
onChange: onChange,
|
|
6
|
+
disableSelection: true,
|
|
7
|
+
name: "Root org unit",
|
|
8
|
+
roots: ['A0000000000'],
|
|
9
|
+
selected: ['/A0000000000/A0000000001'],
|
|
10
|
+
initiallyExpanded: ['/A0000000000']
|
|
11
|
+
});
|
|
12
|
+
NoSelection.storyName = 'No selection';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export const ReplaceRoots = () => {
|
|
3
|
+
return /*#__PURE__*/React.createElement("p", null, "This is currently not working due to limitations of the data engine in the app runtime. Normally the root unit would've been replaced after 1000 milliseconds."); //const [roots, setRoots] = useState(['A0000000000'])
|
|
4
|
+
//useEffect(() => {
|
|
5
|
+
// setTimeout(() => setRoots(['A0000000001']), delay)
|
|
6
|
+
//}, [])
|
|
7
|
+
//return (
|
|
8
|
+
// <OrganisationUnitTree
|
|
9
|
+
// name="Root org unit"
|
|
10
|
+
// roots={roots}
|
|
11
|
+
// onChange={console.log.bind(null, 'onChange')}
|
|
12
|
+
// initiallyExpanded={['/A0000000001']}
|
|
13
|
+
// />
|
|
14
|
+
//)
|
|
15
|
+
};
|
|
16
|
+
ReplaceRoots.storyName = 'Replace roots';
|
|
@@ -0,0 +1,33 @@
|
|
|
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
|
+
export const RootError = () => /*#__PURE__*/React.createElement(CustomDataProvider, {
|
|
6
|
+
data: { ...customData,
|
|
7
|
+
organisationUnits: (...args) => {
|
|
8
|
+
const [, {
|
|
9
|
+
id
|
|
10
|
+
}] = args;
|
|
11
|
+
|
|
12
|
+
if (id === 'A0000000000') {
|
|
13
|
+
return Promise.reject('This is a custom error message, it could be anything');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return customData.organisationUnits(...args);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}, /*#__PURE__*/React.createElement("fieldset", {
|
|
20
|
+
style: {
|
|
21
|
+
maxWidth: 600
|
|
22
|
+
}
|
|
23
|
+
}, /*#__PURE__*/React.createElement("legend", {
|
|
24
|
+
style: {
|
|
25
|
+
padding: '0 10px'
|
|
26
|
+
}
|
|
27
|
+
}, "Custom container (max-width: 600px)"), /*#__PURE__*/React.createElement(OrganisationUnitTree, {
|
|
28
|
+
onChange: onChange,
|
|
29
|
+
name: "Root org unit",
|
|
30
|
+
roots: ['A0000000000'],
|
|
31
|
+
initiallyExpanded: ['/A0000000000/A0000000001']
|
|
32
|
+
})));
|
|
33
|
+
RootError.storyName = 'Root error';
|
|
@@ -0,0 +1,33 @@
|
|
|
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
|
+
export const RootLoading = () => /*#__PURE__*/React.createElement(CustomDataProvider, {
|
|
6
|
+
data: { ...customData,
|
|
7
|
+
organisationUnits: (...args) => {
|
|
8
|
+
const [, {
|
|
9
|
+
id
|
|
10
|
+
}] = args;
|
|
11
|
+
|
|
12
|
+
if (id === 'A0000000000') {
|
|
13
|
+
return new Promise(() => null);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return customData.organisationUnits(...args);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}, /*#__PURE__*/React.createElement("fieldset", {
|
|
20
|
+
style: {
|
|
21
|
+
maxWidth: 600
|
|
22
|
+
}
|
|
23
|
+
}, /*#__PURE__*/React.createElement("legend", {
|
|
24
|
+
style: {
|
|
25
|
+
padding: '0 10px'
|
|
26
|
+
}
|
|
27
|
+
}, "Custom container (max-width: 600px)"), /*#__PURE__*/React.createElement(OrganisationUnitTree, {
|
|
28
|
+
onChange: onChange,
|
|
29
|
+
name: "Root org unit",
|
|
30
|
+
roots: ['A0000000000'],
|
|
31
|
+
initiallyExpanded: ['/A0000000000/A0000000001']
|
|
32
|
+
})));
|
|
33
|
+
RootLoading.storyName = 'Root loading';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { OrganisationUnitTree } from '../index.js';
|
|
3
|
+
import { onChange } from './shared.js';
|
|
4
|
+
export const SelectedMultiple = () => /*#__PURE__*/React.createElement(OrganisationUnitTree, {
|
|
5
|
+
onChange: onChange,
|
|
6
|
+
name: "Root org unit",
|
|
7
|
+
roots: ['A0000000000'],
|
|
8
|
+
selected: ['/A0000000000/A0000000002', '/A0000000000/A0000000001/A0000000003'],
|
|
9
|
+
initiallyExpanded: ['/A0000000000', '/A0000000000/A0000000001']
|
|
10
|
+
});
|
|
11
|
+
SelectedMultiple.storyName = 'Selected multiple';
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
export const log = true;
|
|
2
|
+
export const onChange = (...args) => log && console.log('onChange', ...args);
|
|
3
|
+
export const onExpand = (...args) => log && console.log('onExpand', ...args);
|
|
4
|
+
export const onCollapse = (...args) => log && console.log('onCollapse', ...args);
|
|
5
|
+
export const onChildrenLoaded = (...args) => log && console.log('onChildrenLoaded', ...args);
|
|
6
|
+
export const customData = {
|
|
7
|
+
organisationUnits: (type, {
|
|
8
|
+
id
|
|
9
|
+
}) => {
|
|
10
|
+
let data;
|
|
11
|
+
let delay = 0;
|
|
12
|
+
|
|
13
|
+
if (id === 'A0000000000') {
|
|
14
|
+
delay = 1000;
|
|
15
|
+
data = {
|
|
16
|
+
id: 'A0000000000',
|
|
17
|
+
path: '/A0000000000',
|
|
18
|
+
displayName: 'Org Unit 1',
|
|
19
|
+
children: [{
|
|
20
|
+
id: 'A0000000001',
|
|
21
|
+
path: '/A0000000000/A0000000001',
|
|
22
|
+
children: [{
|
|
23
|
+
id: 'A0000000003'
|
|
24
|
+
}, {
|
|
25
|
+
id: 'A0000000004'
|
|
26
|
+
}],
|
|
27
|
+
displayName: 'Org Unit 2'
|
|
28
|
+
}, {
|
|
29
|
+
id: 'A0000000002',
|
|
30
|
+
path: '/A0000000000/A0000000002',
|
|
31
|
+
children: [],
|
|
32
|
+
displayName: 'Org Unit 3'
|
|
33
|
+
}, {
|
|
34
|
+
id: 'A0000000006',
|
|
35
|
+
path: '/A0000000000/A0000000006',
|
|
36
|
+
children: [],
|
|
37
|
+
displayName: 'Org Unit 7'
|
|
38
|
+
}]
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (id === 'A0000000001') {
|
|
43
|
+
data = {
|
|
44
|
+
id: 'A0000000001',
|
|
45
|
+
path: '/A0000000000/A0000000001',
|
|
46
|
+
displayName: 'Org Unit 2',
|
|
47
|
+
children: [{
|
|
48
|
+
id: 'A0000000003',
|
|
49
|
+
path: '/A0000000000/A0000000001/A0000000003',
|
|
50
|
+
children: [],
|
|
51
|
+
displayName: 'Org Unit 4'
|
|
52
|
+
}, {
|
|
53
|
+
id: 'A0000000004',
|
|
54
|
+
path: '/A0000000000/A0000000001/A0000000004',
|
|
55
|
+
children: [],
|
|
56
|
+
displayName: 'Org Unit 5'
|
|
57
|
+
}]
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (id === 'A0000000002') {
|
|
62
|
+
delay = 1000;
|
|
63
|
+
data = {
|
|
64
|
+
displayName: 'Org Unit 3',
|
|
65
|
+
id: 'A0000000002',
|
|
66
|
+
path: '/A0000000000/A0000000002',
|
|
67
|
+
children: []
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (id === 'A0000000003') {
|
|
72
|
+
data = {
|
|
73
|
+
displayName: 'Org Unit 4',
|
|
74
|
+
id: 'A0000000003',
|
|
75
|
+
path: '/A0000000000/A0000000001/A0000000003',
|
|
76
|
+
children: [{
|
|
77
|
+
id: 'A0000000007',
|
|
78
|
+
path: '/A0000000000/A0000000001/A0000000003/A0000000007',
|
|
79
|
+
children: [],
|
|
80
|
+
displayName: 'Org Unit 8'
|
|
81
|
+
}]
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (id === 'A0000000004') {
|
|
86
|
+
data = {
|
|
87
|
+
displayName: 'Org Unit 5',
|
|
88
|
+
id: 'A0000000004',
|
|
89
|
+
path: '/A0000000000/A0000000001/A0000000004',
|
|
90
|
+
children: []
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (id === 'A0000000006') {
|
|
95
|
+
data = {
|
|
96
|
+
displayName: 'Org Unit 7',
|
|
97
|
+
id: 'A0000000006',
|
|
98
|
+
path: '/A0000000000/A0000000006',
|
|
99
|
+
children: []
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (id === 'A0000000007') {
|
|
104
|
+
data = {
|
|
105
|
+
displayName: 'Org Unit 8',
|
|
106
|
+
id: 'A0000000007',
|
|
107
|
+
path: '/A0000000000/A0000000001/A0000000003/A0000000007',
|
|
108
|
+
children: []
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!data) {
|
|
113
|
+
return Promise.reject(new Error('404 - Org unit not found'));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return new Promise(resolve => {
|
|
117
|
+
setTimeout(() => resolve(data), delay);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { OrganisationUnitTree } from '../index.js';
|
|
3
|
+
import { onChange } from './shared.js';
|
|
4
|
+
export const SingleSelection = () => /*#__PURE__*/React.createElement(OrganisationUnitTree, {
|
|
5
|
+
onChange: onChange,
|
|
6
|
+
singleSelection: true,
|
|
7
|
+
name: "Root org unit",
|
|
8
|
+
roots: ['A0000000000'],
|
|
9
|
+
selected: ['/A0000000000/A0000000001'],
|
|
10
|
+
initiallyExpanded: ['/A0000000000']
|
|
11
|
+
});
|
|
12
|
+
SingleSelection.storyName = 'Single selection';
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Given, When, Then } from 'cypress-cucumber-preprocessor/steps';
|
|
2
|
+
import { getOrganisationUnitData, namespace } from '../../__e2e__/common.js';
|
|
3
|
+
|
|
4
|
+
const expectOrgUnitsToBeDisplayed = ids => {
|
|
5
|
+
const expandedLabels = ids.map(id => getOrganisationUnitData(id).displayName);
|
|
6
|
+
expandedLabels.forEach(label => {
|
|
7
|
+
cy.get(`:contains("${label}")`).should('exist');
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const expectOrgUnitsToNotBeDisplayed = ids => {
|
|
12
|
+
const expandedLabels = ids.map(id => {
|
|
13
|
+
const data = getOrganisationUnitData(id);
|
|
14
|
+
return data.displayName;
|
|
15
|
+
});
|
|
16
|
+
expandedLabels.forEach(label => {
|
|
17
|
+
cy.get(`:contains("${label}")`).should('not.exist');
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
Given('the initial state of the controlled expanded prop has some paths', () => {
|
|
22
|
+
cy.visitStory(namespace, 'Controlled');
|
|
23
|
+
cy.window().then(win => {
|
|
24
|
+
cy.wrap(win.initiallyExpandedPaths).as('providedPaths');
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
When('the org unit tree should is done loading the provided paths', () => {
|
|
28
|
+
cy.window().then(win => {
|
|
29
|
+
const expandedIds = win.initiallyExpandedPaths.map(path => path.match(/[^/]+$/)[0]);
|
|
30
|
+
expectOrgUnitsToBeDisplayed(expandedIds);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
When('the user clicks on a button to collapse one of the opened paths', () => {
|
|
34
|
+
cy.window().then(win => {
|
|
35
|
+
cy.wrap([win.orgUnitPathToExpand]).as('providedPaths');
|
|
36
|
+
});
|
|
37
|
+
cy.get('[data-test="org-unit-toggle"]').click();
|
|
38
|
+
});
|
|
39
|
+
Then('the org unit tree should open the provided paths when done loading', () => {
|
|
40
|
+
cy.get('@providedPaths').then(providedPaths => {
|
|
41
|
+
const providedIds = providedPaths.map(path => path.match(/[^/]+$/)[0]);
|
|
42
|
+
expectOrgUnitsToBeDisplayed(providedIds);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
Then('the path should close', () => {
|
|
46
|
+
cy.get('@providedPaths').then(providedPaths => {
|
|
47
|
+
const providedIds = providedPaths.map(path => path.match(/[^/]+$/)[0]);
|
|
48
|
+
const hiddenChildrenIds = providedIds.reduce((acc, cur) => {
|
|
49
|
+
const curData = getOrganisationUnitData(cur);
|
|
50
|
+
const childrenIds = curData.children.map(({
|
|
51
|
+
id
|
|
52
|
+
}) => id);
|
|
53
|
+
return [...acc, ...childrenIds];
|
|
54
|
+
}, []);
|
|
55
|
+
expectOrgUnitsToNotBeDisplayed(hiddenChildrenIds);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Feature: The expanded paths of the org unit tree can be controlled
|
|
2
|
+
|
|
3
|
+
Scenario: The org unit tree expands some paths initially
|
|
4
|
+
Given the initial state of the controlled expanded prop has some paths
|
|
5
|
+
Then the org unit tree should open the provided paths when done loading
|
|
6
|
+
|
|
7
|
+
Scenario: The user collapses a path by pressing a button
|
|
8
|
+
Given the initial state of the controlled expanded prop has some paths
|
|
9
|
+
When the org unit tree should is done loading the provided paths
|
|
10
|
+
When the user clicks on a button to collapse one of the opened paths
|
|
11
|
+
Then the path should close
|
|
@@ -98,8 +98,6 @@ Then("the payload contains the loaded children's data", () => {
|
|
|
98
98
|
const {
|
|
99
99
|
args
|
|
100
100
|
} = calls[calls.length - 1];
|
|
101
|
-
expect(args[0]).to.
|
|
102
|
-
id: 'A0000000001'
|
|
103
|
-
}));
|
|
101
|
+
expect(args[0].id).to.equal('A0000000001');
|
|
104
102
|
});
|
|
105
103
|
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @template T
|
|
3
|
+
* @param {Array.<T>} arr
|
|
4
|
+
* @returns {Array.<T>}
|
|
5
|
+
*/
|
|
6
|
+
const removeDuplicates = arr => Array.from(new Set(arr));
|
|
7
|
+
/**
|
|
8
|
+
* @param {string} path
|
|
9
|
+
* @returns {string[]}
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const extractAllPathsFromPath = path => {
|
|
14
|
+
// remove leading slash and split by path delimiter/slashes
|
|
15
|
+
const segments = path.replace(/^\//, '').split('/');
|
|
16
|
+
const withSubPaths = segments.map((segment, index) => {
|
|
17
|
+
// take all segments from 0 to index and join them with the delimiter
|
|
18
|
+
return `/${segments.slice(0, index + 1).join('/')}`;
|
|
19
|
+
});
|
|
20
|
+
return removeDuplicates(withSubPaths);
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* @param {string[]} initiallyExpanded
|
|
24
|
+
* @returns {string[]}
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
export const getAllExpandedPaths = initiallyExpanded => initiallyExpanded.reduce((all, curPath) => {
|
|
29
|
+
const allPathsInCurPath = extractAllPathsFromPath(curPath);
|
|
30
|
+
return [...all, ...allPathsInCurPath];
|
|
31
|
+
}, []);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { getAllExpandedPaths } from './get-all-expanded-paths.js';
|
|
2
|
+
describe('OrganisationUnitTree - getAllExpandedPaths', () => {
|
|
3
|
+
const initiallyExpanded = ['/foo/bar/baz', '/foobar/barbaz/bazfoo'];
|
|
4
|
+
it('should include all initiallyExpanded paths in the returned expanded array', () => {
|
|
5
|
+
const actual = getAllExpandedPaths(initiallyExpanded);
|
|
6
|
+
const expected = expect.arrayContaining(initiallyExpanded);
|
|
7
|
+
expect(actual).toEqual(expected);
|
|
8
|
+
});
|
|
9
|
+
it('should include all sub paths of the paths in initiallyExpanded in the returned exanded array', () => {
|
|
10
|
+
const actual = getAllExpandedPaths(initiallyExpanded);
|
|
11
|
+
const expected = expect.arrayContaining(['/foo', '/foo/bar', '/foobar', '/foobar/barbaz']);
|
|
12
|
+
expect(actual).toEqual(expected);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getAllExpandedPaths } from './get-all-expanded-paths.js';
|
package/build/es/index.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export { OrganisationUnitTree } from './organisation-unit-tree/index.js';
|
|
1
|
+
export { OrganisationUnitTree } from './organisation-unit-tree/index.js';
|
|
2
|
+
export { getAllExpandedPaths as getAllExpandedOrgUnitPaths } from './get-all-expanded-paths/index.js';
|
|
@@ -20,30 +20,25 @@ export const useOpenState = ({
|
|
|
20
20
|
}) => {
|
|
21
21
|
const autoExpand = autoExpandLoadingError && !!errorMessage;
|
|
22
22
|
const [openedOnceDueToError, setOpenedOnce] = useState(!!errorMessage);
|
|
23
|
-
const [open, setOpen] = useState(autoExpand || expanded.includes(path));
|
|
24
23
|
useEffect(() => {
|
|
25
24
|
if (autoExpand && !openedOnceDueToError) {
|
|
26
|
-
|
|
25
|
+
onExpand({
|
|
26
|
+
path
|
|
27
|
+
});
|
|
27
28
|
setOpenedOnce(true);
|
|
28
29
|
}
|
|
29
30
|
}, [autoExpand, openedOnceDueToError]);
|
|
31
|
+
const open = autoExpand && !openedOnceDueToError || !!expanded.includes(path);
|
|
30
32
|
|
|
31
|
-
const onToggleOpen = () => {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
setOpen(newOpen);
|
|
37
|
-
|
|
38
|
-
if (onExpand && newOpen) {
|
|
39
|
-
onExpand(payload);
|
|
40
|
-
} else if (onCollapse && !newOpen) {
|
|
41
|
-
onCollapse(payload);
|
|
42
|
-
}
|
|
43
|
-
};
|
|
33
|
+
const onToggleOpen = () => !open ? onExpand({
|
|
34
|
+
path
|
|
35
|
+
}) : onCollapse({
|
|
36
|
+
path
|
|
37
|
+
});
|
|
44
38
|
|
|
45
39
|
return {
|
|
46
40
|
open,
|
|
47
|
-
onToggleOpen
|
|
41
|
+
onToggleOpen,
|
|
42
|
+
openedOnceDueToError
|
|
48
43
|
};
|
|
49
44
|
};
|