@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.
Files changed (164) hide show
  1. package/index.ts +1 -0
  2. package/package.json +26 -9
  3. package/public/bundle.js +205 -0
  4. package/public/bundle.js.LICENSE.txt +88 -0
  5. package/public/package.json +29 -0
  6. package/scripts/build/index.js +20 -0
  7. package/src/__tests__/GraphView.test.tsx +25 -0
  8. package/src/components/CircleLayout/CircleLayout.tsx +76 -0
  9. package/src/components/CircleLayout/__tests__/CircleLayout.test.tsx +194 -0
  10. package/src/components/GotoButton/GotoButton.tsx +23 -0
  11. package/src/components/GotoButton/__tests__/GotoButton.test.tsx +33 -0
  12. package/src/components/GotoButton/styles.ts +15 -0
  13. package/src/components/GraphArea/GraphArea.tsx +113 -0
  14. package/src/components/GraphArea/__tests__/GraphArea.test.tsx +202 -0
  15. package/src/components/GraphArea/styles.ts +30 -0
  16. package/src/components/GraphLayoutSelector/GraphLayoutSelector.tsx +43 -0
  17. package/src/components/GraphLayoutSelector/__tests__/GraphLayoutSelector.spec.tsx +44 -0
  18. package/src/components/GraphLayoutSelector/styles.ts +15 -0
  19. package/src/components/GraphPerspectiveView/GraphPerspectiveView.tsx +58 -0
  20. package/src/components/GraphPerspectiveView/__tests__/GraphPerspectiveView.test.tsx +115 -0
  21. package/src/components/GraphPerspectiveView/__tests__/useGraphLoader.test.tsx +1519 -0
  22. package/src/components/GraphPerspectiveView/__tests__/useRelationshipTable.test.tsx +1003 -0
  23. package/src/components/GraphPerspectiveView/__tests__/useSelectedEntity.test.tsx +373 -0
  24. package/src/components/GraphPerspectiveView/styles.ts +34 -0
  25. package/src/components/GraphRightSidePanel/GraphRightSidePanel.tsx +27 -0
  26. package/src/components/GraphRightSidePanel/__tests__/GraphRightSidePanel.test.tsx +18 -0
  27. package/src/components/GraphRightSidePanel/icons/relationship-icon.svg +3 -0
  28. package/src/components/GraphRightSidePanel/styles.ts +8 -0
  29. package/src/components/GraphTypeSelector/GraphTypeSelector.tsx +56 -0
  30. package/src/components/GraphTypeSelector/__tests__/GraphTypeSelector.test.tsx +109 -0
  31. package/src/components/GraphTypeSelector/styles.ts +17 -0
  32. package/src/components/HierarchyLayout/HierarchyLayout.ts +102 -0
  33. package/src/components/HierarchyLayout/__tests__/HierarchyLayout.spec.tsx +241 -0
  34. package/src/components/HierarchyLayout/__tests__/buildHierarchy.spec.ts +130 -0
  35. package/src/components/HierarchyLayout/__tests__/calculations.spec.ts +230 -0
  36. package/src/components/HierarchyLayout/buildHierarchy.ts +109 -0
  37. package/src/components/HierarchyLayout/calculations.ts +86 -0
  38. package/src/components/RightPanelEntityDetails/RightPanelEntityDetails.tsx +33 -0
  39. package/src/components/RightPanelEntityDetails/__tests__/RightPanelEntityDetails.test.tsx +39 -0
  40. package/src/components/RightPanelEntityDetails/styles.ts +12 -0
  41. package/src/components/RightPanelProfileBand/RightPanelProfileBand.tsx +33 -0
  42. package/src/components/RightPanelProfileBand/__tests__/RightPanelProfileBand.test.tsx +67 -0
  43. package/src/components/RightPanelProfileBand/styles.ts +8 -0
  44. package/src/components/RightPanelRelationship/RightPanelRelationship.tsx +25 -0
  45. package/src/components/RightPanelRelationship/__tests__/RightPanelRelationship.test.tsx +18 -0
  46. package/src/components/RightPanelRelationship/components/CollapsibleTable/CollapsibleTable.tsx +100 -0
  47. package/src/components/RightPanelRelationship/components/CollapsibleTable/TableHead.tsx +38 -0
  48. package/src/components/RightPanelRelationship/components/CollapsibleTable/__tests__/CollapsibleTable.test.tsx +169 -0
  49. package/src/components/RightPanelRelationship/components/CollapsibleTable/__tests__/TableHead.test.tsx +107 -0
  50. package/src/components/RightPanelRelationship/components/CollapsibleTable/styles.ts +38 -0
  51. package/src/components/RightPanelRelationship/components/CollapsibleTable/types.ts +20 -0
  52. package/src/components/RightPanelRelationship/components/DeleteRelationDialog/DeleteRelationDialog.tsx +34 -0
  53. package/src/components/RightPanelRelationship/components/DeleteRelationDialog/__tests__/DeleteRelationDialog.test.tsx +46 -0
  54. package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/GraphAddRelationButton.tsx +43 -0
  55. package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/GraphAddRelationDialog.tsx +121 -0
  56. package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/__tests__/GraphAddRelationButton.test.tsx +80 -0
  57. package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/__tests__/GraphAddRelationDialog.test.tsx +262 -0
  58. package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/__tests__/mockdata.ts +75 -0
  59. package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/styles.ts +25 -0
  60. package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/useCreatableInOutRelationTypes.ts +13 -0
  61. package/src/components/RightPanelRelationship/components/RelationshipTable/RelationshipTable.tsx +126 -0
  62. package/src/components/RightPanelRelationship/components/RelationshipTable/__tests__/RelationshipTable.test.tsx +176 -0
  63. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/ControlsCellRenderer.tsx +59 -0
  64. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/DefaultCellRenderer.tsx +29 -0
  65. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/ExpandedRowRenderer.tsx +94 -0
  66. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/HeadCellRenderer.tsx +34 -0
  67. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/ProfileCellRenderer.tsx +41 -0
  68. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/ControlsCellRenderer.test.tsx +80 -0
  69. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/DefaultCellRenderer.test.tsx +47 -0
  70. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/ExpandedRowRenderer.test.tsx +166 -0
  71. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/HeadCellRenderer.test.tsx +23 -0
  72. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/ProfileCellRenderer.test.tsx +47 -0
  73. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/components/DeleteRelationButton.tsx +32 -0
  74. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/components/__tests__/DeleteRelationButton.test.tsx +28 -0
  75. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/styles.ts +113 -0
  76. package/src/components/RightPanelRelationship/components/RelationshipTable/styles.ts +36 -0
  77. package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsFilters.tsx +41 -0
  78. package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsFiltersDialog/RelationshipsFiltersDialog.tsx +91 -0
  79. package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsFiltersDialog/__tests__/RelationshipsFilterDialog.test.tsx +192 -0
  80. package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsFiltersDialog/styles.ts +34 -0
  81. package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsSearchTextField/RelationshipsSearchTextField.tsx +31 -0
  82. package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsSearchTextField/__tests__/RelationshipsSearchTextField.test.tsx +43 -0
  83. package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsSearchTextField/styles.ts +17 -0
  84. package/src/components/RightPanelRelationship/components/RelationshipsFilters/__tests__/RelationshipsFilters.test.tsx +76 -0
  85. package/src/components/RightPanelRelationship/components/RelationshipsFilters/styles.ts +19 -0
  86. package/src/components/RightPanelRelationship/styles.ts +20 -0
  87. package/src/components/SigmaCustomRenderers/SigmaCustomRenderersContainer.tsx +16 -0
  88. package/src/components/SigmaGraphContainer/SigmaGraphContainer.tsx +55 -0
  89. package/src/components/SigmaGraphContainer/__tests__/SigmaGraphContainer.test.tsx +25 -0
  90. package/src/components/SigmaGraphResizer/SigmaGraphResizer.tsx +13 -0
  91. package/src/components/SigmaGraphResizer/__tests__/SigmaGraphResizer.test.tsx +28 -0
  92. package/src/components/TreeLayout/TreeLayout.tsx +33 -0
  93. package/src/components/TreeLayout/__tests__/TreeLayout.test.tsx +42 -0
  94. package/src/components/TreeLayout/styles.ts +10 -0
  95. package/src/components/ZoomSlider/ZoomSlider.tsx +90 -0
  96. package/src/components/ZoomSlider/__tests__/ZoomSlider.test.tsx +84 -0
  97. package/src/components/ZoomSlider/styles.ts +57 -0
  98. package/src/constants/index.ts +1 -0
  99. package/src/contexts/GraphStateContext.tsx +19 -0
  100. package/src/contexts/SigmaCustomRenderersContext.ts +20 -0
  101. package/src/helpers/relationsHelpers.ts +9 -0
  102. package/src/hooks/__tests__/useGraphLayout.test.tsx +825 -0
  103. package/src/hooks/__tests__/useGraphLayoutSelector.test.tsx +19 -0
  104. package/src/hooks/__tests__/useSelfRelationLoopsRenderer.test.ts +198 -0
  105. package/src/hooks/__tests__/useSigmaCustomRenderers.test.ts +273 -0
  106. package/src/hooks/__tests__/useTooltipRenderer.test.ts +289 -0
  107. package/src/hooks/useGraphLayout.ts +308 -0
  108. package/src/hooks/useGraphLayoutSelector.ts +19 -0
  109. package/src/hooks/useGraphLoader.ts +279 -0
  110. package/src/hooks/useGraphRightSidePanelElements.tsx +36 -0
  111. package/src/hooks/useGraphState.ts +40 -0
  112. package/src/hooks/useGraphType.ts +32 -0
  113. package/src/hooks/useRelationshipTable.ts +212 -0
  114. package/src/hooks/useRelationshipTableFilters.ts +43 -0
  115. package/src/hooks/useSelectedEntity.ts +89 -0
  116. package/src/hooks/useSelfRelationLoopsRenderer.ts +52 -0
  117. package/src/hooks/useSigmaCustomRenderers.ts +112 -0
  118. package/src/hooks/useTooltipRenderer.ts +80 -0
  119. package/src/index.tsx +37 -0
  120. package/src/rendering/canvas/__tests__/hover.spec.ts +31 -0
  121. package/src/rendering/canvas/__tests__/label.spec.ts +64 -0
  122. package/src/rendering/canvas/__tests__/nodeBackground.spec.ts +99 -0
  123. package/src/rendering/canvas/__tests__/selfRelationLoop.spec.ts +88 -0
  124. package/src/rendering/canvas/__tests__/tooltip.spec.ts +33 -0
  125. package/src/rendering/canvas/hover.ts +13 -0
  126. package/src/rendering/canvas/label.ts +33 -0
  127. package/src/rendering/canvas/nodeBackground.ts +61 -0
  128. package/src/rendering/canvas/selfRelationLoop.ts +108 -0
  129. package/src/rendering/canvas/tooltip.ts +38 -0
  130. package/src/rendering/icons/collapseIcon.inline.svg.ts +6 -0
  131. package/src/rendering/icons/expandIcon.inline.svg.ts +5 -0
  132. package/src/rendering/icons/no_photo.inline.svg.ts +13 -0
  133. package/src/rendering/webgl/edge.arrowHead.ts +87 -0
  134. package/src/rendering/webgl/edge.clamped.ts +246 -0
  135. package/src/rendering/webgl/edge.reversedArrowHead.ts +14 -0
  136. package/src/rendering/webgl/helpers/__tests__/imageHelper.spec.ts +36 -0
  137. package/src/rendering/webgl/helpers/imageHelper.ts +13 -0
  138. package/src/rendering/webgl/image.ts +115 -0
  139. package/src/rendering/webgl/node.border.ts +78 -0
  140. package/src/rendering/webgl/node.buttons.ts +241 -0
  141. package/src/rendering/webgl/node.image.ts +169 -0
  142. package/src/rendering/webgl/shaders/edge.clamped.vert.glsl.ts +55 -0
  143. package/src/rendering/webgl/shaders/node.border.frag.glsl.ts +30 -0
  144. package/src/rendering/webgl/shaders/node.border.vert.glsl.ts +37 -0
  145. package/src/rendering/webgl/shaders/node.buttons.frag.glsl.ts +32 -0
  146. package/src/rendering/webgl/shaders/node.buttons.vert.glsl.ts +49 -0
  147. package/src/rendering/webgl/shaders/node.image.frag.glsl.ts +46 -0
  148. package/src/rendering/webgl/shaders/node.image.vert.glsl.ts +42 -0
  149. package/src/types/graphDataTypes.ts +143 -0
  150. package/src/types/sigmaCustomRenderersTypes.ts +13 -0
  151. package/src/utils/__tests__/graph.spec.ts +152 -0
  152. package/src/utils/__tests__/graphLayout.spec.ts +125 -0
  153. package/src/utils/__tests__/hopsData.spec.ts +456 -0
  154. package/src/utils/__tests__/processResponceToGraph.spec.ts +165 -0
  155. package/src/utils/graph.ts +83 -0
  156. package/src/utils/graphLayout.ts +70 -0
  157. package/src/utils/hopsData.ts +198 -0
  158. package/src/utils/processResponseToGraph.ts +32 -0
  159. package/tsconfig.json +4 -0
  160. package/webpack.config.js +10 -0
  161. package/bundle.js +0 -2
  162. package/bundle.js.LICENSE.txt +0 -54
  163. /package/{5271a9e7b6651c852e93.png → public/5271a9e7b6651c852e93.png} +0 -0
  164. /package/{main.css → public/main.css} +0 -0
@@ -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);