@reltio/graph 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 +26 -9
- package/public/bundle.js +205 -0
- package/public/bundle.js.LICENSE.txt +88 -0
- package/public/package.json +29 -0
- package/scripts/build/index.js +20 -0
- package/src/__tests__/GraphView.test.tsx +25 -0
- package/src/components/CircleLayout/CircleLayout.tsx +76 -0
- package/src/components/CircleLayout/__tests__/CircleLayout.test.tsx +194 -0
- package/src/components/GotoButton/GotoButton.tsx +23 -0
- package/src/components/GotoButton/__tests__/GotoButton.test.tsx +33 -0
- package/src/components/GotoButton/styles.ts +15 -0
- package/src/components/GraphArea/GraphArea.tsx +113 -0
- package/src/components/GraphArea/__tests__/GraphArea.test.tsx +202 -0
- package/src/components/GraphArea/styles.ts +30 -0
- package/src/components/GraphLayoutSelector/GraphLayoutSelector.tsx +43 -0
- package/src/components/GraphLayoutSelector/__tests__/GraphLayoutSelector.spec.tsx +44 -0
- package/src/components/GraphLayoutSelector/styles.ts +15 -0
- package/src/components/GraphPerspectiveView/GraphPerspectiveView.tsx +58 -0
- package/src/components/GraphPerspectiveView/__tests__/GraphPerspectiveView.test.tsx +115 -0
- package/src/components/GraphPerspectiveView/__tests__/useGraphLoader.test.tsx +1519 -0
- package/src/components/GraphPerspectiveView/__tests__/useRelationshipTable.test.tsx +1003 -0
- package/src/components/GraphPerspectiveView/__tests__/useSelectedEntity.test.tsx +373 -0
- package/src/components/GraphPerspectiveView/styles.ts +34 -0
- package/src/components/GraphRightSidePanel/GraphRightSidePanel.tsx +27 -0
- package/src/components/GraphRightSidePanel/__tests__/GraphRightSidePanel.test.tsx +18 -0
- package/src/components/GraphRightSidePanel/icons/relationship-icon.svg +3 -0
- package/src/components/GraphRightSidePanel/styles.ts +8 -0
- package/src/components/GraphTypeSelector/GraphTypeSelector.tsx +56 -0
- package/src/components/GraphTypeSelector/__tests__/GraphTypeSelector.test.tsx +109 -0
- package/src/components/GraphTypeSelector/styles.ts +17 -0
- package/src/components/HierarchyLayout/HierarchyLayout.ts +102 -0
- package/src/components/HierarchyLayout/__tests__/HierarchyLayout.spec.tsx +241 -0
- package/src/components/HierarchyLayout/__tests__/buildHierarchy.spec.ts +130 -0
- package/src/components/HierarchyLayout/__tests__/calculations.spec.ts +230 -0
- package/src/components/HierarchyLayout/buildHierarchy.ts +109 -0
- package/src/components/HierarchyLayout/calculations.ts +86 -0
- package/src/components/RightPanelEntityDetails/RightPanelEntityDetails.tsx +33 -0
- package/src/components/RightPanelEntityDetails/__tests__/RightPanelEntityDetails.test.tsx +39 -0
- package/src/components/RightPanelEntityDetails/styles.ts +12 -0
- package/src/components/RightPanelProfileBand/RightPanelProfileBand.tsx +33 -0
- package/src/components/RightPanelProfileBand/__tests__/RightPanelProfileBand.test.tsx +67 -0
- package/src/components/RightPanelProfileBand/styles.ts +8 -0
- package/src/components/RightPanelRelationship/RightPanelRelationship.tsx +25 -0
- package/src/components/RightPanelRelationship/__tests__/RightPanelRelationship.test.tsx +18 -0
- package/src/components/RightPanelRelationship/components/CollapsibleTable/CollapsibleTable.tsx +100 -0
- package/src/components/RightPanelRelationship/components/CollapsibleTable/TableHead.tsx +38 -0
- package/src/components/RightPanelRelationship/components/CollapsibleTable/__tests__/CollapsibleTable.test.tsx +169 -0
- package/src/components/RightPanelRelationship/components/CollapsibleTable/__tests__/TableHead.test.tsx +107 -0
- package/src/components/RightPanelRelationship/components/CollapsibleTable/styles.ts +38 -0
- package/src/components/RightPanelRelationship/components/CollapsibleTable/types.ts +20 -0
- package/src/components/RightPanelRelationship/components/DeleteRelationDialog/DeleteRelationDialog.tsx +34 -0
- package/src/components/RightPanelRelationship/components/DeleteRelationDialog/__tests__/DeleteRelationDialog.test.tsx +46 -0
- package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/GraphAddRelationButton.tsx +43 -0
- package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/GraphAddRelationDialog.tsx +121 -0
- package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/__tests__/GraphAddRelationButton.test.tsx +80 -0
- package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/__tests__/GraphAddRelationDialog.test.tsx +262 -0
- package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/__tests__/mockdata.ts +75 -0
- package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/styles.ts +25 -0
- package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/useCreatableInOutRelationTypes.ts +13 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/RelationshipTable.tsx +126 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/__tests__/RelationshipTable.test.tsx +176 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/ControlsCellRenderer.tsx +59 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/DefaultCellRenderer.tsx +29 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/ExpandedRowRenderer.tsx +94 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/HeadCellRenderer.tsx +34 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/ProfileCellRenderer.tsx +41 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/ControlsCellRenderer.test.tsx +80 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/DefaultCellRenderer.test.tsx +47 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/ExpandedRowRenderer.test.tsx +166 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/HeadCellRenderer.test.tsx +23 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/ProfileCellRenderer.test.tsx +47 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/components/DeleteRelationButton.tsx +32 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/components/__tests__/DeleteRelationButton.test.tsx +28 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/styles.ts +113 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/styles.ts +36 -0
- package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsFilters.tsx +41 -0
- package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsFiltersDialog/RelationshipsFiltersDialog.tsx +91 -0
- package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsFiltersDialog/__tests__/RelationshipsFilterDialog.test.tsx +192 -0
- package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsFiltersDialog/styles.ts +34 -0
- package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsSearchTextField/RelationshipsSearchTextField.tsx +31 -0
- package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsSearchTextField/__tests__/RelationshipsSearchTextField.test.tsx +43 -0
- package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsSearchTextField/styles.ts +17 -0
- package/src/components/RightPanelRelationship/components/RelationshipsFilters/__tests__/RelationshipsFilters.test.tsx +76 -0
- package/src/components/RightPanelRelationship/components/RelationshipsFilters/styles.ts +19 -0
- package/src/components/RightPanelRelationship/styles.ts +20 -0
- package/src/components/SigmaCustomRenderers/SigmaCustomRenderersContainer.tsx +16 -0
- package/src/components/SigmaGraphContainer/SigmaGraphContainer.tsx +55 -0
- package/src/components/SigmaGraphContainer/__tests__/SigmaGraphContainer.test.tsx +25 -0
- package/src/components/SigmaGraphResizer/SigmaGraphResizer.tsx +13 -0
- package/src/components/SigmaGraphResizer/__tests__/SigmaGraphResizer.test.tsx +28 -0
- package/src/components/TreeLayout/TreeLayout.tsx +33 -0
- package/src/components/TreeLayout/__tests__/TreeLayout.test.tsx +42 -0
- package/src/components/TreeLayout/styles.ts +10 -0
- package/src/components/ZoomSlider/ZoomSlider.tsx +90 -0
- package/src/components/ZoomSlider/__tests__/ZoomSlider.test.tsx +84 -0
- package/src/components/ZoomSlider/styles.ts +57 -0
- package/src/constants/index.ts +1 -0
- package/src/contexts/GraphStateContext.tsx +19 -0
- package/src/contexts/SigmaCustomRenderersContext.ts +20 -0
- package/src/helpers/relationsHelpers.ts +9 -0
- package/src/hooks/__tests__/useGraphLayout.test.tsx +825 -0
- package/src/hooks/__tests__/useGraphLayoutSelector.test.tsx +19 -0
- package/src/hooks/__tests__/useSelfRelationLoopsRenderer.test.ts +198 -0
- package/src/hooks/__tests__/useSigmaCustomRenderers.test.ts +273 -0
- package/src/hooks/__tests__/useTooltipRenderer.test.ts +289 -0
- package/src/hooks/useGraphLayout.ts +308 -0
- package/src/hooks/useGraphLayoutSelector.ts +19 -0
- package/src/hooks/useGraphLoader.ts +279 -0
- package/src/hooks/useGraphRightSidePanelElements.tsx +36 -0
- package/src/hooks/useGraphState.ts +40 -0
- package/src/hooks/useGraphType.ts +32 -0
- package/src/hooks/useRelationshipTable.ts +212 -0
- package/src/hooks/useRelationshipTableFilters.ts +43 -0
- package/src/hooks/useSelectedEntity.ts +89 -0
- package/src/hooks/useSelfRelationLoopsRenderer.ts +52 -0
- package/src/hooks/useSigmaCustomRenderers.ts +112 -0
- package/src/hooks/useTooltipRenderer.ts +80 -0
- package/src/index.tsx +37 -0
- package/src/rendering/canvas/__tests__/hover.spec.ts +31 -0
- package/src/rendering/canvas/__tests__/label.spec.ts +64 -0
- package/src/rendering/canvas/__tests__/nodeBackground.spec.ts +99 -0
- package/src/rendering/canvas/__tests__/selfRelationLoop.spec.ts +88 -0
- package/src/rendering/canvas/__tests__/tooltip.spec.ts +33 -0
- package/src/rendering/canvas/hover.ts +13 -0
- package/src/rendering/canvas/label.ts +33 -0
- package/src/rendering/canvas/nodeBackground.ts +61 -0
- package/src/rendering/canvas/selfRelationLoop.ts +108 -0
- package/src/rendering/canvas/tooltip.ts +38 -0
- package/src/rendering/icons/collapseIcon.inline.svg.ts +6 -0
- package/src/rendering/icons/expandIcon.inline.svg.ts +5 -0
- package/src/rendering/icons/no_photo.inline.svg.ts +13 -0
- package/src/rendering/webgl/edge.arrowHead.ts +87 -0
- package/src/rendering/webgl/edge.clamped.ts +246 -0
- package/src/rendering/webgl/edge.reversedArrowHead.ts +14 -0
- package/src/rendering/webgl/helpers/__tests__/imageHelper.spec.ts +36 -0
- package/src/rendering/webgl/helpers/imageHelper.ts +13 -0
- package/src/rendering/webgl/image.ts +115 -0
- package/src/rendering/webgl/node.border.ts +78 -0
- package/src/rendering/webgl/node.buttons.ts +241 -0
- package/src/rendering/webgl/node.image.ts +169 -0
- package/src/rendering/webgl/shaders/edge.clamped.vert.glsl.ts +55 -0
- package/src/rendering/webgl/shaders/node.border.frag.glsl.ts +30 -0
- package/src/rendering/webgl/shaders/node.border.vert.glsl.ts +37 -0
- package/src/rendering/webgl/shaders/node.buttons.frag.glsl.ts +32 -0
- package/src/rendering/webgl/shaders/node.buttons.vert.glsl.ts +49 -0
- package/src/rendering/webgl/shaders/node.image.frag.glsl.ts +46 -0
- package/src/rendering/webgl/shaders/node.image.vert.glsl.ts +42 -0
- package/src/types/graphDataTypes.ts +143 -0
- package/src/types/sigmaCustomRenderersTypes.ts +13 -0
- package/src/utils/__tests__/graph.spec.ts +152 -0
- package/src/utils/__tests__/graphLayout.spec.ts +125 -0
- package/src/utils/__tests__/hopsData.spec.ts +456 -0
- package/src/utils/__tests__/processResponceToGraph.spec.ts +165 -0
- package/src/utils/graph.ts +83 -0
- package/src/utils/graphLayout.ts +70 -0
- package/src/utils/hopsData.ts +198 -0
- package/src/utils/processResponseToGraph.ts +32 -0
- package/tsconfig.json +4 -0
- package/webpack.config.js +10 -0
- package/bundle.js +0 -2
- package/bundle.js.LICENSE.txt +0 -54
- /package/{5271a9e7b6651c852e93.png → public/5271a9e7b6651c852e93.png} +0 -0
- /package/{main.css → public/main.css} +0 -0
package/src/components/RightPanelRelationship/components/CollapsibleTable/CollapsibleTable.tsx
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import React, {ElementType, forwardRef, memo, useCallback, useImperativeHandle, useRef, useState} from 'react';
|
|
2
|
+
import classnames from 'classnames';
|
|
3
|
+
import ReactResizeDetector from 'react-resize-detector';
|
|
4
|
+
import {AutoSizeList} from '@reltio/components';
|
|
5
|
+
|
|
6
|
+
import {ColumnsDataItem, RowsDataItem, Sorting} from './types';
|
|
7
|
+
import TableHead from './TableHead';
|
|
8
|
+
import {useStyles} from './styles';
|
|
9
|
+
|
|
10
|
+
type Props = {
|
|
11
|
+
classes?: {
|
|
12
|
+
tableRowWrapper?: string;
|
|
13
|
+
tableRow?: string;
|
|
14
|
+
};
|
|
15
|
+
columnsData?: ColumnsDataItem[];
|
|
16
|
+
rowsData: RowsDataItem[];
|
|
17
|
+
sorting?: Sorting;
|
|
18
|
+
onSort?: ({field, order}: {field: string; order: string}) => void;
|
|
19
|
+
getRowKey?: (index: number, data: unknown) => string;
|
|
20
|
+
ExpandedRowRenderer?: ElementType;
|
|
21
|
+
defaultRowHeight?: number;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const CollapsibleTable = forwardRef(
|
|
25
|
+
(
|
|
26
|
+
{classes, columnsData, rowsData, sorting, onSort, getRowKey, ExpandedRowRenderer, defaultRowHeight}: Props,
|
|
27
|
+
ref
|
|
28
|
+
) => {
|
|
29
|
+
const styles = useStyles();
|
|
30
|
+
const [dimensions, setDimensions] = useState({
|
|
31
|
+
width: 0,
|
|
32
|
+
height: 0
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const renderRow = useCallback(
|
|
36
|
+
({data, index}) => {
|
|
37
|
+
const item = data[index];
|
|
38
|
+
return (
|
|
39
|
+
<div className={classnames(styles.tableRowWrapper, classes?.tableRowWrapper)}>
|
|
40
|
+
<div
|
|
41
|
+
className={classnames(styles.tableRow, classes?.tableRow, {
|
|
42
|
+
[styles.editingRow]: item.expanded
|
|
43
|
+
})}
|
|
44
|
+
>
|
|
45
|
+
{columnsData.map(({id, rowCellValueRenderer, columnClassName}) => {
|
|
46
|
+
const Renderer = rowCellValueRenderer;
|
|
47
|
+
return (
|
|
48
|
+
<div key={id} className={columnClassName}>
|
|
49
|
+
<Renderer value={item[id]} rowValue={item} />
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
})}
|
|
53
|
+
</div>
|
|
54
|
+
{item.expanded && ExpandedRowRenderer && (
|
|
55
|
+
<ExpandedRowRenderer open={item.expanded} rowValue={item} />
|
|
56
|
+
)}
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
59
|
+
},
|
|
60
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
61
|
+
[columnsData, ExpandedRowRenderer]
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const onTableBodyResize = useCallback((width, height) => {
|
|
65
|
+
setDimensions({width, height});
|
|
66
|
+
}, []);
|
|
67
|
+
|
|
68
|
+
const listRef = useRef(null);
|
|
69
|
+
|
|
70
|
+
useImperativeHandle(ref, () => ({
|
|
71
|
+
resetScrollbarPosition: () => {
|
|
72
|
+
listRef.current?.scrollTo(0);
|
|
73
|
+
}
|
|
74
|
+
}));
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<div className={styles.table}>
|
|
78
|
+
<TableHead columnsData={columnsData} sorting={sorting} onSort={onSort} />
|
|
79
|
+
<div className={styles.tableBodyWrapper}>
|
|
80
|
+
<ReactResizeDetector handleHeight handleWidth onResize={onTableBodyResize} />
|
|
81
|
+
<div className={styles.tableBody}>
|
|
82
|
+
<AutoSizeList
|
|
83
|
+
listRef={listRef}
|
|
84
|
+
width={dimensions.width}
|
|
85
|
+
height={dimensions.height}
|
|
86
|
+
data={rowsData}
|
|
87
|
+
defaultItemSize={defaultRowHeight}
|
|
88
|
+
itemKey={getRowKey}
|
|
89
|
+
showNotMeasuredItems
|
|
90
|
+
>
|
|
91
|
+
{renderRow}
|
|
92
|
+
</AutoSizeList>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
export default memo(CollapsibleTable);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React, {memo} from 'react';
|
|
2
|
+
import classnames from 'classnames';
|
|
3
|
+
import {toggleSortOrder} from '@reltio/components';
|
|
4
|
+
|
|
5
|
+
import {ColumnsDataItem, Sorting} from './types';
|
|
6
|
+
import {useStyles} from './styles';
|
|
7
|
+
|
|
8
|
+
type Props = {
|
|
9
|
+
columnsData: ColumnsDataItem[];
|
|
10
|
+
sorting: Sorting;
|
|
11
|
+
onSort?: ({field, order}: {field: string; order: string}) => void;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const TableHead = ({columnsData, sorting, onSort}: Props) => {
|
|
15
|
+
const styles = useStyles();
|
|
16
|
+
return (
|
|
17
|
+
<div className={classnames(styles.tableRow, styles.headRow)}>
|
|
18
|
+
{columnsData.map((columnData) => {
|
|
19
|
+
const {id, sortable, headCellRenderer, columnClassName} = columnData;
|
|
20
|
+
const HeadCellRenderer = headCellRenderer;
|
|
21
|
+
const sortHandler = () => {
|
|
22
|
+
onSort({
|
|
23
|
+
field: id,
|
|
24
|
+
order: sorting.field === id ? toggleSortOrder(sorting.order) : 'asc'
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
const sortingProps = sortable ? {sortField: sorting.field, sortOrder: sorting.order, sortHandler} : {};
|
|
28
|
+
return (
|
|
29
|
+
<div key={id} className={columnClassName}>
|
|
30
|
+
<HeadCellRenderer headCellData={columnData} {...sortingProps} />
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
})}
|
|
34
|
+
</div>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export default memo(TableHead);
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import React, {useImperativeHandle} from 'react';
|
|
2
|
+
import {mount, ReactWrapper, shallow} from 'enzyme';
|
|
3
|
+
import ReactResizeDetector from 'react-resize-detector';
|
|
4
|
+
import {AutoSizeList} from '@reltio/components';
|
|
5
|
+
|
|
6
|
+
import CollapsibleTable from '../CollapsibleTable';
|
|
7
|
+
import TableHead from '../TableHead';
|
|
8
|
+
|
|
9
|
+
jest.mock('react', () => ({
|
|
10
|
+
...jest.requireActual<Record<string, unknown>>('react'),
|
|
11
|
+
useImperativeHandle: jest.fn().mockImplementation(jest.requireActual('react').useImperativeHandle)
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
describe('CollapsibleTable tests', () => {
|
|
15
|
+
const HeadCellRenderer = () => <span>head</span>;
|
|
16
|
+
const RowCellValueRenderer1 = () => <span>value1</span>;
|
|
17
|
+
const RowCellValueRenderer2 = () => <span>value2</span>;
|
|
18
|
+
const ExpandedRowRenderer = () => <span>Expanded content</span>;
|
|
19
|
+
|
|
20
|
+
const defaultProps = {
|
|
21
|
+
columnsData: [
|
|
22
|
+
{
|
|
23
|
+
id: 'id1',
|
|
24
|
+
label: 'Some id',
|
|
25
|
+
headCellRenderer: HeadCellRenderer,
|
|
26
|
+
rowCellValueRenderer: RowCellValueRenderer1,
|
|
27
|
+
sortable: true,
|
|
28
|
+
columnClassName: 'class2'
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: 'id2',
|
|
32
|
+
label: '',
|
|
33
|
+
headCellRenderer: HeadCellRenderer,
|
|
34
|
+
rowCellValueRenderer: RowCellValueRenderer2
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
rowsData: [
|
|
38
|
+
{
|
|
39
|
+
id1: 1,
|
|
40
|
+
id2: 2
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id1: 3,
|
|
44
|
+
id2: 4
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
sorting: {
|
|
48
|
+
order: 'asc',
|
|
49
|
+
field: 'id1'
|
|
50
|
+
},
|
|
51
|
+
onSort: jest.fn(),
|
|
52
|
+
ExpandedRowRenderer,
|
|
53
|
+
defaultRowHeight: 30,
|
|
54
|
+
getRowKey: jest.fn().mockImplementation((index) => index)
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
afterEach(() => {
|
|
58
|
+
jest.clearAllMocks();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should render main parts', () => {
|
|
62
|
+
const component = shallow(<CollapsibleTable {...defaultProps} />);
|
|
63
|
+
expect(component.find(TableHead)).toHaveLength(1);
|
|
64
|
+
expect(component.find(TableHead)).toHaveLength(1);
|
|
65
|
+
const tableBodyWrapper = component.find('.tableBodyWrapper');
|
|
66
|
+
expect(tableBodyWrapper).toHaveLength(1);
|
|
67
|
+
expect(tableBodyWrapper.find(ReactResizeDetector)).toHaveLength(1);
|
|
68
|
+
const tableBody = component.find('.tableBody');
|
|
69
|
+
expect(tableBody).toHaveLength(1);
|
|
70
|
+
expect(tableBody.find(AutoSizeList)).toHaveLength(1);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should provide correct props for TableHead', () => {
|
|
74
|
+
const component = shallow(<CollapsibleTable {...defaultProps} />);
|
|
75
|
+
expect(component.find(TableHead).props()).toEqual({
|
|
76
|
+
columnsData: defaultProps.columnsData,
|
|
77
|
+
sorting: defaultProps.sorting,
|
|
78
|
+
onSort: defaultProps.onSort
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('should provide correct props for AutoSizeList', () => {
|
|
83
|
+
const component = shallow(<CollapsibleTable {...defaultProps} />);
|
|
84
|
+
expect(component.find(AutoSizeList).props()).toMatchObject({
|
|
85
|
+
width: 0,
|
|
86
|
+
height: 0,
|
|
87
|
+
data: defaultProps.rowsData,
|
|
88
|
+
defaultItemSize: defaultProps.defaultRowHeight,
|
|
89
|
+
itemKey: defaultProps.getRowKey,
|
|
90
|
+
showNotMeasuredItems: true
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should set correct width/height for AutoSizeList on parent element resizing', () => {
|
|
95
|
+
const component = shallow(<CollapsibleTable {...defaultProps} />);
|
|
96
|
+
expect(component.find(AutoSizeList).props()).toMatchObject({
|
|
97
|
+
width: 0,
|
|
98
|
+
height: 0
|
|
99
|
+
});
|
|
100
|
+
const resizeDetector = component.find(ReactResizeDetector);
|
|
101
|
+
expect(resizeDetector.props()).toMatchObject({
|
|
102
|
+
handleHeight: true,
|
|
103
|
+
handleWidth: true
|
|
104
|
+
});
|
|
105
|
+
(resizeDetector.prop('onResize') as (width: number, height: number) => void)(100, 200);
|
|
106
|
+
expect(component.find(AutoSizeList).props()).toMatchObject({
|
|
107
|
+
width: 100,
|
|
108
|
+
height: 200
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should provide resetScrollbarPosition imperative handler', () => {
|
|
113
|
+
const component = mount(<CollapsibleTable {...defaultProps} />);
|
|
114
|
+
const useImperativeHandleCalls = (useImperativeHandle as jest.Mock).mock.calls;
|
|
115
|
+
const {resetScrollbarPosition} = useImperativeHandleCalls[useImperativeHandleCalls.length - 1][1]();
|
|
116
|
+
const listRef = component.find(AutoSizeList).prop('listRef');
|
|
117
|
+
const listScrollTo = jest.spyOn(listRef.current, 'scrollTo');
|
|
118
|
+
expect(listScrollTo).not.toHaveBeenCalled();
|
|
119
|
+
resetScrollbarPosition();
|
|
120
|
+
expect(listScrollTo).toHaveBeenCalledWith(0);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('should render correct data rows', () => {
|
|
124
|
+
const component = shallow(<CollapsibleTable {...defaultProps} />);
|
|
125
|
+
const rowRenderer = component.find(AutoSizeList).prop('children');
|
|
126
|
+
const row = new ReactWrapper(rowRenderer({data: defaultProps.rowsData, index: 1}) as JSX.Element);
|
|
127
|
+
const columnWrapper = row.find(`.${defaultProps.columnsData[0].columnClassName}`);
|
|
128
|
+
const cellValue1 = columnWrapper.find(RowCellValueRenderer1);
|
|
129
|
+
expect(cellValue1).toHaveLength(1);
|
|
130
|
+
expect(cellValue1.props()).toEqual({
|
|
131
|
+
value: defaultProps.rowsData[1].id1,
|
|
132
|
+
rowValue: defaultProps.rowsData[1]
|
|
133
|
+
});
|
|
134
|
+
const cellValue2 = row.find(RowCellValueRenderer2);
|
|
135
|
+
expect(cellValue2).toHaveLength(1);
|
|
136
|
+
expect(cellValue2.props()).toEqual({
|
|
137
|
+
value: defaultProps.rowsData[1].id2,
|
|
138
|
+
rowValue: defaultProps.rowsData[1]
|
|
139
|
+
});
|
|
140
|
+
expect(row.find(ExpandedRowRenderer)).toHaveLength(0);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('should render expanded row', () => {
|
|
144
|
+
const props = {
|
|
145
|
+
...defaultProps,
|
|
146
|
+
rowsData: [
|
|
147
|
+
{
|
|
148
|
+
id1: 1,
|
|
149
|
+
id2: 2
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
id1: 3,
|
|
153
|
+
id2: 4,
|
|
154
|
+
expanded: true
|
|
155
|
+
}
|
|
156
|
+
]
|
|
157
|
+
};
|
|
158
|
+
const component = shallow(<CollapsibleTable {...props} />);
|
|
159
|
+
const rowRenderer = component.find(AutoSizeList).prop('children');
|
|
160
|
+
const row1 = new ReactWrapper(rowRenderer({data: props.rowsData, index: 0}) as JSX.Element);
|
|
161
|
+
expect(row1.find(ExpandedRowRenderer)).toHaveLength(0);
|
|
162
|
+
const row2 = new ReactWrapper(rowRenderer({data: props.rowsData, index: 1}) as JSX.Element);
|
|
163
|
+
expect(row2.find(ExpandedRowRenderer)).toHaveLength(1);
|
|
164
|
+
expect(row2.find(ExpandedRowRenderer).props()).toEqual({
|
|
165
|
+
open: true,
|
|
166
|
+
rowValue: props.rowsData[1]
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {shallow} from 'enzyme';
|
|
3
|
+
|
|
4
|
+
import TableHead from '../TableHead';
|
|
5
|
+
|
|
6
|
+
describe('TableHead tests', () => {
|
|
7
|
+
const HeadCellRenderer1 = () => <span>head1</span>;
|
|
8
|
+
const HeadCellRenderer2 = () => <span>head2</span>;
|
|
9
|
+
const RowCellValueRenderer = () => <span>value</span>;
|
|
10
|
+
|
|
11
|
+
const defaultProps = {
|
|
12
|
+
columnsData: [
|
|
13
|
+
{
|
|
14
|
+
id: 'id1',
|
|
15
|
+
label: 'Some id',
|
|
16
|
+
headCellRenderer: HeadCellRenderer1,
|
|
17
|
+
rowCellValueRenderer: RowCellValueRenderer,
|
|
18
|
+
sortable: true,
|
|
19
|
+
columnClassName: 'class1'
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: 'id2',
|
|
23
|
+
label: '',
|
|
24
|
+
headCellRenderer: HeadCellRenderer2,
|
|
25
|
+
rowCellValueRenderer: RowCellValueRenderer,
|
|
26
|
+
columnClassName: 'class2'
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
sorting: {
|
|
30
|
+
order: 'desc',
|
|
31
|
+
field: 'id1'
|
|
32
|
+
},
|
|
33
|
+
onSort: jest.fn()
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
afterEach(() => {
|
|
37
|
+
jest.clearAllMocks();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should render each columns head cell in column wrapper', () => {
|
|
41
|
+
const component = shallow(<TableHead {...defaultProps} />);
|
|
42
|
+
const column1Wrapper = component.find(`.${defaultProps.columnsData[0].columnClassName}`);
|
|
43
|
+
expect(column1Wrapper).toHaveLength(1);
|
|
44
|
+
const headCell1 = column1Wrapper.find(defaultProps.columnsData[0].headCellRenderer);
|
|
45
|
+
expect(headCell1).toHaveLength(1);
|
|
46
|
+
expect(headCell1.prop('headCellData')).toBe(defaultProps.columnsData[0]);
|
|
47
|
+
|
|
48
|
+
const column2Wrapper = component.find(`.${defaultProps.columnsData[1].columnClassName}`);
|
|
49
|
+
expect(column2Wrapper).toHaveLength(1);
|
|
50
|
+
const headCell2 = column2Wrapper.find(defaultProps.columnsData[1].headCellRenderer);
|
|
51
|
+
expect(headCell2).toHaveLength(1);
|
|
52
|
+
expect(headCell2.prop('headCellData')).toBe(defaultProps.columnsData[1]);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should provide sorting props for sortable columns', () => {
|
|
56
|
+
const component = shallow(<TableHead {...defaultProps} />);
|
|
57
|
+
const headCell1 = component.find(defaultProps.columnsData[0].headCellRenderer);
|
|
58
|
+
expect(headCell1.props()).toEqual({
|
|
59
|
+
headCellData: defaultProps.columnsData[0],
|
|
60
|
+
sortField: defaultProps.sorting.field,
|
|
61
|
+
sortOrder: defaultProps.sorting.order,
|
|
62
|
+
sortHandler: expect.any(Function)
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should toggle sort order on sortHandler calling if sorting.field was the same', () => {
|
|
67
|
+
const props = {
|
|
68
|
+
...defaultProps,
|
|
69
|
+
sorting: {
|
|
70
|
+
order: 'asc',
|
|
71
|
+
field: 'id1'
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const component = shallow(<TableHead {...props} />);
|
|
75
|
+
const headCell1 = component.find(props.columnsData[0].headCellRenderer);
|
|
76
|
+
(headCell1.prop('sortHandler') as () => void)();
|
|
77
|
+
expect(props.onSort).toHaveBeenCalledWith({
|
|
78
|
+
field: props.columnsData[0].id,
|
|
79
|
+
order: 'desc'
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should set sort order as "asc" on sortHandler calling if sorting.field was not the same', () => {
|
|
84
|
+
const props = {
|
|
85
|
+
...defaultProps,
|
|
86
|
+
sorting: {
|
|
87
|
+
order: 'asc',
|
|
88
|
+
field: 'id2'
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
const component = shallow(<TableHead {...props} />);
|
|
92
|
+
const headCell1 = component.find(props.columnsData[0].headCellRenderer);
|
|
93
|
+
(headCell1.prop('sortHandler') as () => void)();
|
|
94
|
+
expect(props.onSort).toHaveBeenCalledWith({
|
|
95
|
+
field: props.columnsData[0].id,
|
|
96
|
+
order: 'asc'
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('should not provide sorting props for non sortable columns', () => {
|
|
101
|
+
const component = shallow(<TableHead {...defaultProps} />);
|
|
102
|
+
const headCell2 = component.find(defaultProps.columnsData[1].headCellRenderer);
|
|
103
|
+
expect(headCell2.props()).toEqual({
|
|
104
|
+
headCellData: defaultProps.columnsData[1]
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {makeStyles} from '@mui/styles';
|
|
2
|
+
|
|
3
|
+
const border = '1px solid rgba(0, 0, 0, 0.05)';
|
|
4
|
+
|
|
5
|
+
export const useStyles = makeStyles({
|
|
6
|
+
table: {
|
|
7
|
+
flex: 1,
|
|
8
|
+
height: '100%',
|
|
9
|
+
display: 'flex',
|
|
10
|
+
flexDirection: 'column',
|
|
11
|
+
overflow: 'hidden'
|
|
12
|
+
},
|
|
13
|
+
tableBody: {
|
|
14
|
+
height: '100%',
|
|
15
|
+
overflow: 'auto'
|
|
16
|
+
},
|
|
17
|
+
tableBodyWrapper: {
|
|
18
|
+
height: '100%',
|
|
19
|
+
overflow: 'hidden'
|
|
20
|
+
},
|
|
21
|
+
tableRowWrapper: {
|
|
22
|
+
borderBottom: border
|
|
23
|
+
},
|
|
24
|
+
tableRow: {
|
|
25
|
+
display: 'flex',
|
|
26
|
+
alignItems: 'center',
|
|
27
|
+
'& > div': {
|
|
28
|
+
flexShrink: 0
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
editingRow: {
|
|
32
|
+
paddingTop: '8px',
|
|
33
|
+
paddingBottom: '8px'
|
|
34
|
+
},
|
|
35
|
+
headRow: {
|
|
36
|
+
borderBottom: border
|
|
37
|
+
}
|
|
38
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {ElementType} from 'react';
|
|
2
|
+
|
|
3
|
+
export type ColumnsDataItem = {
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
headCellRenderer: ElementType;
|
|
7
|
+
rowCellValueRenderer: ElementType;
|
|
8
|
+
sortable?: boolean;
|
|
9
|
+
columnClassName?: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type RowsDataItem = {
|
|
13
|
+
expanded?: boolean;
|
|
14
|
+
[id: string]: unknown;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type Sorting = {
|
|
18
|
+
field: string;
|
|
19
|
+
order: string;
|
|
20
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import i18n from 'ui-i18n';
|
|
3
|
+
import {pick} from 'ramda';
|
|
4
|
+
import {ConfirmationDialog, withContext} from '@reltio/components';
|
|
5
|
+
|
|
6
|
+
import {GraphStateContext} from '../../../../contexts/GraphStateContext';
|
|
7
|
+
|
|
8
|
+
type Props = {
|
|
9
|
+
uri: string;
|
|
10
|
+
open: boolean;
|
|
11
|
+
onClose: () => void;
|
|
12
|
+
onDeleteRelation?: (uri) => void;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const DeleteRelationDialog = ({uri, open, onClose, onDeleteRelation}: Props) => {
|
|
16
|
+
return (
|
|
17
|
+
<ConfirmationDialog
|
|
18
|
+
open={open}
|
|
19
|
+
title={i18n.text('Do you want to make a clean break?')}
|
|
20
|
+
content={i18n.text(
|
|
21
|
+
'To end this relationship, click Delete Relationship. To keep the connection, click Cancel.'
|
|
22
|
+
)}
|
|
23
|
+
saveCaption={i18n.text('Delete relationship')}
|
|
24
|
+
discardCaption={i18n.text('Cancel')}
|
|
25
|
+
onDiscard={onClose}
|
|
26
|
+
onSave={() => {
|
|
27
|
+
onDeleteRelation(uri);
|
|
28
|
+
onClose();
|
|
29
|
+
}}
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default withContext(GraphStateContext, pick(['onDeleteRelation']), DeleteRelationDialog);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {mount} from 'enzyme';
|
|
3
|
+
import {identity} from 'ramda';
|
|
4
|
+
import {ConfirmationDialog} from '@reltio/components';
|
|
5
|
+
|
|
6
|
+
import DeleteRelationDialog from '../DeleteRelationDialog';
|
|
7
|
+
import {GraphStateContext} from '../../../../../contexts/GraphStateContext';
|
|
8
|
+
import {GraphState} from '../../../../../types/graphDataTypes';
|
|
9
|
+
|
|
10
|
+
const setUp = ({uri = '', open = false, onClose = identity, onDeleteRelation = identity} = {}) => {
|
|
11
|
+
return mount(
|
|
12
|
+
<GraphStateContext.Provider value={{onDeleteRelation} as GraphState}>
|
|
13
|
+
<DeleteRelationDialog open={open} onClose={onClose} uri={uri} />
|
|
14
|
+
</GraphStateContext.Provider>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
describe('DeleteRelationDialog tests', () => {
|
|
19
|
+
it('should render ConfirmationDialog', () => {
|
|
20
|
+
const open = true;
|
|
21
|
+
const onClose = jest.fn();
|
|
22
|
+
const component = setUp({open, onClose});
|
|
23
|
+
const dialog = component.find(ConfirmationDialog);
|
|
24
|
+
expect(dialog).toHaveLength(1);
|
|
25
|
+
expect(dialog.prop('title')).toBe('Do you want to make a clean break?');
|
|
26
|
+
expect(dialog.prop('content')).toBe(
|
|
27
|
+
'To end this relationship, click Delete Relationship. To keep the connection, click Cancel.'
|
|
28
|
+
);
|
|
29
|
+
expect(dialog.prop('saveCaption')).toBe('Delete relationship');
|
|
30
|
+
expect(dialog.prop('discardCaption')).toBe('Cancel');
|
|
31
|
+
expect(dialog.prop('open')).toBe(open);
|
|
32
|
+
expect(dialog.prop('onDiscard')).toBe(onClose);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should call onDeleteRelation and onClose on dialog "onSave" prop calling', () => {
|
|
36
|
+
const open = true;
|
|
37
|
+
const uri = 'uri1';
|
|
38
|
+
const onClose = jest.fn();
|
|
39
|
+
const onDeleteRelation = jest.fn();
|
|
40
|
+
const component = setUp({uri, open, onClose, onDeleteRelation});
|
|
41
|
+
const dialog = component.find(ConfirmationDialog);
|
|
42
|
+
dialog.prop('onSave')();
|
|
43
|
+
expect(onDeleteRelation).toHaveBeenCalledWith(uri);
|
|
44
|
+
expect(onClose).toHaveBeenCalled();
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React, {useState} from 'react';
|
|
2
|
+
import i18n from 'ui-i18n';
|
|
3
|
+
import {pick} from 'ramda';
|
|
4
|
+
import AddIcon from '@mui/icons-material/Add';
|
|
5
|
+
import {ActionButton, ActionButtonMode, withContext} from '@reltio/components';
|
|
6
|
+
import {Entity} from '@reltio/mdm-sdk';
|
|
7
|
+
|
|
8
|
+
import {GraphStateContext} from '../../../../contexts/GraphStateContext';
|
|
9
|
+
import GraphAddRelationDialog from './GraphAddRelationDialog';
|
|
10
|
+
import {useCreatableInOutRelationTypes} from './useCreatableInOutRelationTypes';
|
|
11
|
+
|
|
12
|
+
type Props = {
|
|
13
|
+
selectedEntity?: Entity;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const GraphAddRelationButton = ({selectedEntity}: Props) => {
|
|
17
|
+
const {inRelationTypes, outRelationTypes} = useCreatableInOutRelationTypes(selectedEntity?.type);
|
|
18
|
+
const canAddSomeRelation = inRelationTypes.length + outRelationTypes.length > 0;
|
|
19
|
+
const [openDialog, setOpenDialog] = useState(false);
|
|
20
|
+
const handleClick = () => {
|
|
21
|
+
setOpenDialog(true);
|
|
22
|
+
};
|
|
23
|
+
const onCancel = () => {
|
|
24
|
+
setOpenDialog(false);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
canAddSomeRelation && (
|
|
29
|
+
<>
|
|
30
|
+
<ActionButton
|
|
31
|
+
data-reltio-id="reltio-add-relationship-button"
|
|
32
|
+
mode={ActionButtonMode.button}
|
|
33
|
+
label={i18n.text('Add relationship')}
|
|
34
|
+
icon={AddIcon}
|
|
35
|
+
onClick={handleClick}
|
|
36
|
+
/>
|
|
37
|
+
<GraphAddRelationDialog open={openDialog} onClose={onCancel} />
|
|
38
|
+
</>
|
|
39
|
+
)
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export default withContext(GraphStateContext, pick(['selectedEntity']), GraphAddRelationButton);
|