Fix#16404 - Show Node level lineage by default (#16445)

* default to node layer

* update cypress

* code cleanup

* fix cypress
This commit is contained in:
Karan Hotchandani 2024-05-29 12:10:02 +05:30 committed by GitHub
parent 0abd3ca5fe
commit f0cda8464f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 96 additions and 95 deletions

View File

@ -199,15 +199,18 @@ const addPipelineBetweenNodes = (
}
};
const expandCols = (nodeFqn, hasShowMore) => {
cy.get(
`[data-testid="lineage-node-${nodeFqn}"] [data-testid="expand-cols-btn"]`
).click({ force: true });
if (hasShowMore) {
cy.get(
`[data-testid="lineage-node-${nodeFqn}"] [data-testid="show-more-cols-btn"]`
).click({ force: true });
}
const activateColumnLayer = () => {
cy.get('[data-testid="lineage-layer-btn"]').click();
cy.get('[data-testid="lineage-layer-column-btn"]').click();
};
const verifyColumnLayerInactive = () => {
cy.get('[data-testid="lineage-layer-btn"]').click(); // Open Layer popover
cy.get('[data-testid="lineage-layer-column-btn"]').should(
'not.have.class',
'active'
);
cy.get('[data-testid="lineage-layer-btn"]').click(); // Close Layer popover
};
const addColumnLineage = (fromNode, toNode, exitEditMode = true) => {
@ -243,6 +246,7 @@ describe('Lineage verification', { tags: 'DataAssets' }, () => {
});
cy.get('[data-testid="lineage"]').click();
verifyColumnLayerInactive();
cy.get('[data-testid="edit-lineage"]').click();
performZoomOut();
@ -329,6 +333,7 @@ describe('Lineage verification', { tags: 'DataAssets' }, () => {
const targetEntity = LINEAGE_ITEMS[i];
if (targetEntity.columns.length > 0) {
addPipelineBetweenNodes(sourceEntity, targetEntity);
activateColumnLayer();
// Add column lineage
addColumnLineage(sourceEntity, targetEntity);
cy.get('[data-testid="edit-lineage"]').click();

View File

@ -20,7 +20,6 @@ import CustomControlsComponent from './CustomControls.component';
const mockOnOptionSelect = jest.fn();
const mockOnLineageConfigUpdate = jest.fn();
const mockOnEditLineageClick = jest.fn();
const mockOnExpandColumnClick = jest.fn();
const mockHandleFullScreenViewClick = jest.fn();
const mockOnExitFullScreenViewClick = jest.fn();
const mockOnZoomHandler = jest.fn();
@ -50,7 +49,6 @@ jest.mock('reactflow', () => ({
jest.mock('../../../context/LineageProvider/LineageProvider', () => ({
useLineageProvider: jest.fn().mockImplementation(() => ({
toggleColumnView: mockOnExpandColumnClick,
onLineageEditClick: mockOnEditLineageClick,
onExportClick: mockOnExportClick,
activeLayer: [LineageLayerView.COLUMN],

View File

@ -87,7 +87,6 @@ jest.mock('../../../context/LineageProvider/LineageProvider', () => ({
downstreamEdges: [],
},
activeLayer: [LineageLayerView.COLUMN],
expandedNodes: [],
fetchPipelineStatus: jest.fn(),
onColumnClick: onMockColumnClick,
})),

View File

@ -61,7 +61,6 @@ jest.mock('../../../../context/LineageProvider/LineageProvider', () => ({
downstreamEdges: [],
},
activeLayer: [],
expandedNodes: [],
fetchPipelineStatus: jest.fn(),
onColumnClick: onMockColumnClick,
onUpdateLayerView: onMockUpdateLayerView,

View File

@ -24,7 +24,7 @@ import { getEntityIcon } from '../../../../utils/TableUtils';
import './lineage-layers.less';
const LineageLayers = () => {
const { activeLayer, onUpdateLayerView } = useLineageProvider();
const { activeLayer, onUpdateLayerView, isEditMode } = useLineageProvider();
const onButtonClick = (value: LineageLayerView) => {
const index = activeLayer.indexOf(value);
@ -43,6 +43,7 @@ const LineageLayers = () => {
className={classNames('lineage-layer-button h-15', {
active: activeLayer.includes(LineageLayerView.COLUMN),
})}
data-testid="lineage-layer-column-btn"
onClick={() => onButtonClick(LineageLayerView.COLUMN)}>
<div className="lineage-layer-btn">
<div className="layer-icon">
@ -59,6 +60,7 @@ const LineageLayers = () => {
LineageLayerView.DATA_OBSERVARABILITY
),
})}
data-testid="lineage-layer-observability-btn"
onClick={() =>
onButtonClick(LineageLayerView.DATA_OBSERVARABILITY)
}>
@ -78,7 +80,9 @@ const LineageLayers = () => {
trigger="click">
<Button
ghost
className="layers-btn h-15"
className={classNames('layers-btn h-15', {
'layers-btn-edit-mode': isEditMode,
})}
data-testid="lineage-layer-btn"
type="primary">
<div className="lineage-layer-btn">

View File

@ -51,3 +51,7 @@
.layers-btn {
background-color: @white !important;
}
.layers-btn-edit-mode {
margin-left: @lineage-sidebar-width;
}

View File

@ -13,7 +13,6 @@
@import (reference) url('../../../styles/variables.less');
@lineage-sidebar-width: 110px;
@lineage-breadcrumb-panel: 50px;
@lineage-toolbar-height: 54px;

View File

@ -156,6 +156,9 @@ const Lineage = ({
deleteKeyCode={null}
edgeTypes={customEdges}
edges={edges}
fitViewOptions={{
padding: 48,
}}
maxZoom={MAX_ZOOM_VALUE}
minZoom={MIN_ZOOM_VALUE}
nodeTypes={nodeTypes}

View File

@ -19,7 +19,7 @@ import { SearchIndex } from '../enums/search.enum';
import { Source } from '../generated/type/entityLineage';
export const FOREIGN_OBJECT_SIZE = 40;
export const ZOOM_VALUE = 0.75;
export const ZOOM_VALUE = 0.65;
export const MIN_ZOOM_VALUE = 0.1;
export const MAX_ZOOM_VALUE = 2.5;
export const ZOOM_SLIDER_STEP = 0.1;

View File

@ -53,7 +53,6 @@ export interface LineageContextType {
reactFlowInstance?: ReactFlowInstance;
nodes: Node[];
edges: Edge[];
expandedNodes: string[];
tracedNodes: string[];
tracedColumns: string[];
lineageConfig: LineageConfig;
@ -67,7 +66,6 @@ export interface LineageContextType {
selectedNode: SourceType;
upstreamDownstreamData: UpstreamDownstreamData;
selectedColumn: string;
expandAllColumns: boolean;
activeLayer: LineageLayerView[];
onInitReactFlow: (reactFlowInstance: ReactFlowInstance) => void;
onPaneClick: () => void;
@ -83,7 +81,6 @@ export interface LineageContextType {
onNodeCollapse: (node: Node | NodeProps, direction: EdgeTypeEnum) => void;
onNodesChange: (changes: NodeChange[]) => void;
onEdgesChange: (changes: EdgeChange[]) => void;
toggleColumnView: () => void;
loadChildNodesHandler: (
node: SourceType,
direction: EdgeTypeEnum

View File

@ -59,7 +59,6 @@ import {
import { SourceType } from '../../components/SearchedData/SearchedData.interface';
import {
ELEMENT_DELETE_STATE,
ZOOM_TRANSITION_DURATION,
ZOOM_VALUE,
} from '../../constants/Lineage.constants';
import { mockDatasetData } from '../../constants/mockTourData.constants';
@ -78,6 +77,7 @@ import { useFqn } from '../../hooks/useFqn';
import { getLineageDataByFQN, updateLineageEdge } from '../../rest/lineageAPI';
import {
addLineageHandler,
centerNodePosition,
createEdges,
createNewEdge,
createNodes,
@ -124,14 +124,10 @@ const LineageProvider = ({ children }: LineageProviderProps) => {
const [selectedNode, setSelectedNode] = useState<SourceType>(
{} as SourceType
);
const [activeLayer, setActiveLayer] = useState<LineageLayerView[]>([
LineageLayerView.COLUMN,
]);
const [activeLayer, setActiveLayer] = useState<LineageLayerView[]>([]);
const [activeNode, setActiveNode] = useState<Node>();
const [selectedColumn, setSelectedColumn] = useState<string>('');
const [showAddEdgeModal, setShowAddEdgeModal] = useState<boolean>(false);
const [expandedNodes, setExpandedNodes] = useState<string[]>([]);
const [expandAllColumns, setExpandAllColumns] = useState(false);
const [selectedEdge, setSelectedEdge] = useState<Edge>();
const [entityLineage, setEntityLineage] = useState<EntityLineageResponse>({
nodes: [],
@ -679,10 +675,6 @@ const LineageProvider = ({ children }: LineageProviderProps) => {
}, []);
const onInitReactFlow = (reactFlowInstance: ReactFlowInstance) => {
setTimeout(() => {
onLoad(reactFlowInstance);
}, 0);
setReactFlowInstance(reactFlowInstance);
};
@ -698,43 +690,6 @@ const LineageProvider = ({ children }: LineageProviderProps) => {
setZoomValue(value);
}, []);
const toggleColumnView = useCallback(() => {
const updatedVal = !expandAllColumns;
setExpandAllColumns(updatedVal);
setNodes((prevNodes) => {
const updatedNode = prevNodes.map((node) => {
const nodeId = node.data.node.id;
// Update the expandedNodes state based on the toggle value
if (updatedVal && !expandedNodes.includes(nodeId)) {
setExpandedNodes((prevExpandedNodes) => [
...prevExpandedNodes,
nodeId,
]);
} else if (!updatedVal) {
setExpandedNodes((prevExpandedNodes) =>
prevExpandedNodes.filter((id) => id !== nodeId)
);
}
return node;
});
const { edge, node } = getLayoutedElements(
{
node: updatedNode,
edge: edges,
},
EntityLineageDirection.LEFT_RIGHT,
updatedVal
);
setEdges(edge);
return node;
});
}, [expandAllColumns, expandedNodes, edges]);
const onRemove = useCallback(async () => {
try {
setDeletionState({ ...ELEMENT_DELETE_STATE, loading: true });
@ -1066,14 +1021,42 @@ const LineageProvider = ({ children }: LineageProviderProps) => {
);
const selectNode = (node: Node) => {
const { position } = node;
// moving selected node in center
reactFlowInstance?.setCenter(position.x, position.y, {
duration: ZOOM_TRANSITION_DURATION,
zoom: zoomValue,
});
centerNodePosition(node, reactFlowInstance);
};
const repositionLayout = useCallback(
(activateNode = false) => {
const isColView = activeLayer.includes(LineageLayerView.COLUMN);
const { node, edge } = getLayoutedElements(
{
node: nodes,
edge: edges,
},
EntityLineageDirection.LEFT_RIGHT,
isColView
);
setNodes(node);
setEdges(edge);
const rootNode = node.find((n) => n.data.isRootNode);
if (!rootNode) {
if (activateNode && reactFlowInstance) {
onLoad(reactFlowInstance); // Call fitview in case of pipeline
}
return;
}
// Center the root node in the view
centerNodePosition(rootNode, reactFlowInstance);
if (activateNode) {
onNodeClick(rootNode);
}
},
[reactFlowInstance, activeLayer, nodes, edges, onNodeClick]
);
const redrawLineage = useCallback(
(lineageData: EntityLineageResponse) => {
const allNodes = uniqWith(
@ -1087,7 +1070,8 @@ const LineageProvider = ({ children }: LineageProviderProps) => {
const updatedNodes = createNodes(
allNodes,
lineageData.edges ?? [],
decodedFqn
decodedFqn,
activeLayer.includes(LineageLayerView.COLUMN)
);
const updatedEdges = createEdges(
allNodes,
@ -1105,11 +1089,11 @@ const LineageProvider = ({ children }: LineageProviderProps) => {
);
setUpstreamDownstreamData(data);
if (activeNode) {
if (activeNode && !isEditMode) {
selectNode(activeNode);
}
},
[decodedFqn, activeNode]
[decodedFqn, activeNode, activeLayer, isEditMode]
);
useEffect(() => {
@ -1164,19 +1148,15 @@ const LineageProvider = ({ children }: LineageProviderProps) => {
}, [isEditMode, deletePressed, backspacePressed, activeNode, selectedEdge]);
useEffect(() => {
const { node, edge } = getLayoutedElements(
{
node: nodes,
edge: edges,
},
EntityLineageDirection.LEFT_RIGHT,
activeLayer.includes(LineageLayerView.COLUMN)
);
setNodes(node);
setEdges(edge);
repositionLayout();
}, [activeLayer]);
useEffect(() => {
if (reactFlowInstance?.viewportInitialized) {
repositionLayout(true); // Activate the root node
}
}, [reactFlowInstance?.viewportInitialized]);
const activityFeedContextValues = useMemo(() => {
return {
isDrawerOpen,
@ -1191,10 +1171,8 @@ const LineageProvider = ({ children }: LineageProviderProps) => {
selectedColumn,
zoomValue,
status,
expandedNodes,
tracedNodes,
tracedColumns,
expandAllColumns,
upstreamDownstreamData,
init,
activeLayer,
@ -1210,7 +1188,6 @@ const LineageProvider = ({ children }: LineageProviderProps) => {
onZoomUpdate,
updateEntityType,
onDrawerClose,
toggleColumnView,
loadChildNodesHandler,
fetchLineageData,
removeNodeHandler,
@ -1236,10 +1213,8 @@ const LineageProvider = ({ children }: LineageProviderProps) => {
selectedColumn,
zoomValue,
status,
expandedNodes,
tracedNodes,
tracedColumns,
expandAllColumns,
upstreamDownstreamData,
init,
activeLayer,
@ -1257,7 +1232,6 @@ const LineageProvider = ({ children }: LineageProviderProps) => {
updateEntityType,
loadChildNodesHandler,
fetchLineageData,
toggleColumnView,
removeNodeHandler,
onNodeClick,
onEdgeClick,

View File

@ -118,6 +118,7 @@
@welcome-page-height: calc(100vh - 112px);
@data-product-page-height: calc(100vh - 156px);
@glossary-page-tab-height: calc(100vh - 206px);
@lineage-sidebar-width: 110px;
// Severity
@severity-1: #9c0700;

View File

@ -68,6 +68,7 @@ import {
LINEAGE_EXPORT_HEADERS,
NODE_HEIGHT,
NODE_WIDTH,
ZOOM_TRANSITION_DURATION,
ZOOM_VALUE,
} from '../constants/Lineage.constants';
import {
@ -120,6 +121,22 @@ export const onLoad = (reactFlowInstance: ReactFlowInstance) => {
reactFlowInstance.fitView();
reactFlowInstance.zoomTo(ZOOM_VALUE);
};
export const centerNodePosition = (
node: Node,
reactFlowInstance?: ReactFlowInstance
) => {
const { position, width } = node;
reactFlowInstance?.setCenter(
position.x + (width ?? 1 / 2),
position.y + NODE_HEIGHT / 2,
{
zoom: ZOOM_VALUE,
duration: ZOOM_TRANSITION_DURATION,
}
);
};
/* eslint-disable-next-line */
export const onNodeMouseEnter = (_event: ReactMouseEvent, _node: Node) => {
return;
@ -631,7 +648,8 @@ const getNodeType = (
export const createNodes = (
nodesData: EntityReference[],
edgesData: EdgeDetails[],
entityFqn: string
entityFqn: string,
isExpanded = false
) => {
const uniqueNodesData = removeDuplicateNodes(nodesData).sort((a, b) =>
getEntityName(a).localeCompare(getEntityName(b))
@ -651,7 +669,7 @@ export const createNodes = (
// Add nodes to the graph
uniqueNodesData.forEach((node) => {
const { childrenHeight } = getEntityChildrenAndLabel(node as SourceType);
const nodeHeight = childrenHeight + 220;
const nodeHeight = isExpanded ? childrenHeight + 220 : NODE_HEIGHT;
graph.setNode(node.id, { width: NODE_WIDTH, height: nodeHeight });
});