@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.
- package/index.ts +1 -0
- package/package.json +38 -21
- package/public/bundle.js +205 -0
- package/public/bundle.js.LICENSE.txt +79 -0
- package/public/package.json +22 -0
- package/scripts/build/index.js +20 -0
- package/src/components/CrosswalkTreeView/CrosswalkTreeView.tsx +47 -0
- package/src/components/CrosswalkTreeView/__tests__/CrosswalkTreeView.spec.tsx +72 -0
- package/src/components/CrosswalkTreeView/__tests__/helpers.spec.ts +961 -0
- package/src/components/CrosswalkTreeView/helpers.ts +91 -0
- package/src/components/CrosswalkTreeView/styles.ts +10 -0
- package/src/components/EmptyState/EmptyState.tsx +20 -0
- package/src/components/EmptyState/__tests__/EmptyState.test.tsx +13 -0
- package/src/components/EmptyState/icons/EmptySources.svg +43 -0
- package/src/components/EmptyState/styles.ts +19 -0
- package/src/components/LegendTable/LegendTable.tsx +124 -0
- package/src/components/LegendTable/LegendTableRow/ContributorRow/ContributorRow.tsx +46 -0
- package/src/components/LegendTable/LegendTableRow/ContributorRow/__tests__/ContributorRow.test.tsx +103 -0
- package/src/components/LegendTable/LegendTableRow/ContributorRow/styles.ts +31 -0
- package/src/components/LegendTable/LegendTableRow/LegendTableRow.tsx +179 -0
- package/src/components/LegendTable/LegendTableRow/__tests__/LegendTableRow.test.tsx +371 -0
- package/src/components/LegendTable/LegendTableRow/styles.ts +31 -0
- package/src/components/LegendTable/__tests__/LegendTable.test.tsx +273 -0
- package/src/components/LegendTable/__tests__/helpers.test.ts +541 -0
- package/src/components/LegendTable/helpers.ts +64 -0
- package/src/components/LegendTable/styles.ts +17 -0
- package/src/components/LegendView/LegendView.tsx +201 -0
- package/src/components/LegendView/__tests__/LegendView.test.tsx +307 -0
- package/src/components/LegendView/styles.ts +51 -0
- package/src/components/RightSidePanel/RightSidePanel.tsx +25 -0
- package/src/components/RightSidePanel/__tests__/RightSidePanel.test.tsx +28 -0
- package/src/components/RightSidePanel/styles.ts +14 -0
- package/src/components/RulesestsSelector/RulesestsSelector.tsx +31 -0
- package/src/components/RulesestsSelector/RulesetOption/RulesetOption.tsx +25 -0
- package/src/components/RulesestsSelector/RulesetOption/__tests__/RulesetOption.test.tsx +25 -0
- package/src/components/RulesestsSelector/RulesetOption/styles.ts +27 -0
- package/src/components/RulesestsSelector/RulesetsMenuList/RulesetsMenuList.tsx +14 -0
- package/src/components/RulesestsSelector/__tests__/RulesetsSelector.test.tsx +91 -0
- package/src/components/RulesestsSelector/styles.ts +7 -0
- package/src/components/SankeyChart/Link.tsx +31 -0
- package/src/components/SankeyChart/MergeTooltip.tsx +37 -0
- package/src/components/SankeyChart/Node.tsx +137 -0
- package/src/components/SankeyChart/SankeyChart.tsx +103 -0
- package/src/components/SankeyChart/__tests__/Link.spec.tsx +127 -0
- package/src/components/SankeyChart/__tests__/MergeTooltip.spec.tsx +22 -0
- package/src/components/SankeyChart/__tests__/Node.spec.tsx +248 -0
- package/src/components/SankeyChart/__tests__/SankeyChart.spec.tsx +161 -0
- package/src/components/SankeyChart/__tests__/__snapshots__/SankeyChart.spec.tsx.snap +183 -0
- package/src/components/SankeyChart/sankey.ts +322 -0
- package/src/components/SankeyChart/styles.ts +41 -0
- package/src/components/SankeyChart/useSankey.tsx +44 -0
- package/src/components/SelectableTree/SelectableTree.tsx +46 -0
- package/src/components/SelectableTree/__tests__/SelectableTree.test.tsx +28 -0
- package/src/components/SelectableTree/__tests__/__snapshots__/SelectableTree.test.tsx.snap +59 -0
- package/src/components/SelectableTree/styles.ts +42 -0
- package/src/components/SourcesView/SourcesView.tsx +318 -0
- package/src/components/SourcesView/__tests__/IntegrationSourcesView.spec.tsx +199 -0
- package/src/components/SourcesView/__tests__/SourcesView.spec.tsx +903 -0
- package/src/components/SourcesView/__tests__/data/metadata.data.ts +27 -0
- package/src/components/SourcesView/__tests__/data/store.data.ts +65 -0
- package/src/components/SourcesView/icons/LegendIcon.svg +8 -0
- package/src/components/SourcesView/index.tsx +57 -0
- package/src/components/SourcesView/styles.ts +44 -0
- package/src/components/TreeActionSnackbar/TreeActionSnackbar.tsx +38 -0
- package/src/components/TreeActionSnackbar/__tests__/TreeActionSnackbar.test.tsx +38 -0
- package/src/components/TreeActionSnackbar/styles.ts +11 -0
- package/src/components/UnmergeDialog/UnmergeDialog.tsx +78 -0
- package/src/components/UnmergeDialog/__tests__/UnmergeDialog.test.tsx +124 -0
- package/src/components/UnmergeDialog/__tests__/testData.data.ts +271 -0
- package/src/components/UnmergeDialog/styles.ts +34 -0
- package/src/components/UnsubscribeDialog/UnsubscribeDialog.tsx +64 -0
- package/src/components/UnsubscribeDialog/__tests__/UnsubscribeDialog.test.tsx +59 -0
- package/src/components/UnsubscribeDialog/styles.ts +31 -0
- package/src/hooks/__tests__/useCrosswalkTree.specs.tsx +68 -0
- package/src/hooks/__tests__/useCrosswalkTreeActions.specs.ts +110 -0
- package/src/hooks/__tests__/useCrosswalksDisplay.specs.tsx +213 -0
- package/src/hooks/__tests__/useEntityWithSurvivorshipGroups.specs.ts +160 -0
- package/src/hooks/useCrosswalkTree.ts +38 -0
- package/src/hooks/useCrosswalkTreeActions.ts +83 -0
- package/src/hooks/useCrosswalksDisplay.ts +110 -0
- package/src/hooks/useEntityWithSurvivorshipGroups.tsx +51 -0
- package/src/icons/notMatch.svg +14 -0
- package/src/index.ts +1 -0
- package/src/services/errors.ts +11 -0
- package/src/types/LegendMode.ts +5 -0
- package/src/types/SankeyChartData.ts +31 -0
- package/src/types/SourcesSavedState.ts +3 -0
- package/src/types/UnmergeContributorEvent.ts +7 -0
- package/src/types/UnsubscribeContributorEvent.ts +6 -0
- package/src/types/index.ts +4 -0
- package/tsconfig.json +4 -0
- package/webpack.config.js +10 -0
- package/bundle.js +0 -2
- package/bundle.js.LICENSE.txt +0 -42
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import React, {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react';
|
|
2
|
+
import {useSelector} from 'react-redux';
|
|
3
|
+
import InfoIcon from '@mui/icons-material/Info';
|
|
4
|
+
import i18n from 'ui-i18n';
|
|
5
|
+
import {isEmpty} from 'ramda';
|
|
6
|
+
import mdmModule from '@reltio/mdm-module';
|
|
7
|
+
import {
|
|
8
|
+
AttributeType,
|
|
9
|
+
calculateCrosswalkTreeDeep,
|
|
10
|
+
checkMetadataPermission,
|
|
11
|
+
Contributor,
|
|
12
|
+
Crosswalk,
|
|
13
|
+
CrosswalkBase,
|
|
14
|
+
CrosswalkTree,
|
|
15
|
+
DataTenant,
|
|
16
|
+
Entity,
|
|
17
|
+
getEntityType,
|
|
18
|
+
getLabel,
|
|
19
|
+
Metadata,
|
|
20
|
+
MetadataPermissions,
|
|
21
|
+
TEntityType,
|
|
22
|
+
UnmergeOperation
|
|
23
|
+
} from '@reltio/mdm-sdk';
|
|
24
|
+
import {
|
|
25
|
+
AddCrosswalkEvent,
|
|
26
|
+
DeleteCrosswalkEvent,
|
|
27
|
+
EditCrosswalkEvent,
|
|
28
|
+
ModeSwitcher,
|
|
29
|
+
noop,
|
|
30
|
+
ResizablePanes
|
|
31
|
+
} from '@reltio/components';
|
|
32
|
+
import {LegendMode, UnmergeContributorEvent, UnsubscribeContributorEvent} from '../../types';
|
|
33
|
+
import CrosswalkTreeView from '../CrosswalkTreeView/CrosswalkTreeView';
|
|
34
|
+
import LegendTable from '../LegendTable/LegendTable';
|
|
35
|
+
import {UnmergeDialog} from '../UnmergeDialog/UnmergeDialog';
|
|
36
|
+
import {UnsubscribeDialog} from '../UnsubscribeDialog/UnsubscribeDialog';
|
|
37
|
+
|
|
38
|
+
import {useStyles} from './styles';
|
|
39
|
+
|
|
40
|
+
export const DEFAULT_LINK_HEIGHT = 60;
|
|
41
|
+
export const MIN_PANE1_SIZE = 170;
|
|
42
|
+
export const MIN_PANE2_SIZE = 170;
|
|
43
|
+
|
|
44
|
+
type Props = {
|
|
45
|
+
activeMode: LegendMode;
|
|
46
|
+
onChangeMode: (mode: LegendMode) => void;
|
|
47
|
+
crosswalkTree: CrosswalkTree;
|
|
48
|
+
entity: Entity;
|
|
49
|
+
contributors: Contributor[];
|
|
50
|
+
selectedAttributeTypes?: AttributeType[];
|
|
51
|
+
readOnly?: boolean;
|
|
52
|
+
onAddCrosswalk?: (event: AddCrosswalkEvent) => void;
|
|
53
|
+
onEditCrosswalk?: (event: EditCrosswalkEvent) => void;
|
|
54
|
+
onDeleteCrosswalk?: (event: DeleteCrosswalkEvent) => void;
|
|
55
|
+
onUnmergeContributor?: (event: UnmergeContributorEvent) => void;
|
|
56
|
+
onUnsubscribeContributor?: (event: UnsubscribeContributorEvent) => void;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const LegendView = ({
|
|
60
|
+
activeMode,
|
|
61
|
+
contributors,
|
|
62
|
+
crosswalkTree,
|
|
63
|
+
entity,
|
|
64
|
+
onChangeMode,
|
|
65
|
+
onUnmergeContributor = noop,
|
|
66
|
+
onUnsubscribeContributor = noop,
|
|
67
|
+
...tableProps
|
|
68
|
+
}: Props) => {
|
|
69
|
+
const styles = useStyles();
|
|
70
|
+
|
|
71
|
+
const metadata: Metadata = useSelector(mdmModule.selectors.getMetadata);
|
|
72
|
+
const entityType: TEntityType = getEntityType(metadata, entity?.type);
|
|
73
|
+
|
|
74
|
+
const viewRef = useRef<HTMLDivElement>();
|
|
75
|
+
const [paneSize, setPaneSize] = useState(MIN_PANE1_SIZE);
|
|
76
|
+
const handlePaneSizeChange = useCallback(({percentageSize}) => setPaneSize(percentageSize), []);
|
|
77
|
+
|
|
78
|
+
const [contributorForUnmerge, setContributorForUnmerge] = useState<string>();
|
|
79
|
+
const [unsubscribeInfo, setUnsubscribeInfo] = useState<{
|
|
80
|
+
contributorUri: string;
|
|
81
|
+
dataTenant: DataTenant;
|
|
82
|
+
crosswalk: Crosswalk;
|
|
83
|
+
}>();
|
|
84
|
+
|
|
85
|
+
const crosswalkTreeDeep = useMemo(() => calculateCrosswalkTreeDeep(crosswalkTree), [crosswalkTree]);
|
|
86
|
+
const canUnmerge = crosswalkTreeDeep > 1;
|
|
87
|
+
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
const height = Math.max(MIN_PANE1_SIZE, crosswalkTreeDeep * DEFAULT_LINK_HEIGHT);
|
|
90
|
+
const maxPaneHeight = viewRef.current?.clientHeight - MIN_PANE2_SIZE;
|
|
91
|
+
setPaneSize(Math.min(maxPaneHeight, height));
|
|
92
|
+
}, [crosswalkTreeDeep]);
|
|
93
|
+
|
|
94
|
+
const modes = useMemo(
|
|
95
|
+
() => [
|
|
96
|
+
{
|
|
97
|
+
id: LegendMode.Crosswalk,
|
|
98
|
+
title: i18n.text('Crosswalk')
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
id: LegendMode.Source,
|
|
102
|
+
title: i18n.text('Source')
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
id: LegendMode.Contributor,
|
|
106
|
+
title: i18n.text('Contributor')
|
|
107
|
+
}
|
|
108
|
+
],
|
|
109
|
+
[]
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
const [visibleCrosswalks, setVisibleCrosswalks] = useState<CrosswalkBase[]>();
|
|
113
|
+
const accentContributors = activeMode === LegendMode.Contributor;
|
|
114
|
+
const disableUnmerge = tableProps.readOnly || !checkMetadataPermission(MetadataPermissions.UNMERGE, entityType);
|
|
115
|
+
|
|
116
|
+
return (
|
|
117
|
+
<div className={styles.root} ref={viewRef}>
|
|
118
|
+
{contributorForUnmerge && (
|
|
119
|
+
<UnmergeDialog
|
|
120
|
+
canUnmerge={canUnmerge}
|
|
121
|
+
onClose={() => setContributorForUnmerge(null)}
|
|
122
|
+
onUnmergeContributor={(operationType: UnmergeOperation) => {
|
|
123
|
+
onUnmergeContributor({
|
|
124
|
+
entityUri: entity.uri,
|
|
125
|
+
contributorUri: contributorForUnmerge,
|
|
126
|
+
operationType
|
|
127
|
+
});
|
|
128
|
+
}}
|
|
129
|
+
crosswalkTree={crosswalkTree}
|
|
130
|
+
contributor={contributors.find(({uri}) => uri === contributorForUnmerge)}
|
|
131
|
+
/>
|
|
132
|
+
)}
|
|
133
|
+
{unsubscribeInfo && (
|
|
134
|
+
<UnsubscribeDialog
|
|
135
|
+
canUnsubscribe={canUnmerge}
|
|
136
|
+
onClose={() => setUnsubscribeInfo(null)}
|
|
137
|
+
onUnsubscribeContributor={() =>
|
|
138
|
+
onUnsubscribeContributor({
|
|
139
|
+
dataTenant: unsubscribeInfo.dataTenant,
|
|
140
|
+
crosswalk: unsubscribeInfo.crosswalk
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
crosswalkTree={crosswalkTree}
|
|
144
|
+
contributor={contributors.find(({uri}) => uri === unsubscribeInfo.contributorUri)}
|
|
145
|
+
/>
|
|
146
|
+
)}
|
|
147
|
+
<ModeSwitcher<LegendMode>
|
|
148
|
+
modes={modes}
|
|
149
|
+
modeId={activeMode}
|
|
150
|
+
className={styles.modeSwitcher}
|
|
151
|
+
onChange={onChangeMode}
|
|
152
|
+
/>
|
|
153
|
+
<ResizablePanes
|
|
154
|
+
className={styles.resizablePanesWrapper}
|
|
155
|
+
orientation="horizontal"
|
|
156
|
+
size={paneSize}
|
|
157
|
+
minSize={MIN_PANE1_SIZE}
|
|
158
|
+
maxSize={-MIN_PANE2_SIZE}
|
|
159
|
+
allowResize
|
|
160
|
+
onChange={handlePaneSizeChange}
|
|
161
|
+
>
|
|
162
|
+
<div className={styles.pane}>
|
|
163
|
+
{crosswalkTree && !isEmpty(visibleCrosswalks) && (
|
|
164
|
+
<CrosswalkTreeView
|
|
165
|
+
entityLabel={getLabel(entity?.label)}
|
|
166
|
+
crosswalkTree={crosswalkTree}
|
|
167
|
+
visibleCrosswalks={visibleCrosswalks}
|
|
168
|
+
accentContributors={accentContributors}
|
|
169
|
+
disableUnmerge={disableUnmerge || !canUnmerge}
|
|
170
|
+
onUnmerge={setContributorForUnmerge}
|
|
171
|
+
/>
|
|
172
|
+
)}
|
|
173
|
+
</div>
|
|
174
|
+
<div className={styles.pane}>
|
|
175
|
+
<div className={styles.hint}>
|
|
176
|
+
<InfoIcon className={styles.infoIcon} />
|
|
177
|
+
<span className={styles.hintText}>
|
|
178
|
+
{i18n.text('You can drag a crosswalk to add values to attributes swimlanes')}
|
|
179
|
+
</span>
|
|
180
|
+
</div>
|
|
181
|
+
{entity && (
|
|
182
|
+
<LegendTable
|
|
183
|
+
onUnmergeContributor={setContributorForUnmerge}
|
|
184
|
+
onUnsubscribeContributor={setUnsubscribeInfo}
|
|
185
|
+
accentContributors={accentContributors}
|
|
186
|
+
contributors={contributors}
|
|
187
|
+
entity={entity}
|
|
188
|
+
entityType={entityType}
|
|
189
|
+
onChangeVisibleCrosswalks={setVisibleCrosswalks}
|
|
190
|
+
canUnmerge={canUnmerge}
|
|
191
|
+
disableUnmerge={disableUnmerge}
|
|
192
|
+
{...tableProps}
|
|
193
|
+
/>
|
|
194
|
+
)}
|
|
195
|
+
</div>
|
|
196
|
+
</ResizablePanes>
|
|
197
|
+
</div>
|
|
198
|
+
);
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
export default memo(LegendView);
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import * as reactRedux from 'react-redux';
|
|
3
|
+
import mdmModule from '@reltio/mdm-module';
|
|
4
|
+
import {mount, shallow} from 'enzyme';
|
|
5
|
+
import LegendView, {DEFAULT_LINK_HEIGHT, MIN_PANE1_SIZE, MIN_PANE2_SIZE} from '../LegendView';
|
|
6
|
+
import {ModeSwitcher, ResizablePanes} from '@reltio/components';
|
|
7
|
+
import {LegendMode} from '../../../types';
|
|
8
|
+
import CrosswalkTreeView from '../../CrosswalkTreeView/CrosswalkTreeView';
|
|
9
|
+
import LegendTable from '../../LegendTable/LegendTable';
|
|
10
|
+
import {UnmergeDialog} from '../../UnmergeDialog/UnmergeDialog';
|
|
11
|
+
import {act} from 'react-dom/test-utils';
|
|
12
|
+
import * as mdmSdk from '@reltio/mdm-sdk';
|
|
13
|
+
import {CrosswalkTree, UnmergeOperation} from '@reltio/mdm-sdk';
|
|
14
|
+
import {UnsubscribeDialog} from '../../UnsubscribeDialog/UnsubscribeDialog';
|
|
15
|
+
import {rerenderWrapper} from '../../../../../../__mocks__/test-utils';
|
|
16
|
+
|
|
17
|
+
jest.mock('@reltio/mdm-sdk', () => ({
|
|
18
|
+
...jest.requireActual<Record<string, unknown>>('@reltio/mdm-sdk'),
|
|
19
|
+
calculateCrosswalkTreeDeep: jest.fn()
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
jest.mock('../../LegendTable/LegendTable', () => {
|
|
23
|
+
const LegendTable = () => <div />;
|
|
24
|
+
return LegendTable;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const PANE_HEIGHT = 800;
|
|
28
|
+
|
|
29
|
+
describe('LegendView tests', () => {
|
|
30
|
+
const entityTypes = [
|
|
31
|
+
{
|
|
32
|
+
uri: 'configuration/entityTypes/HCP',
|
|
33
|
+
label: 'Label',
|
|
34
|
+
attributes: [],
|
|
35
|
+
type: 'testType'
|
|
36
|
+
}
|
|
37
|
+
];
|
|
38
|
+
const props = {
|
|
39
|
+
activeMode: LegendMode.Crosswalk,
|
|
40
|
+
onChangeMode: jest.fn(),
|
|
41
|
+
entity: {uri: 'testUri', type: 'configuration/entityTypes/HCP', label: 'Label'},
|
|
42
|
+
crosswalkTree: {
|
|
43
|
+
uri: 'test',
|
|
44
|
+
crosswalks: [],
|
|
45
|
+
merges: [
|
|
46
|
+
{
|
|
47
|
+
losers: [
|
|
48
|
+
{
|
|
49
|
+
merges: []
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
} as CrosswalkTree,
|
|
55
|
+
contributors: [{uri: 'test', crosswalks: []}],
|
|
56
|
+
onAddCrosswalk: jest.fn(),
|
|
57
|
+
onEditCrosswalk: jest.fn(),
|
|
58
|
+
onDeleteCrosswalk: jest.fn(),
|
|
59
|
+
selectedAttrTypes: [],
|
|
60
|
+
onUnmergeContributor: jest.fn(),
|
|
61
|
+
onToggleCrosswalkFocus: jest.fn(),
|
|
62
|
+
onUnsubscribeContributor: jest.fn()
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const crosswalkTreeDeepSpy = jest.spyOn(mdmSdk, 'calculateCrosswalkTreeDeep').mockReturnValue(2);
|
|
66
|
+
const getMetadataSpy = jest.spyOn(mdmModule.selectors, 'getMetadata');
|
|
67
|
+
|
|
68
|
+
beforeAll(() => {
|
|
69
|
+
jest.spyOn(Element.prototype, 'clientHeight', 'get').mockReturnValue(PANE_HEIGHT);
|
|
70
|
+
jest.spyOn(reactRedux, 'useSelector').mockImplementation((selector) => selector({}));
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
afterEach(() => {
|
|
74
|
+
jest.clearAllMocks();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
beforeEach(() => {
|
|
78
|
+
getMetadataSpy.mockReturnValue({entityTypes});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should render component correctly', () => {
|
|
82
|
+
const component = shallow(<LegendView {...props} />);
|
|
83
|
+
|
|
84
|
+
expect(component.find(ModeSwitcher).prop('modeId')).toBe(props.activeMode);
|
|
85
|
+
const panes = component.find(ResizablePanes).find('.pane');
|
|
86
|
+
expect(panes.at(0).find(CrosswalkTreeView).props()).toMatchObject({
|
|
87
|
+
accentContributors: false,
|
|
88
|
+
entityLabel: 'Label',
|
|
89
|
+
crosswalkTree: props.crosswalkTree
|
|
90
|
+
});
|
|
91
|
+
expect(panes.at(1).find(LegendTable).props()).toMatchObject({
|
|
92
|
+
accentContributors: false,
|
|
93
|
+
entity: props.entity,
|
|
94
|
+
entityType: entityTypes[0],
|
|
95
|
+
disableUnmerge: false,
|
|
96
|
+
canUnmerge: true,
|
|
97
|
+
contributors: props.contributors,
|
|
98
|
+
onAddCrosswalk: props.onAddCrosswalk,
|
|
99
|
+
onDeleteCrosswalk: props.onDeleteCrosswalk,
|
|
100
|
+
onEditCrosswalk: props.onEditCrosswalk,
|
|
101
|
+
onToggleCrosswalkFocus: props.onToggleCrosswalkFocus
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should not render crosswalk tree if it is nil', () => {
|
|
106
|
+
const component = shallow(<LegendView {...props} crosswalkTree={null} />);
|
|
107
|
+
expect(component.find(CrosswalkTreeView)).toHaveLength(0);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should not render legend table if entity is nil', () => {
|
|
111
|
+
const component = shallow(<LegendView {...props} entity={null} />);
|
|
112
|
+
expect(component.find(LegendTable)).toHaveLength(0);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should show crosswalks in tree that are visible in table', () => {
|
|
116
|
+
const component = shallow(<LegendView {...props} />);
|
|
117
|
+
expect(component.find(CrosswalkTreeView).prop('visibleCrosswalks')).toBe(undefined);
|
|
118
|
+
const visibleCrosswalks = [
|
|
119
|
+
{
|
|
120
|
+
uri: 'crosswalks/1',
|
|
121
|
+
value: '123',
|
|
122
|
+
type: 'configuration/sources/Reltio'
|
|
123
|
+
}
|
|
124
|
+
];
|
|
125
|
+
component.find(LegendTable).prop('onChangeVisibleCrosswalks')(visibleCrosswalks);
|
|
126
|
+
rerenderWrapper(component);
|
|
127
|
+
expect(component.find(CrosswalkTreeView).prop('visibleCrosswalks')).toBe(visibleCrosswalks);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should not render CrosswalkTreeView if visibleCrosswalks is empty', () => {
|
|
131
|
+
const component = shallow(<LegendView {...props} />);
|
|
132
|
+
expect(component.find(CrosswalkTreeView).prop('visibleCrosswalks')).toBe(undefined);
|
|
133
|
+
const visibleCrosswalks = [];
|
|
134
|
+
component.find(LegendTable).prop('onChangeVisibleCrosswalks')(visibleCrosswalks);
|
|
135
|
+
rerenderWrapper(component);
|
|
136
|
+
expect(component.find(CrosswalkTreeView)).toHaveLength(0);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should call onChangeMode callback when switching mode', () => {
|
|
140
|
+
const component = shallow(<LegendView {...props} />);
|
|
141
|
+
const onChange = component.find(ModeSwitcher).prop('onChange') as (mode: LegendMode) => void;
|
|
142
|
+
onChange(LegendMode.Contributor);
|
|
143
|
+
expect(props.onChangeMode).toHaveBeenCalledWith(LegendMode.Contributor);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('should accent contributors in Contributor mode', () => {
|
|
147
|
+
const component = shallow(<LegendView {...props} activeMode={LegendMode.Contributor} />);
|
|
148
|
+
expect(component.find(LegendTable).prop('accentContributors')).toBe(true);
|
|
149
|
+
expect(component.find(CrosswalkTreeView).prop('accentContributors')).toBe(true);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('should not render UnmergeDialog if contributorForUnmerge is not defined', () => {
|
|
153
|
+
const component = shallow(<LegendView {...props} />);
|
|
154
|
+
expect(component.find(UnmergeDialog)).toHaveLength(0);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('should render UnmergeDialog if contributorForUnmerge is defined correctly', () => {
|
|
158
|
+
const component = shallow(<LegendView {...props} />);
|
|
159
|
+
act(() => {
|
|
160
|
+
component.find(LegendTable).prop('onUnmergeContributor')('test');
|
|
161
|
+
});
|
|
162
|
+
rerenderWrapper(component);
|
|
163
|
+
const unmergeDialog = component.find(UnmergeDialog);
|
|
164
|
+
expect(unmergeDialog.prop('crosswalkTree')).toEqual(props.crosswalkTree);
|
|
165
|
+
expect(unmergeDialog.prop('contributor')).toEqual(props.contributors[0]);
|
|
166
|
+
expect(unmergeDialog.prop('canUnmerge')).toBeTruthy();
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('should call onUnmergeContributor on UnmergeDialog "onUnmergeContributor" prop calling', () => {
|
|
170
|
+
const component = shallow(<LegendView {...props} />);
|
|
171
|
+
act(() => {
|
|
172
|
+
component.find(LegendTable).prop('onUnmergeContributor')('test');
|
|
173
|
+
});
|
|
174
|
+
rerenderWrapper(component);
|
|
175
|
+
component.find(UnmergeDialog).prop('onUnmergeContributor')(UnmergeOperation.TreeUnmerge);
|
|
176
|
+
expect(props.onUnmergeContributor).toHaveBeenCalledWith({
|
|
177
|
+
entityUri: props.entity.uri,
|
|
178
|
+
contributorUri: 'test',
|
|
179
|
+
operationType: UnmergeOperation.TreeUnmerge
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('should unmount UnmergeDialog on UnmergeDialog "onClose" prop calling', () => {
|
|
184
|
+
const component = shallow(<LegendView {...props} />);
|
|
185
|
+
act(() => {
|
|
186
|
+
component.find(LegendTable).prop('onUnmergeContributor')('test');
|
|
187
|
+
});
|
|
188
|
+
rerenderWrapper(component);
|
|
189
|
+
expect(component.find(UnmergeDialog)).toHaveLength(1);
|
|
190
|
+
|
|
191
|
+
act(() => {
|
|
192
|
+
component.find(UnmergeDialog).prop('onClose')();
|
|
193
|
+
});
|
|
194
|
+
rerenderWrapper(component);
|
|
195
|
+
expect(component.find(UnmergeDialog)).toHaveLength(0);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('should not render UnsubscribeDialog if contributorForUnsubscribe is not defined', () => {
|
|
199
|
+
const component = shallow(<LegendView {...props} />);
|
|
200
|
+
expect(component.find(UnsubscribeDialog)).toHaveLength(0);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('should provide canUnmerge === false to unmergeDialog if deep crosswalksTree === 1', () => {
|
|
204
|
+
crosswalkTreeDeepSpy.mockReturnValueOnce(1);
|
|
205
|
+
const component = shallow(<LegendView {...props} crosswalkTree={{uri: '123213'}} />);
|
|
206
|
+
act(() => {
|
|
207
|
+
component.find(LegendTable).prop('onUnmergeContributor')('test');
|
|
208
|
+
});
|
|
209
|
+
rerenderWrapper(component);
|
|
210
|
+
expect(component.find(UnmergeDialog).prop('canUnmerge')).toBeFalsy();
|
|
211
|
+
expect(component.find(LegendTable).prop('canUnmerge')).toBeFalsy();
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('should render UnsubscribeDialog if contributorForUnsubscribe is defined correctly', () => {
|
|
215
|
+
const component = shallow(<LegendView {...props} />);
|
|
216
|
+
act(() => {
|
|
217
|
+
component.find(LegendTable).prop('onUnsubscribeContributor')({
|
|
218
|
+
contributorUri: 'test',
|
|
219
|
+
dataTenant: {id: 'id1', label: 'label1', name: 'name1'},
|
|
220
|
+
crosswalk: {uri: 'crUri1', type: 'type1', value: 'value1'}
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
rerenderWrapper(component);
|
|
224
|
+
const unsubscribeDialog = component.find(UnsubscribeDialog);
|
|
225
|
+
expect(unsubscribeDialog.prop('crosswalkTree')).toEqual(props.crosswalkTree);
|
|
226
|
+
expect(unsubscribeDialog.prop('contributor')).toEqual(props.contributors[0]);
|
|
227
|
+
expect(unsubscribeDialog.prop('canUnsubscribe')).toBeTruthy();
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('should call onUnsubscribeContributor on UnsubscribeDialog "onUnsubscribeContributor" prop calling', () => {
|
|
231
|
+
const component = shallow(<LegendView {...props} />);
|
|
232
|
+
act(() => {
|
|
233
|
+
component.find(LegendTable).prop('onUnsubscribeContributor')({
|
|
234
|
+
contributorUri: 'test',
|
|
235
|
+
dataTenant: {id: 'id1', label: 'label1', name: 'name1'},
|
|
236
|
+
crosswalk: {uri: 'crUri1', type: 'type1', value: 'value1'}
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
rerenderWrapper(component);
|
|
240
|
+
|
|
241
|
+
component.find(UnsubscribeDialog).prop('onUnsubscribeContributor')();
|
|
242
|
+
expect(props.onUnsubscribeContributor).toHaveBeenCalledWith({
|
|
243
|
+
dataTenant: {id: 'id1', label: 'label1', name: 'name1'},
|
|
244
|
+
crosswalk: {uri: 'crUri1', type: 'type1', value: 'value1'}
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('should unmount UnsubscribeDialog on UnsubscribeDialog "onClose" prop calling', () => {
|
|
249
|
+
const component = shallow(<LegendView {...props} />);
|
|
250
|
+
act(() => {
|
|
251
|
+
component.find(LegendTable).prop('onUnsubscribeContributor')({
|
|
252
|
+
contributorUri: 'test',
|
|
253
|
+
dataTenant: {id: 'id1', label: 'label1', name: 'name1'},
|
|
254
|
+
crosswalk: {uri: 'crUri1', type: 'type1', value: 'value1'}
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
rerenderWrapper(component);
|
|
258
|
+
expect(component.find(UnsubscribeDialog)).toHaveLength(1);
|
|
259
|
+
|
|
260
|
+
act(() => {
|
|
261
|
+
component.find(UnsubscribeDialog).prop('onClose')();
|
|
262
|
+
});
|
|
263
|
+
rerenderWrapper(component);
|
|
264
|
+
expect(component.find(UnsubscribeDialog)).toHaveLength(0);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('should provide canUnsubscribe === false to UnsubscribeDialog if deep crosswalksTree === 1', () => {
|
|
268
|
+
crosswalkTreeDeepSpy.mockReturnValueOnce(1);
|
|
269
|
+
const component = shallow(<LegendView {...props} crosswalkTree={{uri: '123213'}} />);
|
|
270
|
+
act(() => {
|
|
271
|
+
component.find(LegendTable).prop('onUnsubscribeContributor')({
|
|
272
|
+
contributorUri: 'test',
|
|
273
|
+
dataTenant: {id: 'id1', label: 'label1', name: 'name1'},
|
|
274
|
+
crosswalk: {uri: 'crUri1', type: 'type1', value: 'value1'}
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
rerenderWrapper(component);
|
|
278
|
+
expect(component.find(UnsubscribeDialog).prop('canUnsubscribe')).toBeFalsy();
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('should render read only legend table if props.readOnly is true', () => {
|
|
282
|
+
const component = shallow(<LegendView {...props} readOnly />);
|
|
283
|
+
expect(component.find(LegendTable).prop('readOnly')).toBe(true);
|
|
284
|
+
component.setProps({readOnly: false});
|
|
285
|
+
expect(component.find(LegendTable).prop('readOnly')).toBe(false);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
describe('pane size tests', () => {
|
|
289
|
+
it('should use min pane size for small crosswalk tree', () => {
|
|
290
|
+
crosswalkTreeDeepSpy.mockReturnValueOnce(1);
|
|
291
|
+
const component = mount(<LegendView {...props} />);
|
|
292
|
+
expect(component.find(ResizablePanes).prop('size')).toBe(MIN_PANE1_SIZE);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('should use correct pane size for medium crosswalk tree', () => {
|
|
296
|
+
crosswalkTreeDeepSpy.mockReturnValueOnce(4);
|
|
297
|
+
const component = mount(<LegendView {...props} />);
|
|
298
|
+
expect(component.find(ResizablePanes).prop('size')).toBe(DEFAULT_LINK_HEIGHT * 4);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it('should use max pane size for large crosswalk tree', () => {
|
|
302
|
+
crosswalkTreeDeepSpy.mockReturnValueOnce(12);
|
|
303
|
+
const component = mount(<LegendView {...props} />);
|
|
304
|
+
expect(component.find(ResizablePanes).prop('size')).toBe(PANE_HEIGHT - MIN_PANE2_SIZE);
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {makeStyles} from '@mui/styles';
|
|
2
|
+
|
|
3
|
+
export const useStyles = makeStyles((theme) => ({
|
|
4
|
+
root: {
|
|
5
|
+
display: 'flex',
|
|
6
|
+
flexDirection: 'column',
|
|
7
|
+
alignItems: 'center',
|
|
8
|
+
height: '100%'
|
|
9
|
+
},
|
|
10
|
+
modeSwitcher: {
|
|
11
|
+
backgroundColor: theme.palette.background.paper,
|
|
12
|
+
marginTop: '8px'
|
|
13
|
+
},
|
|
14
|
+
infoIcon: {
|
|
15
|
+
fontSize: '18px',
|
|
16
|
+
marginRight: '8px'
|
|
17
|
+
},
|
|
18
|
+
hint: {
|
|
19
|
+
color: theme.palette.text.secondary,
|
|
20
|
+
display: 'flex',
|
|
21
|
+
flexDirection: 'row',
|
|
22
|
+
alignItems: 'center',
|
|
23
|
+
alignSelf: 'flex-start',
|
|
24
|
+
margin: '5px 12px 10px 12px'
|
|
25
|
+
},
|
|
26
|
+
hintText: {
|
|
27
|
+
fontSize: '12px',
|
|
28
|
+
lineHeight: '16px'
|
|
29
|
+
},
|
|
30
|
+
crosswalksList: {
|
|
31
|
+
height: '100%',
|
|
32
|
+
width: 'calc(100% - 24px)',
|
|
33
|
+
margin: '8px 12px',
|
|
34
|
+
background: theme.palette.divider,
|
|
35
|
+
opacity: 0.2
|
|
36
|
+
},
|
|
37
|
+
pane: {
|
|
38
|
+
position: 'absolute',
|
|
39
|
+
top: 0,
|
|
40
|
+
left: 0,
|
|
41
|
+
right: 0,
|
|
42
|
+
bottom: 0,
|
|
43
|
+
display: 'flex',
|
|
44
|
+
flexDirection: 'column',
|
|
45
|
+
overflow: 'hidden'
|
|
46
|
+
},
|
|
47
|
+
resizablePanesWrapper: {
|
|
48
|
+
flexGrow: 1,
|
|
49
|
+
width: '100%'
|
|
50
|
+
}
|
|
51
|
+
}));
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import CloseIcon from '@mui/icons-material/Close';
|
|
3
|
+
import {RightPanelTab, SmallIconButton} from '@reltio/components';
|
|
4
|
+
import {useStyles} from './styles';
|
|
5
|
+
|
|
6
|
+
type Props = {
|
|
7
|
+
onClose?: () => void;
|
|
8
|
+
active?: number;
|
|
9
|
+
tabs: RightPanelTab[];
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const RightSidePanel = ({active, onClose, tabs}: Props) => {
|
|
13
|
+
const styles = useStyles();
|
|
14
|
+
const {content, title} = tabs[active] || {};
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<>
|
|
18
|
+
<div className={styles.header}>
|
|
19
|
+
<SmallIconButton className={styles.closeButton} icon={CloseIcon} onClick={onClose} />
|
|
20
|
+
{title}
|
|
21
|
+
</div>
|
|
22
|
+
{content}
|
|
23
|
+
</>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {shallow} from 'enzyme';
|
|
3
|
+
import {SmallIconButton} from '@reltio/components';
|
|
4
|
+
import {RightSidePanel} from '../RightSidePanel';
|
|
5
|
+
|
|
6
|
+
describe('RightSidePanel', () => {
|
|
7
|
+
it('should render correctly', () => {
|
|
8
|
+
const onClose = jest.fn();
|
|
9
|
+
const props = {
|
|
10
|
+
active: 0,
|
|
11
|
+
tabs: [
|
|
12
|
+
{
|
|
13
|
+
content: <div>RSP Content</div>,
|
|
14
|
+
title: <div>Title</div>
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
onClose
|
|
18
|
+
};
|
|
19
|
+
const component = shallow(<RightSidePanel {...props} />);
|
|
20
|
+
|
|
21
|
+
expect(component.findWhere((node) => node.text() === 'Title').exists()).toBe(true);
|
|
22
|
+
expect(component.findWhere((node) => node.text() === 'RSP Content').exists()).toBe(true);
|
|
23
|
+
|
|
24
|
+
const button = component.find(SmallIconButton);
|
|
25
|
+
button.simulate('click');
|
|
26
|
+
expect(onClose).toHaveBeenCalled();
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {makeStyles} from '@mui/styles';
|
|
2
|
+
|
|
3
|
+
export const useStyles = makeStyles({
|
|
4
|
+
header: {
|
|
5
|
+
display: 'flex',
|
|
6
|
+
flexDirection: 'row',
|
|
7
|
+
alignItems: 'center',
|
|
8
|
+
padding: '16px 12px',
|
|
9
|
+
borderBottom: '1px solid rgba(0, 0, 0, 0.12);'
|
|
10
|
+
},
|
|
11
|
+
closeButton: {
|
|
12
|
+
marginRight: '12px'
|
|
13
|
+
}
|
|
14
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import i18n from 'ui-i18n';
|
|
3
|
+
import {pipe, propEq, prop} from 'ramda';
|
|
4
|
+
import {DropDownSelector} from '@reltio/components';
|
|
5
|
+
import {getLabel, SurvivorshipGroupType} from '@reltio/mdm-sdk';
|
|
6
|
+
import {RulesetOption} from './RulesetOption/RulesetOption';
|
|
7
|
+
import {RulesetsMenuList} from './RulesetsMenuList/RulesetsMenuList';
|
|
8
|
+
import {useStyles} from './styles';
|
|
9
|
+
|
|
10
|
+
type Props = {
|
|
11
|
+
survivorshipGroups: SurvivorshipGroupType[];
|
|
12
|
+
currentSurvivorshipGroupUri: string;
|
|
13
|
+
onChange: (uri: string) => void;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const RulesetsSelector = ({survivorshipGroups, currentSurvivorshipGroupUri, onChange}: Props) => {
|
|
17
|
+
const styles = useStyles();
|
|
18
|
+
const options = survivorshipGroups.map((group) => ({...group, label: getLabel(group.label)}));
|
|
19
|
+
const value = options.find(propEq('uri', currentSurvivorshipGroupUri));
|
|
20
|
+
return (
|
|
21
|
+
<DropDownSelector
|
|
22
|
+
height={40}
|
|
23
|
+
className={styles.root}
|
|
24
|
+
components={{Option: RulesetOption, MenuList: RulesetsMenuList}}
|
|
25
|
+
label={i18n.text('Rulesets')}
|
|
26
|
+
options={options}
|
|
27
|
+
value={value}
|
|
28
|
+
onChange={pipe(prop('uri'), onChange)}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {SurvivorshipGroupType} from '@reltio/mdm-sdk';
|
|
3
|
+
import MenuItem from '@mui/material/MenuItem';
|
|
4
|
+
import Typography from '@mui/material/Typography';
|
|
5
|
+
import {useStyles} from './styles';
|
|
6
|
+
|
|
7
|
+
type MenuItemProps = React.ComponentPropsWithoutRef<typeof MenuItem>;
|
|
8
|
+
|
|
9
|
+
type Props = {
|
|
10
|
+
innerRef: React.Ref<HTMLLIElement>;
|
|
11
|
+
innerProps: MenuItemProps;
|
|
12
|
+
data: SurvivorshipGroupType;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const RulesetOption = ({innerRef, innerProps, data}: Props) => {
|
|
16
|
+
const styles = useStyles();
|
|
17
|
+
const {label, description} = data;
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<MenuItem className={styles.root} ref={innerRef} {...innerProps}>
|
|
21
|
+
<Typography className={styles.label}>{label}</Typography>
|
|
22
|
+
{description && <Typography className={styles.description}>{description}</Typography>}
|
|
23
|
+
</MenuItem>
|
|
24
|
+
);
|
|
25
|
+
};
|