@reltio/sources 1.4.1585 → 1.4.1586-mui5

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 (94) hide show
  1. package/index.ts +1 -0
  2. package/package.json +38 -21
  3. package/public/bundle.js +205 -0
  4. package/public/bundle.js.LICENSE.txt +79 -0
  5. package/public/package.json +22 -0
  6. package/scripts/build/index.js +20 -0
  7. package/src/components/CrosswalkTreeView/CrosswalkTreeView.tsx +47 -0
  8. package/src/components/CrosswalkTreeView/__tests__/CrosswalkTreeView.spec.tsx +72 -0
  9. package/src/components/CrosswalkTreeView/__tests__/helpers.spec.ts +961 -0
  10. package/src/components/CrosswalkTreeView/helpers.ts +91 -0
  11. package/src/components/CrosswalkTreeView/styles.ts +10 -0
  12. package/src/components/EmptyState/EmptyState.tsx +20 -0
  13. package/src/components/EmptyState/__tests__/EmptyState.test.tsx +13 -0
  14. package/src/components/EmptyState/icons/EmptySources.svg +43 -0
  15. package/src/components/EmptyState/styles.ts +19 -0
  16. package/src/components/LegendTable/LegendTable.tsx +124 -0
  17. package/src/components/LegendTable/LegendTableRow/ContributorRow/ContributorRow.tsx +46 -0
  18. package/src/components/LegendTable/LegendTableRow/ContributorRow/__tests__/ContributorRow.test.tsx +103 -0
  19. package/src/components/LegendTable/LegendTableRow/ContributorRow/styles.ts +31 -0
  20. package/src/components/LegendTable/LegendTableRow/LegendTableRow.tsx +179 -0
  21. package/src/components/LegendTable/LegendTableRow/__tests__/LegendTableRow.test.tsx +371 -0
  22. package/src/components/LegendTable/LegendTableRow/styles.ts +31 -0
  23. package/src/components/LegendTable/__tests__/LegendTable.test.tsx +273 -0
  24. package/src/components/LegendTable/__tests__/helpers.test.ts +541 -0
  25. package/src/components/LegendTable/helpers.ts +64 -0
  26. package/src/components/LegendTable/styles.ts +17 -0
  27. package/src/components/LegendView/LegendView.tsx +201 -0
  28. package/src/components/LegendView/__tests__/LegendView.test.tsx +307 -0
  29. package/src/components/LegendView/styles.ts +51 -0
  30. package/src/components/RightSidePanel/RightSidePanel.tsx +25 -0
  31. package/src/components/RightSidePanel/__tests__/RightSidePanel.test.tsx +28 -0
  32. package/src/components/RightSidePanel/styles.ts +14 -0
  33. package/src/components/RulesestsSelector/RulesestsSelector.tsx +31 -0
  34. package/src/components/RulesestsSelector/RulesetOption/RulesetOption.tsx +25 -0
  35. package/src/components/RulesestsSelector/RulesetOption/__tests__/RulesetOption.test.tsx +25 -0
  36. package/src/components/RulesestsSelector/RulesetOption/styles.ts +27 -0
  37. package/src/components/RulesestsSelector/RulesetsMenuList/RulesetsMenuList.tsx +14 -0
  38. package/src/components/RulesestsSelector/__tests__/RulesetsSelector.test.tsx +91 -0
  39. package/src/components/RulesestsSelector/styles.ts +7 -0
  40. package/src/components/SankeyChart/Link.tsx +31 -0
  41. package/src/components/SankeyChart/MergeTooltip.tsx +37 -0
  42. package/src/components/SankeyChart/Node.tsx +137 -0
  43. package/src/components/SankeyChart/SankeyChart.tsx +103 -0
  44. package/src/components/SankeyChart/__tests__/Link.spec.tsx +127 -0
  45. package/src/components/SankeyChart/__tests__/MergeTooltip.spec.tsx +22 -0
  46. package/src/components/SankeyChart/__tests__/Node.spec.tsx +248 -0
  47. package/src/components/SankeyChart/__tests__/SankeyChart.spec.tsx +161 -0
  48. package/src/components/SankeyChart/__tests__/__snapshots__/SankeyChart.spec.tsx.snap +183 -0
  49. package/src/components/SankeyChart/sankey.ts +322 -0
  50. package/src/components/SankeyChart/styles.ts +41 -0
  51. package/src/components/SankeyChart/useSankey.tsx +44 -0
  52. package/src/components/SelectableTree/SelectableTree.tsx +46 -0
  53. package/src/components/SelectableTree/__tests__/SelectableTree.test.tsx +28 -0
  54. package/src/components/SelectableTree/__tests__/__snapshots__/SelectableTree.test.tsx.snap +59 -0
  55. package/src/components/SelectableTree/styles.ts +42 -0
  56. package/src/components/SourcesView/SourcesView.tsx +318 -0
  57. package/src/components/SourcesView/__tests__/IntegrationSourcesView.spec.tsx +199 -0
  58. package/src/components/SourcesView/__tests__/SourcesView.spec.tsx +903 -0
  59. package/src/components/SourcesView/__tests__/data/metadata.data.ts +27 -0
  60. package/src/components/SourcesView/__tests__/data/store.data.ts +65 -0
  61. package/src/components/SourcesView/icons/LegendIcon.svg +8 -0
  62. package/src/components/SourcesView/index.tsx +57 -0
  63. package/src/components/SourcesView/styles.ts +44 -0
  64. package/src/components/TreeActionSnackbar/TreeActionSnackbar.tsx +38 -0
  65. package/src/components/TreeActionSnackbar/__tests__/TreeActionSnackbar.test.tsx +38 -0
  66. package/src/components/TreeActionSnackbar/styles.ts +11 -0
  67. package/src/components/UnmergeDialog/UnmergeDialog.tsx +78 -0
  68. package/src/components/UnmergeDialog/__tests__/UnmergeDialog.test.tsx +124 -0
  69. package/src/components/UnmergeDialog/__tests__/testData.data.ts +271 -0
  70. package/src/components/UnmergeDialog/styles.ts +34 -0
  71. package/src/components/UnsubscribeDialog/UnsubscribeDialog.tsx +64 -0
  72. package/src/components/UnsubscribeDialog/__tests__/UnsubscribeDialog.test.tsx +59 -0
  73. package/src/components/UnsubscribeDialog/styles.ts +31 -0
  74. package/src/hooks/__tests__/useCrosswalkTree.specs.tsx +68 -0
  75. package/src/hooks/__tests__/useCrosswalkTreeActions.specs.ts +110 -0
  76. package/src/hooks/__tests__/useCrosswalksDisplay.specs.tsx +213 -0
  77. package/src/hooks/__tests__/useEntityWithSurvivorshipGroups.specs.ts +160 -0
  78. package/src/hooks/useCrosswalkTree.ts +38 -0
  79. package/src/hooks/useCrosswalkTreeActions.ts +83 -0
  80. package/src/hooks/useCrosswalksDisplay.ts +110 -0
  81. package/src/hooks/useEntityWithSurvivorshipGroups.tsx +51 -0
  82. package/src/icons/notMatch.svg +14 -0
  83. package/src/index.ts +1 -0
  84. package/src/services/errors.ts +11 -0
  85. package/src/types/LegendMode.ts +5 -0
  86. package/src/types/SankeyChartData.ts +31 -0
  87. package/src/types/SourcesSavedState.ts +3 -0
  88. package/src/types/UnmergeContributorEvent.ts +7 -0
  89. package/src/types/UnsubscribeContributorEvent.ts +6 -0
  90. package/src/types/index.ts +4 -0
  91. package/tsconfig.json +4 -0
  92. package/webpack.config.js +10 -0
  93. package/bundle.js +0 -2
  94. package/bundle.js.LICENSE.txt +0 -42
@@ -0,0 +1,318 @@
1
+ import React, {useCallback, useEffect, useMemo, useState} from 'react';
2
+ import {Dispatch} from 'redux';
3
+ import {connect} from 'react-redux';
4
+ import i18n from 'ui-i18n';
5
+ import {equals, pipe, pluck, propEq, reject} from 'ramda';
6
+ import mdmModule, {HistoryEvent, profile} from '@reltio/mdm-module';
7
+ import {
8
+ ApiError,
9
+ ApiErrorCode,
10
+ AttributeType,
11
+ collectContributorsFromTree,
12
+ Entity,
13
+ getEntityType,
14
+ Metadata,
15
+ SourcesPerspectiveConfig
16
+ } from '@reltio/mdm-sdk';
17
+ import {
18
+ AttributesTable,
19
+ CrosswalkDragLayer,
20
+ CrosswalksDisplayProvider,
21
+ ExpandedAttributesProvider,
22
+ HistoryHeader,
23
+ HistoryPanelEmptyState,
24
+ HistoryView,
25
+ ProfileResizablePanes,
26
+ ScreenProfileBand,
27
+ useDidUpdateEffect,
28
+ useHistory,
29
+ useHistoryEnabled,
30
+ useHistorySlice,
31
+ useModifiedEntity,
32
+ useSavedState,
33
+ useSnackbar
34
+ } from '@reltio/components';
35
+ import Typography from '@mui/material/Typography';
36
+ import Divider from '@mui/material/Divider';
37
+ import HistoryIcon from '@mui/icons-material/History';
38
+ import {RightSidePanel} from '../RightSidePanel/RightSidePanel';
39
+ import LegendView from '../LegendView/LegendView';
40
+ import {LegendMode, SourcesSavedState} from '../../types';
41
+ import {useCrosswalkTree} from '../../hooks/useCrosswalkTree';
42
+ import LegendIcon from './icons/LegendIcon.svg';
43
+ import {showErrorMessage} from '../../services/errors';
44
+ import {useCrosswalkTreeActions} from '../../hooks/useCrosswalkTreeActions';
45
+ import {useCrosswalksDisplay} from '../../hooks/useCrosswalksDisplay';
46
+ import {useEntityWithSurvivorshipGroups} from '../../hooks/useEntityWithSurvivorshipGroups';
47
+ import HTML5Backend from 'react-dnd-html5-backend';
48
+ import {DndProvider} from 'react-dnd';
49
+ import EmptyState from '../EmptyState/EmptyState';
50
+ import TreeActionSnackbar from '../TreeActionSnackbar/TreeActionSnackbar';
51
+ import {RulesetsSelector} from '../RulesestsSelector/RulesestsSelector';
52
+ import {useStyles} from './styles';
53
+
54
+ const perspectiveId = 'source';
55
+
56
+ type Props = {
57
+ config: SourcesPerspectiveConfig;
58
+ entity: Entity;
59
+ metadata: Metadata;
60
+ saveState: (state: SourcesSavedState) => void;
61
+ getSavedState: () => Promise<SourcesSavedState>;
62
+ dispatch: Dispatch;
63
+ historyEvent: HistoryEvent;
64
+ };
65
+
66
+ enum ActivePanel {
67
+ Legend,
68
+ History
69
+ }
70
+
71
+ const SourcesView = ({
72
+ config,
73
+ entity: defaultEntity,
74
+ metadata,
75
+ getSavedState,
76
+ saveState,
77
+ dispatch,
78
+ historyEvent
79
+ }: Props) => {
80
+ const styles = useStyles();
81
+ const [activeMode, setActiveMode] = useState(LegendMode.Crosswalk);
82
+ const [isCrosswalkTreeLoading, setIsCrosswalkTreeLoading] = useState(false);
83
+
84
+ const {
85
+ survivorshipGroups,
86
+ currentSurvivorshipGroupUri,
87
+ onChangeSurvivorshipGroup,
88
+ entity,
89
+ isDefaultSurvivorshipGroupUri,
90
+ isLoading: isEntityLoading
91
+ } = useEntityWithSurvivorshipGroups(defaultEntity);
92
+
93
+ const {isHistoryEnabled, isProfilePersisted} = useHistoryEnabled({
94
+ perspectiveId,
95
+ entity,
96
+ historyButtonId: ActivePanel.History
97
+ });
98
+
99
+ const persistedEntity = isProfilePersisted ? entity : null;
100
+
101
+ const entityUri = persistedEntity?.uri;
102
+ const entityType = getEntityType(metadata, entity?.type);
103
+
104
+ const {historySlice} = useHistorySlice({entity: persistedEntity, historyEvent});
105
+
106
+ const [selectedAttrTypes, setSelectedAttrTypes] = useState<AttributeType[]>();
107
+ useDidUpdateEffect(() => {
108
+ setSelectedAttrTypes(undefined);
109
+ }, [historySlice]);
110
+ useDidUpdateEffect(() => {
111
+ setSelectedAttrTypes(undefined);
112
+ }, [entityUri]);
113
+
114
+ const {SnackbarRenderer, showSnackbarMessage} = useSnackbar({
115
+ anchorOrigin: {vertical: 'top', horizontal: 'center'},
116
+ showDismiss: true
117
+ });
118
+ const {isLoaded, savedState} = useSavedState<SourcesSavedState>(getSavedState);
119
+ const [visibleColumns, setVisibleColumns] = useState<string[]>();
120
+ useEffect(() => {
121
+ if (isLoaded) {
122
+ setVisibleColumns(savedState.visibleColumns);
123
+ }
124
+ }, [isLoaded]); // eslint-disable-line
125
+ useEffect(() => {
126
+ const hasVisibleColumnsChanged = !equals(visibleColumns, savedState.visibleColumns);
127
+ if (isLoaded && hasVisibleColumnsChanged) {
128
+ saveState({visibleColumns});
129
+ }
130
+ }, [visibleColumns]); // eslint-disable-line
131
+
132
+ const onCrosswalkTreeLoaded = useCallback(() => {
133
+ setIsCrosswalkTreeLoading(false);
134
+ }, []);
135
+
136
+ const {crosswalkTree, reload: reloadCrosswalkTree} = useCrosswalkTree({
137
+ entityUri: historySlice?.aEntity.uri || entityUri,
138
+ onSuccess: onCrosswalkTreeLoaded
139
+ });
140
+ const contributors = useMemo(() => collectContributorsFromTree(crosswalkTree), [crosswalkTree]);
141
+
142
+ const refreshEntity = useCallback(() => {
143
+ entityUri &&
144
+ dispatch(
145
+ profile.entity.actions.loadEntity({
146
+ viewId: config.id,
147
+ uri: entityUri
148
+ })
149
+ );
150
+ }, [entityUri, config, dispatch]);
151
+
152
+ const refreshData = useCallback(pipe(refreshEntity, reloadCrosswalkTree), [refreshEntity, reloadCrosswalkTree]);
153
+
154
+ const {
155
+ modifiedEntity,
156
+ crosswalksMap,
157
+ newlyCreatedAttributes,
158
+ onDeleteAttribute,
159
+ onPinAttribute,
160
+ onIgnoreAttribute,
161
+ onEditAttribute,
162
+ onAddAttribute
163
+ } = useModifiedEntity({
164
+ entity: historySlice?.aEntity || persistedEntity,
165
+ onModify: refreshData,
166
+ onError: showErrorMessage
167
+ });
168
+
169
+ const displayProps = useCrosswalksDisplay({activeMode, contributors, entity});
170
+ const onShowMessage = useCallback((message: string, entity?: Entity) => {
171
+ showSnackbarMessage(entity ? <TreeActionSnackbar entity={entity} message={message} /> : message);
172
+ }, []);
173
+
174
+ const {addCrosswalk, deleteCrosswalk, editCrosswalk, unmergeContributor, unsubscribeContributor} =
175
+ useCrosswalkTreeActions({
176
+ onShowMessage,
177
+ onSuccess: refreshData,
178
+ onError: useCallback(
179
+ (error: ApiError) => {
180
+ showErrorMessage(error);
181
+ if (error.errorCode === ApiErrorCode.CROSSWALK_NOT_FOUND) {
182
+ refreshData();
183
+ }
184
+ },
185
+ [refreshData]
186
+ ),
187
+ onLoad: useCallback(() => setIsCrosswalkTreeLoading(true), [])
188
+ });
189
+
190
+ const {
191
+ historyFilter,
192
+ onApplyFilter,
193
+ isLoading: isHistoryLoading,
194
+ historicUris,
195
+ historyWithTotal,
196
+ canLoadMore,
197
+ onLoadMore
198
+ } = useHistory({entity: persistedEntity, enabled: isHistoryEnabled});
199
+
200
+ const tabs = [
201
+ {
202
+ buttonProps: {
203
+ id: ActivePanel.Legend,
204
+ icon: LegendIcon,
205
+ tooltipTitle: i18n.text('Legend')
206
+ },
207
+ title: <Typography variant="h6">{i18n.text('Legend')}</Typography>,
208
+ content: (
209
+ <LegendView
210
+ activeMode={activeMode}
211
+ onChangeMode={setActiveMode}
212
+ entity={historySlice?.aEntity || persistedEntity}
213
+ crosswalkTree={crosswalkTree}
214
+ contributors={contributors}
215
+ selectedAttributeTypes={selectedAttrTypes}
216
+ readOnly={!!historySlice || isCrosswalkTreeLoading}
217
+ onAddCrosswalk={addCrosswalk}
218
+ onUnmergeContributor={unmergeContributor}
219
+ onUnsubscribeContributor={unsubscribeContributor}
220
+ onEditCrosswalk={editCrosswalk}
221
+ onDeleteCrosswalk={deleteCrosswalk}
222
+ />
223
+ )
224
+ },
225
+ {
226
+ buttonProps: {
227
+ id: ActivePanel.History,
228
+ icon: HistoryIcon,
229
+ tooltipTitle: i18n.text('History')
230
+ },
231
+ title: (
232
+ <HistoryHeader
233
+ total={(historicUris?.length || 0) + 1}
234
+ entityType={entityType}
235
+ filter={historyFilter}
236
+ onApplyFilter={onApplyFilter}
237
+ />
238
+ ),
239
+ content: isProfilePersisted ? (
240
+ <HistoryView
241
+ isLoading={isHistoryLoading}
242
+ historyWithTotal={historyWithTotal}
243
+ contributorsUris={historicUris}
244
+ entityUri={entityUri}
245
+ historyEvent={historyEvent}
246
+ onLoadMore={onLoadMore}
247
+ canLoadMore={canLoadMore}
248
+ />
249
+ ) : (
250
+ <HistoryPanelEmptyState />
251
+ )
252
+ }
253
+ ];
254
+ const additionalHeaderItems = (
255
+ <>
256
+ <RulesetsSelector
257
+ survivorshipGroups={survivorshipGroups}
258
+ currentSurvivorshipGroupUri={currentSurvivorshipGroupUri}
259
+ onChange={onChangeSurvivorshipGroup}
260
+ />
261
+ <Divider className={styles.headerDivider} orientation="vertical" />
262
+ </>
263
+ );
264
+
265
+ return (
266
+ <div className={styles.sourcesView}>
267
+ <CrosswalksDisplayProvider {...displayProps}>
268
+ <DndProvider backend={HTML5Backend}>
269
+ <CrosswalkDragLayer />
270
+ <ProfileResizablePanes
271
+ perspectiveId={perspectiveId}
272
+ buttonsProps={pipe(reject(propEq('hidden', true)), pluck('buttonProps'))(tabs)}
273
+ >
274
+ <>
275
+ <ScreenProfileBand entity={entity} historySlice={historySlice} />
276
+ {isProfilePersisted ? (
277
+ <ExpandedAttributesProvider attributeUris={newlyCreatedAttributes}>
278
+ <AttributesTable
279
+ className={styles.attributesTable}
280
+ isLoading={isEntityLoading}
281
+ visibleColumns={visibleColumns}
282
+ onChangeVisibleColumns={setVisibleColumns}
283
+ entity={modifiedEntity}
284
+ crosswalksMap={crosswalksMap}
285
+ selectedAttributeTypes={selectedAttrTypes}
286
+ onSelectAttributeTypes={setSelectedAttrTypes}
287
+ readOnly={!!historySlice || !isDefaultSurvivorshipGroupUri}
288
+ onDelete={onDeleteAttribute}
289
+ onPin={onPinAttribute}
290
+ onIgnore={onIgnoreAttribute}
291
+ onEdit={onEditAttribute}
292
+ onAdd={onAddAttribute}
293
+ additionalHeaderItems={additionalHeaderItems}
294
+ activeSurvivorshipGroupUri={currentSurvivorshipGroupUri}
295
+ />
296
+ </ExpandedAttributesProvider>
297
+ ) : (
298
+ <EmptyState />
299
+ )}
300
+ </>
301
+ <RightSidePanel tabs={tabs} />
302
+ </ProfileResizablePanes>
303
+ </DndProvider>
304
+ </CrosswalksDisplayProvider>
305
+ <SnackbarRenderer />
306
+ </div>
307
+ );
308
+ };
309
+
310
+ const mapStateToProps = (state) => {
311
+ return {
312
+ entity: mdmModule.selectors.getEntity(state),
313
+ metadata: mdmModule.selectors.getMetadata(state),
314
+ historyEvent: mdmModule.selectors.getHistoryEvent(state)
315
+ };
316
+ };
317
+
318
+ export default connect(mapStateToProps)(SourcesView);
@@ -0,0 +1,199 @@
1
+ import React, {ReactNode} from 'react';
2
+ import {mockResizeObserver} from 'jsdom-testing-mocks';
3
+ import {Provider} from 'react-redux';
4
+ import * as mdmSdk from '@reltio/mdm-sdk';
5
+ import {act, render, screen, within} from '@testing-library/react';
6
+ import userEvent from '@testing-library/user-event';
7
+ import {ActionsHookProvider, PerspectivesSettingsContext} from '@reltio/components';
8
+ import SourcesView from '../SourcesView';
9
+ import {createTestStore} from '../../../../../../__mocks__/store-utils';
10
+ import {SourcesSavedState} from '../../../types';
11
+ import {createInitialState} from './data/store.data';
12
+
13
+ jest.mock('@reltio/mdm-sdk', () => ({
14
+ ...jest.requireActual<Record<string, unknown>>('@reltio/mdm-sdk'),
15
+ getAllUsersForTenant: jest.fn().mockReturnValue(Promise.resolve([])),
16
+ getEntityTimeSlice: jest.fn().mockReturnValue(Promise.resolve({})),
17
+ getCrosswalkTree: jest.fn(),
18
+ unmergeContributor: jest.fn()
19
+ }));
20
+
21
+ describe('SourcesView tests', () => {
22
+ const resizeObserver = mockResizeObserver();
23
+ const getCrosswalkTreeSpy = jest.spyOn(mdmSdk, 'getCrosswalkTree');
24
+ let resolveSavedState;
25
+
26
+ const defaultConfig = {
27
+ id: 'SourcesViewId'
28
+ };
29
+
30
+ const setUp = async ({config = defaultConfig, initialState = createInitialState()} = {}) => {
31
+ const user = userEvent.setup();
32
+ const store = createTestStore(initialState);
33
+ const saveState = jest.fn();
34
+ const getSavedState = jest.fn(
35
+ () =>
36
+ new Promise((_resolve) => {
37
+ resolveSavedState = _resolve;
38
+ })
39
+ ) as () => Promise<SourcesSavedState>;
40
+ const settingsContext = {settings: {source: {active: 0, width: 480}}, onChange: () => {}};
41
+ const Providers = ({children}: {children: ReactNode}) => (
42
+ <Provider store={store}>
43
+ <PerspectivesSettingsContext.Provider value={settingsContext}>
44
+ <ActionsHookProvider hook={() => () => {}}>{children}</ActionsHookProvider>
45
+ </PerspectivesSettingsContext.Provider>
46
+ </Provider>
47
+ );
48
+ const renderer = render(<SourcesView config={config} saveState={saveState} getSavedState={getSavedState} />, {
49
+ wrapper: Providers
50
+ });
51
+ const tree = await screen.findByTestId('reltio-crosswalk-tree');
52
+ resizeObserver.mockElementSize(tree, {contentBoxSize: {inlineSize: 400, blockSize: 400}});
53
+ act(() => {
54
+ resizeObserver.resize();
55
+ });
56
+ return {user, ...renderer};
57
+ };
58
+
59
+ const unmergeContributorSpy = jest.spyOn(mdmSdk, 'unmergeContributor');
60
+ unmergeContributorSpy.mockReturnValue(Promise.resolve({}));
61
+
62
+ describe('Legend behaviour', () => {
63
+ it('should open unmerge dialog after clicking on node in crosswalk tree', async () => {
64
+ getCrosswalkTreeSpy.mockReturnValue(
65
+ Promise.resolve({
66
+ uri: 'entities/1mGpgPSC',
67
+ crosswalks: [
68
+ {
69
+ ownerType: 'entity',
70
+ type: 'configuration/sources/Reltio',
71
+ uri: 'entities/1mGpgPSC/crosswalks/5JS297jHk',
72
+ value: '1mGpgPSC'
73
+ }
74
+ ],
75
+ merges: [
76
+ {
77
+ losers: [
78
+ {
79
+ uri: 'entities/1OCFJIn5',
80
+ crosswalks: [
81
+ {
82
+ ownerType: 'entity',
83
+ type: 'configuration/sources/Reltio',
84
+ uri: 'entities/1mGpgPSC/crosswalks/4eQNj0MiJ',
85
+ value: '1OCFJIn5'
86
+ },
87
+ {
88
+ ownerType: 'relation',
89
+ type: 'configuration/sources/Reltio',
90
+ uri: 'relations/1Idz1R0t/crosswalks/5pO01Grhz',
91
+ value: '1Idz1R0t'
92
+ }
93
+ ]
94
+ }
95
+ ],
96
+ time: 1678135069760
97
+ }
98
+ ]
99
+ })
100
+ );
101
+ const {user} = await setUp();
102
+ await act(async () => {
103
+ await resolveSavedState({
104
+ visibleColumns: ['ovValues', 'name1', 'name2']
105
+ });
106
+ });
107
+ const nodes = await screen.findAllByTestId('reltio-sankey-chart-node');
108
+ await user.click(nodes[0]);
109
+ const popup = await screen.findByTestId('reltio-unmerge-popup');
110
+ const unmergePopup = within(popup).getByRole('button', {name: 'Unmerge'});
111
+ await user.click(unmergePopup);
112
+ await screen.findByRole('heading', {level: 2, name: 'Unmerge'});
113
+ const dialog = screen.getByRole('dialog');
114
+ await user.click(within(dialog).getByRole('button', {name: 'Unmerge'}));
115
+ expect(unmergeContributorSpy).toBeCalledWith({
116
+ entityUri: 'entities/1mGpgPSC',
117
+ contributorUri: 'entities/1mGpgPSC',
118
+ operationType: 'unmerge'
119
+ });
120
+ });
121
+
122
+ it('should not show unmerge option if there is no merges in crosswalk tree', async () => {
123
+ getCrosswalkTreeSpy.mockReturnValue(
124
+ Promise.resolve({
125
+ uri: 'entities/1mGpgPSC',
126
+ crosswalks: [
127
+ {
128
+ ownerType: 'entity',
129
+ type: 'configuration/sources/Reltio',
130
+ uri: 'entities/1mGpgPSC/crosswalks/5JS297jHk',
131
+ value: '1mGpgPSC'
132
+ }
133
+ ]
134
+ })
135
+ );
136
+ const {user} = await setUp();
137
+ await act(async () => {
138
+ await resolveSavedState({
139
+ visibleColumns: ['ovValues', 'name1', 'name2']
140
+ });
141
+ });
142
+ const nodes = await screen.findAllByTestId('reltio-sankey-chart-node');
143
+ await user.click(nodes[0]);
144
+ const popup = screen.queryByTestId('reltio-unmerge-popup');
145
+ expect(popup).not.toBeInTheDocument();
146
+ });
147
+
148
+ it('should not show unmerge option if user does not have permission to unmerge', async () => {
149
+ getCrosswalkTreeSpy.mockReturnValue(
150
+ Promise.resolve({
151
+ uri: 'entities/1mGpgPSC',
152
+ crosswalks: [
153
+ {
154
+ ownerType: 'entity',
155
+ type: 'configuration/sources/Reltio',
156
+ uri: 'entities/1mGpgPSC/crosswalks/5JS297jHk',
157
+ value: '1mGpgPSC'
158
+ }
159
+ ],
160
+ merges: [
161
+ {
162
+ losers: [
163
+ {
164
+ uri: 'entities/1OCFJIn5',
165
+ crosswalks: [
166
+ {
167
+ ownerType: 'entity',
168
+ type: 'configuration/sources/Reltio',
169
+ uri: 'entities/1mGpgPSC/crosswalks/4eQNj0MiJ',
170
+ value: '1OCFJIn5'
171
+ },
172
+ {
173
+ ownerType: 'relation',
174
+ type: 'configuration/sources/Reltio',
175
+ uri: 'relations/1Idz1R0t/crosswalks/5pO01Grhz',
176
+ value: '1Idz1R0t'
177
+ }
178
+ ]
179
+ }
180
+ ],
181
+ time: 1678135069760
182
+ }
183
+ ]
184
+ })
185
+ );
186
+ const initialState = createInitialState({access: 'READ'});
187
+ const {user} = await setUp({initialState});
188
+ await act(async () => {
189
+ await resolveSavedState({
190
+ visibleColumns: ['ovValues', 'name1', 'name2']
191
+ });
192
+ });
193
+ const nodes = await screen.findAllByTestId('reltio-sankey-chart-node');
194
+ await user.click(nodes[0]);
195
+ const popup = screen.queryByTestId('reltio-unmerge-popup');
196
+ expect(popup).not.toBeInTheDocument();
197
+ });
198
+ });
199
+ });