@dhis2-ui/organisation-unit-tree 10.16.3 → 10.16.5

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 (114) hide show
  1. package/build/cjs/__e2e__/children_as_child_nodes.js +8 -11
  2. package/build/cjs/__e2e__/common.js +19 -26
  3. package/build/cjs/__e2e__/controlled_expanded.js +7 -10
  4. package/build/cjs/__e2e__/displaying_loading_error.js +1 -4
  5. package/build/cjs/__e2e__/expanded.js +25 -34
  6. package/build/cjs/__e2e__/force_reload.js +15 -22
  7. package/build/cjs/__e2e__/get-organisation-unit-data.js +25 -29
  8. package/build/cjs/__e2e__/highlight.js +7 -10
  9. package/build/cjs/__e2e__/loading_state.js +7 -13
  10. package/build/cjs/__e2e__/multi_selection.js +8 -11
  11. package/build/cjs/__e2e__/no_selection.js +15 -21
  12. package/build/cjs/__e2e__/path_based_filtering.js +16 -22
  13. package/build/cjs/__e2e__/single_selection.js +10 -16
  14. package/build/cjs/__e2e__/sub_unit_as_root.js +5 -7
  15. package/build/cjs/__e2e__/tree_api.js +15 -21
  16. package/build/cjs/__stories__/custom-expanded-imperative-open.js +7 -10
  17. package/build/cjs/__stories__/custom-node-label.js +4 -5
  18. package/build/cjs/__stories__/development-stories.js +6 -8
  19. package/build/cjs/__stories__/force-reload-all.js +1 -2
  20. package/build/cjs/__stories__/loading-error-grandchild.js +1 -4
  21. package/build/cjs/__stories__/loading.js +1 -4
  22. package/build/cjs/__stories__/multiple-roots.js +9 -12
  23. package/build/cjs/__stories__/root-error.js +1 -4
  24. package/build/cjs/__stories__/root-loading.js +1 -4
  25. package/build/cjs/__stories__/shared.js +46 -79
  26. package/build/cjs/features/controlled_expanded/index.js +3 -6
  27. package/build/cjs/locales/index.js +49 -27
  28. package/build/cjs/organisation-unit-node/error-message.js +10 -13
  29. package/build/cjs/organisation-unit-node/label/disabled-selection-label.js +9 -12
  30. package/build/cjs/organisation-unit-node/label/icon-empty.js +19 -22
  31. package/build/cjs/organisation-unit-node/label/icon-folder-closed.js +25 -28
  32. package/build/cjs/organisation-unit-node/label/icon-folder-open.js +34 -37
  33. package/build/cjs/organisation-unit-node/label/icon-single.js +28 -31
  34. package/build/cjs/organisation-unit-node/label/icon.js +6 -7
  35. package/build/cjs/organisation-unit-node/label/iconized-checkbox.js +12 -13
  36. package/build/cjs/organisation-unit-node/label/label-container.js +13 -16
  37. package/build/cjs/organisation-unit-node/label/label.js +27 -30
  38. package/build/cjs/organisation-unit-node/label/single-selection-label.js +18 -21
  39. package/build/cjs/organisation-unit-node/organisation-unit-node-children.js +27 -29
  40. package/build/cjs/organisation-unit-node/organisation-unit-node.js +22 -23
  41. package/build/cjs/organisation-unit-node/use-open-state.js +8 -9
  42. package/build/cjs/organisation-unit-node/use-org-children.js +14 -21
  43. package/build/cjs/organisation-unit-node/use-org-children.test.js +40 -59
  44. package/build/cjs/organisation-unit-node/use-org-data/use-org-data.js +13 -20
  45. package/build/cjs/organisation-unit-node/use-org-data/use-org-data.test.js +17 -27
  46. package/build/cjs/organisation-unit-tree/default-render-node-label/default-render-node-label.js +3 -6
  47. package/build/cjs/organisation-unit-tree/organisation-unit-tree-root-error.js +9 -12
  48. package/build/cjs/organisation-unit-tree/organisation-unit-tree-root-loading.js +10 -13
  49. package/build/cjs/organisation-unit-tree/organisation-unit-tree.js +41 -35
  50. package/build/cjs/organisation-unit-tree/organisation-unit-tree.test.js +78 -7
  51. package/build/cjs/organisation-unit-tree/use-expanded/create-expand-handlers.js +14 -17
  52. package/build/cjs/organisation-unit-tree/use-expanded/use-expanded.js +8 -9
  53. package/build/cjs/organisation-unit-tree/use-root-org-data/patch-missing-display-name.js +1 -2
  54. package/build/cjs/organisation-unit-tree/use-root-org-data/use-root-org-data.js +10 -14
  55. package/build/cjs/organisation-unit-tree/use-root-org-data/use-root-org-unit.test.js +32 -46
  56. package/build/es/__e2e__/children_as_child_nodes.js +8 -11
  57. package/build/es/__e2e__/common.js +18 -24
  58. package/build/es/__e2e__/controlled_expanded.js +6 -8
  59. package/build/es/__e2e__/displaying_loading_error.js +1 -4
  60. package/build/es/__e2e__/expanded.js +25 -34
  61. package/build/es/__e2e__/force_reload.js +14 -20
  62. package/build/es/__e2e__/get-organisation-unit-data.js +25 -29
  63. package/build/es/__e2e__/highlight.js +7 -10
  64. package/build/es/__e2e__/loading_state.js +7 -13
  65. package/build/es/__e2e__/multi_selection.js +8 -11
  66. package/build/es/__e2e__/no_selection.js +15 -21
  67. package/build/es/__e2e__/path_based_filtering.js +16 -22
  68. package/build/es/__e2e__/single_selection.js +10 -16
  69. package/build/es/__e2e__/sub_unit_as_root.js +4 -5
  70. package/build/es/__e2e__/tree_api.js +15 -21
  71. package/build/es/__stories__/custom-expanded-imperative-open.js +6 -8
  72. package/build/es/__stories__/custom-node-label.js +4 -5
  73. package/build/es/__stories__/development-stories.js +5 -6
  74. package/build/es/__stories__/loading-error-grandchild.js +1 -4
  75. package/build/es/__stories__/loading.js +1 -4
  76. package/build/es/__stories__/multiple-roots.js +9 -12
  77. package/build/es/__stories__/root-error.js +1 -4
  78. package/build/es/__stories__/root-loading.js +1 -4
  79. package/build/es/__stories__/shared.js +45 -77
  80. package/build/es/features/controlled_expanded/index.js +3 -6
  81. package/build/es/locales/index.js +40 -18
  82. package/build/es/organisation-unit-node/error-message.js +10 -13
  83. package/build/es/organisation-unit-node/label/disabled-selection-label.js +9 -12
  84. package/build/es/organisation-unit-node/label/icon-empty.js +19 -22
  85. package/build/es/organisation-unit-node/label/icon-folder-closed.js +25 -28
  86. package/build/es/organisation-unit-node/label/icon-folder-open.js +34 -37
  87. package/build/es/organisation-unit-node/label/icon-single.js +28 -31
  88. package/build/es/organisation-unit-node/label/icon.js +6 -7
  89. package/build/es/organisation-unit-node/label/iconized-checkbox.js +12 -13
  90. package/build/es/organisation-unit-node/label/label-container.js +13 -16
  91. package/build/es/organisation-unit-node/label/label.js +27 -30
  92. package/build/es/organisation-unit-node/label/single-selection-label.js +18 -21
  93. package/build/es/organisation-unit-node/organisation-unit-node-children.js +27 -29
  94. package/build/es/organisation-unit-node/organisation-unit-node.js +22 -23
  95. package/build/es/organisation-unit-node/use-open-state.js +8 -9
  96. package/build/es/organisation-unit-node/use-org-children.js +14 -21
  97. package/build/es/organisation-unit-node/use-org-children.test.js +40 -59
  98. package/build/es/organisation-unit-node/use-org-data/use-org-data.js +13 -20
  99. package/build/es/organisation-unit-node/use-org-data/use-org-data.test.js +17 -27
  100. package/build/es/organisation-unit-tree/default-render-node-label/default-render-node-label.js +3 -6
  101. package/build/es/organisation-unit-tree/organisation-unit-tree-root-error.js +9 -12
  102. package/build/es/organisation-unit-tree/organisation-unit-tree-root-loading.js +10 -13
  103. package/build/es/organisation-unit-tree/organisation-unit-tree.js +34 -27
  104. package/build/es/organisation-unit-tree/organisation-unit-tree.test.js +71 -0
  105. package/build/es/organisation-unit-tree/use-expanded/create-expand-handlers.js +14 -17
  106. package/build/es/organisation-unit-tree/use-expanded/use-expanded.js +8 -9
  107. package/build/es/organisation-unit-tree/use-root-org-data/patch-missing-display-name.js +1 -2
  108. package/build/es/organisation-unit-tree/use-root-org-data/use-root-org-data.js +10 -14
  109. package/build/es/organisation-unit-tree/use-root-org-data/use-root-org-unit.test.js +32 -46
  110. package/package.json +6 -6
  111. package/src/locales/index.js +57 -18
  112. package/src/organisation-unit-tree/organisation-unit-tree.js +14 -3
  113. package/src/organisation-unit-tree/organisation-unit-tree.test.js +64 -0
  114. package/src/organisation-unit-tree/use-root-org-data/use-root-org-unit.test.js +14 -14
@@ -4,10 +4,9 @@ import React from 'react';
4
4
  import { useOrgChildren } from './use-org-children.js';
5
5
  describe('OrganisationUnitTree - useOrgChildren', () => {
6
6
  const dataProviderData = {
7
- organisationUnits: jest.fn((type, _ref) => {
8
- let {
9
- id
10
- } = _ref;
7
+ organisationUnits: jest.fn((type, {
8
+ id
9
+ }) => {
11
10
  if (id === 'A0000000000') {
12
11
  return {
13
12
  children: [{
@@ -21,14 +20,11 @@ describe('OrganisationUnitTree - useOrgChildren', () => {
21
20
  return Promise.reject(`No org unit with id "${id}"`);
22
21
  })
23
22
  };
24
- const wrapper = _ref2 => {
25
- let {
26
- children
27
- } = _ref2;
28
- return /*#__PURE__*/React.createElement(CustomDataProvider, {
29
- data: dataProviderData
30
- }, children);
31
- };
23
+ const wrapper = ({
24
+ children
25
+ }) => /*#__PURE__*/React.createElement(CustomDataProvider, {
26
+ data: dataProviderData
27
+ }, children);
32
28
  const node = {
33
29
  id: 'A0000000000',
34
30
  path: '/A0000000000',
@@ -78,18 +74,15 @@ describe('OrganisationUnitTree - useOrgChildren', () => {
78
74
  });
79
75
  });
80
76
  it('should provide the error', async () => {
81
- const errorWrapper = _ref3 => {
82
- let {
83
- children
84
- } = _ref3;
85
- return /*#__PURE__*/React.createElement(CustomDataProvider, {
86
- data: {
87
- organisationUnits: async () => {
88
- throw new Error('Error message');
89
- }
77
+ const errorWrapper = ({
78
+ children
79
+ }) => /*#__PURE__*/React.createElement(CustomDataProvider, {
80
+ data: {
81
+ organisationUnits: async () => {
82
+ throw new Error('Error message');
90
83
  }
91
- }, children);
92
- };
84
+ }
85
+ }, children);
93
86
  const {
94
87
  result
95
88
  } = renderHook(() => useOrgChildren({
@@ -131,10 +124,9 @@ describe('OrganisationUnitTree - useOrgChildren', () => {
131
124
  });
132
125
  it("should sort the node's children alphabetically by default", async () => {
133
126
  const dataProviderDataWithUnsortedChildren = {
134
- organisationUnits: jest.fn((type, _ref4) => {
135
- let {
136
- id
137
- } = _ref4;
127
+ organisationUnits: jest.fn((type, {
128
+ id
129
+ }) => {
138
130
  if (id === 'A0000000000') {
139
131
  return {
140
132
  children: [{
@@ -153,14 +145,11 @@ describe('OrganisationUnitTree - useOrgChildren', () => {
153
145
  return Promise.reject(`No org unit with id "${id}"`);
154
146
  })
155
147
  };
156
- const wrapperWithUnsortedChildren = _ref5 => {
157
- let {
158
- children
159
- } = _ref5;
160
- return /*#__PURE__*/React.createElement(CustomDataProvider, {
161
- data: dataProviderDataWithUnsortedChildren
162
- }, children);
163
- };
148
+ const wrapperWithUnsortedChildren = ({
149
+ children
150
+ }) => /*#__PURE__*/React.createElement(CustomDataProvider, {
151
+ data: dataProviderDataWithUnsortedChildren
152
+ }, children);
164
153
  const {
165
154
  result
166
155
  } = renderHook(() => useOrgChildren({
@@ -192,10 +181,9 @@ describe('OrganisationUnitTree - useOrgChildren', () => {
192
181
  });
193
182
  it(`should not sort the node's children alphabetically when "suppressAlphabeticalSorting" is true`, async () => {
194
183
  const dataProviderDataWithUnsortedChildren = {
195
- organisationUnits: jest.fn((type, _ref6) => {
196
- let {
197
- id
198
- } = _ref6;
184
+ organisationUnits: jest.fn((type, {
185
+ id
186
+ }) => {
199
187
  if (id === 'A0000000000') {
200
188
  return {
201
189
  children: [{
@@ -214,14 +202,11 @@ describe('OrganisationUnitTree - useOrgChildren', () => {
214
202
  return Promise.reject(`No org unit with id "${id}"`);
215
203
  })
216
204
  };
217
- const wrapperWithUnsortedChildren = _ref7 => {
218
- let {
219
- children
220
- } = _ref7;
221
- return /*#__PURE__*/React.createElement(CustomDataProvider, {
222
- data: dataProviderDataWithUnsortedChildren
223
- }, children);
224
- };
205
+ const wrapperWithUnsortedChildren = ({
206
+ children
207
+ }) => /*#__PURE__*/React.createElement(CustomDataProvider, {
208
+ data: dataProviderDataWithUnsortedChildren
209
+ }, children);
225
210
  const options = {
226
211
  node: {
227
212
  ...node,
@@ -255,10 +240,9 @@ describe('OrganisationUnitTree - useOrgChildren', () => {
255
240
  });
256
241
  it(`should not sort the node's children alphabetically when "suppressAlphabeticalSorting" is true`, async () => {
257
242
  const dataProviderDataWithUnsortedChildren = {
258
- organisationUnits: jest.fn((type, _ref8) => {
259
- let {
260
- id
261
- } = _ref8;
243
+ organisationUnits: jest.fn((type, {
244
+ id
245
+ }) => {
262
246
  if (id === 'A0000000000') {
263
247
  return {
264
248
  children: [{
@@ -277,14 +261,11 @@ describe('OrganisationUnitTree - useOrgChildren', () => {
277
261
  return Promise.reject(`No org unit with id "${id}"`);
278
262
  })
279
263
  };
280
- const wrapperWithUnsortedChildren = _ref9 => {
281
- let {
282
- children
283
- } = _ref9;
284
- return /*#__PURE__*/React.createElement(CustomDataProvider, {
285
- data: dataProviderDataWithUnsortedChildren
286
- }, children);
287
- };
264
+ const wrapperWithUnsortedChildren = ({
265
+ children
266
+ }) => /*#__PURE__*/React.createElement(CustomDataProvider, {
267
+ data: dataProviderDataWithUnsortedChildren
268
+ }, children);
288
269
  const options = {
289
270
  node: {
290
271
  ...node,
@@ -2,21 +2,15 @@ import { useDataQuery } from '@dhis2/app-runtime';
2
2
  const ORG_DATA_QUERY = {
3
3
  orgUnit: {
4
4
  resource: `organisationUnits`,
5
- id: _ref => {
6
- let {
7
- id
8
- } = _ref;
9
- return id;
10
- },
11
- params: _ref2 => {
12
- let {
13
- isUserDataViewFallback
14
- } = _ref2;
15
- return {
16
- isUserDataViewFallback,
17
- fields: ['path', 'children::size']
18
- };
19
- }
5
+ id: ({
6
+ id
7
+ }) => id,
8
+ params: ({
9
+ isUserDataViewFallback
10
+ }) => ({
11
+ isUserDataViewFallback,
12
+ fields: ['path', 'children::size']
13
+ })
20
14
  }
21
15
  };
22
16
 
@@ -27,11 +21,10 @@ const ORG_DATA_QUERY = {
27
21
  * @param {bool} options.isUserDataViewFallback
28
22
  * @returns {Object}
29
23
  */
30
- export const useOrgData = (id, _ref3) => {
31
- let {
32
- displayName,
33
- isUserDataViewFallback
34
- } = _ref3;
24
+ export const useOrgData = (id, {
25
+ displayName,
26
+ isUserDataViewFallback
27
+ }) => {
35
28
  if (!displayName) {
36
29
  throw new Error('"displayName" is required');
37
30
  }
@@ -5,10 +5,7 @@ import { useOrgData } from './use-org-data.js';
5
5
  describe('OrganisationUnitTree - useOrgData', () => {
6
6
  // @TODO: Figure out why this is necessary at all...
7
7
  const origError = console.error;
8
- jest.spyOn(console, 'error').mockImplementation(function () {
9
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
10
- args[_key] = arguments[_key];
11
- }
8
+ jest.spyOn(console, 'error').mockImplementation((...args) => {
12
9
  const [err] = args;
13
10
  if (!err.toString().match(/^Warning: An update to/)) {
14
11
  origError(...args);
@@ -18,10 +15,9 @@ describe('OrganisationUnitTree - useOrgData', () => {
18
15
  console.error.mockRestore();
19
16
  });
20
17
  const dataProviderData = {
21
- organisationUnits: jest.fn((type, _ref) => {
22
- let {
23
- id
24
- } = _ref;
18
+ organisationUnits: jest.fn((type, {
19
+ id
20
+ }) => {
25
21
  if (id === 'A0000000000') {
26
22
  return {
27
23
  id: 'A0000000000',
@@ -32,14 +28,11 @@ describe('OrganisationUnitTree - useOrgData', () => {
32
28
  return Promise.reject(`No org unit with id "${id}"`);
33
29
  })
34
30
  };
35
- const wrapper = _ref2 => {
36
- let {
37
- children
38
- } = _ref2;
39
- return /*#__PURE__*/React.createElement(CustomDataProvider, {
40
- data: dataProviderData
41
- }, children);
42
- };
31
+ const wrapper = ({
32
+ children
33
+ }) => /*#__PURE__*/React.createElement(CustomDataProvider, {
34
+ data: dataProviderData
35
+ }, children);
43
36
  it('should respond with `loading: true`, `error: null` and `data: { displayName, id }` initially', () => {
44
37
  const {
45
38
  result
@@ -78,18 +71,15 @@ describe('OrganisationUnitTree - useOrgData', () => {
78
71
  });
79
72
  });
80
73
  it('should provide the error', async () => {
81
- const errorWrapper = _ref3 => {
82
- let {
83
- children
84
- } = _ref3;
85
- return /*#__PURE__*/React.createElement(CustomDataProvider, {
86
- data: {
87
- organisationUnits: async () => {
88
- throw new Error('Error message');
89
- }
74
+ const errorWrapper = ({
75
+ children
76
+ }) => /*#__PURE__*/React.createElement(CustomDataProvider, {
77
+ data: {
78
+ organisationUnits: async () => {
79
+ throw new Error('Error message');
90
80
  }
91
- }, children);
92
- };
81
+ }
82
+ }, children);
93
83
  const {
94
84
  result
95
85
  } = renderHook(() => useOrgData('A0000000000', {
@@ -1,6 +1,3 @@
1
- export const defaultRenderNodeLabel = _ref => {
2
- let {
3
- label
4
- } = _ref;
5
- return label;
6
- };
1
+ export const defaultRenderNodeLabel = ({
2
+ label
3
+ }) => label;
@@ -1,18 +1,15 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React from 'react';
3
3
  import i18n from '../locales/index.js';
4
- export const OrganisationUnitTreeRootError = _ref => {
5
- let {
6
- dataTest = 'dhis2-uiwidgets-orgunittree-error',
7
- error
8
- } = _ref;
9
- return /*#__PURE__*/React.createElement("div", {
10
- "data-test": dataTest
11
- }, i18n.t('Error: {{ ERRORMESSAGE }}', {
12
- ERRORMESSAGE: error,
13
- nsSeparator: '>'
14
- }));
15
- };
4
+ export const OrganisationUnitTreeRootError = ({
5
+ dataTest = 'dhis2-uiwidgets-orgunittree-error',
6
+ error
7
+ }) => /*#__PURE__*/React.createElement("div", {
8
+ "data-test": dataTest
9
+ }, i18n.t('Error: {{ ERRORMESSAGE }}', {
10
+ ERRORMESSAGE: error,
11
+ nsSeparator: '>'
12
+ }));
16
13
  OrganisationUnitTreeRootError.propTypes = {
17
14
  error: PropTypes.string.isRequired,
18
15
  dataTest: PropTypes.string
@@ -2,19 +2,16 @@ import _JSXStyle from "styled-jsx/style";
2
2
  import { CircularLoader } from '@dhis2-ui/loader';
3
3
  import PropTypes from 'prop-types';
4
4
  import React from 'react';
5
- export const OrganisationUnitTreeRootLoading = _ref => {
6
- let {
7
- dataTest = 'dhis2-uiwidgets-orgunittree-loading'
8
- } = _ref;
9
- return /*#__PURE__*/React.createElement("div", {
10
- "data-test": dataTest,
11
- className: "jsx-814846266"
12
- }, /*#__PURE__*/React.createElement(CircularLoader, {
13
- small: true
14
- }), /*#__PURE__*/React.createElement(_JSXStyle, {
15
- id: "814846266"
16
- }, ["div.jsx-814846266{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;}"]));
17
- };
5
+ export const OrganisationUnitTreeRootLoading = ({
6
+ dataTest = 'dhis2-uiwidgets-orgunittree-loading'
7
+ }) => /*#__PURE__*/React.createElement("div", {
8
+ "data-test": dataTest,
9
+ className: "jsx-814846266"
10
+ }, /*#__PURE__*/React.createElement(CircularLoader, {
11
+ small: true
12
+ }), /*#__PURE__*/React.createElement(_JSXStyle, {
13
+ id: "814846266"
14
+ }, ["div.jsx-814846266{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;}"]));
18
15
  OrganisationUnitTreeRootLoading.propTypes = {
19
16
  dataTest: PropTypes.string
20
17
  };
@@ -1,6 +1,7 @@
1
1
  import { requiredIf } from '@dhis2/prop-types';
2
2
  import PropTypes from 'prop-types';
3
- import React, { useEffect, useState } from 'react';
3
+ import React, { useEffect, useMemo, useState } from 'react';
4
+ import { sortNodeChildrenAlphabetically } from '../helpers/index.js';
4
5
  import { OrganisationUnitNode } from '../organisation-unit-node/index.js';
5
6
  import { orgUnitPathPropType } from '../prop-types.js';
6
7
  import { defaultRenderNodeLabel } from './default-render-node-label/index.js';
@@ -13,30 +14,29 @@ import { useRootOrgData } from './use-root-org-data/index.js';
13
14
 
14
15
  // A stable object to reference
15
16
  const staticArray = [];
16
- const OrganisationUnitTree = _ref => {
17
- let {
18
- onChange,
19
- roots,
20
- autoExpandLoadingError,
21
- dataTest = 'dhis2-uiwidgets-orgunittree',
22
- disableSelection,
23
- displayProperty = 'displayName',
24
- forceReload,
25
- highlighted = staticArray,
26
- isUserDataViewFallback,
27
- initiallyExpanded = staticArray,
28
- filter = staticArray,
29
- renderNodeLabel = defaultRenderNodeLabel,
30
- selected = staticArray,
31
- singleSelection,
32
- suppressAlphabeticalSorting,
33
- expanded: expandedControlled,
34
- handleExpand: handleExpandControlled,
35
- handleCollapse: handleCollapseControlled,
36
- onExpand,
37
- onCollapse,
38
- onChildrenLoaded
39
- } = _ref;
17
+ const OrganisationUnitTree = ({
18
+ onChange,
19
+ roots,
20
+ autoExpandLoadingError,
21
+ dataTest = 'dhis2-uiwidgets-orgunittree',
22
+ disableSelection,
23
+ displayProperty = 'displayName',
24
+ forceReload,
25
+ highlighted = staticArray,
26
+ isUserDataViewFallback,
27
+ initiallyExpanded = staticArray,
28
+ filter = staticArray,
29
+ renderNodeLabel = defaultRenderNodeLabel,
30
+ selected = staticArray,
31
+ singleSelection,
32
+ suppressAlphabeticalSorting,
33
+ expanded: expandedControlled,
34
+ handleExpand: handleExpandControlled,
35
+ handleCollapse: handleCollapseControlled,
36
+ onExpand,
37
+ onCollapse,
38
+ onChildrenLoaded
39
+ }) => {
40
40
  const rootIds = filterRootIds(filter, Array.isArray(roots) ? roots : [roots]);
41
41
  const reloadId = useForceReload(forceReload);
42
42
  const [prevReloadId, setPrevReloadId] = useState(reloadId);
@@ -72,12 +72,19 @@ const OrganisationUnitTree = _ref => {
72
72
  return () => console.warn('@TODO: Why does this component unmount after a force reload?');
73
73
  }, [reloadId, prevReloadId, refetch]);
74
74
  const isLoading = !called || loading;
75
+ const sortedRoots = useMemo(() => {
76
+ if (!data) {
77
+ return staticArray;
78
+ }
79
+ const rootNodes = rootIds.map(rootId => data[rootId]);
80
+ return suppressAlphabeticalSorting ? rootNodes : sortNodeChildrenAlphabetically(rootNodes);
81
+ }, [data, rootIds, suppressAlphabeticalSorting]);
75
82
  return /*#__PURE__*/React.createElement("div", {
76
83
  "data-test": dataTest
77
84
  }, isLoading && /*#__PURE__*/React.createElement(OrganisationUnitTreeRootLoading, null), error && /*#__PURE__*/React.createElement(OrganisationUnitTreeRootError, {
78
85
  error: error
79
- }), !error && !isLoading && rootIds.map(rootId => {
80
- const rootNode = data[rootId];
86
+ }), !error && !isLoading && sortedRoots.map(rootNode => {
87
+ const rootId = rootNode.id;
81
88
  return /*#__PURE__*/React.createElement(OrganisationUnitNode, {
82
89
  key: rootNode.path,
83
90
  rootId: rootId,
@@ -1,4 +1,5 @@
1
1
  import { CustomDataProvider } from '@dhis2/app-runtime';
2
+ import { render } from '@testing-library/react';
2
3
  import { shallow } from 'enzyme';
3
4
  import React from 'react';
4
5
  import { OrganisationUnitTree } from './organisation-unit-tree.js';
@@ -52,4 +53,74 @@ describe('OrganisationUnitTree', () => {
52
53
  });
53
54
  });
54
55
  });
56
+ describe('Root node sorting', () => {
57
+ // displayNames intentionally out of alphabetical order relative to ids
58
+ const rootNodes = {
59
+ A001: {
60
+ id: 'A001',
61
+ path: '/A001',
62
+ displayName: 'Bravo'
63
+ },
64
+ A002: {
65
+ id: 'A002',
66
+ path: '/A002',
67
+ displayName: 'Alpha'
68
+ },
69
+ A003: {
70
+ id: 'A003',
71
+ path: '/A003',
72
+ displayName: 'Charlie'
73
+ }
74
+ };
75
+ const dataProvider = {
76
+ organisationUnits: (type, {
77
+ id
78
+ }) => {
79
+ const node = rootNodes[id];
80
+ if (node) {
81
+ // children: 0 so nodes don't try to load descendants
82
+ return {
83
+ ...node,
84
+ children: 0
85
+ };
86
+ }
87
+ return Promise.reject(`No org unit with id "${id}"`);
88
+ }
89
+ };
90
+ it('sorts root nodes alphabetically by displayName by default', async () => {
91
+ const {
92
+ container,
93
+ findByText
94
+ } = render(/*#__PURE__*/React.createElement(CustomDataProvider, {
95
+ data: dataProvider
96
+ }, /*#__PURE__*/React.createElement(OrganisationUnitTree, {
97
+ roots: ['A001', 'A002', 'A003'],
98
+ onChange: () => {}
99
+ })));
100
+ await findByText('Alpha');
101
+ const {
102
+ textContent
103
+ } = container;
104
+ expect(textContent.indexOf('Alpha')).toBeLessThan(textContent.indexOf('Bravo'));
105
+ expect(textContent.indexOf('Bravo')).toBeLessThan(textContent.indexOf('Charlie'));
106
+ });
107
+ it('keeps the provided roots order when suppressAlphabeticalSorting is true', async () => {
108
+ const {
109
+ container,
110
+ findByText
111
+ } = render(/*#__PURE__*/React.createElement(CustomDataProvider, {
112
+ data: dataProvider
113
+ }, /*#__PURE__*/React.createElement(OrganisationUnitTree, {
114
+ roots: ['A003', 'A001', 'A002'],
115
+ suppressAlphabeticalSorting: true,
116
+ onChange: () => {}
117
+ })));
118
+ await findByText('Charlie');
119
+ const {
120
+ textContent
121
+ } = container;
122
+ expect(textContent.indexOf('Charlie')).toBeLessThan(textContent.indexOf('Bravo'));
123
+ expect(textContent.indexOf('Bravo')).toBeLessThan(textContent.indexOf('Alpha'));
124
+ });
125
+ });
55
126
  });
@@ -6,18 +6,16 @@
6
6
  * @param {Function} [args.onCollapse]
7
7
  * @returns {{ handleExpand: Function, handleCollapse: Function }}
8
8
  */
9
- export const createExpandHandlers = _ref => {
10
- let {
11
- expanded,
12
- setExpanded,
13
- onExpand,
14
- onCollapse
15
- } = _ref;
16
- const handleExpand = _ref2 => {
17
- let {
18
- path,
19
- ...rest
20
- } = _ref2;
9
+ export const createExpandHandlers = ({
10
+ expanded,
11
+ setExpanded,
12
+ onExpand,
13
+ onCollapse
14
+ }) => {
15
+ const handleExpand = ({
16
+ path,
17
+ ...rest
18
+ }) => {
21
19
  if (!expanded.includes(path)) {
22
20
  setExpanded([...expanded, path]);
23
21
  if (onExpand) {
@@ -28,11 +26,10 @@ export const createExpandHandlers = _ref => {
28
26
  }
29
27
  }
30
28
  };
31
- const handleCollapse = _ref3 => {
32
- let {
33
- path,
34
- ...rest
35
- } = _ref3;
29
+ const handleCollapse = ({
30
+ path,
31
+ ...rest
32
+ }) => {
36
33
  const pathIndex = expanded.indexOf(path);
37
34
  if (pathIndex !== -1) {
38
35
  const updatedExpanded = pathIndex === 0 ? expanded.slice(1) : [...expanded.slice(0, pathIndex), ...expanded.slice(pathIndex + 1)];
@@ -8,15 +8,14 @@ import { createExpandHandlers } from './create-expand-handlers.js';
8
8
  * @param {Function} [onCollapse]
9
9
  * @returns {{ expanded: string[], handleExpand: Function, handleCollapse: Function }}
10
10
  */
11
- export const useExpanded = _ref => {
12
- let {
13
- initiallyExpanded,
14
- onExpand,
15
- onCollapse,
16
- expandedControlled,
17
- handleExpandControlled,
18
- handleCollapseControlled
19
- } = _ref;
11
+ export const useExpanded = ({
12
+ initiallyExpanded,
13
+ onExpand,
14
+ onCollapse,
15
+ expandedControlled,
16
+ handleExpandControlled,
17
+ handleCollapseControlled
18
+ }) => {
20
19
  const isControlled = !!expandedControlled;
21
20
  const allInitiallyExpandedPaths = isControlled ? [] : getAllExpandedPaths(initiallyExpanded);
22
21
  const [expanded, setExpanded] = useState(allInitiallyExpandedPaths);
@@ -11,8 +11,7 @@
11
11
  */
12
12
  export const patchMissingDisplayName = nodes => {
13
13
  const nodeEntries = Object.entries(nodes);
14
- const nodesWithDisplayName = nodeEntries.map(_ref => {
15
- let [id, node] = _ref;
14
+ const nodesWithDisplayName = nodeEntries.map(([id, node]) => {
16
15
  const displayName = node.displayName || '';
17
16
  return [id, {
18
17
  ...node,
@@ -6,15 +6,12 @@ export const createRootQuery = (ids, displayProperty) => ids.reduce((query, id)
6
6
  [id]: {
7
7
  id,
8
8
  resource: `organisationUnits`,
9
- params: _ref => {
10
- let {
11
- isUserDataViewFallback
12
- } = _ref;
13
- return {
14
- isUserDataViewFallback,
15
- fields: [displayProperty === 'displayName' ? 'displayName' : `${displayProperty}~rename(displayName)`, 'path', 'id']
16
- };
17
- }
9
+ params: ({
10
+ isUserDataViewFallback
11
+ }) => ({
12
+ isUserDataViewFallback,
13
+ fields: [displayProperty === 'displayName' ? 'displayName' : `${displayProperty}~rename(displayName)`, 'path', 'id']
14
+ })
18
15
  }
19
16
  }), {});
20
17
 
@@ -26,11 +23,10 @@ export const createRootQuery = (ids, displayProperty) => ids.reduce((query, id)
26
23
  * @param {'displayName'|'displayShortName'} [options.displayProperty]
27
24
  * @returns {Object}
28
25
  */
29
- export const useRootOrgData = function (ids) {
30
- let {
31
- isUserDataViewFallback,
32
- displayProperty = 'displayName'
33
- } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
26
+ export const useRootOrgData = (ids, {
27
+ isUserDataViewFallback,
28
+ displayProperty = 'displayName'
29
+ } = {}) => {
34
30
  const query = useMemo(() => createRootQuery(ids, displayProperty), [ids, displayProperty]);
35
31
  const variables = {
36
32
  isUserDataViewFallback