UI : Fixed Lineage Nodes positioning (#2020)

* UI : Fixed Lineage Nodes positioning

* Moved utils to utils file

* Addressing review comment
This commit is contained in:
Sachin Chaurasiya 2022-01-05 14:49:54 +05:30 committed by GitHub
parent 2be8b0c20c
commit 5dd9089b7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 81 additions and 4 deletions

View File

@ -24,6 +24,7 @@
"cookie-storage": "^6.1.0", "cookie-storage": "^6.1.0",
"core-js": "^3.10.1", "core-js": "^3.10.1",
"cronstrue": "^1.122.0", "cronstrue": "^1.122.0",
"dagre": "^0.8.5",
"diff": "^5.0.0", "diff": "^5.0.0",
"draft-js": "^0.11.7", "draft-js": "^0.11.7",
"fast-json-patch": "^3.0.0-1", "fast-json-patch": "^3.0.0-1",

View File

@ -31,6 +31,7 @@ import useToastContext from '../../hooks/useToastContext';
import { import {
dragHandle, dragHandle,
getDataLabel, getDataLabel,
getLayoutedElements,
getLineageData, getLineageData,
getNoLineageDataPlaceholder, getNoLineageDataPlaceholder,
onLoad, onLoad,
@ -107,7 +108,9 @@ const Entitylineage: FunctionComponent<EntityLineageProp> = ({
) as Elements; ) as Elements;
}; };
const [elements, setElements] = useState<Elements>(setElementsHandle()); const [elements, setElements] = useState<Elements>(
getLayoutedElements(setElementsHandle())
);
const closeDrawer = (value: boolean) => { const closeDrawer = (value: boolean) => {
setIsDrawerOpen(value); setIsDrawerOpen(value);
@ -152,7 +155,7 @@ const Entitylineage: FunctionComponent<EntityLineageProp> = ({
}; };
const onNodeExpand = (tableColumns?: Column[]) => { const onNodeExpand = (tableColumns?: Column[]) => {
const elements = setElementsHandle(); const elements = getLayoutedElements(setElementsHandle());
setElements( setElements(
elements.map((preEl) => { elements.map((preEl) => {
if (preEl.id.includes(expandNode?.id as string)) { if (preEl.id.includes(expandNode?.id as string)) {
@ -189,7 +192,7 @@ const Entitylineage: FunctionComponent<EntityLineageProp> = ({
}; };
useEffect(() => { useEffect(() => {
setElements(setElementsHandle()); setElements(getLayoutedElements(setElementsHandle()));
setExpandNode(undefined); setExpandNode(undefined);
setTableColumns([]); setTableColumns([]);
}, [entityLineage, isNodeLoading]); }, [entityLineage, isNodeLoading]);

View File

@ -290,3 +290,6 @@ export const TITLE_FOR_NON_ADMIN_ACTION =
// Entity Lineage Constant // Entity Lineage Constant
export const positionX = 150; export const positionX = 150;
export const positionY = 60; export const positionY = 60;
export const nodeWidth = 172;
export const nodeHeight = 36;

View File

@ -24,3 +24,8 @@ export enum ChangeType {
UPDATED = 'Updated', UPDATED = 'Updated',
REMOVED = 'Removed', REMOVED = 'Removed',
} }
export enum EntityLineageDirection {
TOP_BOTTOM = 'TB',
LEFT_RIGHT = 'LR',
}

View File

@ -27,3 +27,4 @@ declare module 'react-table';
declare module 'recharts'; declare module 'recharts';
declare module 'diff'; declare module 'diff';
declare module '@deuex-solutions/react-tutorial'; declare module '@deuex-solutions/react-tutorial';
declare module 'dagre';

View File

@ -21,17 +21,25 @@ import {
FlowElement, FlowElement,
ArrowHeadType, ArrowHeadType,
Node, Node,
isNode,
} from 'react-flow-renderer'; } from 'react-flow-renderer';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { SelectedNode } from '../components/EntityLineage/EntityLineage.interface'; import { SelectedNode } from '../components/EntityLineage/EntityLineage.interface';
import Loader from '../components/Loader/Loader'; import Loader from '../components/Loader/Loader';
import { positionX, positionY } from '../constants/constants'; import {
nodeHeight,
nodeWidth,
positionX,
positionY,
} from '../constants/constants';
import { import {
EntityLineage, EntityLineage,
Edge as LineageEdge, Edge as LineageEdge,
} from '../generated/type/entityLineage'; } from '../generated/type/entityLineage';
import { EntityReference } from '../generated/type/entityReference'; import { EntityReference } from '../generated/type/entityReference';
import { isLeafNode } from './EntityUtils'; import { isLeafNode } from './EntityUtils';
import dagre from 'dagre';
import { EntityLineageDirection } from '../enums/entity.enum';
export const onLoad = (reactFlowInstance: OnLoadParams) => { export const onLoad = (reactFlowInstance: OnLoadParams) => {
reactFlowInstance.fitView(); reactFlowInstance.fitView();
@ -362,3 +370,44 @@ export const getNoLineageDataPlaceholder = () => {
</div> </div>
); );
}; };
const dagreGraph = new dagre.graphlib.Graph();
dagreGraph.setDefaultEdgeLabel(() => ({}));
export const getLayoutedElements = (
elements: Elements,
direction = EntityLineageDirection.LEFT_RIGHT
) => {
const isHorizontal = direction === EntityLineageDirection.LEFT_RIGHT;
dagreGraph.setGraph({ rankdir: direction });
elements.forEach((el) => {
if (isNode(el)) {
dagreGraph.setNode(el.id, {
width: el?.__rf?.width ?? nodeWidth,
height: el?.__rf?.height ?? nodeHeight,
});
} else {
dagreGraph.setEdge(el.source, el.target);
}
});
dagre.layout(dagreGraph);
return elements.map((el) => {
if (isNode(el)) {
const nodeWithPosition = dagreGraph.node(el.id);
el.targetPosition = isHorizontal ? Position.Left : Position.Top;
el.sourcePosition = isHorizontal ? Position.Right : Position.Bottom;
el.position = {
x:
nodeWithPosition.x -
(el?.__rf?.width ?? nodeWidth) / 2 +
Math.random() / 1000,
y: nodeWithPosition.y - (el?.__rf?.height ?? nodeHeight) / 2,
};
}
return el;
});
};

View File

@ -4300,6 +4300,14 @@ d@1, d@^1.0.1:
es5-ext "^0.10.50" es5-ext "^0.10.50"
type "^1.0.1" type "^1.0.1"
dagre@^0.8.5:
version "0.8.5"
resolved "https://registry.yarnpkg.com/dagre/-/dagre-0.8.5.tgz#ba30b0055dac12b6c1fcc247817442777d06afee"
integrity sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==
dependencies:
graphlib "^2.1.8"
lodash "^4.17.15"
damerau-levenshtein@^1.0.7: damerau-levenshtein@^1.0.7:
version "1.0.7" version "1.0.7"
resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz#64368003512a1a6992593741a09a9d31a836f55d" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz#64368003512a1a6992593741a09a9d31a836f55d"
@ -5965,6 +5973,13 @@ grapheme-splitter@^1.0.4:
resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==
graphlib@^2.1.8:
version "2.1.8"
resolved "https://registry.yarnpkg.com/graphlib/-/graphlib-2.1.8.tgz#5761d414737870084c92ec7b5dbcb0592c9d35da"
integrity sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==
dependencies:
lodash "^4.17.15"
growly@^1.3.0: growly@^1.3.0:
version "1.3.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"