mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-27 18:36:08 +00:00
GEN-712: show column lineage function in edge drawer (#18032)
* show column lineage function * add e2e tests
This commit is contained in:
parent
9219dbe5c1
commit
47cde167b4
@ -10,7 +10,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import test from '@playwright/test';
|
import test, { expect } from '@playwright/test';
|
||||||
import { get } from 'lodash';
|
import { get } from 'lodash';
|
||||||
import { ApiEndpointClass } from '../../support/entity/ApiEndpointClass';
|
import { ApiEndpointClass } from '../../support/entity/ApiEndpointClass';
|
||||||
import { ContainerClass } from '../../support/entity/ContainerClass';
|
import { ContainerClass } from '../../support/entity/ContainerClass';
|
||||||
@ -280,3 +280,85 @@ test('Verify column lineage between table and api endpoint', async ({
|
|||||||
|
|
||||||
await afterAction();
|
await afterAction();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Verify function data in edge drawer', async ({ browser }) => {
|
||||||
|
const { page } = await createNewPage(browser);
|
||||||
|
const { apiContext, afterAction } = await getApiContext(page);
|
||||||
|
const table1 = new TableClass();
|
||||||
|
const table2 = new TableClass();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await table1.create(apiContext);
|
||||||
|
await table2.create(apiContext);
|
||||||
|
const sourceTableFqn = get(table1, 'entityResponseData.fullyQualifiedName');
|
||||||
|
const sourceColName = `${sourceTableFqn}.${get(
|
||||||
|
table1,
|
||||||
|
'entityResponseData.columns[0].name'
|
||||||
|
)}`;
|
||||||
|
|
||||||
|
const targetTableFqn = get(table2, 'entityResponseData.fullyQualifiedName');
|
||||||
|
const targetColName = `${targetTableFqn}.${get(
|
||||||
|
table2,
|
||||||
|
'entityResponseData.columns[0].name'
|
||||||
|
)}`;
|
||||||
|
|
||||||
|
await addPipelineBetweenNodes(page, table1, table2);
|
||||||
|
await activateColumnLayer(page);
|
||||||
|
await addColumnLineage(page, sourceColName, targetColName);
|
||||||
|
|
||||||
|
const lineageReq = page.waitForResponse('/api/v1/lineage/getLineage?*');
|
||||||
|
await page.reload();
|
||||||
|
const lineageRes = await lineageReq;
|
||||||
|
const jsonRes = await lineageRes.json();
|
||||||
|
const edge = jsonRes.edges[0];
|
||||||
|
const columnData = edge.columns[0];
|
||||||
|
|
||||||
|
const newEdge = {
|
||||||
|
edge: {
|
||||||
|
fromEntity: {
|
||||||
|
id: edge.fromEntity.id,
|
||||||
|
type: edge.fromEntity.type,
|
||||||
|
},
|
||||||
|
toEntity: {
|
||||||
|
id: edge.toEntity.id,
|
||||||
|
type: edge.toEntity.type,
|
||||||
|
},
|
||||||
|
lineageDetails: {
|
||||||
|
columnsLineage: [
|
||||||
|
{
|
||||||
|
fromColumns: [columnData.fromColumns[0]],
|
||||||
|
function: 'count',
|
||||||
|
toColumn: columnData.toColumn,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
description: 'test',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
await apiContext.put(`/api/v1/lineage`, {
|
||||||
|
data: newEdge,
|
||||||
|
});
|
||||||
|
const lineageReq1 = page.waitForResponse('/api/v1/lineage/getLineage?*');
|
||||||
|
await page.reload();
|
||||||
|
await lineageReq1;
|
||||||
|
|
||||||
|
await activateColumnLayer(page);
|
||||||
|
await page
|
||||||
|
.locator(
|
||||||
|
`[data-testid="column-edge-${btoa(sourceColName)}-${btoa(
|
||||||
|
targetColName
|
||||||
|
)}"]`
|
||||||
|
)
|
||||||
|
.dispatchEvent('click');
|
||||||
|
|
||||||
|
await page.locator('.edge-info-drawer').isVisible();
|
||||||
|
|
||||||
|
await expect(await page.locator('[data-testid="Function"]')).toContainText(
|
||||||
|
'count'
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
await table1.delete(apiContext);
|
||||||
|
await table2.delete(apiContext);
|
||||||
|
await afterAction();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
@ -27,6 +27,7 @@ import { EntityType } from '../../../enums/entity.enum';
|
|||||||
import { Source } from '../../../generated/type/entityLineage';
|
import { Source } from '../../../generated/type/entityLineage';
|
||||||
import { getNameFromFQN } from '../../../utils/CommonUtils';
|
import { getNameFromFQN } from '../../../utils/CommonUtils';
|
||||||
import {
|
import {
|
||||||
|
getColumnFunctionValue,
|
||||||
getColumnSourceTargetHandles,
|
getColumnSourceTargetHandles,
|
||||||
getLineageDetailsObject,
|
getLineageDetailsObject,
|
||||||
} from '../../../utils/EntityLineageUtils';
|
} from '../../../utils/EntityLineageUtils';
|
||||||
@ -66,6 +67,7 @@ const EdgeInfoDrawer = ({
|
|||||||
const { source, target, data } = edge;
|
const { source, target, data } = edge;
|
||||||
const { sourceHandle, targetHandle } = getColumnSourceTargetHandles(edge);
|
const { sourceHandle, targetHandle } = getColumnSourceTargetHandles(edge);
|
||||||
const { pipeline, pipelineEntityType } = data?.edge ?? {};
|
const { pipeline, pipelineEntityType } = data?.edge ?? {};
|
||||||
|
const isColumnLineage = sourceHandle && targetHandle;
|
||||||
|
|
||||||
let sourceData: Node | undefined, targetData: Node | undefined;
|
let sourceData: Node | undefined, targetData: Node | undefined;
|
||||||
nodes.forEach((node) => {
|
nodes.forEach((node) => {
|
||||||
@ -121,7 +123,13 @@ const EdgeInfoDrawer = ({
|
|||||||
},
|
},
|
||||||
functionInfo: {
|
functionInfo: {
|
||||||
key: t('label.function'),
|
key: t('label.function'),
|
||||||
value: data.columnFunctionValue,
|
value: isColumnLineage
|
||||||
|
? getColumnFunctionValue(
|
||||||
|
data?.edge?.columns ?? [],
|
||||||
|
sourceHandle ?? '',
|
||||||
|
targetHandle ?? ''
|
||||||
|
)
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
|
@ -16,7 +16,7 @@ import { EdgeTypeEnum } from '../components/Entity/EntityLineage/EntityLineage.i
|
|||||||
import { EdgeDetails } from '../components/Lineage/Lineage.interface';
|
import { EdgeDetails } from '../components/Lineage/Lineage.interface';
|
||||||
import { SourceType } from '../components/SearchedData/SearchedData.interface';
|
import { SourceType } from '../components/SearchedData/SearchedData.interface';
|
||||||
import { EntityType } from '../enums/entity.enum';
|
import { EntityType } from '../enums/entity.enum';
|
||||||
import { AddLineage } from '../generated/api/lineage/addLineage';
|
import { AddLineage, ColumnLineage } from '../generated/api/lineage/addLineage';
|
||||||
import {
|
import {
|
||||||
MOCK_CHILD_MAP,
|
MOCK_CHILD_MAP,
|
||||||
MOCK_LINEAGE_DATA_NEW,
|
MOCK_LINEAGE_DATA_NEW,
|
||||||
@ -29,6 +29,7 @@ import {
|
|||||||
createNewEdge,
|
createNewEdge,
|
||||||
getAllTracedEdges,
|
getAllTracedEdges,
|
||||||
getChildMap,
|
getChildMap,
|
||||||
|
getColumnFunctionValue,
|
||||||
getColumnLineageData,
|
getColumnLineageData,
|
||||||
getColumnSourceTargetHandles,
|
getColumnSourceTargetHandles,
|
||||||
getConnectedNodesEdges,
|
getConnectedNodesEdges,
|
||||||
@ -608,4 +609,74 @@ describe('Test EntityLineageUtils utility', () => {
|
|||||||
expect(result.childrenHeading).toEqual('label.column-plural');
|
expect(result.childrenHeading).toEqual('label.column-plural');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getColumnFunctionValue', () => {
|
||||||
|
it('should return the correct function value when a matching column is found', () => {
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
toColumn: 'targetColumn',
|
||||||
|
fromColumns: ['sourceColumn'],
|
||||||
|
function: 'SUM',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toColumn: 'anotherTargetColumn',
|
||||||
|
fromColumns: ['anotherSourceColumn'],
|
||||||
|
function: 'AVG',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const sourceFqn = 'sourceColumn';
|
||||||
|
const targetFqn = 'targetColumn';
|
||||||
|
|
||||||
|
const result = getColumnFunctionValue(columns, sourceFqn, targetFqn);
|
||||||
|
|
||||||
|
expect(result).toBe('SUM');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return undefined when no matching column is found', () => {
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
toColumn: 'targetColumn',
|
||||||
|
fromColumns: ['sourceColumn'],
|
||||||
|
function: 'SUM',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
toColumn: 'anotherTargetColumn',
|
||||||
|
fromColumns: ['anotherSourceColumn'],
|
||||||
|
function: 'AVG',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const sourceFqn = 'nonExistentSourceColumn';
|
||||||
|
const targetFqn = 'nonExistentTargetColumn';
|
||||||
|
|
||||||
|
const result = getColumnFunctionValue(columns, sourceFqn, targetFqn);
|
||||||
|
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return undefined when columns array is empty', () => {
|
||||||
|
const columns: ColumnLineage[] = [];
|
||||||
|
const sourceFqn = 'sourceColumn';
|
||||||
|
const targetFqn = 'targetColumn';
|
||||||
|
|
||||||
|
const result = getColumnFunctionValue(columns, sourceFqn, targetFqn);
|
||||||
|
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return undefined when fromColumns is undefined', () => {
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
toColumn: 'targetColumn',
|
||||||
|
fromColumns: undefined,
|
||||||
|
function: 'SUM',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const sourceFqn = 'sourceColumn';
|
||||||
|
const targetFqn = 'targetColumn';
|
||||||
|
|
||||||
|
const result = getColumnFunctionValue(columns, sourceFqn, targetFqn);
|
||||||
|
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1390,3 +1390,15 @@ export const getPaginatedChildMap = (
|
|||||||
|
|
||||||
return { nodes, edges };
|
return { nodes, edges };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getColumnFunctionValue = (
|
||||||
|
columns: ColumnLineage[],
|
||||||
|
sourceFqn: string,
|
||||||
|
targetFqn: string
|
||||||
|
) => {
|
||||||
|
const column = columns.find(
|
||||||
|
(col) => col.toColumn === targetFqn && col.fromColumns?.includes(sourceFqn)
|
||||||
|
);
|
||||||
|
|
||||||
|
return column?.function;
|
||||||
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user