diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityInfoDrawer/EdgeInfoDrawer.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityInfoDrawer/EdgeInfoDrawer.component.tsx
index 97d63d956cb..ec56f9c4032 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityInfoDrawer/EdgeInfoDrawer.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityInfoDrawer/EdgeInfoDrawer.component.tsx
@@ -21,8 +21,10 @@ import { Node } from 'reactflow';
import { ReactComponent as EditIcon } from '../../../assets/svg/edit-new.svg';
import DescriptionV1 from '../../../components/common/EntityDescription/DescriptionV1';
import { DE_ACTIVE_COLOR } from '../../../constants/constants';
+import { LINEAGE_SOURCE } from '../../../constants/Lineage.constants';
import { CSMode } from '../../../enums/codemirror.enum';
import { EntityType } from '../../../enums/entity.enum';
+import { Source } from '../../../generated/type/entityLineage';
import { getNameFromFQN } from '../../../utils/CommonUtils';
import { getLineageDetailsObject } from '../../../utils/EntityLineageUtils';
import entityUtilClassBase from '../../../utils/EntityUtilClassBase';
@@ -266,6 +268,15 @@ const EdgeInfoDrawer = ({
)}
+
+
+
+ {`${t('label.lineage-source')}`}
+
+
+ {LINEAGE_SOURCE[edgeEntity.source as keyof typeof Source]}
+
+
)}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityInfoDrawer/EdgeInfoDrawer.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityInfoDrawer/EdgeInfoDrawer.test.tsx
new file mode 100644
index 00000000000..7904fd2bbd9
--- /dev/null
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityInfoDrawer/EdgeInfoDrawer.test.tsx
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2024 Collate.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { act, fireEvent, render, screen } from '@testing-library/react';
+import React from 'react';
+import { Edge } from 'reactflow';
+import { MOCK_NODES_AND_EDGES } from '../../../mocks/Lineage.mock';
+import EdgeInfoDrawer from './EdgeInfoDrawer.component';
+
+jest.mock('../../../components/common/EntityDescription/DescriptionV1', () =>
+ jest.fn().mockImplementation(({ onDescriptionUpdate }) => (
+
+ DescriptionV1
+ onDescriptionUpdate('updatedHTML')}>
+ Update Description
+
+
+ ))
+);
+
+jest.mock('../../../utils/CommonUtils', () => ({
+ getNameFromFQN: jest.fn().mockReturnValue('getNameFromFQN'),
+}));
+
+jest.mock('../../../utils/EntityUtils', () => ({
+ getEntityName: jest.fn().mockReturnValue('username'),
+}));
+
+jest.mock('../../common/Loader/Loader', () =>
+ jest.fn().mockImplementation(() => Loader
)
+);
+
+jest.mock('../../Database/SchemaEditor/SchemaEditor', () => {
+ return jest.fn().mockImplementation(() => SchemaEditor.component
);
+});
+
+jest.mock('../../Modals/ModalWithQueryEditor/ModalWithQueryEditor', () => {
+ return jest.fn().mockImplementation(() => ModalWithQueryEditor
);
+});
+
+jest.mock('antd', () => ({
+ ...jest.requireActual('antd'),
+ Drawer: jest.fn().mockImplementation(({ children, title }) => (
+
+ Drawer
+
{title}
+
{children}
+
+ )),
+}));
+
+const mockOnEdgeDetailsUpdate = jest.fn();
+const mockEdgeInfoDrawer = {
+ edge: {
+ id: 'edge-5c97531f-d164-4707-842e-af52e0c43e26-5d816d56-40a2-493f-ae9d-012f1cd337dd',
+ source: '5c97531f-d164-4707-842e-af52e0c43e26',
+ target: '5d816d56-40a2-493f-ae9d-012f1cd337dd',
+ type: 'buttonedge',
+ animated: false,
+ style: {
+ strokeWidth: '2px',
+ },
+ markerEnd: {
+ type: 'arrowclosed',
+ },
+ data: {
+ edge: {
+ toEntity: {
+ fqn: 'RedshiftProd.dev.demo_dbt_jaffle.customers',
+ id: '5d816d56-40a2-493f-ae9d-012f1cd337dd',
+ type: 'table',
+ },
+ pipeline: null,
+ fromEntity: {
+ fqn: 'RedshiftProd.dev.demo_dbt_jaffle.stg_orders',
+ id: '5c97531f-d164-4707-842e-af52e0c43e26',
+ type: 'table',
+ },
+ sqlQuery: null,
+ description: null,
+ source: 'DbtLineage',
+ doc_id:
+ '5c97531f-d164-4707-842e-af52e0c43e26-5d816d56-40a2-493f-ae9d-012f1cd337dd',
+ },
+ isColumnLineage: false,
+ isPipelineRootNode: false,
+ },
+ selected: true,
+ } as Edge,
+ nodes: MOCK_NODES_AND_EDGES.nodes,
+ visible: true,
+ hasEditAccess: true,
+ onEdgeDetailsUpdate: mockOnEdgeDetailsUpdate,
+ onClose: jest.fn(),
+};
+
+describe('EdgeInfoDrawer Component', () => {
+ it('should render the component', async () => {
+ render( );
+
+ expect(await screen.findByTestId('title')).toHaveTextContent(
+ 'label.edge-information'
+ );
+
+ expect(await screen.findByTestId('description-v1')).toBeInTheDocument();
+ expect(
+ await screen.findByText('label.sql-uppercase-query')
+ ).toBeInTheDocument();
+ expect(await screen.findByTestId('edit-sql')).toBeInTheDocument();
+ });
+
+ it('should render no query if no query is present', async () => {
+ render( );
+
+ expect(
+ await screen.findByText('server.no-query-available')
+ ).toBeInTheDocument();
+ });
+
+ it('should render source of lineage', async () => {
+ render( );
+
+ expect(await screen.findByText('label.lineage-source')).toBeInTheDocument();
+ expect(await screen.findByText('dbt Lineage')).toBeInTheDocument();
+ });
+
+ it('should call onEdgeDetailsUpdate on update description', async () => {
+ render( );
+ const updateDescriptionButton = await screen.findByTestId(
+ 'update-description-button'
+ );
+ await act(async () => {
+ fireEvent.click(updateDescriptionButton);
+ });
+
+ expect(mockOnEdgeDetailsUpdate).toHaveBeenCalledWith(
+ expect.objectContaining({
+ edge: expect.objectContaining({
+ lineageDetails: expect.objectContaining({
+ description: 'updatedHTML',
+ }),
+ }),
+ })
+ );
+ });
+
+ it('should not render edit SQL button if has no edit access', () => {
+ render( );
+
+ expect(screen.queryByTestId('edit-sql')).not.toBeInTheDocument();
+ });
+});
diff --git a/openmetadata-ui/src/main/resources/ui/src/constants/Lineage.constants.ts b/openmetadata-ui/src/main/resources/ui/src/constants/Lineage.constants.ts
index 5872d803d3b..5d42310c619 100644
--- a/openmetadata-ui/src/main/resources/ui/src/constants/Lineage.constants.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/constants/Lineage.constants.ts
@@ -14,6 +14,7 @@
import { t } from 'i18next';
import { ElementLoadingState } from '../components/Entity/EntityLineage/EntityLineage.interface';
import { SearchIndex } from '../enums/search.enum';
+import { Source } from '../generated/type/entityLineage';
export const FOREIGN_OBJECT_SIZE = 40;
export const ZOOM_VALUE = 0.75;
@@ -73,3 +74,13 @@ export const LINEAGE_DEFAULT_QUICK_FILTERS = [
'owner.displayName.keyword',
'tags.tagFQN',
];
+
+export const LINEAGE_SOURCE: { [key in Source]: string } = {
+ [Source.DashboardLineage]: 'Dashboard Lineage',
+ [Source.DbtLineage]: 'dbt Lineage',
+ [Source.Manual]: 'Manual',
+ [Source.PipelineLineage]: 'Pipeline Lineage',
+ [Source.QueryLineage]: 'Query Lineage',
+ [Source.SparkLineage]: 'Spark Lineage',
+ [Source.ViewLineage]: 'View Lineage',
+};
diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/de-de.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/de-de.json
index b4a805bd6c9..3487c87ce90 100644
--- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/de-de.json
+++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/de-de.json
@@ -616,6 +616,7 @@
"lineage-ingestion": "Abstammungsinjektion",
"lineage-lowercase": "Abstammung",
"lineage-node-lowercase": "Abstammungsknoten",
+ "lineage-source": "Source of Lineage",
"list": "Liste",
"list-entity": "{{entity}}-Liste",
"live": "Live",
diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json
index 20bc9e655ae..12aedd13e0c 100644
--- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json
+++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json
@@ -616,6 +616,7 @@
"lineage-ingestion": "Lineage Ingestion",
"lineage-lowercase": "lineage",
"lineage-node-lowercase": "lineage node",
+ "lineage-source": "Source of Lineage",
"list": "List",
"list-entity": "List {{entity}}",
"live": "Live",
diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/es-es.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/es-es.json
index 6d347ae084c..234c7ed69e0 100644
--- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/es-es.json
+++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/es-es.json
@@ -613,9 +613,10 @@
"lineage": "Linaje",
"lineage-config": "Configuración del linaje",
"lineage-data-lowercase": "lineage data",
- "lineage-ingestion": "Ingesta de linaje",
- "lineage-lowercase": "linaje",
- "lineage-node-lowercase": "nodo de linaje",
+ "lineage-ingestion": "Ingesta de lineaje",
+ "lineage-lowercase": "lineaje",
+ "lineage-node-lowercase": "lineage node",
+ "lineage-source": "Source of Lineage",
"list": "Lista",
"list-entity": "Lista de {{entity}}",
"live": "Vivo",
diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/fr-fr.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/fr-fr.json
index 0e3519fdefe..5f6e4b05c41 100644
--- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/fr-fr.json
+++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/fr-fr.json
@@ -616,6 +616,7 @@
"lineage-ingestion": "Ingestion de la Traçabilité",
"lineage-lowercase": "traçabilité",
"lineage-node-lowercase": "Nœud de Traçabilité",
+ "lineage-source": "Source of Lineage",
"list": "Liste",
"list-entity": "Liste de {{entity}}",
"live": "En Direct",
diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/he-he.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/he-he.json
index fabd1e11d9a..e0bca98c5ff 100644
--- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/he-he.json
+++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/he-he.json
@@ -616,6 +616,7 @@
"lineage-ingestion": "כניסת שורשים",
"lineage-lowercase": "שורשים",
"lineage-node-lowercase": "צומת שורש",
+ "lineage-source": "Source of Lineage",
"list": "רשימה",
"list-entity": "רשימת {{entity}}",
"live": "שידור חי",
diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/ja-jp.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/ja-jp.json
index 12acc956ea5..1f187b25a92 100644
--- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/ja-jp.json
+++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/ja-jp.json
@@ -616,6 +616,7 @@
"lineage-ingestion": "リネージのインジェスチョン",
"lineage-lowercase": "リネージ",
"lineage-node-lowercase": "lineage node",
+ "lineage-source": "Source of Lineage",
"list": "リスト",
"list-entity": "{{entity}}のリスト",
"live": "Live",
diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/nl-nl.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/nl-nl.json
index e09b93fd682..5b1e53899a5 100644
--- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/nl-nl.json
+++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/nl-nl.json
@@ -616,6 +616,7 @@
"lineage-ingestion": "Herkomstingestie",
"lineage-lowercase": "herkomst",
"lineage-node-lowercase": "herkomstknooppunt",
+ "lineage-source": "Source of Lineage",
"list": "Lijst",
"list-entity": "Lijst {{entity}}",
"live": "Live",
diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-br.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-br.json
index 28a95c64dd5..da1c11557f9 100644
--- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-br.json
+++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-br.json
@@ -616,6 +616,7 @@
"lineage-ingestion": "Ingestão de Linhagem",
"lineage-lowercase": "linhagem",
"lineage-node-lowercase": "nó de linhagem",
+ "lineage-source": "Source of Lineage",
"list": "Lista",
"list-entity": "Listar {{entity}}",
"live": "Ao Vivo",
diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/ru-ru.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/ru-ru.json
index 26dc5ff7fdb..439fbe58f3e 100644
--- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/ru-ru.json
+++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/ru-ru.json
@@ -616,6 +616,7 @@
"lineage-ingestion": "Получение проихождения",
"lineage-lowercase": "происходение",
"lineage-node-lowercase": "узел происхождения",
+ "lineage-source": "Source of Lineage",
"list": "Список",
"list-entity": "Список {{entity}}",
"live": "Процесс",
diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-cn.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-cn.json
index 9e1a4634191..f4d3278a4d7 100644
--- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-cn.json
+++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-cn.json
@@ -616,6 +616,7 @@
"lineage-ingestion": "血缘关系提取",
"lineage-lowercase": "血缘",
"lineage-node-lowercase": "血缘关系节点",
+ "lineage-source": "Source of Lineage",
"list": "列表",
"list-entity": "列出{{entity}}",
"live": "实时",