@truedat/core 5.7.5 → 5.8.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/core",
3
- "version": "5.7.5",
3
+ "version": "5.8.1",
4
4
  "description": "Truedat Web Core",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -35,7 +35,7 @@
35
35
  "@testing-library/jest-dom": "^5.16.5",
36
36
  "@testing-library/react": "^12.0.0",
37
37
  "@testing-library/user-event": "^13.2.1",
38
- "@truedat/test": "5.7.5",
38
+ "@truedat/test": "5.8.1",
39
39
  "babel-jest": "^28.1.0",
40
40
  "babel-plugin-dynamic-import-node": "^2.3.3",
41
41
  "babel-plugin-lodash": "^3.3.4",
@@ -117,5 +117,5 @@
117
117
  "react-dom": ">= 16.8.6 < 17",
118
118
  "semantic-ui-react": ">= 2.0.3 < 2.2"
119
119
  },
120
- "gitHead": "f4ae9f5fba9c949e1d3cfb12939aa330a81e6d93"
120
+ "gitHead": "aacafb9e014ac8d1193a5dc2a37c92ea36c3d816"
121
121
  }
@@ -12,6 +12,7 @@ export const DropdownMenuItem = ({
12
12
  open,
13
13
  name,
14
14
  level,
15
+ disabled = false,
15
16
  }) => {
16
17
  const handleOpen = (e) => {
17
18
  e && e.preventDefault();
@@ -36,7 +37,7 @@ export const DropdownMenuItem = ({
36
37
  {check && (
37
38
  <Icon name={selected ? "check square outline" : "square outline"} />
38
39
  )}
39
- {name}
40
+ <span style={{ opacity: disabled ? 0.45 : 1 }}>{name}</span>
40
41
  </div>
41
42
  </Dropdown.Item>
42
43
  );
@@ -52,6 +53,7 @@ DropdownMenuItem.propTypes = {
52
53
  open: PropTypes.bool,
53
54
  name: PropTypes.string,
54
55
  level: PropTypes.number,
56
+ disabled: PropTypes.bool,
55
57
  };
56
58
 
57
59
  export default DropdownMenuItem;
@@ -9,14 +9,14 @@ import TreeSelector from "./TreeSelector";
9
9
 
10
10
  const HierarchySelector = ({
11
11
  multiple,
12
- hierarchy: hierarchyId,
12
+ hierarchy,
13
13
  onLoad,
14
14
  value,
15
15
  ...props
16
16
  }) => {
17
17
  const { formatMessage } = useIntl();
18
+ const { data: data, error, loading } = useHierarchy(hierarchy.id);
18
19
 
19
- const { data: data, error, loading } = useHierarchy(hierarchyId);
20
20
  if (error) return null;
21
21
  if (loading) return null;
22
22
  onLoad(loading);
@@ -31,6 +31,7 @@ const HierarchySelector = ({
31
31
  return (
32
32
  <TreeSelector
33
33
  options={options}
34
+ minDepth={_.pathOr(0, "min_depth")(hierarchy)}
34
35
  placeholder={formatMessage({
35
36
  id: multiple
36
37
  ? "hierarchy.multiple.placeholder"
@@ -46,6 +47,7 @@ const HierarchySelector = ({
46
47
  HierarchySelector.propTypes = {
47
48
  multiple: PropTypes.bool,
48
49
  onLoad: PropTypes.func,
50
+ hierarchy: PropTypes.object,
49
51
  value: PropTypes.oneOfType([PropTypes.array, PropTypes.number]),
50
52
  };
51
53
 
@@ -74,6 +74,7 @@ export const TreeSelector = ({
74
74
  onBlur,
75
75
  onChange,
76
76
  options,
77
+ minDepth = 0,
77
78
  placeholder,
78
79
  required = false,
79
80
  value: initialValue,
@@ -143,6 +144,8 @@ export const TreeSelector = ({
143
144
  <label>{placeholder}</label>
144
145
  );
145
146
 
147
+ const isEnabled = ({ level }, minDepth) => level >= minDepth;
148
+
146
149
  const items = _.flow(
147
150
  filterSearch,
148
151
  filterDisplayed,
@@ -152,9 +155,11 @@ export const TreeSelector = ({
152
155
  key={option?.id}
153
156
  check={check}
154
157
  onOpen={handleOpen}
155
- onClick={handleClick}
158
+ onClick={isEnabled(option, minDepth) ? handleClick : () => {}}
156
159
  open={_.contains(option.id)(open)}
157
160
  canOpen={!_.isEmpty(option.children)}
161
+ level={option.level}
162
+ disabled={!isEnabled(option, minDepth)}
158
163
  selected={multiple ? _.contains(option.id)(value) : value === option.id}
159
164
  {...option}
160
165
  />
@@ -208,6 +213,7 @@ TreeSelector.propTypes = {
208
213
  onBlur: PropTypes.func,
209
214
  onChange: PropTypes.func,
210
215
  options: PropTypes.array,
216
+ minDepth: PropTypes.number,
211
217
  placeholder: PropTypes.string,
212
218
  required: PropTypes.bool,
213
219
  value: PropTypes.oneOfType([PropTypes.array, PropTypes.string]),
@@ -53,7 +53,7 @@ const props = {
53
53
  multiple: true,
54
54
  onChange: jest.fn(),
55
55
  onLoad: jest.fn(),
56
- hierarchy: 123,
56
+ hierarchy: { hierarchy_id: 123, depth: 0 },
57
57
  };
58
58
 
59
59
  describe("<HierarchySelector />", () => {
@@ -61,4 +61,166 @@ describe("<TreeSelector />", () => {
61
61
  expect(props.onChange.mock.calls.length).toBe(1);
62
62
  expect(props.onChange.mock.calls[0][1]).toEqual({ value: "1" });
63
63
  });
64
+
65
+ it("select node with allowed depth (multiple)", async () => {
66
+ const minDepth = 2;
67
+
68
+ const props = {
69
+ onChange: jest.fn(),
70
+ options,
71
+ placeholder: "Select a domain",
72
+ minDepth: minDepth,
73
+ };
74
+
75
+ const { getByText, getByRole } = render(
76
+ <TreeSelector multiple {...props} />,
77
+ renderOpts
78
+ );
79
+ userEvent.click(getByText("Select a domain"));
80
+
81
+ await waitFor(() => {
82
+ expect(getByRole("option", { name: /foo/i })).toBeTruthy();
83
+ });
84
+
85
+ userEvent.click(
86
+ getByRole("option", { name: /foo/i }).querySelector(
87
+ 'i[class="plus icon"]'
88
+ )
89
+ );
90
+
91
+ await waitFor(() => {
92
+ expect(getByRole("option", { name: /bar/i })).toBeTruthy();
93
+ });
94
+
95
+ userEvent.click(
96
+ getByRole("option", { name: /bar/i }).querySelector(
97
+ 'i[class="plus icon"]'
98
+ )
99
+ );
100
+
101
+ await waitFor(() => {
102
+ expect(getByRole("option", { name: /baz/i })).toBeTruthy();
103
+ });
104
+
105
+ userEvent.click(getByRole("option", { name: /baz/i }));
106
+ expect(props.onChange.mock.calls.length).toBe(1);
107
+ expect(props.onChange.mock.calls[0][1]).toEqual({ value: ["3"] });
108
+ expect(props.options.find((op) => op.id === "3") >= minDepth);
109
+ });
110
+
111
+ it("select node with forbidden depth (multiple)", async () => {
112
+ const minDepth = 2;
113
+
114
+ const props = {
115
+ onChange: jest.fn(),
116
+ options,
117
+ placeholder: "Select a domain",
118
+ minDepth: minDepth,
119
+ };
120
+
121
+ const { getByText, getByRole } = render(
122
+ <TreeSelector multiple {...props} />,
123
+ renderOpts
124
+ );
125
+ userEvent.click(getByText("Select a domain"));
126
+
127
+ await waitFor(() => {
128
+ expect(getByRole("option", { name: /foo/i })).toBeTruthy();
129
+ });
130
+
131
+ userEvent.click(
132
+ getByRole("option", { name: /foo/i }).querySelector(
133
+ 'i[class="plus icon"]'
134
+ )
135
+ );
136
+
137
+ await waitFor(() => {
138
+ expect(getByRole("option", { name: /bar/i })).toBeTruthy();
139
+ });
140
+
141
+ userEvent.click(getByRole("option", { name: /bar/i }));
142
+
143
+ expect(props.onChange.mock.calls.length).toBe(0);
144
+ });
145
+
146
+ it("select node with allowed depth (single)", async () => {
147
+ const minDepth = 2;
148
+
149
+ const props = {
150
+ onChange: jest.fn(),
151
+ options,
152
+ placeholder: "Select a domain",
153
+ minDepth: minDepth,
154
+ };
155
+
156
+ const { getByText, getByRole } = render(
157
+ <TreeSelector {...props} />,
158
+ renderOpts
159
+ );
160
+ userEvent.click(getByText("Select a domain"));
161
+
162
+ await waitFor(() => {
163
+ expect(getByRole("option", { name: /foo/i })).toBeTruthy();
164
+ });
165
+
166
+ userEvent.click(
167
+ getByRole("option", { name: /foo/i }).querySelector(
168
+ 'i[class="plus icon"]'
169
+ )
170
+ );
171
+
172
+ await waitFor(() => {
173
+ expect(getByRole("option", { name: /bar/i })).toBeTruthy();
174
+ });
175
+
176
+ userEvent.click(
177
+ getByRole("option", { name: /bar/i }).querySelector(
178
+ 'i[class="plus icon"]'
179
+ )
180
+ );
181
+
182
+ await waitFor(() => {
183
+ expect(getByRole("option", { name: /baz/i })).toBeTruthy();
184
+ });
185
+
186
+ userEvent.click(getByRole("option", { name: /baz/i }));
187
+ expect(props.onChange.mock.calls.length).toBe(1);
188
+ expect(props.onChange.mock.calls[0][1]).toEqual({ value: "3" });
189
+ expect(props.options.find((op) => op.id === "3") >= minDepth);
190
+ });
191
+
192
+ it("select node with forbidden depth (single)", async () => {
193
+ const minDepth = 2;
194
+
195
+ const props = {
196
+ onChange: jest.fn(),
197
+ options,
198
+ placeholder: "Select a domain",
199
+ minDepth: minDepth,
200
+ };
201
+
202
+ const { getByText, getByRole } = render(
203
+ <TreeSelector {...props} />,
204
+ renderOpts
205
+ );
206
+ userEvent.click(getByText("Select a domain"));
207
+
208
+ await waitFor(() => {
209
+ expect(getByRole("option", { name: /foo/i })).toBeTruthy();
210
+ });
211
+
212
+ userEvent.click(
213
+ getByRole("option", { name: /foo/i }).querySelector(
214
+ 'i[class="plus icon"]'
215
+ )
216
+ );
217
+
218
+ await waitFor(() => {
219
+ expect(getByRole("option", { name: /bar/i })).toBeTruthy();
220
+ });
221
+
222
+ userEvent.click(getByRole("option", { name: /bar/i }));
223
+
224
+ expect(props.onChange.mock.calls.length).toBe(0);
225
+ });
64
226
  });
@@ -48,7 +48,11 @@ exports[`<DomainSelector /> matches latest snapshot 1`] = `
48
48
  aria-hidden="true"
49
49
  class="plus icon"
50
50
  />
51
- barDomain
51
+ <span
52
+ style="opacity: 1;"
53
+ >
54
+ barDomain
55
+ </span>
52
56
  </div>
53
57
  </div>
54
58
  <div
@@ -63,7 +67,11 @@ exports[`<DomainSelector /> matches latest snapshot 1`] = `
63
67
  aria-hidden="true"
64
68
  class="icon"
65
69
  />
66
- bazDomain
70
+ <span
71
+ style="opacity: 1;"
72
+ >
73
+ bazDomain
74
+ </span>
67
75
  </div>
68
76
  </div>
69
77
  <div
@@ -78,7 +86,11 @@ exports[`<DomainSelector /> matches latest snapshot 1`] = `
78
86
  aria-hidden="true"
79
87
  class="icon"
80
88
  />
81
- fooDomain
89
+ <span
90
+ style="opacity: 1;"
91
+ >
92
+ fooDomain
93
+ </span>
82
94
  </div>
83
95
  </div>
84
96
  </div>
@@ -16,7 +16,11 @@ exports[`<DropdownMenuItem /> matches the latest snapshot 1`] = `
16
16
  aria-hidden="true"
17
17
  class="square outline icon"
18
18
  />
19
- foo
19
+ <span
20
+ style="opacity: 1;"
21
+ >
22
+ foo
23
+ </span>
20
24
  </div>
21
25
  </div>
22
26
  </div>
@@ -50,7 +50,11 @@ exports[`<FilterMultilevelDropdown /> matches the latest snapshot 1`] = `
50
50
  aria-hidden="true"
51
51
  class="square outline icon"
52
52
  />
53
- Domain 1
53
+ <span
54
+ style="opacity: 1;"
55
+ >
56
+ Domain 1
57
+ </span>
54
58
  </div>
55
59
  </div>
56
60
  <div
@@ -69,7 +73,11 @@ exports[`<FilterMultilevelDropdown /> matches the latest snapshot 1`] = `
69
73
  aria-hidden="true"
70
74
  class="square outline icon"
71
75
  />
72
- Domain 3
76
+ <span
77
+ style="opacity: 1;"
78
+ >
79
+ Domain 3
80
+ </span>
73
81
  </div>
74
82
  </div>
75
83
  </div>
@@ -50,7 +50,11 @@ exports[`<HierarchyFilterDropdown /> matches the latest snapshot 1`] = `
50
50
  aria-hidden="true"
51
51
  class="square outline icon"
52
52
  />
53
- foo
53
+ <span
54
+ style="opacity: 1;"
55
+ >
56
+ foo
57
+ </span>
54
58
  </div>
55
59
  </div>
56
60
  </div>
@@ -48,7 +48,11 @@ exports[`<HierarchySelector /> matches latest snapshot 1`] = `
48
48
  aria-hidden="true"
49
49
  class="plus icon"
50
50
  />
51
- foo
51
+ <span
52
+ style="opacity: 1;"
53
+ >
54
+ foo
55
+ </span>
52
56
  </div>
53
57
  </div>
54
58
  </div>
@@ -48,7 +48,11 @@ exports[`<TreeSelector /> matches latest snapshot 1`] = `
48
48
  aria-hidden="true"
49
49
  class="plus icon"
50
50
  />
51
- foo
51
+ <span
52
+ style="opacity: 1;"
53
+ >
54
+ foo
55
+ </span>
52
56
  </div>
53
57
  </div>
54
58
  </div>