@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,213 @@
1
+ import * as mdmSdk from '@reltio/mdm-sdk';
2
+ import {LegendMode} from '../../types';
3
+ import {useCrosswalksDisplay} from '../useCrosswalksDisplay';
4
+ import {renderHook, act} from '@testing-library/react-hooks';
5
+
6
+ jest.mock('@reltio/mdm-sdk', () => ({
7
+ ...jest.requireActual<Record<string, unknown>>('@reltio/mdm-sdk'),
8
+ getSourceColor: jest.fn(),
9
+ getContributorColor: jest.fn(),
10
+ getCrosswalkColor: jest.fn(),
11
+ getCrosswalkId: jest.fn(),
12
+ findContributorForCrosswalk: jest.fn(),
13
+ debounce: (x) => x
14
+ }));
15
+
16
+ describe('useCrosswalksDisplay behaviour', () => {
17
+ const getCrosswalksDisplay = (initialProps) => {
18
+ return renderHook(useCrosswalksDisplay, {initialProps}).result.current;
19
+ };
20
+
21
+ const contrCrosswalks = [{uri: 'testContrCrosswalk', type: 'test', value: 'test'}];
22
+
23
+ const getSourceColorMock = jest.spyOn(mdmSdk, 'getSourceColor').mockReturnValue('#111111');
24
+ const getCrosswalkColorMock = jest.spyOn(mdmSdk, 'getCrosswalkColor').mockReturnValue('#000000');
25
+ const getCrosswalkIdMock = jest.spyOn(mdmSdk, 'getCrosswalkId').mockReturnValue('testId');
26
+ const getContributorColorMock = jest.spyOn(mdmSdk, 'getContributorColor').mockReturnValue('#FFFFFF');
27
+ const findContributorForCrosswalkMock = jest
28
+ .spyOn(mdmSdk, 'findContributorForCrosswalk')
29
+ .mockReturnValue({uri: 'testContrId', crosswalks: contrCrosswalks});
30
+
31
+ const contributors = [{uri: 'test'}];
32
+
33
+ afterEach(() => {
34
+ jest.clearAllMocks();
35
+ });
36
+
37
+ it('should return correct getCrosswalkColor function for LegendMode.Crosswalk', () => {
38
+ const {getCrosswalkColor} = getCrosswalksDisplay({
39
+ activeMode: LegendMode.Crosswalk,
40
+ contributors: contributors
41
+ });
42
+
43
+ const crosswalk = {uri: 'testCrosswalk', type: 'testType', value: 'testValue'};
44
+
45
+ const color = getCrosswalkColor(crosswalk);
46
+ expect(getCrosswalkIdMock).toBeCalledWith(crosswalk);
47
+ expect(getCrosswalkColorMock).toBeCalledWith('testId');
48
+ expect(color).toBe('#000000');
49
+ });
50
+
51
+ it('should return correct getCrosswalkColor function for LegendMode.Source', () => {
52
+ const {getCrosswalkColor} = getCrosswalksDisplay({
53
+ activeMode: LegendMode.Source,
54
+ contributors: contributors
55
+ });
56
+
57
+ const crosswalk = {uri: 'testCrosswalk', type: 'testType', value: 'testValue'};
58
+
59
+ const color = getCrosswalkColor(crosswalk);
60
+ expect(getSourceColorMock).toBeCalledWith(crosswalk.type);
61
+ expect(color).toBe('#111111');
62
+ });
63
+
64
+ it('should return correct getCrosswalkColor function for LegendMode.Contributor', () => {
65
+ const {getCrosswalkColor} = getCrosswalksDisplay({
66
+ activeMode: LegendMode.Contributor,
67
+ contributors: contributors
68
+ });
69
+
70
+ const crosswalk = {uri: 'testCrosswalk', type: 'testType', value: 'testValue'};
71
+
72
+ const color = getCrosswalkColor(crosswalk);
73
+ expect(findContributorForCrosswalkMock).toBeCalledWith(contributors, crosswalk);
74
+ expect(getContributorColorMock).toBeCalledWith('testContrId');
75
+ expect(color).toBe('#FFFFFF');
76
+ });
77
+
78
+ it('should return empty array of highlighted crosswalks by default', () => {
79
+ const {highlightedCrosswalks} = getCrosswalksDisplay({
80
+ activeMode: LegendMode.Contributor,
81
+ contributors: contributors
82
+ });
83
+
84
+ expect(highlightedCrosswalks).toEqual([]);
85
+ });
86
+
87
+ it('should return empty array of focused crosswalks by default', () => {
88
+ const {focusedCrosswalks} = getCrosswalksDisplay({
89
+ activeMode: LegendMode.Contributor,
90
+ contributors: contributors
91
+ });
92
+
93
+ expect(focusedCrosswalks).toEqual([]);
94
+ });
95
+
96
+ it('should return correct setCrosswalkHighlighted function', () => {
97
+ const initialProps = {
98
+ activeMode: LegendMode.Crosswalk,
99
+ contributors: contributors
100
+ };
101
+ const {result, rerender} = renderHook(useCrosswalksDisplay, {initialProps});
102
+
103
+ const crosswalk = {uri: 'testCrosswalk', type: 'testType', value: 'testValue'};
104
+
105
+ result.current.setCrosswalkHighlighted(undefined, true);
106
+ expect(result.current.highlightedCrosswalks).toEqual([]);
107
+
108
+ act(() => {
109
+ result.current.setCrosswalkHighlighted(crosswalk, true);
110
+ });
111
+ expect(result.current.highlightedCrosswalks).toEqual([crosswalk]);
112
+
113
+ act(() => {
114
+ result.current.setCrosswalkHighlighted(crosswalk, false);
115
+ });
116
+ expect(result.current.highlightedCrosswalks).toEqual([]);
117
+
118
+ initialProps.activeMode = LegendMode.Contributor;
119
+ rerender();
120
+ act(() => {
121
+ result.current.setCrosswalkHighlighted(crosswalk, true);
122
+ });
123
+ expect(findContributorForCrosswalkMock).toBeCalledWith(contributors, crosswalk);
124
+ expect(result.current.highlightedCrosswalks).toEqual([crosswalk, ...contrCrosswalks]);
125
+ });
126
+
127
+ it('should return correct toggleCrosswalkFocus function', () => {
128
+ const initialProps = {
129
+ activeMode: LegendMode.Crosswalk,
130
+ contributors: contributors
131
+ };
132
+ const {result, rerender} = renderHook(useCrosswalksDisplay, {initialProps});
133
+
134
+ const crosswalk = {uri: 'testCrosswalk', type: 'testType', value: 'testValue'};
135
+
136
+ result.current.toggleCrosswalkFocus(undefined);
137
+ expect(result.current.highlightedCrosswalks).toEqual([]);
138
+ expect(result.current.focusedCrosswalks).toEqual([]);
139
+
140
+ act(() => {
141
+ result.current.toggleCrosswalkFocus(crosswalk);
142
+ });
143
+ expect(result.current.highlightedCrosswalks).toEqual([crosswalk]);
144
+ expect(result.current.focusedCrosswalks).toEqual([crosswalk]);
145
+
146
+ act(() => {
147
+ result.current.toggleCrosswalkFocus(crosswalk);
148
+ });
149
+ expect(result.current.highlightedCrosswalks).toEqual([]);
150
+ expect(result.current.focusedCrosswalks).toEqual([]);
151
+
152
+ initialProps.activeMode = LegendMode.Contributor;
153
+ rerender();
154
+ act(() => {
155
+ result.current.toggleCrosswalkFocus(crosswalk);
156
+ });
157
+ expect(findContributorForCrosswalkMock).toBeCalledWith(contributors, crosswalk);
158
+ expect(result.current.highlightedCrosswalks).toEqual([crosswalk, ...contrCrosswalks]);
159
+ expect(result.current.focusedCrosswalks).toEqual([crosswalk, ...contrCrosswalks]);
160
+
161
+ act(() => {
162
+ result.current.toggleCrosswalkFocus(crosswalk);
163
+ });
164
+ expect(result.current.highlightedCrosswalks).toEqual([]);
165
+ });
166
+
167
+ it('should return correct highlightedCrosswalks when crosswalks focused and highlighted', () => {
168
+ const initialProps = {
169
+ activeMode: LegendMode.Crosswalk,
170
+ contributors: contributors
171
+ };
172
+ const {result} = renderHook(useCrosswalksDisplay, {initialProps});
173
+
174
+ const crosswalk = {uri: 'testCrosswalk', type: 'testType', value: 'testValue'};
175
+ const crosswalkHighlighted = {uri: 'testCrosswalk1', type: 'testType1', value: 'testValue1'};
176
+
177
+ act(() => {
178
+ result.current.toggleCrosswalkFocus(crosswalk);
179
+ result.current.setCrosswalkHighlighted(crosswalkHighlighted, true);
180
+ });
181
+ expect(result.current.highlightedCrosswalks).toEqual([crosswalkHighlighted, crosswalk]);
182
+ });
183
+
184
+ it('should reset focusedCrosswalks on entity change if focusedCrosswalks not empty', () => {
185
+ const initialProps = {
186
+ activeMode: LegendMode.Crosswalk,
187
+ contributors: contributors,
188
+ entity: {
189
+ uri: 'entities/uri1',
190
+ type: 'configuration/entityTypes/HCO'
191
+ }
192
+ };
193
+ const {result, rerender} = renderHook(useCrosswalksDisplay, {initialProps});
194
+ const crosswalk = {uri: 'testCrosswalk', type: 'testType', value: 'testValue'};
195
+
196
+ act(() => {
197
+ result.current.toggleCrosswalkFocus(crosswalk);
198
+ });
199
+
200
+ expect(result.current.focusedCrosswalks).toEqual([crosswalk]);
201
+
202
+ rerender(initialProps);
203
+ expect(result.current.focusedCrosswalks).toEqual([crosswalk]);
204
+
205
+ initialProps.entity = {
206
+ uri: 'entities/uri2',
207
+ type: 'configuration/entityTypes/HCO2'
208
+ };
209
+
210
+ rerender(initialProps);
211
+ expect(result.current.focusedCrosswalks).toEqual([]);
212
+ });
213
+ });
@@ -0,0 +1,160 @@
1
+ import {act, renderHook} from '@testing-library/react-hooks';
2
+ import * as reactRedux from 'react-redux';
3
+ import * as mdmSdk from '@reltio/mdm-sdk';
4
+ import {useEntityWithSurvivorshipGroups} from '../useEntityWithSurvivorshipGroups';
5
+
6
+ jest.mock('@reltio/mdm-sdk', () => ({
7
+ ...jest.requireActual<Record<string, unknown>>('@reltio/mdm-sdk'),
8
+ getEntityBySurvivorshipGroupUri: jest.fn()
9
+ }));
10
+
11
+ const survivorshipGroups = [
12
+ {
13
+ uri: 'configuration/entityTypes/HCP/survivorshipGroups/survivorshipGroups2cwLEgWAo',
14
+ label: 'tests45',
15
+ description: 'rerere',
16
+ default: true,
17
+ mapping: []
18
+ },
19
+ {
20
+ uri: 'configuration/entityTypes/HCP/survivorshipGroups/survivorshipGroups3aGSPnPlj',
21
+ label: 'l1',
22
+ description: 'd1',
23
+ default: false,
24
+ mapping: []
25
+ }
26
+ ];
27
+
28
+ const store = {
29
+ tenant: {
30
+ id: 'sokol'
31
+ },
32
+ metadata: {
33
+ sokol: {
34
+ entityTypes: [{uri: 'configuration/entityTypes/HCP', survivorshipGroups}]
35
+ }
36
+ }
37
+ };
38
+
39
+ const defaultEntity = {
40
+ uri: 'entities/1',
41
+ type: 'configuration/entityTypes/HCP',
42
+ attributes: {
43
+ CountryCode: [
44
+ {
45
+ lookupCode: 'IT',
46
+ lookupRawValue: 'IT',
47
+ ov: true,
48
+ type: 'configuration/entityTypes/HCP/attributes/CountryCode',
49
+ uri: 'entities/1864oxoO/attributes/CountryCode/3TFgmPUK5',
50
+ value: 'Italy'
51
+ }
52
+ ]
53
+ }
54
+ };
55
+
56
+ const loadedEntity = {
57
+ uri: 'entities/1',
58
+ type: 'configuration/entityTypes/HCP',
59
+ attributes: {
60
+ CountryCode: [
61
+ {
62
+ lookupCode: 'IT',
63
+ lookupRawValue: 'IT',
64
+ ov: false,
65
+ type: 'configuration/entityTypes/HCP/attributes/CountryCode',
66
+ uri: 'entities/1864oxoO/attributes/CountryCode/3TFgmPUK5',
67
+ value: 'Italy'
68
+ }
69
+ ]
70
+ }
71
+ };
72
+
73
+ describe('useEntityWithSurvivorshipGroups behaviour', () => {
74
+ const getEntityBySurvivorshipGroupUriSpy = jest.spyOn(mdmSdk, 'getEntityBySurvivorshipGroupUri');
75
+
76
+ beforeEach(() => {
77
+ jest.spyOn(reactRedux, 'useSelector').mockImplementation((selector) => selector(store));
78
+ getEntityBySurvivorshipGroupUriSpy.mockResolvedValue(loadedEntity);
79
+ });
80
+
81
+ afterEach(() => {
82
+ jest.clearAllMocks();
83
+ });
84
+
85
+ it('should return survivorshipGroups correctly', () => {
86
+ const {result} = renderHook(useEntityWithSurvivorshipGroups, {initialProps: defaultEntity});
87
+ expect(result.current.survivorshipGroups).toEqual(survivorshipGroups);
88
+ });
89
+
90
+ it('should return survivorshipGroups as empty array by default if entity is null', () => {
91
+ const {result} = renderHook(useEntityWithSurvivorshipGroups, {initialProps: null});
92
+ expect(result.current.survivorshipGroups).toEqual([]);
93
+ });
94
+
95
+ it('should set default entity and default currentSurvivorshipGroupUri correctly', () => {
96
+ const {result} = renderHook(useEntityWithSurvivorshipGroups, {initialProps: defaultEntity});
97
+ expect(result.current.currentSurvivorshipGroupUri).toBe(
98
+ 'configuration/entityTypes/HCP/survivorshipGroups/survivorshipGroups2cwLEgWAo'
99
+ );
100
+ expect(result.current.entity).toEqual(defaultEntity);
101
+ });
102
+
103
+ it('onChangeSurvivorshipGroup handler should work correctly with not default uri param ', async () => {
104
+ const {result} = renderHook(useEntityWithSurvivorshipGroups, {initialProps: defaultEntity});
105
+ expect(result.current.currentSurvivorshipGroupUri).toBe(
106
+ 'configuration/entityTypes/HCP/survivorshipGroups/survivorshipGroups2cwLEgWAo'
107
+ );
108
+ expect(result.current.entity).toEqual(defaultEntity);
109
+ expect(result.current.isLoading).toBe(false);
110
+ act(() => {
111
+ result.current.onChangeSurvivorshipGroup(
112
+ 'configuration/entityTypes/HCP/survivorshipGroups/survivorshipGroups3aGSPnPlj'
113
+ );
114
+ });
115
+ expect(result.current.currentSurvivorshipGroupUri).toBe(
116
+ 'configuration/entityTypes/HCP/survivorshipGroups/survivorshipGroups3aGSPnPlj'
117
+ );
118
+ expect(result.current.isLoading).toBe(true);
119
+ expect(getEntityBySurvivorshipGroupUriSpy).toHaveBeenCalledWith(
120
+ 'entities/1',
121
+ 'configuration/entityTypes/HCP/survivorshipGroups/survivorshipGroups3aGSPnPlj'
122
+ );
123
+ await act(async () => {
124
+ return Promise.resolve();
125
+ });
126
+ expect(result.current.isLoading).toBe(false);
127
+ expect(result.current.entity).toEqual(loadedEntity);
128
+ });
129
+
130
+ it('onChangeSurvivorshipGroup handler should work correctly with default uri param ', async () => {
131
+ const {result} = renderHook(useEntityWithSurvivorshipGroups, {initialProps: defaultEntity});
132
+ await act(async () => {
133
+ result.current.onChangeSurvivorshipGroup(
134
+ 'configuration/entityTypes/HCP/survivorshipGroups/survivorshipGroups3aGSPnPlj'
135
+ );
136
+ return Promise.resolve();
137
+ });
138
+ expect(getEntityBySurvivorshipGroupUriSpy).toHaveBeenCalledTimes(1);
139
+ expect(result.current.entity).toEqual(loadedEntity);
140
+ act(() => {
141
+ result.current.onChangeSurvivorshipGroup(
142
+ 'configuration/entityTypes/HCP/survivorshipGroups/survivorshipGroups2cwLEgWAo'
143
+ );
144
+ });
145
+ expect(getEntityBySurvivorshipGroupUriSpy).toHaveBeenCalledTimes(1);
146
+ expect(result.current.entity).toEqual(defaultEntity);
147
+ });
148
+
149
+ it('should return isDefaultSurvivorshipGroupUri correctly', async () => {
150
+ const {result} = renderHook(useEntityWithSurvivorshipGroups, {initialProps: defaultEntity});
151
+ expect(result.current.isDefaultSurvivorshipGroupUri).toBe(true);
152
+ await act(async () => {
153
+ result.current.onChangeSurvivorshipGroup(
154
+ 'configuration/entityTypes/HCP/survivorshipGroups/survivorshipGroups3aGSPnPlj'
155
+ );
156
+ return Promise.resolve();
157
+ });
158
+ expect(result.current.isDefaultSurvivorshipGroupUri).toBe(false);
159
+ });
160
+ });
@@ -0,0 +1,38 @@
1
+ import {useCallback, useEffect, useState} from 'react';
2
+ import {getCrosswalkTree, CrosswalkTree} from '@reltio/mdm-sdk';
3
+ import {noop, useSafePromise} from '@reltio/components';
4
+
5
+ type Props = {
6
+ entityUri?: string;
7
+ onSuccess?: () => void;
8
+ };
9
+
10
+ export const useCrosswalkTree = ({entityUri, onSuccess = noop}: Props) => {
11
+ const [crosswalkTree, setCrosswalkTree] = useState<CrosswalkTree>(null);
12
+ const safePromise = useSafePromise();
13
+
14
+ const onError = (e) => {
15
+ console.warn('Failed to load crosswalk tree', e);
16
+ setCrosswalkTree(null);
17
+ };
18
+
19
+ const loadData = useCallback(() => {
20
+ if (entityUri) {
21
+ safePromise(getCrosswalkTree({entityUri}))
22
+ .then((results) => {
23
+ setCrosswalkTree(results);
24
+ })
25
+ .catch(onError)
26
+ .finally(onSuccess);
27
+ } else {
28
+ setCrosswalkTree(null);
29
+ onSuccess();
30
+ }
31
+ }, [entityUri, onSuccess]);
32
+
33
+ useEffect(() => {
34
+ loadData();
35
+ }, [loadData]);
36
+
37
+ return {crosswalkTree, reload: loadData};
38
+ };
@@ -0,0 +1,83 @@
1
+ import {useCallback} from 'react';
2
+ import {useSelector} from 'react-redux';
3
+ import {andThen, pipe} from 'ramda';
4
+ import i18n from 'ui-i18n';
5
+ import mdm from '@reltio/mdm-module';
6
+ import {
7
+ Entity,
8
+ unmergeContributor as unmergeContributorRequest,
9
+ unsubscribeEntityFromDataTenantEntity
10
+ } from '@reltio/mdm-sdk';
11
+ import {useCrosswalkActions, noop} from '@reltio/components';
12
+ import {UnmergeContributorEvent, UnsubscribeContributorEvent} from '../types';
13
+
14
+ type Props = {
15
+ onLoad?: () => void;
16
+ onSuccess?: () => void;
17
+ onError?: (error: unknown) => void;
18
+ onShowMessage?: (message: string, entity?: Entity) => void;
19
+ };
20
+
21
+ export const useCrosswalkTreeActions = ({
22
+ onLoad = noop,
23
+ onSuccess = noop,
24
+ onError = noop,
25
+ onShowMessage = noop
26
+ }: Props) => {
27
+ const {addCrosswalk, editCrosswalk, deleteCrosswalk} = useCrosswalkActions({onLoad, onSuccess, onError});
28
+ const dtssPath = useSelector(mdm.selectors.getDtssPath);
29
+ const tenant = useSelector(mdm.selectors.getTenant);
30
+
31
+ const handleAction = useCallback(
32
+ (request: Promise<unknown>) => {
33
+ onLoad();
34
+ request
35
+ .then(() => {
36
+ onSuccess();
37
+ })
38
+ .catch(onError);
39
+ },
40
+ [onLoad, onError, onSuccess]
41
+ );
42
+
43
+ const unmergeContributor = useCallback(
44
+ (event: UnmergeContributorEvent) =>
45
+ pipe(
46
+ unmergeContributorRequest,
47
+ andThen((response) => {
48
+ onShowMessage(i18n.text('has been unmerged'), response.b);
49
+ return response;
50
+ }),
51
+ handleAction
52
+ )(event),
53
+ [handleAction, onShowMessage]
54
+ );
55
+
56
+ const unsubscribeContributor = useCallback(
57
+ ({crosswalk, dataTenant}: UnsubscribeContributorEvent) =>
58
+ pipe(
59
+ unsubscribeEntityFromDataTenantEntity,
60
+ andThen((response) => {
61
+ if (!response.successful) throw new Error(i18n.text('Failed to unsubscribe contributor'));
62
+ return response;
63
+ }),
64
+ handleAction
65
+ )({
66
+ dtssPath,
67
+ value: crosswalk.value,
68
+ type: crosswalk.type,
69
+ sourceTable: crosswalk.sourceTable,
70
+ dataTenant: dataTenant.id,
71
+ customerTenant: tenant
72
+ }),
73
+ [handleAction, dtssPath, tenant]
74
+ );
75
+
76
+ return {
77
+ addCrosswalk,
78
+ editCrosswalk,
79
+ deleteCrosswalk,
80
+ unmergeContributor,
81
+ unsubscribeContributor
82
+ };
83
+ };
@@ -0,0 +1,110 @@
1
+ import {useCallback, useEffect, useMemo, useState, useRef} from 'react';
2
+ import {any, concat} from 'ramda';
3
+ import {LegendMode} from '../types';
4
+ import {
5
+ Contributor,
6
+ CrosswalkBase,
7
+ debounce,
8
+ Entity,
9
+ eqCrosswalks,
10
+ findContributorForCrosswalk,
11
+ getContributorColor,
12
+ getCrosswalkColor,
13
+ getCrosswalkId,
14
+ getSourceColor
15
+ } from '@reltio/mdm-sdk';
16
+
17
+ type Props = {
18
+ activeMode: LegendMode;
19
+ contributors: Contributor[];
20
+ entity: Entity;
21
+ };
22
+
23
+ export const useCrosswalksDisplay = ({activeMode, contributors, entity}: Props) => {
24
+ const getCrosswalkColorForActiveMode = useCallback(
25
+ (crosswalk: CrosswalkBase) => {
26
+ switch (activeMode) {
27
+ case LegendMode.Source:
28
+ return getSourceColor(crosswalk.type);
29
+ case LegendMode.Contributor:
30
+ return getContributorColor(findContributorForCrosswalk(contributors, crosswalk)?.uri || '');
31
+ case LegendMode.Crosswalk:
32
+ return getCrosswalkColor(getCrosswalkId(crosswalk));
33
+ }
34
+ },
35
+ [activeMode, contributors]
36
+ );
37
+ const [highlightedCrosswalks, setHighlightedCrosswalks] = useState<CrosswalkBase[]>([]);
38
+ const highlightedCrosswalksCache = useRef([]);
39
+ const applyHighlightedCrosswalks = useCallback(
40
+ debounce(() => {
41
+ setHighlightedCrosswalks([...highlightedCrosswalksCache.current]);
42
+ }, 50),
43
+ []
44
+ );
45
+ const cacheHighlightedCrosswalks = useCallback(
46
+ (arr) => {
47
+ highlightedCrosswalksCache.current = arr;
48
+ applyHighlightedCrosswalks(arr);
49
+ },
50
+ [applyHighlightedCrosswalks]
51
+ );
52
+
53
+ const setCrosswalkHighlighted = useCallback(
54
+ (crosswalk: CrosswalkBase, highlighted: boolean) => {
55
+ if (!crosswalk) return;
56
+ if (highlighted) {
57
+ if (activeMode === LegendMode.Contributor) {
58
+ const contributor = findContributorForCrosswalk(contributors, crosswalk);
59
+ cacheHighlightedCrosswalks([crosswalk, ...(contributor?.crosswalks || [])]);
60
+ } else {
61
+ cacheHighlightedCrosswalks([crosswalk]);
62
+ }
63
+ } else {
64
+ cacheHighlightedCrosswalks([]);
65
+ }
66
+ },
67
+ [activeMode, cacheHighlightedCrosswalks, contributors]
68
+ );
69
+
70
+ const [focusedCrosswalks, setFocusedCrosswalks] = useState<CrosswalkBase[]>([]);
71
+ const calculateFocusedCrosswalks = useCallback(
72
+ (prev: CrosswalkBase[], next: CrosswalkBase[]) =>
73
+ concat(
74
+ prev.filter((prevCrosswalk) => !any(eqCrosswalks(prevCrosswalk), next)),
75
+ next.filter((nextCrosswalk) => !any(eqCrosswalks(nextCrosswalk), prev))
76
+ ),
77
+ []
78
+ );
79
+ const toggleCrosswalkFocus = useCallback(
80
+ (crosswalk: CrosswalkBase) => {
81
+ if (!crosswalk) return;
82
+ if (activeMode === LegendMode.Contributor) {
83
+ const contributor = findContributorForCrosswalk(contributors, crosswalk);
84
+ setFocusedCrosswalks((prevValue) =>
85
+ calculateFocusedCrosswalks([crosswalk, ...(contributor?.crosswalks || [])], prevValue)
86
+ );
87
+ } else {
88
+ setFocusedCrosswalks((prevValue) => calculateFocusedCrosswalks([crosswalk], prevValue));
89
+ }
90
+ },
91
+ [activeMode, calculateFocusedCrosswalks, contributors]
92
+ );
93
+
94
+ useEffect(() => {
95
+ if (focusedCrosswalks.length) {
96
+ setFocusedCrosswalks([]);
97
+ }
98
+ }, [activeMode, entity]);
99
+
100
+ return {
101
+ getCrosswalkColor: getCrosswalkColorForActiveMode,
102
+ highlightedCrosswalks: useMemo(
103
+ () => [...highlightedCrosswalks, ...focusedCrosswalks],
104
+ [highlightedCrosswalks, focusedCrosswalks]
105
+ ),
106
+ focusedCrosswalks,
107
+ toggleCrosswalkFocus,
108
+ setCrosswalkHighlighted
109
+ };
110
+ };
@@ -0,0 +1,51 @@
1
+ import {useCallback, useEffect, useState} from 'react';
2
+ import {useSelector} from 'react-redux';
3
+ import {pipe, propOr, find, propEq, prop} from 'ramda';
4
+ import {getEntityType, getEntityBySurvivorshipGroupUri, Entity} from '@reltio/mdm-sdk';
5
+ import mdmModule from '@reltio/mdm-module';
6
+ import {useSafePromise} from '@reltio/components';
7
+
8
+ export const useEntityWithSurvivorshipGroups = (defaultEntity: Entity) => {
9
+ const entityTypeUri = defaultEntity?.type;
10
+ const metadata = useSelector(mdmModule.selectors.getMetadata);
11
+ const survivorshipGroups = pipe(getEntityType(metadata), propOr([], 'survivorshipGroups'))(entityTypeUri);
12
+ const defaultSurvivorshipGroupUri = pipe(find(propEq('default', true)), prop('uri'))(survivorshipGroups);
13
+ const [currentSurvivorshipGroupUri, setCurrentSurvivorshipGroupUri] = useState(null);
14
+ const [entity, setEntity] = useState(null);
15
+ const [isLoading, setIsLoading] = useState(false);
16
+ const safePromise = useSafePromise();
17
+
18
+ useEffect(() => {
19
+ if (defaultEntity) {
20
+ setEntity(defaultEntity);
21
+ setCurrentSurvivorshipGroupUri(defaultSurvivorshipGroupUri);
22
+ }
23
+ }, [defaultEntity, defaultSurvivorshipGroupUri]);
24
+
25
+ const onChangeSurvivorshipGroup = useCallback(
26
+ (survivorshipGroupUri: string) => {
27
+ setCurrentSurvivorshipGroupUri(survivorshipGroupUri);
28
+ const isDefaultSurvivorshipGroupUri = defaultSurvivorshipGroupUri === survivorshipGroupUri;
29
+ if (!isDefaultSurvivorshipGroupUri) {
30
+ setIsLoading(true);
31
+ safePromise(getEntityBySurvivorshipGroupUri(entity.uri, survivorshipGroupUri))
32
+ .then(setEntity)
33
+ .finally(() => setIsLoading(false));
34
+ } else {
35
+ setEntity(defaultEntity);
36
+ }
37
+ },
38
+ [defaultEntity, defaultSurvivorshipGroupUri, entity, safePromise]
39
+ );
40
+
41
+ const isDefaultSurvivorshipGroupUri = defaultSurvivorshipGroupUri === currentSurvivorshipGroupUri;
42
+
43
+ return {
44
+ survivorshipGroups,
45
+ currentSurvivorshipGroupUri,
46
+ onChangeSurvivorshipGroup,
47
+ entity,
48
+ isLoading,
49
+ isDefaultSurvivorshipGroupUri
50
+ };
51
+ };
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3
+ <title>Icon / Not a match</title>
4
+ <defs>
5
+ <path d="M17,13.1383198 L21.5,17.6383198 L17,22.1383198 L17,18.5003198 L15.753258,18.5 L12.265,15.021 L13.678,13.607 L16.579,16.5003198 L17,16.5003198 L17,13.1383198 Z M17,1.5 L21.5,6 L17,10.5 L17,7.138 L16.579,7.138 L5.5497951,18.1383198 L2,18.1383198 L2,16.1383198 L4.723,16.138 L15.753258,5.13831978 L17,5.138 L17,1.5 Z M5.5497951,5.5 L8.844,8.786 L7.43,10.199 L4.723,7.50031978 L2,7.5 L2,5.5 L5.5497951,5.5 Z" id="path-1"></path>
6
+ </defs>
7
+ <g id="Icon-/-Not-a-match" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
8
+ <mask id="mask-2" fill="white">
9
+ <use xlink:href="#path-1"></use>
10
+ </mask>
11
+ <g id="Combined-Shape" fill-rule="nonzero"></g>
12
+ <rect id="Icon-Color" fill-opacity="0.54" fill="#000000" mask="url(#mask-2)" x="0" y="0" width="24" height="24"></rect>
13
+ </g>
14
+ </svg>
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export {default as SourcesView} from './components/SourcesView';
@@ -0,0 +1,11 @@
1
+ import {ErrorPopup} from '@reltio/components';
2
+ import i18n from 'ui-i18n';
3
+ import {getRequestErrorMessage} from '@reltio/mdm-sdk';
4
+
5
+ export const showErrorMessage = (error: unknown) => {
6
+ console.error(error); // eslint-disable-line
7
+ ErrorPopup.addError({
8
+ title: i18n.text('Error'),
9
+ message: getRequestErrorMessage(error, i18n.text('Something went wrong'))
10
+ });
11
+ };