@reltio/components 1.4.2233 → 1.4.2235

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 (49) hide show
  1. package/EntitySelector/EntitySelector.js +1 -1
  2. package/EntitySelector/EntitySelector.test.js +23 -0
  3. package/FileDropZone/FileDropZone.d.ts +9 -0
  4. package/FileDropZone/FileDropZone.js +47 -0
  5. package/FileDropZone/FileDropZone.module.css.js +9 -0
  6. package/FileDropZone/FileDropZone.test.d.ts +1 -0
  7. package/FileDropZone/FileDropZone.test.js +114 -0
  8. package/FileDropZone/index.d.ts +1 -0
  9. package/FileDropZone/index.js +1 -0
  10. package/RelationEditor/RelationEditor.js +35 -4
  11. package/RelationEditor/RelationEditor.test.js +86 -4
  12. package/ScreenProfileBand/ScreenProfileBand.d.ts +2 -1
  13. package/ScreenProfileBand/ScreenProfileBand.js +5 -4
  14. package/ScreenProfileBand/ScreenProfileBand.module.css.js +9 -0
  15. package/ScreenProfileBand/ScreenProfileBand.test.js +5 -0
  16. package/UploadImageDialog/components/TargetBox/TargetBox.js +4 -34
  17. package/UploadImageDialog/components/TargetBox/TargetBox.module.css.js +9 -0
  18. package/UploadImageDialog/components/TargetBox/TargetBox.test.js +5 -38
  19. package/cjs/EntitySelector/EntitySelector.js +1 -1
  20. package/cjs/EntitySelector/EntitySelector.test.js +23 -0
  21. package/cjs/FileDropZone/FileDropZone.d.ts +9 -0
  22. package/cjs/FileDropZone/FileDropZone.js +76 -0
  23. package/cjs/FileDropZone/FileDropZone.module.css.js +9 -0
  24. package/cjs/FileDropZone/FileDropZone.test.d.ts +1 -0
  25. package/cjs/FileDropZone/FileDropZone.test.js +119 -0
  26. package/cjs/FileDropZone/index.d.ts +1 -0
  27. package/cjs/FileDropZone/index.js +5 -0
  28. package/cjs/RelationEditor/RelationEditor.js +34 -3
  29. package/cjs/RelationEditor/RelationEditor.test.js +86 -4
  30. package/cjs/ScreenProfileBand/ScreenProfileBand.d.ts +2 -1
  31. package/cjs/ScreenProfileBand/ScreenProfileBand.js +6 -5
  32. package/cjs/ScreenProfileBand/ScreenProfileBand.module.css.js +9 -0
  33. package/cjs/ScreenProfileBand/ScreenProfileBand.test.js +5 -0
  34. package/cjs/UploadImageDialog/components/TargetBox/TargetBox.js +7 -60
  35. package/cjs/UploadImageDialog/components/TargetBox/TargetBox.module.css.js +9 -0
  36. package/cjs/UploadImageDialog/components/TargetBox/TargetBox.test.js +5 -38
  37. package/cjs/index.d.ts +1 -0
  38. package/cjs/index.js +9 -7
  39. package/index.d.ts +1 -0
  40. package/index.js +1 -0
  41. package/package.json +2 -2
  42. package/ScreenProfileBand/styles.d.ts +0 -1
  43. package/ScreenProfileBand/styles.js +0 -10
  44. package/UploadImageDialog/components/TargetBox/styles.d.ts +0 -1
  45. package/UploadImageDialog/components/TargetBox/styles.js +0 -28
  46. package/cjs/ScreenProfileBand/styles.d.ts +0 -1
  47. package/cjs/ScreenProfileBand/styles.js +0 -13
  48. package/cjs/UploadImageDialog/components/TargetBox/styles.d.ts +0 -1
  49. package/cjs/UploadImageDialog/components/TargetBox/styles.js +0 -31
@@ -94,7 +94,7 @@ export var EntitySelector = function (_a) {
94
94
  return (__assign(__assign({}, (TextFieldProps || {})), (_a = {}, _a['data-reltio-id'] = 'reltio-entity-selector', _a)));
95
95
  }, [TextFieldProps]);
96
96
  return (React.createElement(React.Fragment, null,
97
- React.createElement(DropDownSelector, __assign({ value: !isEmpty(entity) ? entity : undefined, inputValue: inputValue, onInputChange: handleInputChange, getOptions: getOptions, getOptionLabel: prop('entityLabel'), onChange: handleChange, onCreate: handleCreate, onClear: handleClear, label: label, createLabel: createLabel, canCreateOption: canCreateEntity, components: __assign(__assign({ Option: EntityOption, SingleValue: SingleValue }, groupComponent), clearComponent), currentEntityType: currentEntityType, isClearable: true, disableLinkClick: disableLinkClick, TextFieldProps: textFieldProps }, dropDownSelectorProps)),
97
+ React.createElement(DropDownSelector, __assign({ key: entityTypesUris.join(','), value: !isEmpty(entity) ? entity : undefined, inputValue: inputValue, onInputChange: handleInputChange, getOptions: getOptions, getOptionLabel: prop('entityLabel'), onChange: handleChange, onCreate: handleCreate, onClear: handleClear, label: label, createLabel: createLabel, canCreateOption: canCreateEntity, components: __assign(__assign({ Option: EntityOption, SingleValue: SingleValue }, groupComponent), clearComponent), currentEntityType: currentEntityType, isClearable: true, disableLinkClick: disableLinkClick, TextFieldProps: textFieldProps }, dropDownSelectorProps)),
98
98
  isTempEntity && (React.createElement("div", { "data-reltio-id": "entity-creator", className: styles.creatorWrapper },
99
99
  React.createElement(EntityCreator, { mode: mode, attributeTypesSelectionStrategy: attributeTypesSelectionStrategy, entityType: currentEntityType, entityUri: entity.entityUri })))));
100
100
  };
@@ -385,6 +385,29 @@ describe('Entity selector tests', function () {
385
385
  }
386
386
  });
387
387
  }); });
388
+ it('should call typeAheadSearch with new entity types when entityTypesUris prop changes after rerender', function () { return __awaiter(void 0, void 0, void 0, function () {
389
+ var initialProps, _a, user, rerender, updatedProps;
390
+ return __generator(this, function (_b) {
391
+ switch (_b.label) {
392
+ case 0:
393
+ initialProps = __assign(__assign({}, defaultProps), { entityTypesUris: ['configuration/entityTypes/HCP'] });
394
+ _a = setUp({ props: initialProps }), user = _a.user, rerender = _a.rerender;
395
+ return [4 /*yield*/, user.click(screen.getByTestId('select-dropdown-indicator'))];
396
+ case 1:
397
+ _b.sent();
398
+ expect(typeAheadSearch).toHaveBeenCalledWith([defaultMetadata.entityTypes[0]], '', expect.any(Object));
399
+ typeAheadSearch.mockClear();
400
+ updatedProps = __assign(__assign({}, defaultProps), { entityTypesUris: ['configuration/entityTypes/HCP', 'configuration/entityTypes/Company'] });
401
+ rerender(React.createElement(MdmModuleProvider, { values: defaultMdmValues, actions: defaultMdmActions },
402
+ React.createElement(EntitySelector, __assign({}, updatedProps))));
403
+ return [4 /*yield*/, user.click(screen.getByTestId('select-dropdown-indicator'))];
404
+ case 2:
405
+ _b.sent();
406
+ expect(typeAheadSearch).toHaveBeenCalledWith([defaultMetadata.entityTypes[0], defaultMetadata.entityTypes[1]], '', expect.any(Object));
407
+ return [2 /*return*/];
408
+ }
409
+ });
410
+ }); });
388
411
  it('should render create button and handle click correctly for single entity type in case of onCreate prop is passed and input is filled', function () { return __awaiter(void 0, void 0, void 0, function () {
389
412
  var props, user;
390
413
  return __generator(this, function (_a) {
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ type Props = {
3
+ children: React.ReactNode;
4
+ onFileDrop: (file: File) => void;
5
+ isAcceptableFile?: (file: File) => boolean;
6
+ className?: string;
7
+ };
8
+ export declare const FileDropZone: React.MemoExoticComponent<({ children, onFileDrop, isAcceptableFile, className }: Props) => React.JSX.Element>;
9
+ export {};
@@ -0,0 +1,47 @@
1
+ import React, { memo, useCallback, useState } from 'react';
2
+ import classnames from 'classnames';
3
+ import i18n from 'ui-i18n';
4
+ import styles from './FileDropZone.module.css';
5
+ var DEFAULT_ACCEPTABLE_DRAG_TYPE = 'Files';
6
+ export var FileDropZone = memo(function (_a) {
7
+ var _b;
8
+ var children = _a.children, onFileDrop = _a.onFileDrop, isAcceptableFile = _a.isAcceptableFile, className = _a.className;
9
+ var _c = useState(false), isActive = _c[0], setIsActive = _c[1];
10
+ var isAcceptableDragType = useCallback(function (dragType) { return dragType === DEFAULT_ACCEPTABLE_DRAG_TYPE; }, []);
11
+ var handleDragOver = useCallback(function (e) {
12
+ e.preventDefault();
13
+ var dragType = e.dataTransfer.types[0];
14
+ var isValid = isAcceptableDragType(dragType);
15
+ e.dataTransfer.dropEffect = isValid ? 'copy' : 'none';
16
+ setIsActive(isValid);
17
+ }, [isAcceptableDragType]);
18
+ var handleDragEnter = useCallback(function (e) {
19
+ e.preventDefault();
20
+ var dragType = e.dataTransfer.types[0];
21
+ setIsActive(isAcceptableDragType(dragType));
22
+ }, [isAcceptableDragType]);
23
+ var handleDragLeave = useCallback(function (e) {
24
+ e.preventDefault();
25
+ var relatedTarget = e.relatedTarget;
26
+ var isLeave = relatedTarget && !e.currentTarget.contains(relatedTarget);
27
+ if (isLeave || !relatedTarget) {
28
+ setIsActive(false);
29
+ }
30
+ }, []);
31
+ var handleDrop = useCallback(function (e) {
32
+ var _a, _b;
33
+ e.preventDefault();
34
+ setIsActive(false);
35
+ var dragType = e.dataTransfer.types[0];
36
+ if (!isAcceptableDragType(dragType))
37
+ return;
38
+ var file = (_b = (_a = e.dataTransfer.files) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : null;
39
+ if (!file)
40
+ return;
41
+ if (isAcceptableFile && !isAcceptableFile(file))
42
+ return;
43
+ onFileDrop(file);
44
+ }, [isAcceptableDragType, isAcceptableFile, onFileDrop]);
45
+ return (React.createElement("div", { className: classnames(styles.root, className, (_b = {}, _b[styles.active] = isActive, _b)), role: "button", tabIndex: 0, "aria-label": i18n.text('Drop files here'), onDragOver: handleDragOver, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDrop: handleDrop }, children));
46
+ });
47
+ FileDropZone.displayName = 'FileDropZone';
@@ -0,0 +1,9 @@
1
+ const styles = {"root":"FileDropZone-root--9QbaV","active":"FileDropZone-active--FUwfs"};
2
+ if (typeof document !== 'undefined') {
3
+ const head = document.head || document.getElementsByTagName('head')[0]
4
+ const style = document.createElement('style');
5
+ style.type = 'text/css'
6
+ style.innerHTML = `.FileDropZone-root--9QbaV{cursor:pointer}.FileDropZone-active--FUwfs{background-color:rgba(0,114,206,.12)}`;
7
+ head.appendChild(style);
8
+ }
9
+ export default styles;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,114 @@
1
+ import React from 'react';
2
+ import { render, screen, fireEvent } from '@testing-library/react';
3
+ import { FileDropZone } from './FileDropZone';
4
+ var mockOnFileDrop = jest.fn();
5
+ var setUp = function (_a) {
6
+ var _b = _a === void 0 ? {} : _a, isAcceptableFile = _b.isAcceptableFile;
7
+ return render(React.createElement(FileDropZone, { onFileDrop: mockOnFileDrop, isAcceptableFile: isAcceptableFile },
8
+ React.createElement("span", null, "Drop content here")));
9
+ };
10
+ describe('FileDropZone', function () {
11
+ afterEach(function () {
12
+ jest.clearAllMocks();
13
+ });
14
+ it('should render children', function () {
15
+ setUp();
16
+ expect(screen.getByText('Drop content here')).toBeInTheDocument();
17
+ });
18
+ it('should have correct accessibility attributes', function () {
19
+ setUp();
20
+ var dropZone = screen.getByRole('button', { name: 'Drop files here' });
21
+ expect(dropZone).toBeInTheDocument();
22
+ expect(dropZone).toHaveAttribute('tabindex', '0');
23
+ });
24
+ it('should activate drag state on drag over with acceptable file type', function () {
25
+ setUp();
26
+ var dropZone = screen.getByRole('button', { name: 'Drop files here' });
27
+ fireEvent.dragOver(dropZone, {
28
+ dataTransfer: { types: ['Files'], dropEffect: 'copy' }
29
+ });
30
+ expect(dropZone).toHaveClass('active');
31
+ });
32
+ it('should not activate drag state with unacceptable file type', function () {
33
+ setUp();
34
+ var dropZone = screen.getByRole('button', { name: 'Drop files here' });
35
+ fireEvent.dragOver(dropZone, {
36
+ dataTransfer: { types: ['Text'], dropEffect: 'none' }
37
+ });
38
+ expect(dropZone).not.toHaveClass('active');
39
+ });
40
+ it('should activate drag state on drag enter with acceptable file type', function () {
41
+ setUp();
42
+ var dropZone = screen.getByRole('button', { name: 'Drop files here' });
43
+ fireEvent.dragEnter(dropZone, {
44
+ dataTransfer: { types: ['Files'] }
45
+ });
46
+ expect(dropZone).toHaveClass('active');
47
+ });
48
+ it('should deactivate drag state on drag leave', function () {
49
+ setUp();
50
+ var dropZone = screen.getByRole('button', { name: 'Drop files here' });
51
+ fireEvent.dragOver(dropZone, { dataTransfer: { types: ['Files'] } });
52
+ expect(dropZone).toHaveClass('active');
53
+ fireEvent.dragLeave(dropZone);
54
+ expect(dropZone).not.toHaveClass('active');
55
+ });
56
+ it('should call onFileDrop with the dropped file', function () {
57
+ var file = new File(['test content'], 'test.csv', { type: 'text/csv' });
58
+ setUp();
59
+ var dropZone = screen.getByRole('button', { name: 'Drop files here' });
60
+ fireEvent.drop(dropZone, {
61
+ dataTransfer: {
62
+ files: [file],
63
+ types: ['Files']
64
+ }
65
+ });
66
+ expect(mockOnFileDrop).toHaveBeenCalledWith(file);
67
+ });
68
+ it('should not call onFileDrop if dropped item is not of file type', function () {
69
+ setUp();
70
+ var dropZone = screen.getByRole('button', { name: 'Drop files here' });
71
+ fireEvent.drop(dropZone, {
72
+ dataTransfer: { types: ['Text'] }
73
+ });
74
+ expect(mockOnFileDrop).not.toHaveBeenCalled();
75
+ });
76
+ it('should not call onFileDrop if isAcceptableFile returns false', function () {
77
+ var file = new File(['test content'], 'test.exe', { type: 'application/octet-stream' });
78
+ setUp({ isAcceptableFile: function (f) { return f.name.endsWith('.csv'); } });
79
+ var dropZone = screen.getByRole('button', { name: 'Drop files here' });
80
+ fireEvent.drop(dropZone, {
81
+ dataTransfer: {
82
+ files: [file],
83
+ types: ['Files']
84
+ }
85
+ });
86
+ expect(mockOnFileDrop).not.toHaveBeenCalled();
87
+ });
88
+ it('should call onFileDrop if isAcceptableFile returns true', function () {
89
+ var file = new File(['test content'], 'data.csv', { type: 'text/csv' });
90
+ setUp({ isAcceptableFile: function (f) { return f.name.endsWith('.csv'); } });
91
+ var dropZone = screen.getByRole('button', { name: 'Drop files here' });
92
+ fireEvent.drop(dropZone, {
93
+ dataTransfer: {
94
+ files: [file],
95
+ types: ['Files']
96
+ }
97
+ });
98
+ expect(mockOnFileDrop).toHaveBeenCalledWith(file);
99
+ });
100
+ it('should deactivate drag state after drop', function () {
101
+ var file = new File(['test content'], 'test.csv', { type: 'text/csv' });
102
+ setUp();
103
+ var dropZone = screen.getByRole('button', { name: 'Drop files here' });
104
+ fireEvent.dragOver(dropZone, { dataTransfer: { types: ['Files'] } });
105
+ expect(dropZone).toHaveClass('active');
106
+ fireEvent.drop(dropZone, {
107
+ dataTransfer: {
108
+ files: [file],
109
+ types: ['Files']
110
+ }
111
+ });
112
+ expect(dropZone).not.toHaveClass('active');
113
+ });
114
+ });
@@ -0,0 +1 @@
1
+ export { FileDropZone } from './FileDropZone';
@@ -0,0 +1 @@
1
+ export { FileDropZone } from './FileDropZone';
@@ -15,7 +15,7 @@ import classnames from 'classnames';
15
15
  import { always, assoc, concat, differenceWith, equals, forEach, map, path, pick, pipe, prop, propEq, when, uniq, curry, values, flatten, any } from 'ramda';
16
16
  import Button from '@mui/material/Button';
17
17
  import Typography from '@mui/material/Typography';
18
- import { createTemporaryEntity, findRelatedTemporaryEntities, getActivenessAttributes, getCreatableAttributeTypes, getEntityType, getErrorMessage, getErrorId, omitMarks, relationEditorAttributeTypesSelectionStrategy, validateConnection, updateConnectionEntityLabel, isTempUri, isEmptyValue, getRelationAttributesList, getDefaultRelationTypeObject, getInOutRelations, isSuggestMode, isAttributeTypeError, getRelationUriFromConnection, getRelationEditorActiveError, getRelationAttributesFromConnection, getEntityUriFromConnection, evaluateErrorPath, AttributeValuePathItemType, getAllRelationEditorActiveErrors, isAttributeHasMaskedValue } from '@reltio/mdm-sdk';
18
+ import { createTemporaryEntity, Directions, findRelatedTemporaryEntities, getActivenessAttributes, getCreatableAttributeTypes, getEntityType, getErrorMessage, getErrorId, getRelationType, getSuitableEntityTypeUrisForRelationTypes, isAvailableRelationBetweenEntities, omitMarks, relationEditorAttributeTypesSelectionStrategy, validateConnection, updateConnectionEntityLabel, isTempUri, isEmptyValue, getRelationAttributesList, getDefaultRelationTypeObject, getInOutRelations, isSuggestMode, isAttributeTypeError, getRelationUriFromConnection, getRelationEditorActiveError, getRelationAttributesFromConnection, getEntityUriFromConnection, evaluateErrorPath, AttributeValuePathItemType, getAllRelationEditorActiveErrors, isAttributeHasMaskedValue } from '@reltio/mdm-sdk';
19
19
  import { ConnectionRelationTypeSelector } from '../ConnectionRelationTypeSelector';
20
20
  import { ErrorWrapper } from '../ErrorWrapper';
21
21
  import { EntitySelector } from '../EntitySelector';
@@ -110,7 +110,6 @@ var RelationEditor = function (_a) {
110
110
  areRelatedEntitiesChanged(initialRelatedTempEntities.current, relatedTempEntities));
111
111
  var applyAction = useMemo(function () { return curry(isNew ? addRelation : editRelation); }, [isNew, addRelation, editRelation]);
112
112
  var canCreateNewEntity = !isSuggestMode(mode) || !isTempUri(mainEntity === null || mainEntity === void 0 ? void 0 : mainEntity.uri) || !isEmptyValue(authoringItems);
113
- var onRelationTypeChange = useCallback(function (relationType) { return setRelationType(config.id, relationUri, relationType); }, [config, relationUri, setRelationType]);
114
113
  var handleClose = useCallback(function () { return closeRelationEditor(config.id, relationUri); }, [config, relationUri, closeRelationEditor]);
115
114
  var updateModifiedEntityLabel = useCallback(function (connection) {
116
115
  if (modifiedEntity) {
@@ -121,6 +120,31 @@ var RelationEditor = function (_a) {
121
120
  }, [modifiedEntity, metadata]);
122
121
  var setModifiedEntity = useCallback(function (entity) { return entityCreated(entity); }, [entityCreated]);
123
122
  var deleteModifiedEntity = useCallback(function (entityUri) { return entityDeleted(entityUri); }, [entityDeleted]);
123
+ var onRelationTypeChange = useCallback(function (newRelationType) {
124
+ var connectionEntity = connection.entity;
125
+ var hasConnectionEntity = connectionEntity && connectionEntity.entityUri;
126
+ var isEntitySuitableForNewRelationType = mainEntity &&
127
+ newRelationType &&
128
+ hasConnectionEntity &&
129
+ isAvailableRelationBetweenEntities(newRelationType.direction === Directions.OUT, __assign(__assign({}, connectionEntity), { type: connectionEntity.entityType }), mainEntity, metadata, newRelationType.type);
130
+ setRelationType(config.id, relationUri, newRelationType);
131
+ if (hasConnectionEntity && !isEntitySuitableForNewRelationType) {
132
+ if (modifiedEntity) {
133
+ deleteModifiedEntity(modifiedEntity.uri);
134
+ }
135
+ setRelationEntity(config.id, relationUri, {});
136
+ }
137
+ }, [
138
+ metadata,
139
+ connection.entity,
140
+ mainEntity,
141
+ setRelationType,
142
+ config.id,
143
+ relationUri,
144
+ modifiedEntity,
145
+ setRelationEntity,
146
+ deleteModifiedEntity
147
+ ]);
124
148
  var onChangeEntity = useCallback(function (entity) {
125
149
  if (modifiedEntity) {
126
150
  deleteModifiedEntity(modifiedEntity.uri);
@@ -190,8 +214,15 @@ var RelationEditor = function (_a) {
190
214
  var entityTypesUris = useMemo(function () {
191
215
  var _a;
192
216
  var _b = config, content = _b.content, contentSecondLevel = _b.contentSecondLevel;
193
- return ((_a = (contentSecondLevel && connection.parentEntityUri ? contentSecondLevel.entityTypes : content.entityTypes)) !== null && _a !== void 0 ? _a : []);
194
- }, [config, connection.parentEntityUri]);
217
+ var entityTypeUrisFromConfig = (_a = (contentSecondLevel && connection.parentEntityUri ? contentSecondLevel.entityTypes : content.entityTypes)) !== null && _a !== void 0 ? _a : [];
218
+ var relationTypeObj = relationType ? getRelationType(metadata, relationType) : null;
219
+ var suitableEntityTypeUrisForRelationType = relationTypeObj
220
+ ? getSuitableEntityTypeUrisForRelationTypes(direction === Directions.OUT, metadata, [relationTypeObj])
221
+ : [];
222
+ return entityTypeUrisFromConfig.length > 0
223
+ ? entityTypeUrisFromConfig.filter(function (uri) { return suitableEntityTypeUrisForRelationType.includes(uri); })
224
+ : suitableEntityTypeUrisForRelationType;
225
+ }, [config, connection.parentEntityUri, relationType, direction, metadata]);
195
226
  var isEntityHasMaskedAttrValue = pipe(values, flatten, any(isAttributeHasMaskedValue))(((_d = (_c = connection.entity) === null || _c === void 0 ? void 0 : _c.object) === null || _d === void 0 ? void 0 : _d.attributes) || {});
196
227
  var isMasked = showMasking && isEntityHasMaskedAttrValue;
197
228
  return (React.createElement(React.Fragment, null,
@@ -293,6 +293,51 @@ describe('relation editor behaviour', function () {
293
293
  }
294
294
  });
295
295
  }); });
296
+ it('should pass only entity types suitable for current relation type to EntitySelector', function () { return __awaiter(void 0, void 0, void 0, function () {
297
+ var config, props, user;
298
+ return __generator(this, function (_a) {
299
+ switch (_a.label) {
300
+ case 0:
301
+ typeAheadSearch.mockResolvedValue([
302
+ { type: 'configuration/entityTypes/Location', label: 'location entity 1', uri: 'entities/0C32GxR' }
303
+ ]);
304
+ config = __assign(__assign({}, defaultProps.config), { content: {
305
+ entityTypes: ['configuration/entityTypes/Location', 'configuration/entityTypes/HCA'],
306
+ outRelations: [{ uri: 'configuration/relationTypes/HasAddress', label: '{directionalLabel}' }]
307
+ } });
308
+ props = __assign(__assign({}, defaultProps), { config: config });
309
+ user = setUp({ props: props }).user;
310
+ return [4 /*yield*/, user.click(screen.getByTestId('select-dropdown-indicator'))];
311
+ case 1:
312
+ _a.sent();
313
+ expect(typeAheadSearch).toHaveBeenCalledWith([defaultProps.metadata.entityTypes[1]], '', expect.any(Object));
314
+ expect(typeAheadSearch).not.toHaveBeenCalledWith(expect.arrayContaining([expect.objectContaining({ uri: 'configuration/entityTypes/HCA' })]), expect.any(String), expect.any(Object));
315
+ return [2 /*return*/];
316
+ }
317
+ });
318
+ }); });
319
+ it('should pass all suitable entity types from metadata to EntitySelector when entityTypes from config is empty', function () { return __awaiter(void 0, void 0, void 0, function () {
320
+ var config, props, user;
321
+ return __generator(this, function (_a) {
322
+ switch (_a.label) {
323
+ case 0:
324
+ typeAheadSearch.mockResolvedValue([
325
+ { type: 'configuration/entityTypes/Location', label: 'location entity 1', uri: 'entities/0C32GxR' }
326
+ ]);
327
+ config = __assign(__assign({}, defaultProps.config), { content: {
328
+ entityTypes: [],
329
+ outRelations: [{ uri: 'configuration/relationTypes/HasAddress', label: '{directionalLabel}' }]
330
+ } });
331
+ props = __assign(__assign({}, defaultProps), { config: config });
332
+ user = setUp({ props: props }).user;
333
+ return [4 /*yield*/, user.click(screen.getByTestId('select-dropdown-indicator'))];
334
+ case 1:
335
+ _a.sent();
336
+ expect(typeAheadSearch).toHaveBeenCalledWith([defaultProps.metadata.entityTypes[1]], '', expect.any(Object));
337
+ return [2 /*return*/];
338
+ }
339
+ });
340
+ }); });
296
341
  it('should render attributes list correctly', function () { return __awaiter(void 0, void 0, void 0, function () {
297
342
  var labels, values;
298
343
  return __generator(this, function (_a) {
@@ -351,7 +396,7 @@ describe('relation editor behaviour', function () {
351
396
  return __generator(this, function (_a) {
352
397
  switch (_a.label) {
353
398
  case 0:
354
- connection = __assign(__assign({}, defaultProps.connection), { parentEntityUri: 'entities/HsPM72G' });
399
+ connection = __assign(__assign({}, defaultProps.connection), { parentEntityUri: 'entities/HsPM72G', relation: __assign(__assign({}, defaultRelation), { relationType: 'configuration/relationTypes/InternalHCAtoHCA', direction: 'out' }) });
355
400
  config = __assign(__assign({}, defaultProps.config), { contentSecondLevel: {
356
401
  entityTypes: ['configuration/entityTypes/HCA'],
357
402
  outRelations: [{ uri: 'configuration/relationTypes/InternalHCAtoHCA', label: '{directionalLabel}' }]
@@ -458,6 +503,43 @@ describe('relation editor behaviour', function () {
458
503
  }
459
504
  });
460
505
  }); });
506
+ it('should clear connection entity and delete modified entity when relation type changes to one unsuitable for current connection entity', function () { return __awaiter(void 0, void 0, void 0, function () {
507
+ var entityUri, modifiedEntity, connection, config, mdmValues, props, user;
508
+ var _a;
509
+ return __generator(this, function (_b) {
510
+ switch (_b.label) {
511
+ case 0:
512
+ entityUri = 'entities/uri$$tempLocation';
513
+ modifiedEntity = {
514
+ type: 'configuration/entityTypes/Location',
515
+ uri: entityUri,
516
+ attributes: {}
517
+ };
518
+ connection = __assign(__assign({}, defaultProps.connection), { entity: { entityUri: entityUri, entityType: 'configuration/entityTypes/Location' } });
519
+ config = __assign(__assign({}, defaultProps.config), { content: {
520
+ entityTypes: ['configuration/entityTypes/Location', 'configuration/entityTypes/HCA'],
521
+ inRelations: [{ uri: 'configuration/relationTypes/InternalHCAtoHCA', label: '{directionalLabel}' }],
522
+ outRelations: [{ uri: 'configuration/relationTypes/HasAddress', label: '{directionalLabel}' }]
523
+ } });
524
+ mdmValues = __assign(__assign({}, defaultMdmValues), { modifiedEntities: (_a = {}, _a[entityUri] = modifiedEntity, _a) });
525
+ props = __assign(__assign({}, defaultProps), { config: config, connection: connection });
526
+ user = setUp({ mdmValues: mdmValues, props: props }).user;
527
+ return [4 /*yield*/, user.click(within(screen.getByTestId('relation-type-selector')).getByTestId('select-dropdown-indicator'))];
528
+ case 1:
529
+ _b.sent();
530
+ return [4 /*yield*/, user.click(screen.getByText('InternalHCAtoHCA affiliation'))];
531
+ case 2:
532
+ _b.sent();
533
+ expect(mdmActions.setRelationType).toHaveBeenCalledWith(props.config.id, props.connection.relation.relationUri, expect.objectContaining({
534
+ direction: 'in',
535
+ type: expect.objectContaining({ uri: 'configuration/relationTypes/InternalHCAtoHCA' })
536
+ }));
537
+ expect(mdmActions.entityDeleted).toHaveBeenCalledWith(entityUri);
538
+ expect(mdmActions.setRelationEntity).toHaveBeenCalledWith(props.config.id, props.connection.relation.relationUri, {});
539
+ return [2 /*return*/];
540
+ }
541
+ });
542
+ }); });
461
543
  it('should show "create entity" button if mode is not suggesting', function () { return __awaiter(void 0, void 0, void 0, function () {
462
544
  var user, inputs;
463
545
  return __generator(this, function (_a) {
@@ -496,24 +578,24 @@ describe('relation editor behaviour', function () {
496
578
  });
497
579
  }); });
498
580
  it('should hide create button for one of the entity types when user lacks metadata permissions', function () { return __awaiter(void 0, void 0, void 0, function () {
499
- var props, user, inputs;
581
+ var connection, props, user, inputs;
500
582
  return __generator(this, function (_a) {
501
583
  switch (_a.label) {
502
584
  case 0:
585
+ connection = __assign(__assign({}, defaultProps.connection), { relation: __assign(__assign({}, defaultRelation), { relationType: 'configuration/relationTypes/HasAddress', direction: 'out' }) });
503
586
  props = pipe(assocPath(['metadata', 'entityTypes', 1, 'access'], ['READ', 'UPDATE', 'INITIATE_CHANGE_REQUEST']), assocPath(['config', 'content'], {
504
587
  entityTypes: ['configuration/entityTypes/Location', 'configuration/entityTypes/HCA'],
505
588
  outRelations: [
506
589
  { uri: 'configuration/relationTypes/HasAddress', label: '{directionalLabel}' },
507
590
  { uri: 'configuration/relationTypes/InternalHCAtoHCA', label: '{directionalLabel}' }
508
591
  ]
509
- }))(defaultProps);
592
+ }), assocPath(['connection'], connection))(defaultProps);
510
593
  user = setUp({ props: props }).user;
511
594
  inputs = screen.getAllByRole('combobox');
512
595
  return [4 /*yield*/, user.click(inputs[1])];
513
596
  case 1:
514
597
  _a.sent();
515
598
  expect(screen.queryByText('Create new Address')).not.toBeInTheDocument();
516
- expect(screen.getByText('Create new HCA')).toBeInTheDocument();
517
599
  return [2 /*return*/];
518
600
  }
519
601
  });
@@ -4,6 +4,7 @@ type Props = {
4
4
  entity: Entity;
5
5
  className?: string;
6
6
  historySlice?: HistorySlice;
7
+ children?: React.ReactNode;
7
8
  };
8
- export declare const ScreenProfileBand: React.MemoExoticComponent<({ entity, className, historySlice }: Props) => React.JSX.Element>;
9
+ export declare const ScreenProfileBand: React.MemoExoticComponent<({ entity, className, historySlice, children }: Props) => React.JSX.Element>;
9
10
  export {};
@@ -8,16 +8,17 @@ import { CollaborationContextProvider } from '../contexts/CollaborationContext';
8
8
  import { COMMENTS_CONTAINER_VISIBILITY_AREA } from '../constants';
9
9
  import { useCollaboration } from '../hooks/useCollaboration';
10
10
  import { ProfileBandHistory } from '../features/history';
11
- import { useStyles } from './styles';
11
+ import styles from './ScreenProfileBand.module.css';
12
12
  export var ScreenProfileBand = memo(function (_a) {
13
- var entity = _a.entity, className = _a.className, historySlice = _a.historySlice;
14
- var styles = useStyles();
13
+ var entity = _a.entity, className = _a.className, historySlice = _a.historySlice, children = _a.children;
15
14
  var objectIds = useMemo(function () { return getProfileBandObjectIdsForCollaboration(entity); }, [entity]);
16
15
  var collaboration = useCollaboration({ objectIds: objectIds });
17
16
  var entityUri = getEntityUriForLink(entity);
18
17
  return (React.createElement(CollaborationContextProvider, { collaboration: collaboration },
19
18
  React.createElement(ProfileBand, { className: classnames(className, COMMENTS_CONTAINER_VISIBILITY_AREA), entity: (historySlice === null || historySlice === void 0 ? void 0 : historySlice.aEntity) || entity }, historySlice ? (React.createElement(ProfileBandHistory, null)) : (React.createElement(React.Fragment, null,
20
- React.createElement(ProfileBandNavigation, { className: styles.profileBandNavigation }),
19
+ children ? (React.createElement("div", { className: classnames(styles.profileBandNavigation, styles.navigationRow) },
20
+ React.createElement(ProfileBandNavigation, null),
21
+ children)) : (React.createElement(ProfileBandNavigation, { className: styles.profileBandNavigation })),
21
22
  React.createElement(CommentsContainer, { className: styles.comments, uri: entityUri, relatedObjectUris: createRelatedObjectUris(CollaborationObjectTypes.ENTITY, {
22
23
  entityUri: entityUri
23
24
  }), objectType: CollaborationObjectTypes.ENTITY }))))));
@@ -0,0 +1,9 @@
1
+ const styles = {"profileBandNavigation":"ScreenProfileBand-profileBandNavigation--5BMn5","navigationRow":"ScreenProfileBand-navigationRow---CH-F","comments":"ScreenProfileBand-comments--RRYzS"};
2
+ if (typeof document !== 'undefined') {
3
+ const head = document.head || document.getElementsByTagName('head')[0]
4
+ const style = document.createElement('style');
5
+ style.type = 'text/css'
6
+ style.innerHTML = `.ScreenProfileBand-profileBandNavigation--5BMn5{margin-bottom:10px}.ScreenProfileBand-navigationRow---CH-F{align-items:center;display:flex;gap:8px}.ScreenProfileBand-comments--RRYzS{display:flex;justify-content:flex-end}`;
7
+ head.appendChild(style);
8
+ }
9
+ export default styles;
@@ -122,6 +122,11 @@ describe('Screen profile band tests', function () {
122
122
  }
123
123
  });
124
124
  }); });
125
+ it('should render children when provided', function () {
126
+ var props = __assign(__assign({}, defaultProps), { children: React.createElement("button", null, "Custom Action") });
127
+ setUp({ props: props });
128
+ expect(screen.getByRole('button', { name: 'Custom Action' })).toBeInTheDocument();
129
+ });
125
130
  it('should render profile band history if historySlice prop is provided', function () { return __awaiter(void 0, void 0, void 0, function () {
126
131
  var historySlice, props, mdmValues;
127
132
  return __generator(this, function (_a) {
@@ -1,45 +1,15 @@
1
- import React, { useCallback, useState } from 'react';
1
+ import React from 'react';
2
2
  import classnames from 'classnames';
3
3
  import i18n from 'ui-i18n';
4
4
  import Typography from '@mui/material/Typography';
5
+ import { FileDropZone } from '../../../FileDropZone';
5
6
  import { SelectImageButton } from '../SelectImageButton';
6
7
  import UploadIcon from '../../../icons/UploadIcon';
7
8
  import { MAX_IMAGE_SIZE } from '../../constants';
8
- import { useStyles } from './styles';
9
- var ACCEPTABLE_FILE_TYPE = 'Files';
9
+ import styles from './TargetBox.module.css';
10
10
  export var TargetBox = function (_a) {
11
- var _b;
12
11
  var onAppendFile = _a.onAppendFile, className = _a.className;
13
- var styles = useStyles();
14
- var _c = useState(false), isActive = _c[0], setIsActive = _c[1];
15
- var handleDragOver = useCallback(function (e) {
16
- e.preventDefault();
17
- e.stopPropagation();
18
- var filesType = e.dataTransfer.types[0];
19
- var isValidType = filesType === ACCEPTABLE_FILE_TYPE;
20
- e.dataTransfer.dropEffect = isValidType ? 'copy' : 'none';
21
- setIsActive(isValidType);
22
- }, []);
23
- var handleDragLeave = useCallback(function (e) {
24
- e.preventDefault();
25
- e.stopPropagation();
26
- var relatedTarget = e.relatedTarget;
27
- var isLeave = relatedTarget && !e.currentTarget.contains(relatedTarget);
28
- if (isLeave || !relatedTarget) {
29
- setIsActive(false);
30
- }
31
- }, []);
32
- var handleDrop = useCallback(function (e) {
33
- e.preventDefault();
34
- e.stopPropagation();
35
- setIsActive(false);
36
- var filesType = e.dataTransfer.types[0];
37
- if (filesType === ACCEPTABLE_FILE_TYPE) {
38
- var file = e.dataTransfer.files[0];
39
- onAppendFile(file);
40
- }
41
- }, [onAppendFile]);
42
- return (React.createElement("div", { className: classnames(styles.root, (_b = {}, _b[styles.isActive] = isActive, _b), className), onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop },
12
+ return (React.createElement(FileDropZone, { className: classnames(styles.root, className), onFileDrop: onAppendFile },
43
13
  React.createElement(UploadIcon, { className: styles.icon }),
44
14
  React.createElement(Typography, { className: styles.title }, i18n.text('Drag an image here')),
45
15
  React.createElement(Typography, { className: styles.description }, i18n.text('Acceptable image types would include JPG, PNG, TIFF, GIF, BMP. Maximum image size: ${MAX_IMAGE_SIZE}Mb', {
@@ -0,0 +1,9 @@
1
+ const styles = {"root":"TargetBox-root--T8Dyg","icon":"TargetBox-icon--qfl13","title":"TargetBox-title--zQaNU","description":"TargetBox-description--Jyqo5"};
2
+ if (typeof document !== 'undefined') {
3
+ const head = document.head || document.getElementsByTagName('head')[0]
4
+ const style = document.createElement('style');
5
+ style.type = 'text/css'
6
+ style.innerHTML = `.TargetBox-root--T8Dyg{padding:36px 0 29px}.TargetBox-icon--qfl13{height:190px;margin-bottom:24px;pointer-events:none;width:190px}.TargetBox-title--zQaNU{color:var(--mui-palette-text-primary);font-size:20px;font-weight:500;line-height:24px;margin-bottom:8px}.TargetBox-description--Jyqo5{color:var(--mui-palette-text-secondary);font-size:14px;line-height:16px;margin-bottom:24px}`;
7
+ head.appendChild(style);
8
+ }
9
+ export default styles;
@@ -9,38 +9,15 @@ describe('TargetBox', function () {
9
9
  afterEach(function () {
10
10
  jest.clearAllMocks();
11
11
  });
12
- it('should renders well', function () {
12
+ it('should render correctly', function () {
13
13
  setUp();
14
14
  expect(screen.getByText('Drag an image here')).toBeInTheDocument();
15
+ expect(screen.getByRole('button', { name: 'Drop files here' })).toBeInTheDocument();
15
16
  });
16
- it('should activates drag state on drag over with acceptable file type', function () {
17
- var container = setUp().container;
18
- var dropZone = container.firstChild;
19
- fireEvent.dragOver(dropZone, {
20
- dataTransfer: { types: ['Files'], dropEffect: 'copy' }
21
- });
22
- expect(dropZone).toHaveClass('isActive');
23
- });
24
- it('should does not activate drag state with unacceptable file type', function () {
25
- var container = setUp().container;
26
- var dropZone = container.firstChild;
27
- fireEvent.dragOver(dropZone, {
28
- dataTransfer: { types: ['Text'], dropEffect: 'none' }
29
- });
30
- expect(dropZone).not.toHaveClass('isActive');
31
- });
32
- it('should deactivates drag state on drag leave', function () {
33
- var container = setUp().container;
34
- var dropZone = container.firstChild;
35
- fireEvent.dragOver(dropZone, { dataTransfer: { types: ['Files'] } });
36
- expect(dropZone).toHaveClass('isActive');
37
- fireEvent.dragLeave(dropZone);
38
- expect(dropZone).not.toHaveClass('isActive');
39
- });
40
- it('should calls onAppendFile with the dropped file', function () {
17
+ it('should call onAppendFile when file is dropped', function () {
41
18
  var file = new File(['test content'], 'test.png', { type: 'image/png' });
42
- var container = setUp().container;
43
- var dropZone = container.firstChild;
19
+ setUp();
20
+ var dropZone = screen.getByRole('button', { name: 'Drop files here' });
44
21
  fireEvent.drop(dropZone, {
45
22
  dataTransfer: {
46
23
  files: [file],
@@ -49,14 +26,4 @@ describe('TargetBox', function () {
49
26
  });
50
27
  expect(mockOnAppendFile).toHaveBeenCalledWith(file);
51
28
  });
52
- it('should does not call onAppendFile if dropped item is not of file type', function () {
53
- var container = setUp().container;
54
- var dropZone = container.firstChild;
55
- fireEvent.drop(dropZone, {
56
- dataTransfer: {
57
- types: ['Text']
58
- }
59
- });
60
- expect(mockOnAppendFile).not.toHaveBeenCalled();
61
- });
62
29
  });
@@ -123,7 +123,7 @@ var EntitySelector = function (_a) {
123
123
  return (__assign(__assign({}, (TextFieldProps || {})), (_a = {}, _a['data-reltio-id'] = 'reltio-entity-selector', _a)));
124
124
  }, [TextFieldProps]);
125
125
  return (react_1.default.createElement(react_1.default.Fragment, null,
126
- react_1.default.createElement(DropDownSelector_1.DropDownSelector, __assign({ value: !(0, ramda_1.isEmpty)(entity) ? entity : undefined, inputValue: inputValue, onInputChange: handleInputChange, getOptions: getOptions, getOptionLabel: (0, ramda_1.prop)('entityLabel'), onChange: handleChange, onCreate: handleCreate, onClear: handleClear, label: label, createLabel: createLabel, canCreateOption: canCreateEntity, components: __assign(__assign({ Option: EntityOption_1.EntityOption, SingleValue: SingleValue_1.SingleValue }, groupComponent), clearComponent), currentEntityType: currentEntityType, isClearable: true, disableLinkClick: disableLinkClick, TextFieldProps: textFieldProps }, dropDownSelectorProps)),
126
+ react_1.default.createElement(DropDownSelector_1.DropDownSelector, __assign({ key: entityTypesUris.join(','), value: !(0, ramda_1.isEmpty)(entity) ? entity : undefined, inputValue: inputValue, onInputChange: handleInputChange, getOptions: getOptions, getOptionLabel: (0, ramda_1.prop)('entityLabel'), onChange: handleChange, onCreate: handleCreate, onClear: handleClear, label: label, createLabel: createLabel, canCreateOption: canCreateEntity, components: __assign(__assign({ Option: EntityOption_1.EntityOption, SingleValue: SingleValue_1.SingleValue }, groupComponent), clearComponent), currentEntityType: currentEntityType, isClearable: true, disableLinkClick: disableLinkClick, TextFieldProps: textFieldProps }, dropDownSelectorProps)),
127
127
  isTempEntity && (react_1.default.createElement("div", { "data-reltio-id": "entity-creator", className: styles.creatorWrapper },
128
128
  react_1.default.createElement(EntityCreator_1.EntityCreator, { mode: mode, attributeTypesSelectionStrategy: attributeTypesSelectionStrategy, entityType: currentEntityType, entityUri: entity.entityUri })))));
129
129
  };