@reltio/components 1.4.2158 → 1.4.2160

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 (59) hide show
  1. package/AddressAutocompleteEditor/AddressAutocompleteEditor.d.ts +10 -0
  2. package/AddressAutocompleteEditor/AddressAutocompleteEditor.js +223 -0
  3. package/AddressAutocompleteEditor/AddressAutocompleteEditor.module.css.js +9 -0
  4. package/AddressAutocompleteEditor/AddressAutocompleteEditor.test.d.ts +1 -0
  5. package/AddressAutocompleteEditor/AddressAutocompleteEditor.test.js +522 -0
  6. package/AddressAutocompleteEditor/helpers.d.ts +10 -0
  7. package/AddressAutocompleteEditor/helpers.js +18 -0
  8. package/AddressAutocompleteEditor/index.d.ts +1 -0
  9. package/AddressAutocompleteEditor/index.js +1 -0
  10. package/BasicAttributeSelector/BasicAttributeSelector.d.ts +1 -1
  11. package/BasicAttributeSelector/BasicAttributeSelector.js +2 -2
  12. package/EditModeAttributesPager/components/AttributeRenderer/AttributeRenderer.js +1 -1
  13. package/EditorsFactory/EditorsFactory.js +4 -0
  14. package/ReferenceAttributeEditor/ReferenceAttributeEditor.js +5 -3
  15. package/RelationEditor/RelationEditor.js +6 -4
  16. package/SelectionPopup/SelectionPopup.d.ts +2 -1
  17. package/SelectionPopup/SelectionPopup.js +11 -9
  18. package/SelectionPopup/SelectionPopup.module.css.js +9 -0
  19. package/SimpleAttributeEditor/SimpleAttributeEditor.d.ts +1 -0
  20. package/SimpleAttributeEditor/SimpleAttributeEditor.js +15 -4
  21. package/cjs/AddressAutocompleteEditor/AddressAutocompleteEditor.d.ts +10 -0
  22. package/cjs/AddressAutocompleteEditor/AddressAutocompleteEditor.js +253 -0
  23. package/cjs/AddressAutocompleteEditor/AddressAutocompleteEditor.module.css.js +9 -0
  24. package/cjs/AddressAutocompleteEditor/AddressAutocompleteEditor.test.d.ts +1 -0
  25. package/cjs/AddressAutocompleteEditor/AddressAutocompleteEditor.test.js +527 -0
  26. package/cjs/AddressAutocompleteEditor/helpers.d.ts +10 -0
  27. package/cjs/AddressAutocompleteEditor/helpers.js +24 -0
  28. package/cjs/AddressAutocompleteEditor/index.d.ts +1 -0
  29. package/cjs/AddressAutocompleteEditor/index.js +5 -0
  30. package/cjs/BasicAttributeSelector/BasicAttributeSelector.d.ts +1 -1
  31. package/cjs/BasicAttributeSelector/BasicAttributeSelector.js +2 -2
  32. package/cjs/EditModeAttributesPager/components/AttributeRenderer/AttributeRenderer.js +1 -1
  33. package/cjs/EditorsFactory/EditorsFactory.js +4 -0
  34. package/cjs/ReferenceAttributeEditor/ReferenceAttributeEditor.js +5 -3
  35. package/cjs/RelationEditor/RelationEditor.js +6 -4
  36. package/cjs/SelectionPopup/SelectionPopup.d.ts +2 -1
  37. package/cjs/SelectionPopup/SelectionPopup.js +13 -11
  38. package/cjs/SelectionPopup/SelectionPopup.module.css.js +9 -0
  39. package/cjs/SimpleAttributeEditor/SimpleAttributeEditor.d.ts +1 -0
  40. package/cjs/SimpleAttributeEditor/SimpleAttributeEditor.js +14 -3
  41. package/cjs/contexts/AttributeValueContext/index.d.ts +3 -0
  42. package/cjs/contexts/AttributeValueContext/index.js +9 -0
  43. package/cjs/contexts/AutoCompleteContext/helpers.d.ts +24 -0
  44. package/cjs/contexts/AutoCompleteContext/helpers.js +165 -0
  45. package/cjs/contexts/AutoCompleteContext/index.d.ts +12 -0
  46. package/cjs/contexts/AutoCompleteContext/index.js +83 -0
  47. package/cjs/types/index.d.ts +1 -0
  48. package/contexts/AttributeValueContext/index.d.ts +3 -0
  49. package/contexts/AttributeValueContext/index.js +3 -0
  50. package/contexts/AutoCompleteContext/helpers.d.ts +24 -0
  51. package/contexts/AutoCompleteContext/helpers.js +159 -0
  52. package/contexts/AutoCompleteContext/index.d.ts +12 -0
  53. package/contexts/AutoCompleteContext/index.js +56 -0
  54. package/package.json +2 -2
  55. package/types/index.d.ts +1 -0
  56. package/SelectionPopup/styles.d.ts +0 -6
  57. package/SelectionPopup/styles.js +0 -38
  58. package/cjs/SelectionPopup/styles.d.ts +0 -6
  59. package/cjs/SelectionPopup/styles.js +0 -41
@@ -0,0 +1,522 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
13
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
14
+ return new (P || (P = Promise))(function (resolve, reject) {
15
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
16
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
17
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
18
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
19
+ });
20
+ };
21
+ var __generator = (this && this.__generator) || function (thisArg, body) {
22
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
23
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
24
+ function verb(n) { return function (v) { return step([n, v]); }; }
25
+ function step(op) {
26
+ if (f) throw new TypeError("Generator is already executing.");
27
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
28
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
29
+ if (y = 0, t) op = [op[0] & 2, t.value];
30
+ switch (op[0]) {
31
+ case 0: case 1: t = op; break;
32
+ case 4: _.label++; return { value: op[1], done: false };
33
+ case 5: _.label++; y = op[1]; op = [0]; continue;
34
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
35
+ default:
36
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
37
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
38
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
39
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
40
+ if (t[2]) _.ops.pop();
41
+ _.trys.pop(); continue;
42
+ }
43
+ op = body.call(thisArg, _);
44
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
45
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
46
+ }
47
+ };
48
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
49
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
50
+ if (ar || !(i in from)) {
51
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
52
+ ar[i] = from[i];
53
+ }
54
+ }
55
+ return to.concat(ar || Array.prototype.slice.call(from));
56
+ };
57
+ import React from 'react';
58
+ import { assocPath } from 'ramda';
59
+ import { render, screen, waitForElementToBeRemoved } from '@testing-library/react';
60
+ import userEvent from '@testing-library/user-event';
61
+ import { AddressAutocompleteEditor } from './AddressAutocompleteEditor';
62
+ import { MdmModuleProvider } from '../contexts/MdmModuleContext';
63
+ import { searchAddresses, fetchAddressDetails, DataTypes, AddressType, InputCleanseAttributeType } from '@reltio/mdm-sdk';
64
+ import { AddressAutoCompleteProvider } from '../contexts/AutoCompleteContext';
65
+ import { AttributeValueContext } from '../contexts/AttributeValueContext';
66
+ jest.mock('@reltio/mdm-sdk', function () { return (__assign(__assign({}, jest.requireActual('@reltio/mdm-sdk')), { searchAddresses: jest.fn(), fetchAddressDetails: jest.fn(), debounce: function (fn) { return fn; } })); });
67
+ var tempUriCounter = 1;
68
+ var getTempUriCounter = function () {
69
+ return tempUriCounter++;
70
+ };
71
+ var resetTempUriCounter = function () {
72
+ tempUriCounter = 1;
73
+ return tempUriCounter;
74
+ };
75
+ jest.mock('nanoid', function () {
76
+ return {
77
+ customAlphabet: function () { return function () { return "tempuri".concat(getTempUriCounter(), "_"); }; }
78
+ };
79
+ });
80
+ var mockSearchAddresses = searchAddresses;
81
+ var mockFetchAddressDetails = fetchAddressDetails;
82
+ var defaultProps = {
83
+ value: '',
84
+ onChange: jest.fn(),
85
+ fullWidth: true,
86
+ attributeTypeUri: 'configuration/entityTypes/Location/attributes/AddressInput'
87
+ };
88
+ var mockAddressSearchResults = [
89
+ {
90
+ Id: 'address-1',
91
+ Type: AddressType.Address,
92
+ Text: 'Avenida Jose Malhoa 22, Lisbon',
93
+ Description: 'Jose Malhoa 22'
94
+ }
95
+ ];
96
+ var mockAddressDetails = [
97
+ {
98
+ Id: 'address-1',
99
+ PostalCode: '1070-040',
100
+ City: 'Lisbon',
101
+ Country: 'PT',
102
+ Line1: 'Avenida Jose Malhoa 22'
103
+ }
104
+ ];
105
+ var mockMetadata = {
106
+ entityTypes: [
107
+ {
108
+ uri: 'configuration/entityTypes/Location',
109
+ label: 'Location',
110
+ attributes: [
111
+ {
112
+ uri: 'configuration/entityTypes/Location/attributes/AddressInput',
113
+ name: 'AddressInput',
114
+ label: 'AddressInput',
115
+ type: DataTypes.TYPE_STRING
116
+ },
117
+ {
118
+ uri: 'configuration/entityTypes/Location/attributes/City',
119
+ name: 'City',
120
+ label: 'City',
121
+ type: DataTypes.TYPE_STRING
122
+ },
123
+ {
124
+ uri: 'configuration/entityTypes/Location/attributes/AddressLine1',
125
+ name: 'AddressLine1',
126
+ label: 'AddressLine1',
127
+ type: DataTypes.TYPE_STRING
128
+ },
129
+ {
130
+ uri: 'configuration/entityTypes/Location/attributes/Country',
131
+ name: 'Country',
132
+ label: 'Country',
133
+ type: DataTypes.TYPE_STRING
134
+ },
135
+ {
136
+ uri: 'configuration/entityTypes/Location/attributes/AddressNested',
137
+ name: 'AddressNested',
138
+ label: 'AddressNested',
139
+ type: DataTypes.TYPE_NESTED,
140
+ attributes: [
141
+ {
142
+ uri: 'configuration/entityTypes/Location/attributes/AddressNested/attributes/AddressInput',
143
+ name: 'AddressInput',
144
+ label: 'AddressInput',
145
+ type: DataTypes.TYPE_STRING
146
+ },
147
+ {
148
+ uri: 'configuration/entityTypes/Location/attributes/AddressNested/attributes/City',
149
+ name: 'City',
150
+ label: 'City',
151
+ type: DataTypes.TYPE_STRING
152
+ }
153
+ ]
154
+ }
155
+ ],
156
+ cleanseConfig: {
157
+ mappings: [],
158
+ addressAutoCompleteConfig: {
159
+ minSearchTextLen: 3,
160
+ providerOpts: {
161
+ defaultCountries: 'PT;US',
162
+ limit: 10
163
+ },
164
+ inputMapping: [
165
+ {
166
+ attribute: 'configuration/entityTypes/Location/attributes/AddressInput',
167
+ cleanseAttribute: InputCleanseAttributeType.Text,
168
+ allValues: false,
169
+ mandatory: false
170
+ },
171
+ {
172
+ attribute: 'configuration/entityTypes/Location/attributes/Country',
173
+ cleanseAttribute: InputCleanseAttributeType.Countries,
174
+ allValues: false,
175
+ mandatory: false
176
+ }
177
+ ],
178
+ outputMapping: [
179
+ {
180
+ attribute: 'configuration/entityTypes/Location/attributes/City',
181
+ cleanseAttribute: 'City',
182
+ allValues: false,
183
+ mandatory: false
184
+ },
185
+ {
186
+ attribute: 'configuration/entityTypes/Location/attributes/AddressLine1',
187
+ cleanseAttribute: 'Line1',
188
+ allValues: false,
189
+ mandatory: false
190
+ }
191
+ ]
192
+ }
193
+ }
194
+ }
195
+ ]
196
+ };
197
+ var mockEntity = {
198
+ uri: 'entities/entity1',
199
+ type: 'configuration/entityTypes/Location',
200
+ label: 'Entity 1'
201
+ };
202
+ var mockModifiedEntity = {
203
+ uri: 'entities/entity1',
204
+ type: 'configuration/entityTypes/Location',
205
+ label: 'Entity 1'
206
+ };
207
+ var mockMdmValues = {
208
+ metadata: mockMetadata,
209
+ entity: mockEntity,
210
+ entityWithDiff: mockEntity,
211
+ modifiedEntities: {
212
+ 'entities/entity1': mockModifiedEntity
213
+ }
214
+ };
215
+ var mockMdmActions = {
216
+ modifyAttribute: jest.fn()
217
+ };
218
+ var setUp = function (props, mdmValues, attributeValue) {
219
+ if (props === void 0) { props = {}; }
220
+ if (mdmValues === void 0) { mdmValues = {}; }
221
+ if (attributeValue === void 0) { attributeValue = {}; }
222
+ var Providers = function (_a) {
223
+ var children = _a.children;
224
+ return (React.createElement(MdmModuleProvider, { values: __assign(__assign({}, mockMdmValues), mdmValues), actions: mockMdmActions },
225
+ React.createElement(AddressAutoCompleteProvider, null,
226
+ React.createElement(AttributeValueContext.Provider, { value: __assign({ uri: 'entities/entity1/attributes/AddressInput/value', type: defaultProps.attributeTypeUri, value: '' }, attributeValue) }, children))));
227
+ };
228
+ return __assign(__assign({}, render(React.createElement(AddressAutocompleteEditor, __assign({}, defaultProps, props)), { wrapper: Providers })), { user: userEvent.setup() });
229
+ };
230
+ describe('AddressAutocompleteEditor', function () {
231
+ beforeAll(function () {
232
+ jest.spyOn(Date, 'now').mockImplementation(function () { return 1752748853454; });
233
+ });
234
+ afterAll(function () {
235
+ Date.now.mockRestore();
236
+ });
237
+ beforeEach(function () {
238
+ jest.clearAllMocks();
239
+ resetTempUriCounter();
240
+ mockSearchAddresses.mockResolvedValue(mockAddressSearchResults);
241
+ mockFetchAddressDetails.mockResolvedValue(mockAddressDetails);
242
+ });
243
+ it('should render main components', function () { return __awaiter(void 0, void 0, void 0, function () {
244
+ var user, input;
245
+ return __generator(this, function (_a) {
246
+ switch (_a.label) {
247
+ case 0:
248
+ user = setUp().user;
249
+ expect(screen.getByRole('combobox')).toBeInTheDocument();
250
+ expect(screen.getByPlaceholderText('Start typing to autocomplete')).toBeInTheDocument();
251
+ return [4 /*yield*/, user.type(screen.getByRole('combobox'), 'Lisbon')];
252
+ case 1:
253
+ _a.sent();
254
+ input = screen.getByRole('combobox');
255
+ return [4 /*yield*/, user.click(input)];
256
+ case 2:
257
+ _a.sent();
258
+ return [4 /*yield*/, user.paste('Lisbon')];
259
+ case 3:
260
+ _a.sent();
261
+ expect(screen.getByText('To search in a different country, update the Country field')).toBeInTheDocument();
262
+ expect(screen.getByText('Searching in: PT, US')).toBeInTheDocument();
263
+ expect(screen.getByText('Avenida Jose Malhoa 22, Lisbon')).toBeInTheDocument();
264
+ return [2 /*return*/];
265
+ }
266
+ });
267
+ }); });
268
+ it('should show loading state during search', function () { return __awaiter(void 0, void 0, void 0, function () {
269
+ var resolveSearch, searchPromise, user, input;
270
+ return __generator(this, function (_a) {
271
+ switch (_a.label) {
272
+ case 0:
273
+ searchPromise = new Promise(function (resolve) {
274
+ resolveSearch = resolve;
275
+ });
276
+ mockSearchAddresses.mockReturnValue(searchPromise);
277
+ user = setUp().user;
278
+ input = screen.getByRole('combobox');
279
+ return [4 /*yield*/, user.click(input)];
280
+ case 1:
281
+ _a.sent();
282
+ return [4 /*yield*/, user.paste('Lisbon')];
283
+ case 2:
284
+ _a.sent();
285
+ expect(screen.getByText('Searching addresses...')).toBeInTheDocument();
286
+ resolveSearch([]);
287
+ return [4 /*yield*/, waitForElementToBeRemoved(function () { return screen.queryByText('Searching addresses...'); })];
288
+ case 3:
289
+ _a.sent();
290
+ return [2 /*return*/];
291
+ }
292
+ });
293
+ }); });
294
+ describe('Address search', function () {
295
+ it('should fetch address suggestions when user types minimum characters', function () { return __awaiter(void 0, void 0, void 0, function () {
296
+ var user, input;
297
+ return __generator(this, function (_a) {
298
+ switch (_a.label) {
299
+ case 0:
300
+ mockSearchAddresses.mockResolvedValue([
301
+ { Id: '1', Type: AddressType.Address, Text: '123 Main St', Description: 'Test' }
302
+ ]);
303
+ user = setUp().user;
304
+ input = screen.getByRole('combobox');
305
+ return [4 /*yield*/, user.click(input)];
306
+ case 1:
307
+ _a.sent();
308
+ return [4 /*yield*/, user.paste('Main St')];
309
+ case 2:
310
+ _a.sent();
311
+ expect(mockSearchAddresses).toHaveBeenCalledWith({
312
+ text: 'Main St',
313
+ limit: 10,
314
+ countries: ['PT', 'US']
315
+ });
316
+ return [2 /*return*/];
317
+ }
318
+ });
319
+ }); });
320
+ it('should not fetch suggestions when input is too short', function () { return __awaiter(void 0, void 0, void 0, function () {
321
+ var user, input;
322
+ return __generator(this, function (_a) {
323
+ switch (_a.label) {
324
+ case 0:
325
+ user = setUp().user;
326
+ input = screen.getByRole('combobox');
327
+ return [4 /*yield*/, user.click(input)];
328
+ case 1:
329
+ _a.sent();
330
+ return [4 /*yield*/, user.paste('Li')];
331
+ case 2:
332
+ _a.sent();
333
+ expect(mockSearchAddresses).not.toHaveBeenCalled();
334
+ return [2 /*return*/];
335
+ }
336
+ });
337
+ }); });
338
+ });
339
+ describe('Option selection', function () {
340
+ it('should handle option selection correctly', function () { return __awaiter(void 0, void 0, void 0, function () {
341
+ var onChange, user, input, option;
342
+ return __generator(this, function (_a) {
343
+ switch (_a.label) {
344
+ case 0:
345
+ onChange = jest.fn();
346
+ user = setUp({ onChange: onChange }).user;
347
+ input = screen.getByRole('combobox');
348
+ return [4 /*yield*/, user.click(input)];
349
+ case 1:
350
+ _a.sent();
351
+ return [4 /*yield*/, user.paste('Lisbon')];
352
+ case 2:
353
+ _a.sent();
354
+ expect(screen.getByText('Avenida Jose Malhoa 22, Lisbon')).toBeInTheDocument();
355
+ option = screen.getByText('Avenida Jose Malhoa 22, Lisbon');
356
+ return [4 /*yield*/, user.click(option)];
357
+ case 3:
358
+ _a.sent();
359
+ expect(onChange).toHaveBeenCalledWith('Avenida Jose Malhoa 22, Lisbon');
360
+ expect(mockFetchAddressDetails).toHaveBeenCalledWith('address-1');
361
+ expect(mockMdmActions.modifyAttribute).toHaveBeenCalledWith({
362
+ attributeType: mockMetadata.entityTypes[0].attributes[1],
363
+ uri: 'entities/entity1/attributes/City/uri$$tempuri1_1752748853454',
364
+ value: 'Lisbon'
365
+ });
366
+ expect(mockMdmActions.modifyAttribute).toHaveBeenCalledWith({
367
+ attributeType: mockMetadata.entityTypes[0].attributes[2],
368
+ uri: 'entities/entity1/attributes/AddressLine1/uri$$tempuri2_1752748853454',
369
+ value: 'Avenida Jose Malhoa 22'
370
+ });
371
+ return [2 /*return*/];
372
+ }
373
+ });
374
+ }); });
375
+ it('should not select container options', function () { return __awaiter(void 0, void 0, void 0, function () {
376
+ var onChange, user, input, option;
377
+ return __generator(this, function (_a) {
378
+ switch (_a.label) {
379
+ case 0:
380
+ onChange = jest.fn();
381
+ mockSearchAddresses.mockResolvedValue([
382
+ { Id: 'container-1', Type: AddressType.Container, Text: 'Container Option', Description: 'Container' }
383
+ ]);
384
+ user = setUp({ onChange: onChange }).user;
385
+ input = screen.getByRole('combobox');
386
+ return [4 /*yield*/, user.click(input)];
387
+ case 1:
388
+ _a.sent();
389
+ return [4 /*yield*/, user.paste('Lisbon')];
390
+ case 2:
391
+ _a.sent();
392
+ expect(screen.getByText('Container Option')).toBeInTheDocument();
393
+ option = screen.getByText('Container Option');
394
+ return [4 /*yield*/, user.click(option)];
395
+ case 3:
396
+ _a.sent();
397
+ expect(onChange).not.toHaveBeenCalled();
398
+ expect(mockFetchAddressDetails).not.toHaveBeenCalled();
399
+ return [2 /*return*/];
400
+ }
401
+ });
402
+ }); });
403
+ it('should populate only attributes under the trigger attribute for nested attributes', function () { return __awaiter(void 0, void 0, void 0, function () {
404
+ var onChange, attributeTypeUri, addressAutoCompleteConfig, metadata, mdmValues, attributeValue, user, input, option;
405
+ return __generator(this, function (_a) {
406
+ switch (_a.label) {
407
+ case 0:
408
+ onChange = jest.fn();
409
+ attributeTypeUri = 'configuration/entityTypes/Location/attributes/AddressNested/attributes/AddressInput';
410
+ addressAutoCompleteConfig = __assign({}, mockMetadata.entityTypes[0].cleanseConfig.addressAutoCompleteConfig);
411
+ addressAutoCompleteConfig.inputMapping = __spreadArray(__spreadArray([], addressAutoCompleteConfig.inputMapping, true), [
412
+ {
413
+ attribute: 'configuration/entityTypes/Location/attributes/AddressNested/attributes/AddressInput',
414
+ cleanseAttribute: InputCleanseAttributeType.Text,
415
+ allValues: false,
416
+ mandatory: false
417
+ }
418
+ ], false);
419
+ addressAutoCompleteConfig.outputMapping = __spreadArray(__spreadArray([], addressAutoCompleteConfig.outputMapping, true), [
420
+ {
421
+ attribute: 'configuration/entityTypes/Location/attributes/AddressNested/attributes/City',
422
+ cleanseAttribute: 'City',
423
+ allValues: false,
424
+ mandatory: false
425
+ }
426
+ ], false);
427
+ metadata = assocPath(['entityTypes', 0, 'cleanseConfig', 'addressAutoCompleteConfig'], addressAutoCompleteConfig, mockMetadata);
428
+ mdmValues = __assign(__assign({}, mockMdmValues), { metadata: metadata });
429
+ attributeValue = {
430
+ uri: 'entities/entity1/attributes/AddressNested/AddressNestedUri/AddressInput/AddressInputUri',
431
+ type: attributeTypeUri
432
+ };
433
+ user = setUp({ attributeTypeUri: attributeTypeUri, onChange: onChange }, mdmValues, attributeValue).user;
434
+ input = screen.getByRole('combobox');
435
+ return [4 /*yield*/, user.click(input)];
436
+ case 1:
437
+ _a.sent();
438
+ return [4 /*yield*/, user.paste('Lisbon')];
439
+ case 2:
440
+ _a.sent();
441
+ expect(screen.getByText('Avenida Jose Malhoa 22, Lisbon')).toBeInTheDocument();
442
+ option = screen.getByText('Avenida Jose Malhoa 22, Lisbon');
443
+ return [4 /*yield*/, user.click(option)];
444
+ case 3:
445
+ _a.sent();
446
+ expect(onChange).toHaveBeenCalledWith('Avenida Jose Malhoa 22, Lisbon');
447
+ expect(mockFetchAddressDetails).toHaveBeenCalledWith('address-1');
448
+ expect(mockMdmActions.modifyAttribute).toHaveBeenCalledTimes(1);
449
+ expect(mockMdmActions.modifyAttribute).toHaveBeenCalledWith({
450
+ attributeType: mockMetadata.entityTypes[0].attributes[4].attributes[1],
451
+ uri: 'entities/entity1/attributes/AddressNested/AddressNestedUri/City/uri$$tempuri1_1752748853454',
452
+ value: 'Lisbon'
453
+ });
454
+ return [2 /*return*/];
455
+ }
456
+ });
457
+ }); });
458
+ });
459
+ describe('Autocomplete settings', function () {
460
+ it('should use default autocomplete settings, when no settings from metadata', function () { return __awaiter(void 0, void 0, void 0, function () {
461
+ var metadata, user, input;
462
+ return __generator(this, function (_a) {
463
+ switch (_a.label) {
464
+ case 0:
465
+ metadata = {
466
+ entityTypes: [
467
+ __assign(__assign({}, mockMetadata.entityTypes[0]), { cleanseConfig: {
468
+ addressAutoCompleteConfig: undefined
469
+ } })
470
+ ]
471
+ };
472
+ user = setUp({}, {
473
+ metadata: metadata
474
+ }).user;
475
+ input = screen.getByRole('combobox');
476
+ return [4 /*yield*/, user.click(input)];
477
+ case 1:
478
+ _a.sent();
479
+ return [4 /*yield*/, user.paste('Li')];
480
+ case 2:
481
+ _a.sent();
482
+ expect(mockSearchAddresses).not.toHaveBeenCalled();
483
+ return [4 /*yield*/, user.paste('sbon')];
484
+ case 3:
485
+ _a.sent();
486
+ expect(mockSearchAddresses).toHaveBeenCalledWith({
487
+ text: 'Lisbon',
488
+ limit: 10,
489
+ countries: []
490
+ });
491
+ return [2 /*return*/];
492
+ }
493
+ });
494
+ }); });
495
+ it('should use autocomplete settings from metadata', function () { return __awaiter(void 0, void 0, void 0, function () {
496
+ var user, input;
497
+ return __generator(this, function (_a) {
498
+ switch (_a.label) {
499
+ case 0:
500
+ user = setUp().user;
501
+ input = screen.getByRole('combobox');
502
+ return [4 /*yield*/, user.click(input)];
503
+ case 1:
504
+ _a.sent();
505
+ return [4 /*yield*/, user.paste('Li')];
506
+ case 2:
507
+ _a.sent();
508
+ expect(mockSearchAddresses).not.toHaveBeenCalled();
509
+ return [4 /*yield*/, user.paste('sbon')];
510
+ case 3:
511
+ _a.sent();
512
+ expect(mockSearchAddresses).toHaveBeenCalledWith({
513
+ text: 'Lisbon',
514
+ limit: 10,
515
+ countries: ['PT', 'US']
516
+ });
517
+ return [2 /*return*/];
518
+ }
519
+ });
520
+ }); });
521
+ });
522
+ });
@@ -0,0 +1,10 @@
1
+ import { AddressSearchResult } from '@reltio/mdm-sdk';
2
+ export type AddressOption = {
3
+ id: string;
4
+ type: string;
5
+ fullAddress: string;
6
+ description?: string;
7
+ };
8
+ export declare const convertSearchResultToOption: (result: AddressSearchResult) => AddressOption;
9
+ export declare const getOptionLabel: (option: AddressOption | string) => string;
10
+ export declare const isOptionEqualToValue: (option: AddressOption, value: string) => boolean;
@@ -0,0 +1,18 @@
1
+ import { AddressType } from '@reltio/mdm-sdk';
2
+ export var convertSearchResultToOption = function (result) {
3
+ return {
4
+ id: result.Id,
5
+ type: result.Type,
6
+ fullAddress: result.Text,
7
+ description: result.Description
8
+ };
9
+ };
10
+ export var getOptionLabel = function (option) {
11
+ return typeof option === 'string' ? option : option.fullAddress;
12
+ };
13
+ export var isOptionEqualToValue = function (option, value) {
14
+ if (option.type === AddressType.Container) {
15
+ return false;
16
+ }
17
+ return option.fullAddress === value;
18
+ };
@@ -0,0 +1 @@
1
+ export { AddressAutocompleteEditor } from './AddressAutocompleteEditor';
@@ -0,0 +1 @@
1
+ export { AddressAutocompleteEditor } from './AddressAutocompleteEditor';
@@ -1,4 +1,4 @@
1
1
  import React from 'react';
2
2
  import { BasicAttributeSelectorProps } from '../types';
3
- declare const _default: React.MemoExoticComponent<({ className, itemsGroups, value, getLabel, onSelect, onRestoreFocus, onOpenPopup, disableRestoreFocus, disableEnforceFocus, single, ungroup, disabled, hideCheckBox }: BasicAttributeSelectorProps) => React.JSX.Element>;
3
+ declare const _default: React.MemoExoticComponent<({ className, itemsGroups, value, getLabel, onSelect, onRestoreFocus, onOpenPopup, disableRestoreFocus, disableEnforceFocus, single, ungroup, disabled, hideCheckBox, additionalInfo }: BasicAttributeSelectorProps) => React.JSX.Element>;
4
4
  export default _default;
@@ -11,7 +11,7 @@ import { filterSelectedAttributes, getAttributeIndex, getContainerWidth, getOnEn
11
11
  import { ATTRIBUTES_LIST_WIDTH, ATTRIBUTES_LIST_HEIGHT, ATTRIBUTES_POPUP_HEIGHT, ATTRIBUTES_LIST_MAX_WIDTH } from './constants';
12
12
  import { useStyles } from './styles';
13
13
  var BasicAttributeSelector = function (_a) {
14
- var className = _a.className, itemsGroups = _a.itemsGroups, value = _a.value, getLabel = _a.getLabel, onSelect = _a.onSelect, _b = _a.onRestoreFocus, onRestoreFocus = _b === void 0 ? identity : _b, _c = _a.onOpenPopup, onOpenPopup = _c === void 0 ? identity : _c, _d = _a.disableRestoreFocus, disableRestoreFocus = _d === void 0 ? false : _d, _e = _a.disableEnforceFocus, disableEnforceFocus = _e === void 0 ? false : _e, _f = _a.single, single = _f === void 0 ? false : _f, _g = _a.ungroup, ungroup = _g === void 0 ? false : _g, _h = _a.disabled, disabled = _h === void 0 ? false : _h, _j = _a.hideCheckBox, hideCheckBox = _j === void 0 ? false : _j;
14
+ var className = _a.className, itemsGroups = _a.itemsGroups, value = _a.value, getLabel = _a.getLabel, onSelect = _a.onSelect, _b = _a.onRestoreFocus, onRestoreFocus = _b === void 0 ? identity : _b, _c = _a.onOpenPopup, onOpenPopup = _c === void 0 ? identity : _c, _d = _a.disableRestoreFocus, disableRestoreFocus = _d === void 0 ? false : _d, _e = _a.disableEnforceFocus, disableEnforceFocus = _e === void 0 ? false : _e, _f = _a.single, single = _f === void 0 ? false : _f, _g = _a.ungroup, ungroup = _g === void 0 ? false : _g, _h = _a.disabled, disabled = _h === void 0 ? false : _h, _j = _a.hideCheckBox, hideCheckBox = _j === void 0 ? false : _j, additionalInfo = _a.additionalInfo;
15
15
  var styles = useStyles();
16
16
  var _k = useState(null), selectAnchor = _k[0], setSelectAnchor = _k[1];
17
17
  var openPopup = function (event) {
@@ -64,7 +64,7 @@ var BasicAttributeSelector = function (_a) {
64
64
  }), focusIndex = _o.focusIndex, handleKeyDown = _o.handleKeyDown;
65
65
  return (React.createElement("div", { className: classnames(styles.selector, className), "data-reltio-id": "attribute-selector" },
66
66
  React.createElement(AttributeTitle, { value: value, getLabel: getLabel, onSelectAttributeClick: openPopup, disabled: disabled }),
67
- React.createElement(SelectionPopup, { open: isPopupOpen, anchorEl: selectAnchor, onClose: handleOnClose, onSearch: setFilterText, title: i18n.text('Select attribute'), containerWidth: containerWidth, containerHeight: ATTRIBUTES_POPUP_HEIGHT, searchInputOnKeyDown: handleKeyDown, anchorOrigin: { horizontal: 'right', vertical: 'bottom' }, searchInputRef: searchInputRef, disableRestoreFocus: disableRestoreFocus, disableEnforceFocus: disableEnforceFocus },
67
+ React.createElement(SelectionPopup, { open: isPopupOpen, anchorEl: selectAnchor, onClose: handleOnClose, onSearch: setFilterText, title: i18n.text('Select attribute'), additionalInfo: additionalInfo, containerWidth: containerWidth, containerHeight: ATTRIBUTES_POPUP_HEIGHT, searchInputOnKeyDown: handleKeyDown, anchorOrigin: { horizontal: 'right', vertical: 'bottom' }, searchInputRef: searchInputRef, disableRestoreFocus: disableRestoreFocus, disableEnforceFocus: disableEnforceFocus },
68
68
  React.createElement(SelectAttributesList, { items: items, onItemClick: onListItemClick, selectedAttributes: selectedAttributes, width: containerWidth, height: ATTRIBUTES_LIST_HEIGHT, focusIndex: focusIndex, hideCheckBox: hideCheckBox }))));
69
69
  };
70
70
  export default memo(BasicAttributeSelector);
@@ -100,7 +100,7 @@ var AttributeRenderer = function (_a) {
100
100
  isEditableMode && React.createElement(CardinalityMessage, { cardinality: cardinality }),
101
101
  isEditableMode && React.createElement(ErrorMessage, { message: errorMessage, className: styles.typeError }),
102
102
  React.createElement("div", { className: styles.attributesWrapper },
103
- shownValues.map(function (value, idx) { return (React.createElement(EditModeAttribute, { key: value.uri, attributeValue: value, attributeType: attributeType, lazy: showEmpty && !isRequired, showEmptyEditors: showEmptyEditors, errors: errors, ownError: getAttributeOwnError(value, idx, attributeType.uri, errors), mode: mode, crosswalks: crosswalks, onAddOneMore: lastIndex === idx ? onAddOneMore : null, onAddAttributes: onAddAttributes, onDeleteAttribute: onDelete, onChangeAttribute: onChangeAttribute, onDeactivateError: onDeactivateError, additionalControlsRenderer: additionalControlsRenderer, className: idx === 0 ? highlightedClassName : null, ref: idx === 0 ? attributeRef : null, isEmptyEditor: showEmpty })); }),
103
+ shownValues.map(function (value, idx) { return (React.createElement(EditModeAttribute, { key: value.uri, attributeValue: value, attributeType: attributeType, lazy: showEmpty && !isRequired, showEmptyEditors: showEmptyEditors, errors: errors, ownError: getAttributeOwnError(value, idx, attributeType.uri, errors), mode: mode, crosswalks: crosswalks, onAddOneMore: lastIndex === idx ? onAddOneMore : null, onAddAttributes: onAddAttributes, onDeleteAttribute: onDelete, onChangeAttribute: onChangeAttribute, onDeactivateError: onDeactivateError, additionalControlsRenderer: additionalControlsRenderer, className: idx === 0 ? highlightedClassName : null, ref: idx === 0 ? attributeRef : null, isFirstEditor: idx === 0, isEmptyEditor: showEmpty })); }),
104
104
  showMore && (React.createElement(ShowMore, { moreNumber: min(max, hiddenValuesCount), valueNumber: hiddenValuesCount, onClick: onShowMore })),
105
105
  showLess && React.createElement(ShowLess, { onClick: onShowLess })))));
106
106
  };
@@ -32,9 +32,11 @@ import { TypeaheadEditor } from '../TypeaheadEditor';
32
32
  import { DependentLookupEditor } from '../DependentLookupEditor';
33
33
  import { FileTypeEditor } from '../FileTypeEditor';
34
34
  import { SelectEditor } from '../SelectEditor';
35
+ import { AddressAutocompleteEditor } from '../AddressAutocompleteEditor/AddressAutocompleteEditor';
35
36
  var EditorsFactory = /** @class */ (function () {
36
37
  function EditorsFactory() {
37
38
  }
39
+ // prettier-ignore
38
40
  EditorsFactory.build = function (type, _a) {
39
41
  if (_a === void 0) { _a = {}; }
40
42
  var fullWidth = _a.fullWidth, TextFieldProps = _a.TextFieldProps, color = _a.color, booleanRadioEditorClassName = _a.booleanRadioEditorClassName, otherProps = __rest(_a, ["fullWidth", "TextFieldProps", "color", "booleanRadioEditorClassName"]);
@@ -83,6 +85,8 @@ var EditorsFactory = /** @class */ (function () {
83
85
  return React.createElement(DependentLookupEditor, __assign({ fullWidth: fullWidth, TextFieldProps: TextFieldProps }, otherProps));
84
86
  case DataTypes.TYPE_FILE:
85
87
  return React.createElement(FileTypeEditor, __assign({}, otherProps));
88
+ case DataTypes.TYPE_ADDRESS_AUTOCOMPLETE:
89
+ return React.createElement(AddressAutocompleteEditor, __assign({ fullWidth: fullWidth }, TextFieldProps, otherProps));
86
90
  default:
87
91
  return React.createElement(TextEditor, __assign({ fullWidth: fullWidth }, TextFieldProps, otherProps));
88
92
  }
@@ -32,6 +32,7 @@ import { useAttributeValueConfigPermissions } from '../contexts/ConfigPermission
32
32
  import { isHighlightedErrorType, ScrollToElementContext } from '../contexts/ScrollToElementContext';
33
33
  import { useMdmAction, useMdmGlobalSearchRequestOptions, useMdmMetadata, useMdmModifiedEntity, useMdmShowMasking } from '../contexts/MdmModuleContext';
34
34
  import { useScrollToAttributeError } from '../hooks/useScrollToAttributeError';
35
+ import { AddressAutoCompleteProvider } from '../contexts/AutoCompleteContext';
35
36
  import { useStyles } from './styles';
36
37
  var ReferenceAttributeEditor = function (props) {
37
38
  var _a;
@@ -122,9 +123,10 @@ var ReferenceAttributeEditor = function (props) {
122
123
  return (React.createElement(EditModeComplexAttribute, __assign({}, ownProps, { label: getLabel(label), attributeTypesList: editableAttrTypes, crosswalks: allCrosswalks, metadata: metadata }),
123
124
  React.createElement("div", { ref: ref, className: errorClassName },
124
125
  React.createElement(ErrorWrapper, { errorMessage: errorMessage },
125
- React.createElement(EntitySelector, { className: classnames(styles.item, (_a = {},
126
- _a[styles.dense] = errorMessage || (selectedEntity && isTempUri(selectedEntity.entityUri)),
127
- _a)), entity: selectedEntity || {}, entityTypesUris: entityTypesUris, globalSearchRequestOptions: globalSearchRequestOptions, mode: mode, isDisabled: !canChangeReferencedEntity || !!attributeValue.masked, onChange: onChangeEntity, onCreate: canCreateReferencedEntity ? onCreateEntity : undefined, metadata: metadata, attributeTypesSelectionStrategy: newEntityAttrTypesSelectionStrategy, isMasked: isMasked })))));
126
+ React.createElement(AddressAutoCompleteProvider, { entityUri: entityUri },
127
+ React.createElement(EntitySelector, { className: classnames(styles.item, (_a = {},
128
+ _a[styles.dense] = errorMessage || (selectedEntity && isTempUri(selectedEntity.entityUri)),
129
+ _a)), entity: selectedEntity || {}, entityTypesUris: entityTypesUris, globalSearchRequestOptions: globalSearchRequestOptions, mode: mode, isDisabled: !canChangeReferencedEntity || !!attributeValue.masked, onChange: onChangeEntity, onCreate: canCreateReferencedEntity ? onCreateEntity : undefined, metadata: metadata, attributeTypesSelectionStrategy: newEntityAttrTypesSelectionStrategy, isMasked: isMasked }))))));
128
130
  };
129
131
  export default withContext(ScrollToElementContext, function (contextValue, _a) {
130
132
  var attributeValue = _a.attributeValue, attributeType = _a.attributeType;