You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by pp...@apache.org on 2026/03/17 09:13:02 UTC

(atlas) branch master updated: ATLAS-5184: Incomplete Metadata Display for Entities in Atlas Search Results (#570)

This is an automated email from the ASF dual-hosted git repository.

ppawar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/atlas.git


The following commit(s) were added to refs/heads/master by this push:
     new 30e3f2ea7 ATLAS-5184: Incomplete Metadata Display for Entities in Atlas Search Results (#570)
30e3f2ea7 is described below

commit 30e3f2ea7ff9628ade92deb1afc5cd2385e1db43
Author: Prasad Pawar <49...@users.noreply.github.com>
AuthorDate: Tue Mar 17 14:42:57 2026 +0530

    ATLAS-5184: Incomplete Metadata Display for Entities in Atlas Search Results (#570)
    
    * ATLAS-5184: Incomplete Metadata Display for Entities in Atlas Search Results
    
    * ATLAS-5184: Incomplete Metadata Display for Entities in Atlas Search Results
---
 dashboard/package.json                             |   1 +
 .../src/api/apiMethods/detailpageApiMethod.ts      | 116 ++-
 .../src/api/apiMethods/entityFormApiMethod.ts      |   2 +-
 dashboard/src/api/apiMethods/searchApiMethod.ts    |  11 +-
 dashboard/src/api/apiUrlLinks/detailpageUrl.ts     |   7 +-
 dashboard/src/styles/detailPage.scss               | 402 +++++++++++
 .../BusinessMetadataAtrributeForm.tsx              |  62 +-
 .../src/views/DetailPage/EntityDetailPage.tsx      |  15 +-
 .../PropertiesTab/BMAttributesFields.tsx           |  27 +-
 .../EntityDetailTabs/RelationshipCard.tsx          | 406 +++++++++++
 .../EntityDetailTabs/RelationshipCardSkeleton.tsx  |  47 ++
 .../EntityDetailTabs/RelationshipLineage.tsx       |  53 +-
 .../EntityDetailTabs/RelationshipsTab.tsx          | 586 +++++++++++++---
 dashboard/src/views/SearchResult/SearchResult.tsx  | 159 ++++-
 .../src/views/SideBar/SideBarTree/EntitiesTree.tsx |   2 +-
 dashboardv2/gruntfile.js                           |   5 +-
 dashboardv2/public/css/scss/relationship.scss      | 507 ++++++++++++++
 dashboardv2/public/css/scss/table.scss             |   1 +
 .../BusinessMetadataAttributeItemView_tmpl.html    |   2 +-
 .../RelationshipCardsLayoutView_tmpl.html          |  18 +
 .../graph/RelationshipLayoutView_tmpl.html         |  11 +-
 dashboardv2/public/js/utils/UrlLinks.js            |  28 +-
 .../js/views/detail_page/DetailPageLayoutView.js   |  61 +-
 .../detail_page/RelationshipCardsLayoutView.js     | 780 +++++++++++++++++++++
 .../js/views/graph/RelationshipLayoutView.js       | 540 +++++++++-----
 25 files changed, 3499 insertions(+), 350 deletions(-)

diff --git a/dashboard/package.json b/dashboard/package.json
index 50b3f1275..6cb8364f1 100644
--- a/dashboard/package.json
+++ b/dashboard/package.json
@@ -4,6 +4,7 @@
   "version": "0.0.0",
   "type": "module",
   "scripts": {
+    "postinstall": "chmod +x node_modules/@esbuild/linux-x64/bin/esbuild 2>/dev/null || true",
     "dev": "vite",
     "build": "tsc && vite build",
     "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 200",
diff --git a/dashboard/src/api/apiMethods/detailpageApiMethod.ts b/dashboard/src/api/apiMethods/detailpageApiMethod.ts
index b74a98454..323d92aa9 100644
--- a/dashboard/src/api/apiMethods/detailpageApiMethod.ts
+++ b/dashboard/src/api/apiMethods/detailpageApiMethod.ts
@@ -22,14 +22,15 @@ import {
   detailPageBusinessMetadataApiUrl,
   detailPageLabelApiUrl,
   detailPageRauditApiUrl,
-  detailPageRelationshipApiUrl
+  detailPageRelationshipApiUrl,
+  detailPageRelationshipAttributesApiUrl
 } from "../apiUrlLinks/detailpageUrl";
 import { _get } from "./apiMethod";
 
 const getDetailPageData = (guid: string, params: object, header?: string) => {
   const config = {
     method: "GET",
-    params: params
+    params: { ...params, ignoreRelationships: true }
   };
   return _get(detailpageApiUrl(guid, header), config);
 };
@@ -85,6 +86,114 @@ const getDetailPageRelationship = (guid: string) => {
   return _get(detailPageRelationshipApiUrl(guid), config);
 };
 
+// TODO: Mock data for relationship attributes (disabled now that API is used).
+// const MOCK_DATA_CONFIG: Record<string, number> = {
+//   tables: 500,
+//   inputToProcess: 150,
+//   "outputTo Process": 3,
+//   ddlQueries: 230,
+//   outputFromProcesses: 1,
+//   model: 0
+// };
+//
+// const getMockRelationshipAttributes = (
+//   params: { limit?: number; offset?: number; attributeName?: string }
+// ) => {
+//   const limit = params.limit || 100;
+//   const offset = params.offset || 0;
+//   const attributeName = params.attributeName;
+//
+//   const generateMockItem = (index: number, type: string) => {
+//     const cleanType = type.replace(/\s+/g, "");
+//     const displayIndex = offset + index + 1;
+//
+//     return {
+//       guid: `mock-guid-${cleanType}-${displayIndex}`,
+//       typeName: "hive_table",
+//       entityStatus: "ACTIVE",
+//       displayText: `hivetable${displayIndex}`,
+//       relationshipType: `hive_table_db`,
+//       relationshipGuid: `mock-rel-guid-${cleanType}-${displayIndex}`,
+//       relationshipStatus: "ACTIVE",
+//       relationshipAttributes: {
+//         typeName: `hive_table_db`
+//       },
+//       qualifiedName: `db88232_1.hivetable${displayIndex}@cm`
+//     };
+//   };
+//
+//   if (attributeName) {
+//     const totalCount = MOCK_DATA_CONFIG[attributeName] || 0;
+//     const remainingCount = Math.max(0, totalCount - offset);
+//     const itemCount = Math.min(limit, remainingCount);
+//
+//     const mockData = [];
+//     for (let i = 0; i < itemCount; i++) {
+//       mockData.push(generateMockItem(i, attributeName));
+//     }
+//
+//     return {
+//       data: {
+//         relationshipAttributes: {
+//           [attributeName]: mockData
+//         },
+//         totalCounts: {
+//           [attributeName]: totalCount
+//         }
+//       }
+//     };
+//   }
+//
+//   const mockResponse: any = {
+//     data: {
+//       relationshipAttributes: {},
+//       totalCounts: {}
+//     }
+//   };
+//
+//   const relationshipTypes = [
+//     "tables",
+//     "inputToProcess",
+//     "outputTo Process",
+//     "ddlQueries",
+//     "outputFromProcesses",
+//     "model"
+//   ];
+//
+//   relationshipTypes.forEach((type) => {
+//     const totalCount = MOCK_DATA_CONFIG[type] || 0;
+//     const itemCount = Math.min(limit, totalCount);
+//
+//     const mockData = [];
+//     for (let i = 0; i < itemCount; i++) {
+//       mockData.push(generateMockItem(i, type));
+//     }
+//
+//     mockResponse.data.relationshipAttributes[type] = mockData;
+//     mockResponse.data.totalCounts[type] = totalCount;
+//   });
+//
+//   return mockResponse;
+// };
+
+const getDetailPageRelationshipAttributes = async (
+  guid: string,
+  params: { limit?: number; offset?: number; attributeName?: string }
+) => {
+  const config = {
+    method: "GET",
+    params: params
+  };
+  
+  try {
+    return await _get(detailPageRelationshipAttributesApiUrl(guid), config);
+  } catch (error: any) {
+    // Mock fallback disabled now that real API is used.
+    // return getMockRelationshipAttributes(params);
+    throw error;
+  }
+};
+
 export {
   getDetailPageData,
   getDetailPageAuditData,
@@ -92,5 +201,6 @@ export {
   getAuditData,
   getLabels,
   getEntityBusinessMetadata,
-  getDetailPageRelationship
+  getDetailPageRelationship,
+  getDetailPageRelationshipAttributes
 };
diff --git a/dashboard/src/api/apiMethods/entityFormApiMethod.ts b/dashboard/src/api/apiMethods/entityFormApiMethod.ts
index 1abe8c4d5..36d17764e 100644
--- a/dashboard/src/api/apiMethods/entityFormApiMethod.ts
+++ b/dashboard/src/api/apiMethods/entityFormApiMethod.ts
@@ -48,7 +48,7 @@ const createEntity = (params: object) => {
 const getEntity = (guid: string, method: string, params: any) => {
   const config: importTmplConfigs = {
     method: method,
-    params: params,
+    params: { ...params, ignoreRelationships: true },
   };
   return _get(getEntityUrl(guid), config);
 };
diff --git a/dashboard/src/api/apiMethods/searchApiMethod.ts b/dashboard/src/api/apiMethods/searchApiMethod.ts
index fea515635..bf32a5832 100644
--- a/dashboard/src/api/apiMethods/searchApiMethod.ts
+++ b/dashboard/src/api/apiMethods/searchApiMethod.ts
@@ -49,9 +49,18 @@ const getRelationShip = (params: any) => {
   return fetchApi(searchApiUrl("relationship"), config);
 };
 
+const getRelationShipV2 = (params: any) => {
+  const config: any = {
+    method: "GET",
+    ...params
+  };
+  return fetchApi(searchApiUrl("relationship"), config);
+};
+
 export {
   getBasicSearchResult,
   getRelationShipResult,
   getGlobalSearchResult,
-  getRelationShip
+  getRelationShip,
+  getRelationShipV2
 };
diff --git a/dashboard/src/api/apiUrlLinks/detailpageUrl.ts b/dashboard/src/api/apiUrlLinks/detailpageUrl.ts
index 5b130028a..59466c4cf 100644
--- a/dashboard/src/api/apiUrlLinks/detailpageUrl.ts
+++ b/dashboard/src/api/apiUrlLinks/detailpageUrl.ts
@@ -48,6 +48,10 @@ const detailPageRelationshipApiUrl = (guid: string) => {
   return `${getBaseApiUrl("urlV2")}/relationship/guid/${guid}`;
 };
 
+const detailPageRelationshipAttributesApiUrl = (guid: string) => {
+  return `${entitiesApiUrl()}/guid/${guid}/relationshipAttributes`;
+};
+
 export {
   detailpageApiUrl,
   detailPageAuditApiUrl,
@@ -55,5 +59,6 @@ export {
   auditApiurl,
   detailPageLabelApiUrl,
   detailPageBusinessMetadataApiUrl,
-  detailPageRelationshipApiUrl
+  detailPageRelationshipApiUrl,
+  detailPageRelationshipAttributesApiUrl
 };
diff --git a/dashboard/src/styles/detailPage.scss b/dashboard/src/styles/detailPage.scss
index 2583c0cb7..0322027e3 100644
--- a/dashboard/src/styles/detailPage.scss
+++ b/dashboard/src/styles/detailPage.scss
@@ -151,6 +151,408 @@ pre.code-block .json-string {
   display: none;
 }
 
+.relationship-cards-grid {
+  display: grid;
+  grid-template-columns: repeat(1, minmax(0, 1fr));
+  gap: 12px;
+  align-items: start;
+}
+
+@media (min-width: 900px) {
+  .relationship-cards-grid {
+    grid-template-columns: repeat(2, minmax(0, 1fr));
+  }
+}
+
+@media (min-width: 1200px) {
+  .relationship-cards-grid {
+    grid-template-columns: repeat(3, minmax(0, 1fr));
+  }
+}
+
+@media (min-width: 1400px) {
+  .relationship-cards-grid {
+    grid-template-columns: repeat(4, minmax(0, 1fr));
+  }
+}
+
+/* Custom column layout: >5 records = 1/col, 1-5 and 0 = 2/col */
+.relationship-cards-grid--custom {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 12px;
+  align-items: flex-start;
+}
+
+.relationship-cards-column {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+  min-width: 280px;
+  flex: 0 0 auto;
+}
+
+@media (max-width: 599px) {
+  .relationship-cards-column {
+    min-width: 100%;
+  }
+}
+
+.relationship-cards-empty {
+  grid-column: 1 / -1;
+  text-align: center;
+  color: #9ca3af;
+  font-size: 0.875rem;
+}
+
+.relationship-cards-grid--custom .relationship-cards-empty {
+  width: 100%;
+  flex: 1 1 100%;
+}
+
+.relationship-card {
+  border: 1px solid #e2e8f0;
+  border-radius: 10px;
+  background-color: #ffffff;
+  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08);
+  min-height: 80px;
+}
+
+.relationship-card__header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 8px 12px;
+  border-top-left-radius: 10px;
+  border-top-right-radius: 10px;
+  background-color: #f2f6f7;
+  color: #37bb9b;
+}
+
+.relationship-card__title {
+  font-size: 0.875rem;
+  font-weight: 500;
+  text-transform: capitalize;
+}
+
+.relationship-card__count {
+  margin-left: 6px;
+  font-size: 0.75rem;
+  color: #37bb9b;
+}
+
+.relationship-card__actions {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  color: #64748b;
+}
+
+.relationship-card__action-button {
+  background: transparent;
+  border: 1px solid transparent;
+  border-radius: 4px;
+  padding: 2px 6px;
+  cursor: pointer;
+  color: inherit;
+}
+
+.relationship-card__action-button.is-active {
+  color: #2563eb;
+}
+
+.relationship-card__toggle {
+  display: flex;
+  align-items: center;
+  gap: 4px;
+  font-size: 0.75rem;
+  color: #64748b;
+}
+
+.relationship-card__toggle input {
+  margin: 0;
+}
+
+.relationship-card__body {
+  overflow-y: auto;
+  padding: 8px 12px;
+  flex: 1 1 auto;
+  display: flex;
+  flex-direction: column;
+}
+
+.relationship-card__body--empty {
+  overflow: hidden;
+}
+
+.relationship-card__inline-loader {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  min-height: 40px;
+  width: 100%;
+}
+
+.relationship-card__content {
+  display: flex;
+  flex-direction: column;
+}
+
+.relationship-card__search {
+  padding: 6px 12px;
+}
+
+.relationship-card__search-input {
+  width: 100%;
+  border: 1px solid #d1d5db;
+  border-radius: 6px;
+  padding: 6px 10px;
+  font-size: 0.75rem;
+  color: #1f2937;
+  background-color: #f9fafb;
+}
+
+.relationship-card__search-input::placeholder {
+  color: #9ca3af;
+}
+
+.relationship-card__search-input:focus {
+  outline: 2px solid #c7d2fe;
+  outline-offset: 1px;
+}
+
+.relationship-card__list {
+  list-style: none;
+  margin: 0;
+  padding: 0;
+  text-align: left;
+}
+
+.relationship-card__item {
+  font-size: 0.875rem;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  line-height: 1.5;
+}
+
+.relationship-card__link {
+  color: #2563eb;
+  text-decoration: none;
+}
+
+.relationship-card__link:hover {
+  text-decoration: underline;
+}
+
+.relationship-card__text {
+  color: #334155;
+}
+
+.relationship-card__empty {
+  padding: 8px 0;
+  font-size: 0.875rem;
+  color: #9ca3af;
+  align-self: flex-start;
+  text-align: center;
+  width: 100%;
+}
+
+.relationship-card__no-match {
+  padding: 8px 0;
+  font-size: 0.875rem;
+  color: #9ca3af;
+  align-self: flex-start;
+}
+
+.relationship-card__footer {
+  border-top: 1px solid #e2e8f0;
+  padding: 0;
+  text-align: center;
+  font-size: 0.75rem;
+  color: #9ca3af;
+  margin-top: auto;
+  display: flex;
+  align-items: center;
+  min-height: 24px;
+}
+
+.relationship-card__footer-row {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  gap: 8px;
+  padding: 0 12px;
+  height: 24px;
+  line-height: 24px;
+  width: 100%;
+}
+
+.relationship-card__page-limit {
+  display: flex;
+  align-items: center;
+  gap: 6px;
+  font-size: 0.75rem;
+  color: #64748b;
+}
+
+.relationship-card__page-limit input {
+  width: 64px;
+  border: 1px solid #d1d5db;
+  border-radius: 4px;
+  padding: 2px 6px;
+  font-size: 0.75rem;
+  color: #1f2937;
+  background-color: #f9fafb;
+}
+
+.relationship-card__loading {
+  padding: 8px 0;
+  text-align: center;
+  font-size: 0.75rem;
+  color: #6b7280;
+  display: flex;
+  justify-content: center;
+}
+
+.relationship-card__load-more {
+  margin-top: 6px;
+  padding: 6px 0;
+  font-size: 0.75rem;
+  text-align: center;
+  color: #9ca3af;
+  min-height: 28px;
+}
+
+/* Relationship Card Skeleton Loader */
+.relationship-card-skeleton {
+  border: 1px solid #e2e8f0;
+  border-radius: 10px;
+  background-color: #ffffff;
+  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08);
+  min-height: 80px;
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
+}
+
+.relationship-card-skeleton__header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 8px 12px;
+  border-top-left-radius: 10px;
+  border-top-right-radius: 10px;
+  background-color: #f2f6f7;
+  border-bottom: 1px solid #e2e8f0;
+}
+
+.relationship-card-skeleton__title-wrap {
+  display: flex;
+  align-items: baseline;
+  gap: 6px;
+}
+
+.relationship-card-skeleton__line {
+  display: block;
+  height: 14px;
+  background: linear-gradient(
+    90deg,
+    #e2e8f0 25%,
+    #f1f5f9 50%,
+    #e2e8f0 75%
+  );
+  background-size: 200% 100%;
+  animation: relationship-skeleton-pulse 1.5s ease-in-out infinite;
+  border-radius: 4px;
+
+  &--title {
+    width: 100px;
+  }
+
+  &--count {
+    width: 36px;
+  }
+
+  &--short {
+    width: 60%;
+  }
+
+  &--footer {
+    width: 80px;
+    height: 12px;
+  }
+}
+
+.relationship-card-skeleton__actions {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+
+.relationship-card-skeleton__box {
+  display: block;
+  background: linear-gradient(
+    90deg,
+    #e2e8f0 25%,
+    #f1f5f9 50%,
+    #e2e8f0 75%
+  );
+  background-size: 200% 100%;
+  animation: relationship-skeleton-pulse 1.5s ease-in-out infinite;
+  border-radius: 4px;
+
+  &--button {
+    width: 28px;
+    height: 24px;
+  }
+
+  &--checkbox {
+    width: 80px;
+    height: 16px;
+  }
+
+  &--input {
+    width: 60px;
+    height: 24px;
+  }
+}
+
+.relationship-card-skeleton__content {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  padding: 12px;
+}
+
+.relationship-card-skeleton__body {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+  flex: 1;
+  min-height: 80px;
+}
+
+.relationship-card-skeleton__footer {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  gap: 12px;
+  margin-top: auto;
+  padding-top: 8px;
+  border-top: 1px solid #e2e8f0;
+}
+
+@keyframes relationship-skeleton-pulse {
+  0%,
+  100% {
+    background-position: 200% 0;
+  }
+  50% {
+    background-position: -200% 0;
+  }
+}
+
 .long-descriptions,
 .long-descriptions * {
   display: contents;
diff --git a/dashboard/src/views/BusinessMetadata/BusinessMetadataAtrributeForm.tsx b/dashboard/src/views/BusinessMetadata/BusinessMetadataAtrributeForm.tsx
index 91f2653d7..6c360731c 100644
--- a/dashboard/src/views/BusinessMetadata/BusinessMetadataAtrributeForm.tsx
+++ b/dashboard/src/views/BusinessMetadata/BusinessMetadataAtrributeForm.tsx
@@ -465,31 +465,31 @@ const BusinessMetadataAttributeForm = ({
               watched?.[index]?.multiValueSelect) ||
               isEmpty(editbmAttribute)) && (
               <>
-                <Controller
-                  control={control}
-                  name={`attributeDefs.${index}.multiValueSelect` as const}
-                  key={`attributeDefs.${index}.multiValueSelect`}
-                  data-cy={`attributeDefs.${index}.multiValueSelect`}
-                  defaultValue={field?.multiValueSelect}
-                  render={({ field: { value, onChange } }) => (
-                    <>
-                      <Grid
-                        container
-                        columnSpacing={{ xs: 1, sm: 2, md: 2 }}
-                        marginBottom="1rem"
-                        alignItems="center"
-                      >
-                        <Grid item md={3} textAlign="right">
-                          <InputLabel>Enable Multivalues</InputLabel>
-                        </Grid>
-                        <Grid item md={7}>
+              <Controller
+                control={control}
+                name={`attributeDefs.${index}.multiValueSelect` as const}
+                key={`attributeDefs.${index}.multiValueSelect`}
+                data-cy={`attributeDefs.${index}.multiValueSelect`}
+                defaultValue={field?.multiValueSelect}
+                render={({ field: { value, onChange } }) => (
+                  <>
+                    <Grid
+                      container
+                      columnSpacing={{ xs: 1, sm: 2, md: 2 }}
+                      marginBottom="1rem"
+                      alignItems="center"
+                    >
+                      <Grid item md={3} textAlign="right">
+                        <InputLabel>Enable Multivalues</InputLabel>
+                      </Grid>
+                      <Grid item md={7}>
                           <Stack direction="row" spacing={2} alignItems="center">
-                            <FormControlLabel
-                              control={
-                                <Checkbox
-                                  disabled={isEmpty(editbmAttribute) ? false : true}
-                                  size="small"
-                                  checked={value}
+                        <FormControlLabel
+                          control={
+                            <Checkbox
+                              disabled={isEmpty(editbmAttribute) ? false : true}
+                              size="small"
+                              checked={value}
                                   onChange={(e) => {
                                     onChange(e.target.checked);
                                     // Reset cardinality toggle when multivalues is unchecked
@@ -500,10 +500,10 @@ const BusinessMetadataAttributeForm = ({
                                       );
                                     }
                                   }}
-                                />
-                              }
-                              label={undefined}
                             />
+                          }
+                          label={undefined}
+                        />
                             {value && (
                               <Controller
                                 control={control}
@@ -535,10 +535,10 @@ const BusinessMetadataAttributeForm = ({
                             )}
                           </Stack>
                         </Grid>
-                      </Grid>
-                    </>
-                  )}
-                />
+                    </Grid>
+                  </>
+                )}
+              />
               </>
             )}
             {watched?.[index] && watched?.[index]?.typeName == "string" && (
diff --git a/dashboard/src/views/DetailPage/EntityDetailPage.tsx b/dashboard/src/views/DetailPage/EntityDetailPage.tsx
index dfec7b491..994d3adef 100644
--- a/dashboard/src/views/DetailPage/EntityDetailPage.tsx
+++ b/dashboard/src/views/DetailPage/EntityDetailPage.tsx
@@ -160,9 +160,11 @@ const EntityDetailPage: React.FC = () => {
     removeTab("raudits");
   }
 
+  // To render profile tab check for attribute "profileData" or typeName = "hive_db","hbase_namespace"
+  // Match Classic UI: check if profileData is not undefined (even if null/empty)
   if (
     !isEmpty(entity) &&
-    (!isEmpty(entity?.attributes?.["profileData"]) ||
+    (entity?.attributes?.["profileData"] !== undefined ||
       entity.typeName == "hive_db" ||
       entity.typeName == "hbase_namespace")
   ) {
@@ -529,10 +531,17 @@ const EntityDetailPage: React.FC = () => {
               <LinkTab label="Export/Import Audits" />
             )}
             {!isEmpty(entity) &&
-              (!isEmpty(entity?.attributes?.["profileData"]) ||
+              (entity?.attributes?.["profileData"] !== undefined ||
                 entity.typeName == "hive_db" ||
                 entity.typeName == "hbase_namespace") && (
-                <LinkTab label="Table" />
+                <LinkTab
+                  label={
+                    entity.typeName == "hive_db" ||
+                    entity.typeName == "hbase_namespace"
+                      ? "Tables"
+                      : "Table"
+                  }
+                />
               )}
             {taskTabEnabled && uiTaskTabEnabled && <LinkTab label="Tasks" />}
           </Tabs>
diff --git a/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/BMAttributesFields.tsx b/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/BMAttributesFields.tsx
index e5da5fb97..9017f961e 100644
--- a/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/BMAttributesFields.tsx
+++ b/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/BMAttributesFields.tsx
@@ -157,8 +157,24 @@ const BMAttributesFields = ({ obj, control, index }: any) => {
                 <TextField
                   margin="none"
                   fullWidth
-                  onChange={(text) => {
-                    field.onChange(text);
+                  onChange={(e) => {
+                    const inputValue = e.target.value;
+                    // For numeric types, allow string input while typing, convert to number on blur
+                    if (typeName !== "string") {
+                      // Store as string to allow partial input (e.g., "-", "1.", etc.)
+                      field.onChange(inputValue);
+                    } else {
+                      field.onChange(inputValue);
+                    }
+                  }}
+                  onBlur={(e) => {
+                    // On blur, convert valid numeric strings to numbers
+                    if (typeName !== "string" && e.target.value !== "") {
+                      const numValue = Number(e.target.value);
+                      if (!isNaN(numValue)) {
+                        field.onChange(numValue);
+                      }
+                    }
                   }}
                   variant="outlined"
                   size="small"
@@ -169,10 +185,13 @@ const BMAttributesFields = ({ obj, control, index }: any) => {
                       ? typeof field.value === "string"
                         ? field.value
                         : ""
-                      : typeof field.value === "number"
-                      ? field.value
+                      : field.value !== null && field.value !== undefined
+                      ? String(field.value)
                       : ""
                   }
+                  inputProps={{
+                    step: typeName === "float" || typeName === "double" ? "any" : undefined
+                  }}
                 />
               )}
             </div>
diff --git a/dashboard/src/views/DetailPage/EntityDetailTabs/RelationshipCard.tsx b/dashboard/src/views/DetailPage/EntityDetailTabs/RelationshipCard.tsx
new file mode 100644
index 000000000..dc7ea748e
--- /dev/null
+++ b/dashboard/src/views/DetailPage/EntityDetailTabs/RelationshipCard.tsx
@@ -0,0 +1,406 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import { Link } from 'react-router-dom'
+import { isEmpty } from '@utils/Utils'
+import { CircularProgress, LightTooltip } from '@components/muiComponents'
+
+type RelationshipCardProps = {
+	attributeName: string
+	data: any[]
+	referredEntities: any
+	showEmptyValues: boolean
+	showTypeNameInDisplay?: boolean
+	onLoadMore?: (attributeName: string) => void
+	totalCount?: number
+	isLoading?: boolean
+	isResetting?: boolean
+	isSorted?: boolean
+	showDeleted?: boolean
+	pageLimit?: number
+	onToggleSort?: (attributeName: string) => void
+	onToggleShowDeleted?: (attributeName: string) => void
+	onPageLimitChange?: (attributeName: string, value: string) => void
+	onPageLimitSubmit?: (attributeName: string) => void
+}
+
+function RelationshipCard({
+	attributeName,
+	data,
+	referredEntities,
+	showEmptyValues: _showEmptyValues,
+	showTypeNameInDisplay = false,
+	onLoadMore,
+	totalCount,
+	isLoading,
+	isResetting,
+	isSorted,
+	showDeleted,
+	pageLimit,
+	onToggleSort,
+	onToggleShowDeleted,
+	onPageLimitChange,
+	onPageLimitSubmit
+}: RelationshipCardProps) {
+	const scrollRef = useRef<HTMLDivElement | null>(null)
+	const resolvedTotal = useMemo(() => {
+		if (typeof totalCount === 'number') return totalCount
+		return data.length
+	}, [totalCount, data.length])
+
+	const canLoadMore = resolvedTotal > data.length
+	const lastRequestSizeRef = useRef<number | null>(null)
+	const prevScrollRef = useRef<{ height: number; top: number } | null>(null)
+	const lastScrollTopRef = useRef<number>(0)
+	const loadRequestedRef = useRef<boolean>(false)
+	const scrollDebounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(
+		null
+	)
+	const [searchQuery, setSearchQuery] = useState<string>('')
+
+	const getDisplayText = useCallback(
+		(item: any) => {
+			const ref = item?.guid ? referredEntities?.[item.guid] : null
+			const displayText =
+				ref?.displayText ||
+				ref?.attributes?.name ||
+				item?.displayText ||
+				item?.attributes?.name ||
+				item?.qualifiedName ||
+				item?.guid ||
+				'N/A'
+			const typeName = ref?.typeName || item?.typeName || ''
+			if (showTypeNameInDisplay && typeName) {
+				return `${displayText} (${typeName})`
+			}
+			return displayText
+		},
+		[referredEntities, showTypeNameInDisplay]
+	)
+
+	const handleSearchChange = useCallback(
+		(event: React.ChangeEvent<HTMLInputElement>) => {
+			setSearchQuery(event.currentTarget.value)
+		},
+		[]
+	)
+
+	const handleSearchKeyDown = useCallback(
+		(event: React.KeyboardEvent<HTMLInputElement>) => {
+			if (event.key === 'Escape') {
+				setSearchQuery('')
+			}
+		},
+		[]
+	)
+
+	const handleSearchKeyUp = useCallback(
+		(event: React.KeyboardEvent<HTMLInputElement>) => {
+			setSearchQuery(event.currentTarget.value)
+		},
+		[]
+	)
+
+	const handleKeyDown = (
+		event: React.KeyboardEvent<HTMLElement>,
+		href?: string
+	) => {
+		if (!href) return
+		if (event.key === 'Enter' || event.key === ' ') {
+			event.preventDefault()
+			window.location.href = href
+		}
+	}
+
+	const handleSortToggle = () => {
+		onToggleSort?.(attributeName)
+	}
+
+	const handleShowDeletedToggle = (
+		event: React.ChangeEvent<HTMLInputElement>
+	) => {
+		event.stopPropagation()
+		onToggleShowDeleted?.(attributeName)
+	}
+
+	const handlePageLimitInputChange = (
+		event: React.ChangeEvent<HTMLInputElement>
+	) => {
+		onPageLimitChange?.(attributeName, event.currentTarget.value)
+	}
+
+	const handlePageLimitKeyDown = (
+		event: React.KeyboardEvent<HTMLInputElement>
+	) => {
+		if (event.key === 'Enter') {
+			onPageLimitSubmit?.(attributeName)
+		}
+	}
+
+	const handleLoadMore = useCallback(() => {
+		if (loadRequestedRef.current || !canLoadMore) {
+			return
+		}
+		loadRequestedRef.current = true
+		const container = scrollRef.current
+		if (container) {
+			prevScrollRef.current = {
+				height: container.scrollHeight,
+				top: container.scrollTop
+			}
+		}
+		onLoadMore?.(attributeName)
+	}, [canLoadMore, onLoadMore])
+
+	const handleScroll = useCallback(() => {
+		const container = scrollRef.current
+		if (!container || loadRequestedRef.current || !canLoadMore) {
+			return
+		}
+		const distanceFromBottom =
+			container.scrollHeight - container.scrollTop - container.clientHeight
+		const isNearBottom = distanceFromBottom <= 4
+		const isScrollingDown = container.scrollTop > lastScrollTopRef.current
+		lastScrollTopRef.current = container.scrollTop
+		if (!isNearBottom || !isScrollingDown) {
+			if (scrollDebounceTimerRef.current) {
+				clearTimeout(scrollDebounceTimerRef.current)
+				scrollDebounceTimerRef.current = null
+			}
+			return
+		}
+		if (lastRequestSizeRef.current === data.length) {
+			return
+		}
+		if (scrollDebounceTimerRef.current) {
+			clearTimeout(scrollDebounceTimerRef.current)
+		}
+		scrollDebounceTimerRef.current = setTimeout(() => {
+			scrollDebounceTimerRef.current = null
+			if (loadRequestedRef.current || lastRequestSizeRef.current === data.length) {
+				return
+			}
+			lastRequestSizeRef.current = data.length
+			handleLoadMore()
+		}, 400)
+	}, [canLoadMore, data.length, handleLoadMore])
+
+	useEffect(() => {
+		if (!isLoading) {
+			loadRequestedRef.current = false
+		}
+	}, [isLoading])
+
+	useEffect(() => {
+		return () => {
+			if (scrollDebounceTimerRef.current) {
+				clearTimeout(scrollDebounceTimerRef.current)
+				scrollDebounceTimerRef.current = null
+			}
+		}
+	}, [])
+
+	useEffect(() => {
+		lastRequestSizeRef.current = null
+		const container = scrollRef.current
+		const prevScroll = prevScrollRef.current
+		if (container && prevScroll) {
+			prevScrollRef.current = null
+			const applyScroll = () => {
+				const maxScroll = container.scrollHeight - container.clientHeight
+				if (maxScroll > 0) {
+					const scrollUpBy = Math.floor(container.clientHeight * 0.3)
+					container.scrollTop = Math.max(0, maxScroll - scrollUpBy)
+				} else {
+					container.scrollTop = 0
+				}
+			}
+			requestAnimationFrame(() => {
+				requestAnimationFrame(applyScroll)
+			})
+		}
+	}, [data.length])
+
+	const showSearch = data.length > 1
+	const isEmptyCard = resolvedTotal === 0 && isEmpty(data)
+	const isZeroOrOneRecord = data.length <= 1
+	const bodyStyle = useMemo(() => {
+		if (isZeroOrOneRecord) {
+			return { minHeight: 72 }
+		}
+		const maxVisibleRows = 9
+		const rowHeight = 22
+		const bodyPadding = 16
+		const visibleRows = Math.min(data.length, maxVisibleRows)
+		const baseHeight = visibleRows * rowHeight + bodyPadding
+		const maxHeight = maxVisibleRows * rowHeight + bodyPadding
+		return { height: Math.min(baseHeight, maxHeight), minHeight: 0 }
+	}, [data.length, isZeroOrOneRecord])
+
+	const filteredData = useMemo(() => {
+		const query = searchQuery.trim().toLowerCase()
+		if (!query) return data
+		return data.filter((item) => {
+			const displayText = getDisplayText(item)
+			const qualifiedName = item?.qualifiedName || ''
+			const name = item?.attributes?.name || ''
+			const searchTarget = `${displayText} ${qualifiedName} ${name}`.toLowerCase()
+			return searchTarget.includes(query)
+		})
+	}, [data, getDisplayText, searchQuery])
+
+	return (
+		<div className='relationship-card'>
+			<div className='relationship-card__header'>
+				<div className='relationship-card__title'>
+					{attributeName}
+					<span className='relationship-card__count'>
+						({resolvedTotal})
+					</span>
+				</div>
+				<div className='relationship-card__actions'>
+					<button
+						type='button'
+						className={`relationship-card__action-button${
+							isSorted ? ' is-active' : ''
+						}`}
+						onClick={handleSortToggle}
+						aria-label='Toggle sort by name'
+					>
+						<i className={`fa ${isSorted ? 'fa-sort-alpha-asc' : 'fa-sort'}`} />
+					</button>
+					<label className='relationship-card__toggle'>
+						<input
+							type='checkbox'
+							checked={!!showDeleted}
+							onChange={handleShowDeletedToggle}
+							aria-label='Show deleted relationships'
+						/>
+						<span>Show deleted</span>
+					</label>
+				</div>
+			</div>
+			<div className='relationship-card__content'>
+				{showSearch && (
+					<div className='relationship-card__search'>
+						<input
+							className='relationship-card__search-input'
+							type='text'
+							placeholder='Search...'
+							aria-label='Search relationship records'
+							value={searchQuery}
+							onChange={handleSearchChange}
+							onKeyDown={handleSearchKeyDown}
+							onKeyUp={handleSearchKeyUp}
+						/>
+					</div>
+				)}
+				<div
+					ref={scrollRef}
+					onScroll={handleScroll}
+					className={`relationship-card__body${
+						isEmptyCard ? ' relationship-card__body--empty' : ''
+					}`}
+					style={bodyStyle}
+				>
+					{isResetting ? (
+						<div className='relationship-card__inline-loader'>
+							<CircularProgress size={16} />
+						</div>
+					) : isEmpty(data) ? (
+						<div className='relationship-card__empty'>
+							No records to display
+						</div>
+					) : searchQuery.trim() && isEmpty(filteredData) ? (
+						<div className='relationship-card__no-match'>
+							No record found for "{searchQuery}"
+						</div>
+					) : (
+						<ul className='relationship-card__list'>
+							{filteredData.map((item, index) => {
+								const itemGuid = item?.guid
+								const href = itemGuid ? `/detailPage/${itemGuid}` : ''
+								const displayText = getDisplayText(item)
+								return (
+									<li
+										key={`${attributeName}-${index}`}
+										className='relationship-card__item'
+									>
+										{href ? (
+											<LightTooltip title={displayText}>
+												<Link
+													to={href}
+													tabIndex={0}
+													aria-label={`Open ${displayText}`}
+													onKeyDown={(event) =>
+														handleKeyDown(event, href)
+													}
+													className='relationship-card__link'
+												>
+													{displayText}
+												</Link>
+											</LightTooltip>
+										) : (
+											<span className='relationship-card__text'>
+												{displayText}
+											</span>
+										)}
+									</li>
+								)
+							})}
+						</ul>
+					)}
+					{canLoadMore && resolvedTotal > 0 && (
+						<div className='relationship-card__load-more'>
+							Scroll to load more data
+						</div>
+					)}
+					{isLoading && (
+						<div className='relationship-card__loading'>
+							<CircularProgress size={16} />
+						</div>
+					)}
+				</div>
+				<div className='relationship-card__footer'>
+					<div className='relationship-card__footer-row'>
+						<span>
+							Showing {data.length} of {resolvedTotal}
+						</span>
+						<div className='relationship-card__page-limit'>
+							<label htmlFor={`page-limit-${attributeName}`}>
+								Limit
+							</label>
+							<input
+								id={`page-limit-${attributeName}`}
+								type='number'
+								min={1}
+								max={resolvedTotal}
+								value={pageLimit && pageLimit > 0 ? pageLimit : ''}
+								onChange={handlePageLimitInputChange}
+								onKeyDown={handlePageLimitKeyDown}
+								aria-label='Page limit'
+							/>
+						</div>
+					</div>
+				</div>
+			</div>
+		</div>
+	)
+}
+
+export default RelationshipCard
diff --git a/dashboard/src/views/DetailPage/EntityDetailTabs/RelationshipCardSkeleton.tsx b/dashboard/src/views/DetailPage/EntityDetailTabs/RelationshipCardSkeleton.tsx
new file mode 100644
index 000000000..210f69738
--- /dev/null
+++ b/dashboard/src/views/DetailPage/EntityDetailTabs/RelationshipCardSkeleton.tsx
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.
+ */
+
+function RelationshipCardSkeleton() {
+	return (
+		<div className='relationship-card-skeleton' aria-hidden='true'>
+			<div className='relationship-card-skeleton__header'>
+				<div className='relationship-card-skeleton__title-wrap'>
+					<span className='relationship-card-skeleton__line relationship-card-skeleton__line--title' />
+					<span className='relationship-card-skeleton__line relationship-card-skeleton__line--count' />
+				</div>
+				<div className='relationship-card-skeleton__actions'>
+					<span className='relationship-card-skeleton__box relationship-card-skeleton__box--button' />
+					<span className='relationship-card-skeleton__box relationship-card-skeleton__box--checkbox' />
+				</div>
+			</div>
+			<div className='relationship-card-skeleton__content'>
+				<div className='relationship-card-skeleton__body'>
+					<span className='relationship-card-skeleton__line' />
+					<span className='relationship-card-skeleton__line' />
+					<span className='relationship-card-skeleton__line' />
+					<span className='relationship-card-skeleton__line relationship-card-skeleton__line--short' />
+				</div>
+				<div className='relationship-card-skeleton__footer'>
+					<span className='relationship-card-skeleton__line relationship-card-skeleton__line--footer' />
+					<span className='relationship-card-skeleton__box relationship-card-skeleton__box--input' />
+				</div>
+			</div>
+		</div>
+	)
+}
+
+export default RelationshipCardSkeleton
diff --git a/dashboard/src/views/DetailPage/EntityDetailTabs/RelationshipLineage.tsx b/dashboard/src/views/DetailPage/EntityDetailTabs/RelationshipLineage.tsx
index 7820a0ef6..61a86a8f3 100644
--- a/dashboard/src/views/DetailPage/EntityDetailTabs/RelationshipLineage.tsx
+++ b/dashboard/src/views/DetailPage/EntityDetailTabs/RelationshipLineage.tsx
@@ -20,6 +20,7 @@
 import {
   Button,
   Chip,
+  CircularProgress,
   IconButton,
   InputBase,
   Paper,
@@ -34,7 +35,7 @@ import {
   isArray,
   isEmpty
 } from "@utils/Utils";
-import { useEffect, useRef, useState } from "react";
+import { useEffect, useMemo, useRef, useState } from "react";
 import * as d3 from "d3";
 import { Link as RouterLink, useLocation, useParams } from "react-router-dom";
 import { entityStateReadOnly, graphIcon } from "@utils/Enum";
@@ -74,8 +75,19 @@ const CustomLink = ({
   );
 };
 
-const RelationshipLineage = ({ entity }: { entity: Record<string, any> }) => {
+const RelationshipLineage = ({
+  entity,
+  relationshipAttributes,
+  isLoading
+}: {
+  entity: Record<string, any>;
+  relationshipAttributes?: Record<string, any[]>;
+  isLoading?: boolean;
+}) => {
   const entityData = cloneDeep(entity);
+  if (relationshipAttributes) {
+    entityData.relationshipAttributes = relationshipAttributes;
+  }
   const { guid } = useParams();
   const location = useLocation();
   const searchParams = new URLSearchParams(location.search);
@@ -117,7 +129,7 @@ const RelationshipLineage = ({ entity }: { entity: Record<string, any> }) => {
     return { nodes: nodes, links: links };
   };
 
-  let graphData = createData(entityData);
+  const graphData = useMemo(() => createData(entityData), [entityData]);
   const createGraph = (data) => {
     // Use getBoundingClientRect to get the actual width and height
     const svgElement = svgRef?.current;
@@ -409,10 +421,26 @@ const RelationshipLineage = ({ entity }: { entity: Record<string, any> }) => {
   };
 
   useEffect(() => {
-    if (svgRef?.current) {
+    if (!svgRef?.current) {
+      return;
+    }
+    d3.select(svgRef.current).selectAll("*").remove();
+    if (!isEmpty(graphData.links)) {
       createGraph(graphData);
     }
-  }, []);
+  }, [graphData]);
+
+  if (isLoading) {
+    return (
+      <Stack
+        alignItems="center"
+        justifyContent="center"
+        sx={{ minHeight: "320px" }}
+      >
+        <CircularProgress />
+      </Stack>
+    );
+  }
 
   if (graphData && isEmpty(graphData.links)) {
     return <Typography>No relationship data found</Typography>;
@@ -587,7 +615,7 @@ const RelationshipLineage = ({ entity }: { entity: Record<string, any> }) => {
         const valObj = { ...val, entityName: name };
 
         if (searchString) {
-          if (name.search(new RegExp(searchString, "i")) !== -1) {
+          if (name.toLowerCase().includes(searchString.toLowerCase())) {
             listString.push(getElement(valObj));
           } else {
             continue;
@@ -600,7 +628,7 @@ const RelationshipLineage = ({ entity }: { entity: Record<string, any> }) => {
       listString.push(getElement(data));
     }
     return (
-      <Stack sx={{ background: "white" }} minHeight={"150px"} maxWidth="400px">
+      <Stack sx={{ background: "white" }} minHeight={"150px"} maxWidth="520px">
         {/* {listString?.length > 1 && ( */}
         <Paper
           variant="outlined"
@@ -626,7 +654,14 @@ const RelationshipLineage = ({ entity }: { entity: Record<string, any> }) => {
         </Paper>
         {/* )} */}
 
-        <Stack gap={"0.875rem"}>{listString}</Stack>
+        <Stack
+          gap={"0.875rem"}
+          paddingLeft="0.5rem"
+          maxHeight="220px"
+          sx={{ overflowY: "auto" }}
+        >
+          {listString}
+        </Stack>
       </Stack>
     );
   };
@@ -735,7 +770,7 @@ const RelationshipLineage = ({ entity }: { entity: Record<string, any> }) => {
                 </Stack>
 
                 <Stack
-                  maxHeight={"350px"}
+                  maxHeight={"320px"}
                   gap={1}
                   padding="0.875rem"
                   textAlign="left"
diff --git a/dashboard/src/views/DetailPage/EntityDetailTabs/RelationshipsTab.tsx b/dashboard/src/views/DetailPage/EntityDetailTabs/RelationshipsTab.tsx
index 9f5413b9b..c6e07e8e2 100644
--- a/dashboard/src/views/DetailPage/EntityDetailTabs/RelationshipsTab.tsx
+++ b/dashboard/src/views/DetailPage/EntityDetailTabs/RelationshipsTab.tsx
@@ -21,37 +21,95 @@ import {
   Grid,
   Stack,
   ToggleButton,
-  ToggleButtonGroup,
-  Typography
+  ToggleButtonGroup
 } from "@mui/material";
-import { useMemo, useState } from "react";
-import { TableLayout } from "@components/Table/TableLayout";
-import { getValues } from "@components/commonComponents";
-import { customSortByObjectKeys, isArray, isEmpty } from "@utils/Utils";
+import { useState, useEffect, useRef, useMemo } from "react";
+import { isArray, isEmpty } from "@utils/Utils";
 import { EntityDetailTabProps } from "@models/entityDetailType";
 import RelationshipLineage from "./RelationshipLineage";
 import { AntSwitch } from "@utils/Muiutils";
+import RelationshipCard from "./RelationshipCard";
+import RelationshipCardSkeleton from "./RelationshipCardSkeleton";
+import { getRelationShipV2 } from "@api/apiMethods/searchApiMethod";
+import { useParams } from "react-router-dom";
+import { serverError } from "@utils/Utils";
+import { useSelector } from "react-redux";
+import { EntityState } from "@models/relationshipSearchType";
 
 const RelationshipsTab: React.FC<EntityDetailTabProps> = ({
   entity,
-  referredEntities,
-  loading
+  referredEntities
 }) => {
-  const { relationshipAttributes = {} } = entity || {};
-  let columnData = { ...relationshipAttributes };
-
-  let rowData = [];
-  for (let key in columnData) {
-    rowData.push({ [key]: columnData[key] });
-  }
-
-  let nonEmptyRowData = rowData.filter((obj) => {
-    const entries = Object.entries(obj);
-    return entries.every(([_key, value]) => !isEmpty(value));
-  });
+  const { guid } = useParams<{ guid: string }>();
+  const toastId = useRef<any>(null);
+  const fetchStartedRef = useRef<boolean>(false);
+  const { entityData } = useSelector((state: EntityState) => state.entity);
+  const entityTypeName = entity?.typeName;
 
   const [alignment, setAlignment] = useState<string>("table");
   const [checked, setChecked] = useState<boolean>(false);
+  
+  // Card view state
+  const [cardData, setCardData] = useState<Record<string, any[]>>({});
+  const [cardTotalCounts, setCardTotalCounts] = useState<Record<string, number>>({});
+  const [cardLoading, setCardLoading] = useState<boolean>(false);
+  const [cardLoadingByName, setCardLoadingByName] = useState<
+    Record<string, boolean>
+  >({});
+  const [initialLoadDone, setInitialLoadDone] = useState<boolean>(false);
+  const [sortByNameByAttr, setSortByNameByAttr] = useState<
+    Record<string, boolean>
+  >({});
+  const [showDeletedByAttr, setShowDeletedByAttr] = useState<
+    Record<string, boolean>
+  >({});
+  const [pageLimitByAttr, setPageLimitByAttr] = useState<
+    Record<string, number>
+  >({});
+  const [cardResettingByName, setCardResettingByName] = useState<
+    Record<string, boolean>
+  >({});
+  const [showInitialSkeletons, setShowInitialSkeletons] = useState<boolean>(true);
+  const initialSkeletonTimerRef = useRef<ReturnType<typeof setTimeout> | null>(
+    null
+  );
+
+  useEffect(() => {
+    setInitialLoadDone(false);
+    setCardData({});
+    setCardTotalCounts({});
+    setShowInitialSkeletons(true);
+    fetchStartedRef.current = false;
+
+    if (initialSkeletonTimerRef.current) {
+      clearTimeout(initialSkeletonTimerRef.current);
+      initialSkeletonTimerRef.current = null;
+    }
+    initialSkeletonTimerRef.current = setTimeout(() => {
+      setShowInitialSkeletons(false);
+      initialSkeletonTimerRef.current = null;
+    }, 5000);
+
+    return () => {
+      if (initialSkeletonTimerRef.current) {
+        clearTimeout(initialSkeletonTimerRef.current);
+      }
+    };
+  }, [guid]);
+
+  const relationNames = useMemo((): string[] => {
+    if (!entityTypeName || !entityData?.entityDefs) {
+      return [];
+    }
+    const entityDef = entityData.entityDefs.find(
+      (def: { name: string }) => def.name === entityTypeName
+    );
+    const relationshipDefs = (entityDef?.relationshipAttributeDefs || []) as Array<{ name: string }>;
+    const names = relationshipDefs
+      .map((def) => def.name)
+      .filter(Boolean) as string[];
+    return [...new Set(names)];
+  }, [entityData, entityTypeName]);
 
   const handleChange = (
     _event: React.MouseEvent<HTMLElement>,
@@ -67,53 +125,363 @@ const RelationshipsTab: React.FC<EntityDetailTabProps> = ({
     setChecked(event.target.checked);
   };
 
-  const defaultColumns = useMemo(
-    () => [
-      {
-        id: "relationKey",
-        accessorKey: "relationKey",
-        accessorFn: (row: Record<string, any>) => Object.keys(row)[0] || "",
-        cell: (info: any) => {
-          const keyName: string = info.getValue();
-          const values = info.row.original;
-          return (
-            <Typography fontWeight="600">{`${keyName} ${
-              isArray(values[keyName]) && !isEmpty(values[keyName])
-                ? `(${values[keyName].length})`
-                : ""
-            }`}</Typography>
-          );
-        },
-        header: "Key",
-        width: "30%"
-      },
-      {
-        id: "relationValue",
-        accessorKey: "relationValue",
-        accessorFn: (row: Record<string, any>) => row[Object.keys(row)[0]],
-        cell: (info: any) => {
-          const keyName: string = Object.keys(info.row.original)[0];
-          const value = info.getValue();
-          return (
-            <span className="value-text">
-              {getValues(
-                value,
-                columnData,
-                entity,
-                undefined,
-                "properties",
-                referredEntities,
-                undefined,
-                keyName
-              )}
-            </span>
-          );
-        },
-        header: "Value"
+  // Fetch initial relationship attributes data
+  const getPageLimit = (relationName: string, totalCount?: number) => {
+    const defaultLimit =
+      typeof totalCount === "number" && totalCount < 100 ? totalCount : 100;
+    const currentLimit = pageLimitByAttr[relationName];
+    if (typeof currentLimit !== "number") {
+      return defaultLimit;
+    }
+    if (typeof totalCount === "number" && currentLimit > totalCount) {
+      return totalCount;
+    }
+    return currentLimit;
+  };
+
+  const getRelationshipParams = (
+    relationName: string,
+    offset: number,
+    totalCount?: number,
+    overrides?: {
+      isSorted?: boolean;
+      showDeleted?: boolean;
+      limit?: number;
+    }
+  ) => {
+    const isSorted =
+      typeof overrides?.isSorted === "boolean"
+        ? overrides.isSorted
+        : !!sortByNameByAttr[relationName];
+    const showDeleted =
+      typeof overrides?.showDeleted === "boolean"
+        ? overrides.showDeleted
+        : !!showDeletedByAttr[relationName];
+    const limit =
+      typeof overrides?.limit === "number"
+        ? overrides.limit
+        : getPageLimit(relationName, totalCount);
+    return {
+      limit,
+      offset,
+      guid,
+      sortBy: isSorted ? "name" : undefined,
+      sortOrder: isSorted ? "ASCENDING" : undefined,
+      disableDefaultSorting: !isSorted,
+      excludeDeletedEntities: !showDeleted,
+      includeSubClassifications: true,
+      includeSubTypes: true,
+      includeClassificationAttributes: true,
+      relation: relationName,
+      getApproximateCount: offset === 0
+    };
+  };
+
+  const fetchRelationshipData = async (
+    relationName: string,
+    offset: number,
+    totalCount?: number,
+    overrides?: {
+      isSorted?: boolean;
+      showDeleted?: boolean;
+      limit?: number;
+    }
+  ) => {
+    const params = getRelationshipParams(
+      relationName,
+      offset,
+      totalCount,
+      overrides
+    );
+    const response = await getRelationShipV2({ params });
+    return {
+      entities: response?.data?.entities || [],
+      approximateCount:
+        response?.data?.approximateCount ?? response?.data?.totalCount
+    };
+  };
+
+  const fetchInitialRelationshipData = async () => {
+    if (!guid || initialLoadDone || isEmpty(relationNames)) {
+      return;
+    }
+
+    setCardLoading(true);
+    let completedCount = 0;
+    const totalCount = relationNames.length;
+
+    relationNames.forEach((relationName) => {
+      fetchRelationshipData(relationName, 0, undefined, {
+        showDeleted: true
+      })
+        .then((response) => {
+          const entities = response.entities;
+          const entityList = isArray(entities)
+            ? entities
+            : !isEmpty(entities)
+            ? [entities]
+            : [];
+          setCardData((prev) => ({ ...prev, [relationName]: entityList }));
+          if (response.approximateCount !== undefined) {
+            setCardTotalCounts((prev) => ({
+              ...prev,
+              [relationName]: response.approximateCount
+            }));
+          }
+          setSortByNameByAttr((prev) => ({
+            ...prev,
+            [relationName]: prev[relationName] ?? false
+          }));
+          setShowDeletedByAttr((prev) => ({
+            ...prev,
+            [relationName]: prev[relationName] ?? true
+          }));
+        })
+        .catch((err) => {
+          console.error(`Error fetching relationship ${relationName}:`, err);
+          setCardData((prev) => ({ ...prev, [relationName]: [] }));
+          setSortByNameByAttr((prev) => ({
+            ...prev,
+            [relationName]: prev[relationName] ?? false
+          }));
+          setShowDeletedByAttr((prev) => ({
+            ...prev,
+            [relationName]: prev[relationName] ?? true
+          }));
+        })
+        .finally(() => {
+          completedCount += 1;
+          if (completedCount >= totalCount) {
+            setInitialLoadDone(true);
+            setCardLoading(false);
+          }
+        });
+    });
+  };
+
+  // Load initial data when tab is switched to card/graph view
+  useEffect(() => {
+    if (
+      (alignment === "table" || alignment === "graph") &&
+      guid &&
+      !initialLoadDone &&
+      !cardLoading &&
+      !isEmpty(relationNames)
+    ) {
+      if (fetchStartedRef.current) {
+        return;
       }
-    ],
-    []
-  );
+      fetchStartedRef.current = true;
+      fetchInitialRelationshipData().finally(() => {
+        fetchStartedRef.current = false;
+      });
+    }
+  }, [alignment, guid, relationNames, initialLoadDone, cardLoading]);
+
+  useEffect(() => {
+    if (!isEmpty(relationNames)) {
+      setShowInitialSkeletons(false);
+      if (initialSkeletonTimerRef.current) {
+        clearTimeout(initialSkeletonTimerRef.current);
+        initialSkeletonTimerRef.current = null;
+      }
+    }
+  }, [relationNames]);
+
+  // Handle load more for a specific card
+  const handleCardLoadMore = async (attributeName: string) => {
+    if (!guid || cardLoadingByName[attributeName]) {
+      return;
+    }
+    const existingData = cardData[attributeName] || [];
+    setCardLoadingByName((prev) => ({ ...prev, [attributeName]: true }));
+    try {
+      const totalCount = cardTotalCounts[attributeName];
+      const response = await fetchRelationshipData(
+        attributeName,
+        existingData.length,
+        totalCount
+      );
+      const updated = [...existingData, ...(response.entities || [])];
+      setCardData((prev) => ({
+        ...prev,
+        [attributeName]: updated
+      }));
+    } catch (error: any) {
+      console.error("Error loading more relationship data:", error);
+      serverError(error, toastId);
+    } finally {
+      setCardLoadingByName((prev) => ({ ...prev, [attributeName]: false }));
+    }
+  };
+
+  useEffect(() => {
+    if (isEmpty(cardTotalCounts)) {
+      return;
+    }
+    setPageLimitByAttr((prev) => {
+      const next = { ...prev };
+      Object.keys(cardTotalCounts).forEach((relationName) => {
+        const totalCount = cardTotalCounts[relationName];
+        const defaultLimit = totalCount < 100 ? totalCount : 100;
+        const current = next[relationName];
+        if (typeof current !== "number") {
+          next[relationName] = defaultLimit;
+          return;
+        }
+        if (current > totalCount) {
+          next[relationName] = totalCount;
+        }
+      });
+      return next;
+    });
+  }, [cardTotalCounts]);
+
+  const resetRelationshipData = async (
+    relationName: string,
+    overrides?: {
+      isSorted?: boolean;
+      showDeleted?: boolean;
+      limit?: number;
+    }
+  ) => {
+    if (!guid || cardLoadingByName[relationName]) {
+      return;
+    }
+    setCardResettingByName((prev) => ({ ...prev, [relationName]: true }));
+    try {
+      const totalCount = cardTotalCounts[relationName];
+      const response = await fetchRelationshipData(
+        relationName,
+        0,
+        totalCount,
+        overrides
+      );
+      const entities = response.entities;
+      const updated = isArray(entities)
+        ? entities
+        : !isEmpty(entities)
+        ? [entities]
+        : [];
+      setCardData((prev) => ({
+        ...prev,
+        [relationName]: updated
+      }));
+      if (response.approximateCount !== undefined) {
+        setCardTotalCounts((prev) => ({
+          ...prev,
+          [relationName]: response.approximateCount
+        }));
+      }
+    } catch (error: any) {
+      console.error("Error resetting relationship data:", error);
+      serverError(error, toastId);
+    } finally {
+      setCardResettingByName((prev) => ({ ...prev, [relationName]: false }));
+    }
+  };
+
+  const handleToggleSort = (relationName: string) => {
+    const nextSorted = !sortByNameByAttr[relationName];
+    setSortByNameByAttr((prev) => ({
+      ...prev,
+      [relationName]: nextSorted
+    }));
+    resetRelationshipData(relationName, { isSorted: nextSorted });
+  };
+
+  const handleToggleShowDeleted = (relationName: string) => {
+    const nextShowDeleted = !showDeletedByAttr[relationName];
+    setShowDeletedByAttr((prev) => ({
+      ...prev,
+      [relationName]: nextShowDeleted
+    }));
+    resetRelationshipData(relationName, { showDeleted: nextShowDeleted });
+  };
+
+  const handlePageLimitChange = (relationName: string, value: string) => {
+    const parsed = parseInt(value, 10);
+    if (!Number.isFinite(parsed)) {
+      setPageLimitByAttr((prev) => ({ ...prev, [relationName]: 0 }));
+      return;
+    }
+    setPageLimitByAttr((prev) => ({ ...prev, [relationName]: parsed }));
+  };
+
+  const handlePageLimitSubmit = (relationName: string) => {
+    const totalCount = cardTotalCounts[relationName] ?? 0;
+    const defaultLimit = totalCount < 100 ? totalCount : 100;
+    const currentLimit = pageLimitByAttr[relationName];
+    let nextLimit = currentLimit;
+    if (!Number.isFinite(currentLimit) || currentLimit <= 0) {
+      nextLimit = defaultLimit;
+    }
+    if (totalCount > 0 && nextLimit > totalCount) {
+      nextLimit = totalCount;
+    }
+    setPageLimitByAttr((prev) => ({ ...prev, [relationName]: nextLimit }));
+    resetRelationshipData(relationName, { limit: nextLimit });
+  };
+
+  /**
+   * Computes column layout based on record count:
+   * - >5 records: 1 card per column
+   * - 1-5 records: 2 cards per column
+   * - 0 records: 2 cards per column (when showEmptyValues is true)
+   * During loading, uses relationNames in pairs for stable layout.
+   */
+  const relationshipColumns = useMemo((): string[][] => {
+    const loadedNames = Object.keys(cardData);
+    const allLoaded = relationNames.length > 0 && relationNames.every((r) => r in cardData);
+    const names = allLoaded ? loadedNames : relationNames;
+
+    if (isEmpty(names)) {
+      return [];
+    }
+
+    const getCount = (name: string) =>
+      cardTotalCounts[name] ?? cardData[name]?.length ?? 0;
+
+    const largeCards: string[] = [];
+    const smallCards: string[] = [];
+    const emptyCards: string[] = [];
+
+    names.forEach((name) => {
+      const count = getCount(name);
+      if (count > 5) {
+        largeCards.push(name);
+      } else if (count >= 1 && count <= 5) {
+        smallCards.push(name);
+      } else {
+        emptyCards.push(name);
+      }
+    });
+
+    const sortNames = (arr: string[]) =>
+      arr.sort((a, b) => a.localeCompare(b));
+
+    sortNames(largeCards);
+    sortNames(smallCards);
+    sortNames(emptyCards);
+
+    const columns: string[][] = [];
+
+    largeCards.forEach((name) => columns.push([name]));
+
+    for (let i = 0; i < smallCards.length; i += 2) {
+      const chunk = smallCards.slice(i, i + 2);
+      columns.push(chunk);
+    }
+
+    if (checked || !allLoaded) {
+      for (let i = 0; i < emptyCards.length; i += 2) {
+        const chunk = emptyCards.slice(i, i + 2);
+        columns.push(chunk);
+      }
+    }
+
+    return columns;
+  }, [cardData, cardTotalCounts, checked, relationNames]);
 
   return (
     <Grid container marginTop={0} className="properties-container">
@@ -165,26 +533,78 @@ const RelationshipsTab: React.FC<EntityDetailTabProps> = ({
             )}
           </Stack>
 
-          {alignment == "graph" && <RelationshipLineage entity={entity} />}
+          {alignment == "graph" && (
+            <RelationshipLineage
+              entity={entity}
+              relationshipAttributes={cardData}
+              isLoading={cardLoading && Object.keys(cardData).length === 0}
+            />
+          )}
 
           {alignment == "table" && (
-            <TableLayout
-              data={
-                !isEmpty(checked ? rowData : nonEmptyRowData)
-                  ? customSortByObjectKeys(checked ? rowData : nonEmptyRowData)
-                  : []
-              }
-              columns={defaultColumns.filter(
-                (value) => Object.keys(value).length !== 0
+            <>
+              {showInitialSkeletons ? (
+                <div className="relationship-cards-grid relationship-cards-grid--custom">
+                  <div className="relationship-cards-column">
+                    <RelationshipCardSkeleton />
+                    <RelationshipCardSkeleton />
+                  </div>
+                </div>
+              ) : isEmpty(relationNames) ||
+                (relationNames.every((r) => r in cardData) &&
+                  Object.values(cardData).every((arr) => isEmpty(arr)) &&
+                  !checked) ? (
+                <div className="relationship-cards-empty">
+                  No relationship data available
+                </div>
+              ) : (
+                <div className="relationship-cards-grid relationship-cards-grid--custom">
+                  {relationshipColumns.map((columnNames, colIndex) => (
+                    <div
+                      key={`col-${colIndex}`}
+                      className="relationship-cards-column"
+                    >
+                      {columnNames.map((attributeName) => {
+                        const data = cardData[attributeName];
+                        const hasData = attributeName in cardData;
+                        if (hasData) {
+                          if (isEmpty(data) && !checked) {
+                            return null;
+                          }
+                          return (
+                            <RelationshipCard
+                              key={attributeName}
+                              attributeName={attributeName}
+                              data={data ?? []}
+                              referredEntities={referredEntities}
+                              showEmptyValues={checked}
+                              showTypeNameInDisplay={relationNames.length > 1}
+                              onLoadMore={handleCardLoadMore}
+                              totalCount={cardTotalCounts[attributeName]}
+                              isLoading={cardLoadingByName[attributeName]}
+                              isResetting={cardResettingByName[attributeName]}
+                              isSorted={!!sortByNameByAttr[attributeName]}
+                              showDeleted={!!showDeletedByAttr[attributeName]}
+                              pageLimit={getPageLimit(
+                                attributeName,
+                                cardTotalCounts[attributeName]
+                              )}
+                              onToggleSort={handleToggleSort}
+                              onToggleShowDeleted={handleToggleShowDeleted}
+                              onPageLimitChange={handlePageLimitChange}
+                              onPageLimitSubmit={handlePageLimitSubmit}
+                            />
+                          );
+                        }
+                        return (
+                          <RelationshipCardSkeleton key={attributeName} />
+                        );
+                      })}
+                    </div>
+                  ))}
+                </div>
               )}
-              emptyText="No Records found!"
-              isFetching={loading}
-              columnVisibility={false}
-              columnSort={false}
-              showPagination={false}
-              showRowSelection={false}
-              tableFilters={false}
-            />
+            </>
           )}
         </Stack>
       </Grid>
diff --git a/dashboard/src/views/SearchResult/SearchResult.tsx b/dashboard/src/views/SearchResult/SearchResult.tsx
index fc4603194..a026e1175 100644
--- a/dashboard/src/views/SearchResult/SearchResult.tsx
+++ b/dashboard/src/views/SearchResult/SearchResult.tsx
@@ -90,6 +90,8 @@ const SearchResult = ({ classificationParams, glossaryTypeParams, hideFilters }:
   const toastId: any = useRef(null);
   const [updateTable, setUpdateTable] = useState(moment.now());
   const { entityData } = useSelector((state: EntityState) => state.entity);
+  const { businessMetaData } = useSelector((state: any) => state.businessMetaData);
+  const { businessMetadataDefs } = businessMetaData || {};
   const [pageCount, setPageCount] = useState<number>(0);
   const [totalCount, setTotalCount] = useState<number>(0);
   const [isEmptyData, setIsEmptyData] = useState(false);
@@ -433,18 +435,26 @@ const SearchResult = ({ classificationParams, glossaryTypeParams, hideFilters }:
     {
       accessorFn: (row: any) => row.typeName,
       accessorKey: "typeName",
-      cell: (info: any) => (
-        <LightTooltip title={`Search ${info.getValue()}`}>
-          <Link
-            className="text-blue text-decoration-none"
-            to={{
-              pathname: "/"
-            }}
-          >
-            {info.getValue()}
-          </Link>
-        </LightTooltip>
-      ),
+      cell: (info: any) => {
+        const typeName = info.getValue();
+        const searchParams = new URLSearchParams();
+        searchParams.set("query", typeName);
+        searchParams.set("searchType", "dsl");
+        
+        return (
+          <LightTooltip title={`Search ${typeName}`}>
+            <Link
+              className="text-blue text-decoration-none"
+              to={{
+                pathname: "/search/searchResult",
+                search: searchParams.toString()
+              }}
+            >
+              {typeName}
+            </Link>
+          </LightTooltip>
+        );
+      },
       header: "Type",
       show: true
     },
@@ -700,11 +710,120 @@ const SearchResult = ({ classificationParams, glossaryTypeParams, hideFilters }:
       }
     );
 
+  // Function to get business metadata attribute columns
+  const getBusinessMetadataAttributeCols = () => {
+    let businessMetadataAttrCols: any = [];
+    let businessAttributes: any = {};
+
+    // Get business attributes based on search type
+    if (searchParams.get("type") === "_ALL_ENTITY_TYPES") {
+      // For _ALL_ENTITY_TYPES, get all business metadata definitions
+      if (businessMetadataDefs && businessMetadataDefs.length > 0) {
+        businessMetadataDefs.forEach((bmDef: any) => {
+          const attributes = bmDef.attributeDefs || [];
+          if (attributes.length > 0) {
+            // Sort attributes by name to match Classic UI behavior
+            const sortedAttributes = [...attributes].sort((a: any, b: any) => {
+              if (a.name < b.name) return -1;
+              if (a.name > b.name) return 1;
+              return 0;
+            });
+            businessAttributes[bmDef.name] = sortedAttributes;
+          }
+        });
+      }
+    } else {
+      // For specific type, get from entity definition
+      const rawBusinessAttributes = typeDefEntityData?.businessAttributeDefs || {};
+      // Sort attributes within each business metadata
+      Object.keys(rawBusinessAttributes).forEach((bmName: string) => {
+        const attributes = rawBusinessAttributes[bmName];
+        if (Array.isArray(attributes)) {
+          businessAttributes[bmName] = [...attributes].sort((a: any, b: any) => {
+            if (a.name < b.name) return -1;
+            if (a.name > b.name) return 1;
+            return 0;
+          });
+        } else {
+          businessAttributes[bmName] = attributes;
+        }
+      });
+    }
+
+    // Create columns for each business metadata attribute
+    if (businessAttributes && Object.keys(businessAttributes).length > 0) {
+      Object.keys(businessAttributes).forEach((businessMetadataName: string) => {
+        const attributes = businessAttributes[businessMetadataName];
+        if (attributes && Array.isArray(attributes)) {
+          attributes.forEach((attr: any) => {
+            const attributeKey = `${businessMetadataName}.${attr.name}`;
+            businessMetadataAttrCols.push({
+              id: attributeKey, // Set id to match accessorKey for URL params tracking
+              accessorFn: (row: any) => {
+                // Business metadata attributes are flattened in the API response
+                // Format: attributes["bm1.BM_attr1"] (matching Classic UI behavior)
+                // Try flattened format first
+                if (row.attributes?.[attributeKey] !== undefined) {
+                  return row.attributes[attributeKey];
+                }
+                // Fallback to nested format: attributes[bmName][attrName]
+                const bmData = row.attributes?.[businessMetadataName];
+                if (bmData && bmData[attr.name] !== undefined) {
+                  return bmData[attr.name];
+                }
+                return null;
+              },
+              accessorKey: attributeKey,
+              header: attributeKey, // Display as "bm1.BM_attr1" format
+              cell: (info: any) => {
+                const rowData = info.row.original;
+                // Try flattened format first: attributes["bm1.BM_attr1"]
+                let attrValue = rowData.attributes?.[attributeKey];
+                
+                // Fallback to nested format: attributes[bmName][attrName]
+                if (attrValue === undefined || attrValue === null) {
+                  const bmData = rowData.attributes?.[businessMetadataName];
+                  attrValue = bmData?.[attr.name];
+                }
+
+                if (attrValue === undefined || attrValue === null || attrValue === "") {
+                  return <span>NA</span>;
+                }
+
+                // Use getValues helper to format the value properly
+                // Pass attributeKey as the name so getValues can access attributes[attributeKey]
+                return getValues(
+                  info,
+                  typeDefEntityData,
+                  {
+                    ...attr,
+                    name: attributeKey,
+                    isBusinessAttributes: true
+                  }
+                );
+              },
+              show: false, // Default to unchecked/hidden
+              enableSorting:
+                attr.typeName?.search(
+                  /(string|date|boolean|int|number|byte|float|long|double|short)/i
+                ) == 0
+            });
+          });
+        }
+      });
+    }
+
+    return businessMetadataAttrCols;
+  };
+
+  let businessMetadataAttributeCols = getBusinessMetadataAttributeCols();
+
   let dynamicColumns: any = customSortBy(
     [
       ...(entitytAttributeDefsCol || []),
       ...(relationshipAttributeDefsCol || []),
-      ...(superTypeAttributeDefsCol || [])
+      ...(superTypeAttributeDefsCol || []),
+      ...(businessMetadataAttributeCols || [])
     ],
     ["header"]
   );
@@ -862,19 +981,21 @@ const SearchResult = ({ classificationParams, glossaryTypeParams, hideFilters }:
     let hideColumns: any = {};
 
     for (let col of columns) {
+      // If column is explicitly in URL params, show it (true = visible in React Table)
       if (
         !isEmpty(columnsParams) &&
         columnsParams.split(",").includes(col.accessorKey)
       ) {
         hideColumns[col.accessorKey] = true;
-      } else if (col.show == false) {
-        hideColumns[col.accessorKey] = false;
-      } else if (
-        !isEmpty(columnsParams) &&
-        columnsParams.split(",").includes(col.accessorKey) == false
-      ) {
+      } 
+      // If column has show: false (like business metadata), hide it by default (false = hidden in React Table)
+      else if (col.show === false) {
         hideColumns[col.accessorKey] = false;
       }
+      // For columns with show: true or default columns, show them
+      else {
+        hideColumns[col.accessorKey] = true;
+      }
     }
 
     return hideColumns;
diff --git a/dashboard/src/views/SideBar/SideBarTree/EntitiesTree.tsx b/dashboard/src/views/SideBar/SideBarTree/EntitiesTree.tsx
index 262c7dcdf..74ffd5448 100644
--- a/dashboard/src/views/SideBar/SideBarTree/EntitiesTree.tsx
+++ b/dashboard/src/views/SideBar/SideBarTree/EntitiesTree.tsx
@@ -161,7 +161,7 @@ const EntitiesTree = ({ sideBarOpen, searchTerm }: Props) => {
   ) => {
     const rootEntityChildren: ChildrenInterface = {
       gType: "Entity",
-      guid: addOnEntities[0],
+      guid: addOnEntities[0], 
       id: addOnEntities[0],
       name: addOnEntities[0],
       type: allEntityTypesData?.category,
diff --git a/dashboardv2/gruntfile.js b/dashboardv2/gruntfile.js
index ddf1cf719..85fa372b4 100644
--- a/dashboardv2/gruntfile.js
+++ b/dashboardv2/gruntfile.js
@@ -50,6 +50,7 @@ module.exports = function(grunt) {
         },
         connect: {
             server: {
+
                 options: {
                     port: 9999,
                     base: distPath,
@@ -224,11 +225,11 @@ module.exports = function(grunt) {
             bootstrap: {
                 files: [
                     {
-                        src: nodeModulePath + 'bootstrap/dist/js/bootstrap-patched.min.js',
+                        src: nodeModulePath + 'bootstrap/dist/js/bootstrap.min.js',
                         dest: libPath + 'bootstrap/js/bootstrap.min.js'
                     },
                     {
-                        src: nodeModulePath + 'bootstrap/dist/css/bootstrap-patched.min.css',
+                        src: nodeModulePath + 'bootstrap/dist/css/bootstrap.min.css',
                         dest: libPath + 'bootstrap/css/bootstrap.min.css'
                     }
                 ]
diff --git a/dashboardv2/public/css/scss/relationship.scss b/dashboardv2/public/css/scss/relationship.scss
index 7bf256072..98e22a8fc 100644
--- a/dashboardv2/public/css/scss/relationship.scss
+++ b/dashboardv2/public/css/scss/relationship.scss
@@ -19,6 +19,7 @@
     position: absolute;
     height: 100%;
     width: 100%;
+    min-height: 700px;
     overflow: hidden;
     z-index: 1;
 
@@ -26,10 +27,516 @@
         fill: none;
         stroke-width: 1.5px;
     }
+
+    svg {
+        min-height: 700px;
+        height: 100%;
+    }
+
+    .relationship-node-icon,
+    .relationship-node-label,
+    .relationship-node-count {
+        pointer-events: none;
+    }
 }
 
 .relationship-node-details {
     &.box-panel {
         top: 0;
     }
+
+    &.slide-to-left {
+        right: 0 !important;
+        left: 0 !important;
+    }
+}
+
+// Relationship Cards Styles - Match React UI structure and breakpoints
+.relationship-cards-container {
+    padding: 0;
+    min-height: 600px;
+
+    .relationship-cards-controls {
+        margin-bottom: 12px;
+        display: flex;
+        justify-content: flex-end;
+        padding: 0 4px;
+    }
+
+    .relationship-cards-loader {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        min-height: 400px;
+    }
+
+    .relationship-cards-empty {
+        text-align: center;
+        color: #999;
+        padding: 32px;
+    }
+}
+
+// Grid - same structure as React UI: direct children are relationship-card
+.relationship-cards-grid {
+    display: grid;
+    grid-template-columns: repeat(1, minmax(0, 1fr));
+    gap: 12px;
+    align-items: start;
+    padding: 16px;
+}
+
+@media (min-width: 900px) {
+    .relationship-cards-grid {
+        grid-template-columns: repeat(2, minmax(0, 1fr));
+    }
+}
+
+@media (min-width: 1200px) {
+    .relationship-cards-grid {
+        grid-template-columns: repeat(3, minmax(0, 1fr));
+    }
+}
+
+@media (min-width: 1400px) {
+    .relationship-cards-grid {
+        grid-template-columns: repeat(4, minmax(0, 1fr));
+    }
+}
+
+.relationship-cards-grid .relationship-cards-empty {
+    grid-column: 1 / -1;
+}
+
+/* Custom column layout: >5 records = 1/col, 1-5 and 0 = 2/col (matches React UI) */
+.relationship-cards-grid--custom {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 12px;
+    align-items: flex-start;
+}
+
+.relationship-cards-column {
+    display: flex;
+    flex-direction: column;
+    gap: 12px;
+    min-width: 280px;
+    flex: 0 0 auto;
+}
+
+@media (max-width: 599px) {
+    .relationship-cards-column {
+        min-width: 100%;
+    }
+}
+
+.relationship-cards-grid--custom .relationship-cards-empty {
+    width: 100%;
+    flex: 1 1 100%;
+}
+
+.relationship-card {
+    display: flex;
+    flex-direction: column;
+    width: 100%;
+    min-width: 0;
+    min-height: 80px;
+    border: 1px solid #e2e8f0;
+    border-radius: 10px;
+    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08);
+    overflow: hidden;
+    background: #fff;
+    height: auto;
+
+    .relationship-card-header {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        padding: 8px 12px;
+        border-top-left-radius: 10px;
+        border-top-right-radius: 10px;
+        background-color: $white;
+        color: $color_jungle_green_approx;
+        border-bottom: 1px solid #e2e8f0;
+
+        .relationship-card-title-wrap {
+            display: flex;
+            align-items: baseline;
+        }
+
+        .relationship-card-title {
+            font-size: 15px;
+            font-weight: 600;
+            text-transform: capitalize;
+            color: $color_jungle_green_approx;
+            font-family: inherit;
+            letter-spacing: 0.01em;
+            -webkit-font-smoothing: antialiased;
+        }
+
+        .relationship-card-count {
+            margin-left: 6px;
+            font-size: 13px;
+            font-weight: 500;
+            color: $color_jungle_green_approx;
+        }
+
+        .relationship-card-actions {
+            display: flex;
+            align-items: center;
+            gap: 8px;
+            color: #64748b;
+        }
+
+        .relationship-card-action-button {
+            background: transparent;
+            border: 1px solid transparent;
+            border-radius: 4px;
+            padding: 2px 6px;
+            cursor: pointer;
+            color: inherit;
+
+            &.is-active {
+                color: #2563eb;
+            }
+        }
+
+        .relationship-card-toggle {
+            display: flex;
+            align-items: center;
+            gap: 4px;
+            font-size: 13px;
+            color: #64748b;
+
+            input {
+                margin: 0;
+            }
+        }
+    }
+
+    .relationship-card-content {
+        flex: 1;
+        display: flex;
+        flex-direction: column;
+        padding: 12px;
+        min-height: 0;
+        overflow: hidden;
+
+        .relationship-card-search {
+            margin-bottom: 6px;
+
+            .relationship-card-search-input {
+                width: 100%;
+                border: 1px solid #d1d5db;
+                border-radius: 6px;
+                padding: 6px 10px;
+                font-size: 12px;
+                color: #1f2937;
+                background-color: #f9fafb;
+            }
+        }
+
+        .relationship-card-scroll {
+            flex: 1;
+            overflow-y: auto;
+            overflow-x: hidden;
+            min-height: 0;
+            position: relative;
+
+            &::-webkit-scrollbar {
+                width: 8px;
+            }
+
+            &::-webkit-scrollbar-track {
+                background: #f1f1f1;
+                border-radius: 4px;
+            }
+
+            &::-webkit-scrollbar-thumb {
+                background: #888;
+                border-radius: 4px;
+
+                &:hover {
+                    background: #555;
+                }
+            }
+        }
+
+        .relationship-card-list {
+            list-style: none;
+            padding: 0;
+            margin: 0;
+            text-align: left;
+
+            .relationship-card-item {
+                padding: 8px 0;
+                border-bottom: 1px solid #f0f0f0;
+
+                &:last-child {
+                    border-bottom: none;
+                }
+
+                &:hover {
+                    background-color: #f9f9f9;
+                }
+
+                &.has-border {
+                    border-bottom: 1px solid #f0f0f0;
+                }
+
+                .relationship-card-link {
+                    color: #1976d2;
+                    text-decoration: none;
+                    font-size: 13px;
+                    font-family: inherit;
+                    line-height: 1.5;
+                    word-break: break-word;
+
+                    &:hover {
+                        text-decoration: underline;
+                    }
+                }
+
+                .value-text {
+                    word-break: break-word;
+                    font-size: 13px;
+                    font-family: inherit;
+                    line-height: 1.5;
+                    color: #333;
+
+                    a {
+                        color: #1976d2;
+                        text-decoration: none;
+                        font-size: 13px;
+                        font-family: inherit;
+
+                        &:hover {
+                            text-decoration: underline;
+                        }
+                    }
+                }
+            }
+
+            .relationship-card-empty {
+                color: #999;
+                font-style: italic;
+                padding: 16px;
+                text-align: center;
+            }
+        }
+
+        .relationship-card-loader {
+            display: flex;
+            justify-content: center;
+            padding: 16px;
+        }
+
+        .relationship-card-inline-loader {
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            min-height: 40px;
+            width: 100%;
+        }
+    }
+
+    .relationship-card-footer {
+        border-top: 1px solid #e2e8f0;
+        margin-top: auto;
+        padding: 8px 12px;
+
+        .relationship-card-footer-row {
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            gap: 12px;
+            min-height: 24px;
+        }
+
+        .relationship-card-count {
+            font-size: 13px;
+            color: #64748b;
+            font-family: inherit;
+            flex-shrink: 0;
+        }
+
+        .relationship-card-page-limit {
+            display: flex;
+            align-items: center;
+            gap: 6px;
+
+            label {
+                font-size: 13px;
+                color: #64748b;
+                margin: 0;
+                white-space: nowrap;
+            }
+
+            .relationship-card-page-limit-input {
+                width: 60px;
+                padding: 4px 8px;
+                font-size: 12px;
+                border: 1px solid #d1d5db;
+                border-radius: 4px;
+            }
+        }
+    }
+}
+
+.relationship-card--empty {
+    .relationship-card-scroll--empty {
+        overflow: hidden;
+    }
+}
+
+.relationship-card-load-more {
+    margin-top: 6px;
+    padding: 6px 0;
+    font-size: 12px;
+    text-align: center;
+    color: #9ca3af;
+}
+
+.relationship-card-no-match {
+    padding: 8px 0;
+    font-size: 12px;
+    color: #9ca3af;
+}
+
+.entity-relationship-table-toggle {
+    width: 100%;
+    display: flex;
+    position: relative;
+    margin-top: 12px;
+    justify-content: flex-end;
+    align-items: center;
+}
+
+/* Relationship Card Skeleton Loader */
+.relationship-card-skeleton {
+    border: 1px solid #e2e8f0;
+    border-radius: 10px;
+    background-color: #ffffff;
+    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08);
+    min-height: 80px;
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+}
+
+.relationship-card-skeleton__header {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 8px 12px;
+    border-top-left-radius: 10px;
+    border-top-right-radius: 10px;
+    background-color: $white;
+    border-bottom: 1px solid #e2e8f0;
+}
+
+.relationship-card-skeleton__title-wrap {
+    display: flex;
+    align-items: baseline;
+    gap: 6px;
+}
+
+.relationship-card-skeleton__line {
+    display: block;
+    height: 14px;
+    background: linear-gradient(
+        90deg,
+        #e2e8f0 25%,
+        #f1f5f9 50%,
+        #e2e8f0 75%
+    );
+    background-size: 200% 100%;
+    animation: relationship-skeleton-pulse 1.5s ease-in-out infinite;
+    border-radius: 4px;
+
+    &--title {
+        width: 100px;
+    }
+
+    &--count {
+        width: 36px;
+    }
+
+    &--short {
+        width: 60%;
+    }
+
+    &--footer {
+        width: 80px;
+        height: 12px;
+    }
+}
+
+.relationship-card-skeleton__actions {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+}
+
+.relationship-card-skeleton__box {
+    display: block;
+    background: linear-gradient(
+        90deg,
+        #e2e8f0 25%,
+        #f1f5f9 50%,
+        #e2e8f0 75%
+    );
+    background-size: 200% 100%;
+    animation: relationship-skeleton-pulse 1.5s ease-in-out infinite;
+    border-radius: 4px;
+
+    &--button {
+        width: 28px;
+        height: 24px;
+    }
+
+    &--checkbox {
+        width: 80px;
+        height: 16px;
+    }
+
+    &--input {
+        width: 60px;
+        height: 24px;
+    }
+}
+
+.relationship-card-skeleton__content {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    padding: 12px;
+}
+
+.relationship-card-skeleton__body {
+    display: flex;
+    flex-direction: column;
+    gap: 10px;
+    flex: 1;
+    min-height: 80px;
+}
+
+.relationship-card-skeleton__footer {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    gap: 12px;
+    margin-top: auto;
+    padding-top: 8px;
+    border-top: 1px solid #e2e8f0;
+}
+
+@keyframes relationship-skeleton-pulse {
+    0%,
+    100% {
+        background-position: 200% 0;
+    }
+    50% {
+        background-position: -200% 0;
+    }
 }
\ No newline at end of file
diff --git a/dashboardv2/public/css/scss/table.scss b/dashboardv2/public/css/scss/table.scss
index f59c096fc..905b5eddf 100644
--- a/dashboardv2/public/css/scss/table.scss
+++ b/dashboardv2/public/css/scss/table.scss
@@ -44,6 +44,7 @@ tr.empty {
 .type-node-details,
 .relationship-detail-table {
     position: relative;
+    min-height: 600px;
 
     .hide-empty-value {
         .hide-row {
diff --git a/dashboardv2/public/js/templates/business_metadata/BusinessMetadataAttributeItemView_tmpl.html b/dashboardv2/public/js/templates/business_metadata/BusinessMetadataAttributeItemView_tmpl.html
index 8ffb689b4..8b0ac5e26 100644
--- a/dashboardv2/public/js/templates/business_metadata/BusinessMetadataAttributeItemView_tmpl.html
+++ b/dashboardv2/public/js/templates/business_metadata/BusinessMetadataAttributeItemView_tmpl.html
@@ -70,7 +70,7 @@
         <div class="col-sm-8">
             <div class="row">
                 <div class="col-sm-6">
-                    <input type="checkbox" class="form-check-input multi-value-select" data-id="multiValueSelectStatus">
+            <input type="checkbox" class="form-check-input multi-value-select" data-id="multiValueSelectStatus">
                 </div>
                 <div class="col-sm-6" data-id="cardinalityToggleContainer" style="display: none;">
                     <div class="btn-group" role="group" data-id="cardinalityToggle">
diff --git a/dashboardv2/public/js/templates/detail_page/RelationshipCardsLayoutView_tmpl.html b/dashboardv2/public/js/templates/detail_page/RelationshipCardsLayoutView_tmpl.html
new file mode 100644
index 000000000..704beef7b
--- /dev/null
+++ b/dashboardv2/public/js/templates/detail_page/RelationshipCardsLayoutView_tmpl.html
@@ -0,0 +1,18 @@
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+-->
+<div class="relationship-cards-container" data-id="relationshipCardsContainer"></div>
diff --git a/dashboardv2/public/js/templates/graph/RelationshipLayoutView_tmpl.html b/dashboardv2/public/js/templates/graph/RelationshipLayoutView_tmpl.html
index acf9bb3a3..aeb7174e7 100644
--- a/dashboardv2/public/js/templates/graph/RelationshipLayoutView_tmpl.html
+++ b/dashboardv2/public/js/templates/graph/RelationshipLayoutView_tmpl.html
@@ -18,10 +18,10 @@
     <div class="btn-group pull-left">
         <span class="pull-left">Graph</span>
         <label class="switch pull-left">
-            <input type="checkbox" checked class="switch-input" name="relationshipViewToggle" value="text">
+            <input type="checkbox" class="switch-input" name="relationshipViewToggle" value="text">
             <span class="switch-slider"></span>
         </label>
-        <span class="pull-left">Table</span>
+        <span class="pull-left">Card</span>
     </div>
     <div class="pull-right" data-id="zoomControl">
         <div class="btn-group pull-right">
@@ -52,8 +52,8 @@
         </div>
     </div>
 </div>
-<div class="relationship-detail-table">
-    <div class="entity-relationship-table-toggle">
+<div class="relationship-detail-table" style="display: none;">
+    <div class="entity-relationship-table-toggle" style="padding: 12px 16px;">
         <div class="pretty p-switch p-fill">
             <input type="checkbox" data-id="noValueToggle" />
             <div class="state p-primary">
@@ -61,6 +61,9 @@
             </div>
         </div>
     </div>
+    <div data-id="relationshipCardsView" style="position: relative;top: 40px;">
+        <!-- Card view will be rendered here -->
+    </div>
     <table class="table table-quickMenu bold-key" data-id="relationshipDetailTable">
         <thead>
             <tr>
diff --git a/dashboardv2/public/js/utils/UrlLinks.js b/dashboardv2/public/js/utils/UrlLinks.js
index c6b1af06a..0594b3e0f 100644
--- a/dashboardv2/public/js/utils/UrlLinks.js
+++ b/dashboardv2/public/js/utils/UrlLinks.js
@@ -95,19 +95,25 @@ define(['require', 'utils/Enums', 'utils/Utils', 'underscore'], function(require
                     name = options.name,
                     minExtInfo = options.minExtInfo;
                 if (guid && name && associatedGuid) {
-                    return entitiesUrl + '/guid/' + guid + '/classification/' + name + '?associatedEntityGuid=' + associatedGuid;
+                    return entitiesUrl + '/guid/' + guid + '/classification/' + name + '?associatedEntityGuid=' + associatedGuid + '&ignoreRelationships=true';
                 } else if (guid && name) {
-                    entitiesUrl += '/guid/' + guid + '/classification/' + name;
+                    return entitiesUrl + '/guid/' + guid + '/classification/' + name + '?ignoreRelationships=true';
                 } else if (guid && !name) {
                     entitiesUrl += '/guid/' + guid;
                 }
             }
 
-            if (!minExtInfo) {
-                return entitiesUrl;
-            } else {
-                return entitiesUrl += '?minExtInfo=' + (minExtInfo);
+            if (entitiesUrl.indexOf('/guid/') !== -1) {
+                var queryParams = ['ignoreRelationships=true'];
+                if (options && options.minExtInfo !== undefined && options.minExtInfo !== false) {
+                    queryParams.unshift('minExtInfo=' + options.minExtInfo);
+                }
+                return entitiesUrl + '?' + queryParams.join('&');
+            }
+            if (options && options.minExtInfo) {
+                return entitiesUrl + '?minExtInfo=' + (options.minExtInfo);
             }
+            return entitiesUrl;
         },
         relationApiUrl: function(options) {
             var relationsUrl = this.baseUrlV2 + '/relationship';
@@ -120,10 +126,10 @@ define(['require', 'utils/Enums', 'utils/Utils', 'underscore'], function(require
             return relationsUrl;
         },
         entityLabelsAPIUrl: function(guid) {
-            return this.entitiesApiUrl({ guid: guid }) + "/labels";
+            return this.baseUrlV2 + '/entity/guid/' + guid + '/labels';
         },
         entityHeaderApiUrl: function(guid) {
-            return this.entitiesApiUrl({ guid: guid }) + "/header"
+            return this.baseUrlV2 + '/entity/guid/' + guid + '/header';
         },
         entitiesTraitsApiUrl: function(token) {
             if (token) {
@@ -191,9 +197,15 @@ define(['require', 'utils/Enums', 'utils/Utils', 'underscore'], function(require
                 return relationshipUrl
             }
         },
+        relationshipSearchV2ApiUrl: function() {
+            return this.baseUrlV2 + '/search/relationship';
+        },
         relationshipSearchApiUrl: function() {
             return this.baseUrlV2 + '/search/relations';
         },
+        relationshipAttributesApiUrl: function(guid) {
+            return this.entitiesApiUrl() + '/guid/' + guid + '/relationshipAttributes';
+        },
         schemaApiUrl: function(guid) {
             var lineageUrl = this.baseUrl + '/lineage';
             if (guid) {
diff --git a/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js b/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
index afd6da380..0c4328f54 100644
--- a/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
+++ b/dashboardv2/public/js/views/detail_page/DetailPageLayoutView.js
@@ -116,6 +116,7 @@ define(['require',
                 events["click " + this.ui.deleteTerm] = 'onClickTermCross';
                 events["click " + this.ui.addTag] = 'onClickAddTagBtn';
                 events["click " + this.ui.tablist] = function(e) {
+                    var that = this;
                     var tabValue = $(e.currentTarget).attr('role');
                     Utils.setUrl({
                         url: Utils.getUrlState.getQueryUrl().queyParams[0],
@@ -124,7 +125,15 @@ define(['require',
                         trigger: false,
                         updateTabState: true
                     });
-
+                    if (tabValue === 'relationship') {
+                        if (this.detailPageObj) {
+                            this.ensureRelationshipView();
+                        } else {
+                            this.listenToOnce(this.collection, 'reset', function() {
+                                that.ensureRelationshipView();
+                            });
+                        }
+                    }
                 };
                 return events;
             },
@@ -144,7 +153,7 @@ define(['require',
                 this.listenTo(this.collection, 'reset', function() {
                     this.entityObject = this.collection.first().toJSON();
                     var collectionJSON = this.entityObject.entity;
-                    this.activeEntityDef = this.entityDefCollection.fullCollection.find({ name: collectionJSON.typeName });
+                    this.activeEntityDef = this.entityDefCollection.fullCollection.findWhere({ name: collectionJSON.typeName });
                     if (!this.activeEntityDef) {
                         Utils.backButtonClick();
                         Utils.notifyError({
@@ -320,7 +329,11 @@ define(['require',
                     if (obj.businessMetadataCollection) {
                         this.renderEntityBusinessMetadataView(obj);
                     }
-                    this.renderRelationshipLayoutView(obj);
+                    this.detailPageObj = obj;
+                    if ((this.value && this.value.tabActive === 'relationship') ||
+                        this.$('.tab-content .tab-pane[role="relationship"]').hasClass('active')) {
+                        this.renderRelationshipLayoutView(obj);
+                    }
                     this.renderAuditTableLayoutView(obj);
                     this.renderTagTableLayoutView(obj);
                     if (Globals.isTasksEnabled && Globals.isUiTasksTabEnabled) { this.renderPendingTaskTableLayoutView(); }
@@ -385,6 +398,15 @@ define(['require',
                         });
                     }
                 }, this);
+                this.$('a[href="#tab-relationship"]').on('shown.bs.tab', function() {
+                    if (that.detailPageObj) {
+                        that.ensureRelationshipView();
+                    } else {
+                        that.listenToOnce(that.collection, 'reset', function() {
+                            that.ensureRelationshipView();
+                        });
+                    }
+                });
             },
             onRender: function() {
                 var that = this;
@@ -438,6 +460,22 @@ define(['require',
                     this.$('.nav.nav-tabs').find('[role="' + this.value.tabActive + '"]').addClass('active').siblings().removeClass('active');
                     this.$('.tab-content').find('[role="' + this.value.tabActive + '"]').addClass('active').siblings().removeClass('active');
                     $("html, body").animate({ scrollTop: (this.$('.tab-content').offset().top + 1200) }, 1000);
+                    if (this.value.tabActive === 'relationship') {
+                        this.ensureRelationshipView();
+                    }
+                } else if (this.$('.tab-content .tab-pane[role="relationship"]').hasClass('active')) {
+                    this.ensureRelationshipView();
+                }
+            },
+            ensureRelationshipView: function() {
+                if (!this.detailPageObj) {
+                    return;
+                }
+                var relationshipView = this.RRelationshipLayoutView.currentView;
+                if (relationshipView && relationshipView.ensureCardsView) {
+                    relationshipView.ensureCardsView(false);
+                } else {
+                    this.renderRelationshipLayoutView(this.detailPageObj);
                 }
             },
             onShow: function() {
@@ -467,6 +505,18 @@ define(['require',
                     return [];
                 }
             },
+            getEntityDefForRelationships: function() {
+                if (this.activeEntityDef) {
+                    var data = this.activeEntityDef.toJSON();
+                    return Utils.getNestedSuperTypeObj({
+                        data: data,
+                        collection: this.entityDefCollection,
+                        attrMerge: true,
+                        seperateRelatioshipAttr: true
+                    });
+                }
+                return {};
+            },
             onClickTagCross: function(e) {
                 var that = this,
                     tagName = $(e.currentTarget).parent().text().split('@')[0],
@@ -663,7 +713,10 @@ define(['require',
             renderRelationshipLayoutView: function(obj) {
                 var that = this;
                 require(['views/graph/RelationshipLayoutView'], function(RelationshipLayoutView) {
-                    that.RRelationshipLayoutView.show(new RelationshipLayoutView(obj));
+                    var relationshipObj = _.extend({}, obj, {
+                        attributeDefs: that.getEntityDefForRelationships()
+                    });
+                    that.RRelationshipLayoutView.show(new RelationshipLayoutView(relationshipObj));
                 });
             },
             renderSchemaLayoutView: function(obj) {
diff --git a/dashboardv2/public/js/views/detail_page/RelationshipCardsLayoutView.js b/dashboardv2/public/js/views/detail_page/RelationshipCardsLayoutView.js
new file mode 100644
index 000000000..b0444cc40
--- /dev/null
+++ b/dashboardv2/public/js/views/detail_page/RelationshipCardsLayoutView.js
@@ -0,0 +1,780 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+define([
+    "require",
+    "backbone",
+    "hbs!tmpl/detail_page/RelationshipCardsLayoutView_tmpl",
+    "utils/UrlLinks",
+    "utils/Utils"
+], function(require, Backbone, RelationshipCardsLayoutViewTmpl, UrlLinks, Utils) {
+    "use strict";
+
+    var RelationshipCardsLayoutView = Backbone.Marionette.LayoutView.extend({
+        template: RelationshipCardsLayoutViewTmpl,
+        ui: {
+            container: "[data-id='relationshipCardsContainer']"
+        },
+        initialize: function(options) {
+            _.extend(this, _.pick(options, "entity", "guid", "attributeDefs", "entityDefCollection", "referredEntities", "showEmptyValues", "onDataLoaded", "onDataLoading"));
+            this.cardData = {};
+            this.cardCounts = {};
+            this.loadingByName = {};
+            this.resettingByName = {};
+            this.searchByName = {};
+            this.lastRequestSizeByName = {};
+            this.lastTriggerAtByName = {};
+            this.lastScrollTopByName = {};
+            this.scrollRestoreByName = {};
+            this.exhaustedByName = {};
+            this.sortByName = {};
+            this.showDeletedByName = {};
+            this.pageLimitByName = {};
+            this.isInitialLoading = false;
+        },
+        onRender: function() {
+            this.fetchInitialCards();
+        },
+        getRelationNames: function() {
+            var relationDefs = [];
+            if (this.attributeDefs) {
+                relationDefs = this.attributeDefs.relationshipAttributeDefs || this.attributeDefs.relationships || [];
+                if (_.isEmpty(relationDefs) && _.isArray(this.attributeDefs)) {
+                    relationDefs = _.filter(this.attributeDefs, function(def) {
+                        return def && (def.relationshipTypeName || def.relationshipType);
+                    });
+                }
+            }
+            
+            if (_.isEmpty(relationDefs) && this.entityDefCollection && this.entity && this.entity.typeName) {
+                var entityDef = this.entityDefCollection.fullCollection.findWhere({ name: this.entity.typeName });
+                
+                if (entityDef) {
+                    this.attributeDefs = Utils.getNestedSuperTypeObj({
+                        data: entityDef.toJSON(),
+                        collection: this.entityDefCollection,
+                        attrMerge: true,
+                        seperateRelatioshipAttr: true
+                    });
+                    relationDefs = (this.attributeDefs && this.attributeDefs.relationshipAttributeDefs) || [];
+                } else {
+                    console.warn("[RelationshipCardsLayoutView] EntityDef not found for type:", this.entity.typeName);
+                }
+            }
+            
+            // If still empty, try to extract from entity.relationshipAttributes
+            if (_.isEmpty(relationDefs) && this.entity && this.entity.relationshipAttributes) {
+                var relationNames = _.uniq(_.keys(this.entity.relationshipAttributes));
+                return relationNames;
+            }
+            
+            var relationNames = _.uniq(_.compact(_.map(relationDefs, function(def) {
+                if (!def) return null;
+                return def.name || def.attributeName || (def.attribute && (def.attribute.name || def.attribute.attributeName));
+            })));
+            
+            return relationNames;
+        },
+        getPageLimit: function(relationName, totalCount) {
+            var count = _.isNumber(totalCount) ? totalCount : parseInt(totalCount, 10);
+            var defaultLimit = _.isFinite(count) && count < 100 ? count : 100;
+            var currentLimit = this.pageLimitByName[relationName];
+            if (!_.isNumber(currentLimit)) {
+                return defaultLimit;
+            }
+            if (_.isFinite(count) && currentLimit > count) {
+                return count;
+            }
+            return currentLimit;
+        },
+        getRelationshipParams: function(relationName, offset, totalCount, overrides) {
+            var isSorted = _.isBoolean(overrides && overrides.isSorted)
+                ? overrides.isSorted
+                : !!this.sortByName[relationName];
+            var showDeleted = _.isBoolean(overrides && overrides.showDeleted)
+                ? overrides.showDeleted
+                : !!this.showDeletedByName[relationName];
+            var limit = _.isNumber(overrides && overrides.limit)
+                ? overrides.limit
+                : this.getPageLimit(relationName, totalCount);
+            return {
+                limit: limit,
+                offset: offset,
+                guid: this.guid,
+                sortBy: isSorted ? "name" : undefined,
+                sortOrder: isSorted ? "ASCENDING" : undefined,
+                disableDefaultSorting: !isSorted,
+                excludeDeletedEntities: !showDeleted,
+                includeSubClassifications: true,
+                includeSubTypes: true,
+                includeClassificationAttributes: true,
+                relation: relationName,
+                getApproximateCount: offset === 0
+            };
+        },
+        fetchRelationshipData: function(relationName, offset, totalCount, overrides) {
+            var params = {
+                limit: 2,
+                offset: offset,
+                guid: this.guid,
+                sortBy: "name",
+                sortOrder: "ASCENDING",
+                disableDefaultSorting: true,
+                excludeDeletedEntities: true,
+                includeSubClassifications: true,
+                includeSubTypes: true,
+                includeClassificationAttributes: true,
+                relation: relationName,
+                getApproximateCount: true
+            };
+            params = this.getRelationshipParams(relationName, offset, totalCount, overrides);
+            
+            var apiUrl = UrlLinks.relationshipSearchV2ApiUrl();
+
+            return $.ajax({
+                url: apiUrl,
+                data: params,
+                contentType: "application/json",
+                dataType: "json",
+                type: "GET",
+                success: function(response) {
+                },
+                error: function(xhr, status, error) {
+                    console.error("[RelationshipCardsLayoutView] API ERROR for", relationName, ":", {
+                        status: status,
+                        error: error,
+                        responseText: xhr.responseText,
+                        statusCode: xhr.status
+                    });
+                }
+            });
+        },
+        fetchInitialCards: function() {
+            var that = this;
+            
+            if (!this.guid) {
+                console.warn("[RelationshipCardsLayoutView] No GUID provided, cannot fetch cards");
+                return;
+            }
+            
+            var relationNames = this.getRelationNames();
+
+            if (_.isEmpty(relationNames)) {
+                this.renderCards();
+                return;
+            }
+
+            if (_.isFunction(this.onDataLoading)) {
+                this.onDataLoading(true);
+            }
+            this.renderCards();
+
+            var processResponse = function(name, response) {
+                if (!response) {
+                    that.cardData[name] = [];
+                    that.cardCounts[name] = 0;
+                    if (_.isUndefined(that.sortByName[name])) { that.sortByName[name] = false; }
+                    if (_.isUndefined(that.showDeletedByName[name])) { that.showDeletedByName[name] = true; }
+                    that.pageLimitByName[name] = that.getPageLimit(name, 0);
+                    return;
+                }
+                var entities = response.entities ? response.entities : [];
+                if (response && response.referredEntities) {
+                    that.referredEntities = _.extend({}, that.referredEntities, response.referredEntities);
+                }
+                that.cardData[name] = _.isArray(entities) ? entities : (entities ? [entities] : []);
+                if (!_.isUndefined(response.approximateCount)) {
+                    that.cardCounts[name] = response.approximateCount;
+                } else if (!_.isUndefined(response.totalCount)) {
+                    that.cardCounts[name] = response.totalCount;
+                } else {
+                    that.cardCounts[name] = that.cardData[name].length;
+                }
+                if (_.isUndefined(that.sortByName[name])) {
+                    that.sortByName[name] = false;
+                }
+                if (_.isUndefined(that.showDeletedByName[name])) {
+                    that.showDeletedByName[name] = true;
+                }
+                if (_.isUndefined(that.pageLimitByName[name])) {
+                    that.pageLimitByName[name] = that.getPageLimit(name, that.cardCounts[name]);
+                }
+                var updatedCount = that.getTotalCountForName(name, that.cardData[name].length);
+                if (updatedCount <= that.cardData[name].length) {
+                    that.exhaustedByName[name] = true;
+                }
+            };
+
+            var completedCount = 0;
+            var totalCount = relationNames.length;
+
+            _.each(relationNames, function(name) {
+                that.fetchRelationshipData(name, 0, undefined, { showDeleted: true })
+                    .then(
+                        function(response) {
+                            processResponse(name, response);
+                            that.renderCards();
+                            return response;
+                        },
+                        function(error) {
+                            console.error("[RelationshipCardsLayoutView] API error for", name, ":", error);
+                            processResponse(name, null);
+                            that.renderCards();
+                            return null;
+                        }
+                    )
+                    .always(function() {
+                        completedCount += 1;
+                        if (completedCount >= totalCount) {
+                            if (_.isFunction(that.onDataLoaded)) {
+                                var loadedCounts = {};
+                                _.each(that.cardData, function(values, key) {
+                                    loadedCounts[key] = values ? values.length : 0;
+                                });
+                                that.onDataLoaded({
+                                    data: _.clone(that.cardData),
+                                    counts: _.clone(that.cardCounts),
+                                    loadedCounts: loadedCounts,
+                                    referredEntities: _.clone(that.referredEntities)
+                                });
+                            }
+                            if (_.isFunction(that.onDataLoading)) {
+                                that.onDataLoading(false);
+                            }
+                        }
+                    });
+            });
+        },
+        getTotalCountForName: function(name, fallbackCount) {
+            var totalCount = this.cardCounts[name];
+            var parsed = _.isNumber(totalCount) ? totalCount : parseInt(totalCount, 10);
+            if (!_.isFinite(parsed)) {
+                return _.isNumber(fallbackCount) ? fallbackCount : 0;
+            }
+            return parsed;
+        },
+        handleLoadMore: function(relationName, containerEl) {
+            var that = this;
+            if (this.loadingByName[relationName]) {
+                return;
+            }
+            if (this.resettingByName[relationName]) {
+                return;
+            }
+            var existing = this.cardData[relationName] || [];
+            var totalCount = this.getTotalCountForName(relationName, existing.length);
+            if (this.exhaustedByName[relationName] || totalCount <= existing.length) {
+                return;
+            }
+            if (containerEl && containerEl.length) {
+                this.scrollRestoreByName[relationName] = {
+                    height: containerEl[0].scrollHeight,
+                    top: containerEl[0].scrollTop
+                };
+            }
+            this.loadingByName[relationName] = true;
+            this.renderCards();
+            if (_.isFunction(this.onDataLoading)) {
+                this.onDataLoading(true);
+            }
+            var totalCount = that.cardCounts[relationName];
+            this.fetchRelationshipData(relationName, existing.length, totalCount).then(function(response) {
+                var entities = response && response.entities ? response.entities : [];
+                if (response && response.referredEntities) {
+                    that.referredEntities = _.extend({}, that.referredEntities, response.referredEntities);
+                }
+                var newItems = _.isArray(entities) ? entities : (entities ? [entities] : []);
+                that.cardData[relationName] = existing.concat(newItems);
+                var updatedCount = that.getTotalCountForName(relationName, that.cardData[relationName].length);
+                if (newItems.length === 0 || updatedCount <= that.cardData[relationName].length) {
+                    that.exhaustedByName[relationName] = true;
+                }
+                that.renderCards();
+                if (_.isFunction(that.onDataLoaded)) {
+                    var loadedCounts = {};
+                    _.each(that.cardData, function(values, key) {
+                        loadedCounts[key] = values ? values.length : 0;
+                    });
+                    that.onDataLoaded({
+                        data: _.clone(that.cardData),
+                        counts: _.clone(that.cardCounts),
+                        loadedCounts: loadedCounts,
+                        referredEntities: _.clone(that.referredEntities)
+                    });
+                }
+            }).fail(function(error) {
+                Utils.notifyError({
+                    content: (error && error.responseJSON && error.responseJSON.errorMessage) || "Failed to load relationship data"
+                });
+            }).always(function() {
+                that.loadingByName[relationName] = false;
+                if (_.isFunction(that.onDataLoading)) {
+                    that.onDataLoading(false);
+                }
+            });
+        },
+        resetRelationshipData: function(relationName, overrides) {
+            var that = this;
+            if (this.loadingByName[relationName]) {
+                return;
+            }
+            this.resettingByName[relationName] = true;
+            this.lastRequestSizeByName[relationName] = null;
+            this.lastTriggerAtByName[relationName] = 0;
+            this.lastScrollTopByName[relationName] = 0;
+            this.renderCards();
+            var totalCount = this.cardCounts[relationName];
+            this.fetchRelationshipData(relationName, 0, totalCount, overrides).then(function(response) {
+                var entities = response && response.entities ? response.entities : [];
+                if (response && response.referredEntities) {
+                    that.referredEntities = _.extend({}, that.referredEntities, response.referredEntities);
+                }
+                var newItems = _.isArray(entities) ? entities : (entities ? [entities] : []);
+                that.cardData[relationName] = newItems;
+                if (!_.isUndefined(response.approximateCount)) {
+                    that.cardCounts[relationName] = response.approximateCount;
+                } else if (!_.isUndefined(response.totalCount)) {
+                    that.cardCounts[relationName] = response.totalCount;
+                }
+                that.exhaustedByName[relationName] = false;
+            }).fail(function(error) {
+                Utils.notifyError({
+                    content: (error && error.responseJSON && error.responseJSON.errorMessage) || "Failed to load relationship data"
+                });
+            }).always(function() {
+                that.resettingByName[relationName] = false;
+                that.renderCards();
+            });
+        },
+        buildCardHtml: function(name, list, totalCount) {
+            var that = this;
+            if (_.isEmpty(list) && !this.showEmptyValues && !this.resettingByName[name]) {
+                return "";
+            }
+            var relationNames = this.getRelationNames();
+            var showTypeNameInDisplay = relationNames.length > 1;
+            var count = this.getTotalCountForName(name, list.length);
+            var searchQuery = this.searchByName[name] || "";
+            var normalizedQuery = searchQuery.trim().toLowerCase();
+            var filteredList = normalizedQuery
+                ? _.filter(list, function(item) {
+                    var ref = item && item.guid ? that.referredEntities && that.referredEntities[item.guid] : null;
+                    var displayText = (ref && (ref.displayText || (ref.attributes && ref.attributes.name))) ||
+                        item.displayText || (item.attributes && item.attributes.name) || item.qualifiedName || item.guid || "N/A";
+                    var qualifiedName = item && item.qualifiedName ? item.qualifiedName : "";
+                    var nameValue = item && item.attributes && item.attributes.name ? item.attributes.name : "";
+                    var searchTarget = (displayText + " " + qualifiedName + " " + nameValue).toLowerCase();
+                    return searchTarget.includes(normalizedQuery);
+                })
+                : list;
+            var itemsHtml = _.map(filteredList, function(item) {
+                var ref = item && item.guid ? that.referredEntities && that.referredEntities[item.guid] : null;
+                var displayText = (ref && (ref.displayText || (ref.attributes && ref.attributes.name))) ||
+                    item.displayText || (item.attributes && item.attributes.name) || item.qualifiedName || item.guid || "N/A";
+                var typeName = (ref && ref.typeName) || item.typeName || "";
+                var displayLabel = showTypeNameInDisplay && typeName
+                    ? displayText + " (" + typeName + ")"
+                    : displayText;
+                var href = item && item.guid ? "#/detailPage/" + item.guid : "";
+                var qualifiedName = item && item.qualifiedName ? item.qualifiedName : "";
+                var nameValue = item && item.attributes && item.attributes.name ? item.attributes.name : "";
+                var searchText = _.escape((displayText + " " + qualifiedName + " " + nameValue).toLowerCase());
+                return "<li class='relationship-card-item' data-search='" + searchText + "'>" +
+                    (href ? "<a class='relationship-card-link' href='" + href + "'>" + _.escape(displayLabel) + "</a>" :
+                        "<span class='relationship-card-link'>" + _.escape(displayLabel) + "</span>") +
+                    "</li>";
+            }).join("");
+
+            var canLoadMore = !this.exhaustedByName[name] && count > list.length;
+            var showSearch = list.length > 1;
+            var rowHeight = 30;
+            var bodyPadding = 8;
+            var maxVisibleRows = showSearch ? 8 : 9;
+            var visibleRows = Math.min(filteredList.length || 0, maxVisibleRows);
+            var scrollHeight = filteredList.length
+                ? (visibleRows * rowHeight + bodyPadding)
+                : 0;
+            var isZeroOrOneRecord = list.length <= 1;
+            var scrollStyle = isZeroOrOneRecord
+                ? "style='min-height:72px;overflow-y:auto;'"
+                : "style='max-height:" + scrollHeight + "px; overflow-y: auto;'";
+            var emptyClass = list.length ? "" : " relationship-card--empty";
+            var noMatchHtml = "<div class='relationship-card-no-match' style='display:none'></div>";
+            var loadMoreHtml = canLoadMore
+                ? "<div class='relationship-card-load-more'>Scroll to load more data</div>"
+                : "";
+            var loaderHtml = this.loadingByName[name] && canLoadMore
+                ? "<div class='relationship-card-loader'><i class='fa fa-spinner fa-spin'></i></div>"
+                : "";
+            var resetLoaderHtml = this.resettingByName[name]
+                ? "<div class='relationship-card-inline-loader'><i class='fa fa-spinner fa-spin'></i></div>"
+                : "";
+            if (this.resettingByName[name]) {
+                loadMoreHtml = "";
+                loaderHtml = "";
+            }
+            var searchHtml = showSearch
+                ? "<div class='relationship-card-search'><input class='relationship-card-search-input' data-name='" + _.escape(name) + "' type='text' placeholder='Search...' value='" + _.escape(searchQuery) + "'/></div>"
+                : "";
+            var sortIcon = this.sortByName[name] ? "fa-sort-alpha-asc" : "fa-sort";
+            var headerActions = "<div class='relationship-card-actions'>" +
+                "<button type='button' class='relationship-card-action-button" + (this.sortByName[name] ? " is-active" : "") + "' data-action='toggleSort' data-name='" + _.escape(name) + "' aria-label='Toggle sort by name'>" +
+                "<i class='fa " + sortIcon + "'></i></button>" +
+                "<label class='relationship-card-toggle'>" +
+                "<input type='checkbox' data-action='toggleDeleted' data-name='" + _.escape(name) + "' " + (this.showDeletedByName[name] ? "checked" : "") + " />" +
+                "<span>Show deleted</span></label>" +
+                "</div>";
+            var pageLimit = this.getPageLimit(name, count);
+            var footerHtml = "<div class='relationship-card-footer'>" +
+                "<div class='relationship-card-footer-row'>" +
+                "<span class='relationship-card-count'>Showing " + list.length + " of " + count + "</span>" +
+                "<div class='relationship-card-page-limit'>" +
+                "<label for='page-limit-" + _.escape(name) + "'>Limit</label>" +
+                "<input id='page-limit-" + _.escape(name) + "' class='relationship-card-page-limit-input' type='number' min='1' max='" + count + "' data-name='" + _.escape(name) + "' value='" + pageLimit + "' />" +
+                "</div>" +
+                "</div>" +
+                "</div>";
+
+            return "<div class='relationship-card panel panel-default" + emptyClass + "' data-name='" + _.escape(name) + "'>" +
+                "<div class='relationship-card-header'>" +
+                "<div class='relationship-card-title-wrap'><span class='relationship-card-title'>" + _.escape(name) + "</span><span class='relationship-card-count'> (" + count + ")</span></div>" +
+                headerActions + "</div>" +
+                "<div class='relationship-card-content'>" +
+                searchHtml +
+                "<div class='relationship-card-scroll" + (list.length ? "" : " relationship-card-scroll--empty") + "' data-name='" + _.escape(name) + "' " + scrollStyle + ">" +
+                (this.resettingByName[name] ? resetLoaderHtml : (itemsHtml ? "<ul class='relationship-card-list'>" + itemsHtml + "</ul>" : "<div class='relationship-card-empty'>No records to display</div>")) +
+                noMatchHtml +
+                loadMoreHtml +
+                loaderHtml +
+                "</div>" +
+                footerHtml +
+                "</div>" +
+                "</div>";
+        },
+        /**
+         * Computes column layout based on record count (matches React UI):
+         * - >5 records: 1 card per column
+         * - 1-5 records: 2 cards per column
+         * - 0 records: 2 cards per column (when showEmptyValues is true or during loading)
+         * @param {string[]} names - list of relation names to use (relationNames when loading, keys(cardData) when loaded)
+         */
+        computeColumnsFromNames: function(names) {
+            if (_.isEmpty(names)) {
+                return [];
+            }
+            var that = this;
+            var getCount = function(name) {
+                var total = that.cardCounts[name];
+                var parsed = _.isNumber(total) ? total : parseInt(total, 10);
+                if (!_.isFinite(parsed)) {
+                    return (that.cardData[name] || []).length;
+                }
+                return parsed;
+            };
+            var largeCards = [];
+            var smallCards = [];
+            var emptyCards = [];
+            _.each(names, function(name) {
+                var count = getCount(name);
+                if (count > 5) {
+                    largeCards.push(name);
+                } else if (count >= 1 && count <= 5) {
+                    smallCards.push(name);
+                } else {
+                    emptyCards.push(name);
+                }
+            });
+            var sortNames = function(arr) {
+                return arr.sort(function(a, b) { return a.localeCompare(b); });
+            };
+            sortNames(largeCards);
+            sortNames(smallCards);
+            sortNames(emptyCards);
+            var columns = [];
+            _.each(largeCards, function(name) {
+                columns.push([name]);
+            });
+            for (var i = 0; i < smallCards.length; i += 2) {
+                columns.push(smallCards.slice(i, i + 2));
+            }
+            if (this.showEmptyValues || !_.every(names, function(n) { return _.has(that.cardData, n); })) {
+                for (var j = 0; j < emptyCards.length; j += 2) {
+                    columns.push(emptyCards.slice(j, j + 2));
+                }
+            }
+            return columns;
+        },
+        buildSkeletonCardHtml: function() {
+            return "<div class='relationship-card-skeleton' aria-hidden='true'>" +
+                "<div class='relationship-card-skeleton__header'>" +
+                "<div class='relationship-card-skeleton__title-wrap'>" +
+                "<span class='relationship-card-skeleton__line relationship-card-skeleton__line--title'></span>" +
+                "<span class='relationship-card-skeleton__line relationship-card-skeleton__line--count'></span>" +
+                "</div>" +
+                "<div class='relationship-card-skeleton__actions'>" +
+                "<span class='relationship-card-skeleton__box relationship-card-skeleton__box--button'></span>" +
+                "<span class='relationship-card-skeleton__box relationship-card-skeleton__box--checkbox'></span>" +
+                "</div>" +
+                "</div>" +
+                "<div class='relationship-card-skeleton__content'>" +
+                "<div class='relationship-card-skeleton__body'>" +
+                "<span class='relationship-card-skeleton__line'></span>" +
+                "<span class='relationship-card-skeleton__line'></span>" +
+                "<span class='relationship-card-skeleton__line'></span>" +
+                "<span class='relationship-card-skeleton__line relationship-card-skeleton__line--short'></span>" +
+                "</div>" +
+                "<div class='relationship-card-skeleton__footer'>" +
+                "<span class='relationship-card-skeleton__line relationship-card-skeleton__line--footer'></span>" +
+                "<span class='relationship-card-skeleton__box relationship-card-skeleton__box--input'></span>" +
+                "</div>" +
+                "</div>" +
+                "</div>";
+        },
+        renderCards: function() {
+            var that = this;
+            var relationNames = this.getRelationNames();
+
+            if (_.isEmpty(relationNames)) {
+                this.$el.html("<div class='relationship-cards-loader'><i class='fa fa-spinner fa-spin'></i></div>");
+                return;
+            }
+
+            var allLoaded = _.every(relationNames, function(name) {
+                return _.has(that.cardData, name);
+            });
+            var namesForColumns = allLoaded ? _.keys(this.cardData) : relationNames;
+
+            var columns = this.computeColumnsFromNames(namesForColumns);
+            var html = "<div class='relationship-cards-grid relationship-cards-grid--custom'>";
+            var cardCount = 0;
+            _.each(columns, function(columnNames) {
+                html += "<div class='relationship-cards-column'>";
+                _.each(columnNames, function(name) {
+                    var hasData = _.has(that.cardData, name);
+                    if (hasData) {
+                        var list = that.cardData[name] || [];
+                        var cardHtml = that.buildCardHtml(name, list, that.cardCounts[name]);
+                        if (cardHtml) {
+                            html += cardHtml;
+                            cardCount++;
+                        }
+                    } else {
+                        html += that.buildSkeletonCardHtml();
+                    }
+                });
+                html += "</div>";
+            });
+            html += "</div>";
+
+            var allLoadedAndEmpty = _.every(relationNames, function(n) {
+                return _.has(that.cardData, n) && _.isEmpty(that.cardData[n]);
+            });
+            if (cardCount === 0 && allLoadedAndEmpty && !this.showEmptyValues) {
+                html = "<div class='relationship-cards-empty'>No relationship data available</div>";
+            }
+            
+            if (this.$el && this.$el.length) {
+                this.$el.html(html);
+                this.bindCardEvents();
+            } else {
+                console.warn("[RelationshipCardsLayoutView] $el not available, cannot render cards");
+            }
+        }
+    });
+
+    RelationshipCardsLayoutView.prototype.bindCardEvents = function() {
+        var that = this;
+        this.$el.find(".relationship-card-action-button")
+            .off("click")
+            .on("click", function(e) {
+                e.preventDefault();
+                var name = $(e.currentTarget).data("name");
+                if (!name || that.resettingByName[name]) {
+                    return;
+                }
+                var nextSorted = !that.sortByName[name];
+                that.sortByName[name] = nextSorted;
+                that.resetRelationshipData(name, { isSorted: nextSorted });
+            });
+
+        this.$el.find("input[data-action='toggleDeleted']")
+            .off("change")
+            .on("change", function(e) {
+                var name = $(e.currentTarget).data("name");
+                if (!name || that.resettingByName[name]) {
+                    return;
+                }
+                var isChecked = $(e.currentTarget).is(":checked");
+                that.showDeletedByName[name] = isChecked;
+                that.resetRelationshipData(name, { showDeleted: isChecked });
+            });
+
+        this.$el.find(".relationship-card-page-limit-input")
+            .off("keydown change")
+            .on("change", function(e) {
+                var name = $(e.currentTarget).data("name");
+                if (!name) {
+                    return;
+                }
+                var rawValue = $(e.currentTarget).val();
+                var parsed = parseInt(rawValue, 10);
+                if (!_.isFinite(parsed)) {
+                    that.pageLimitByName[name] = 0;
+                    return;
+                }
+                that.pageLimitByName[name] = parsed;
+            })
+            .on("keydown", function(e) {
+                if (e.key !== "Enter") {
+                    return;
+                }
+                var name = $(e.currentTarget).data("name");
+                if (!name || that.resettingByName[name]) {
+                    return;
+                }
+                var count = that.getTotalCountForName(name, 0);
+                var defaultLimit = count < 100 ? count : 100;
+                var currentLimit = that.pageLimitByName[name];
+                var nextLimit = currentLimit;
+                if (!_.isFinite(nextLimit) || nextLimit <= 0) {
+                    nextLimit = defaultLimit;
+                }
+                if (count > 0 && nextLimit > count) {
+                    nextLimit = count;
+                }
+                that.pageLimitByName[name] = nextLimit;
+                that.resetRelationshipData(name, { limit: nextLimit });
+            });
+
+        this.$el.find(".relationship-card-search-input")
+            .off("keyup keypress keydown")
+            .on("keyup keypress", function(e) {
+                var name = $(e.currentTarget).data("name");
+                that.searchByName[name] = $(e.currentTarget).val() || "";
+                that.applySearchFilter(name);
+            })
+            .on("keydown", function(e) {
+                if (e.key === "Escape") {
+                    var name = $(e.currentTarget).data("name");
+                    that.searchByName[name] = "";
+                    $(e.currentTarget).val("");
+                    that.applySearchFilter(name);
+                }
+            });
+
+        this.$el.find(".relationship-card-scroll")
+            .off("scroll")
+            .on("scroll", function(e) {
+                var container = $(e.currentTarget);
+                var name = container.data("name");
+                
+                if (!name) {
+                    console.warn("[RelationshipCardsLayoutView] No name found on scroll container");
+                    return;
+                }
+                
+                if (that.loadingByName[name]) {
+                    return;
+                }
+                if (that.resettingByName[name]) {
+                    return;
+                }
+                if (that.exhaustedByName[name]) {
+                    return;
+                }
+                
+                var list = that.cardData[name] || [];
+                var count = that.getTotalCountForName(name, list.length);
+                var canLoadMore = count > list.length;
+                
+                if (!canLoadMore) {
+                    return;
+                }
+                
+                var now = Date.now();
+                var distanceFromBottom = container[0].scrollHeight - container[0].scrollTop - container[0].clientHeight;
+                var isNearBottom = distanceFromBottom <= 10;
+                var isScrollingDown = container[0].scrollTop > (that.lastScrollTopByName[name] || 0);
+                
+                that.lastScrollTopByName[name] = container[0].scrollTop;
+                
+                if (!isNearBottom || !isScrollingDown) {
+                    return;
+                }
+                
+                var timeSinceLastTrigger = now - (that.lastTriggerAtByName[name] || 0);
+                if (timeSinceLastTrigger < 400) {
+                    return;
+                }
+                
+                if (that.lastRequestSizeByName[name] === list.length) {
+                    return;
+                }
+                
+                that.lastRequestSizeByName[name] = list.length;
+                that.lastTriggerAtByName[name] = now;
+                that.handleLoadMore(name, container);
+            });
+
+        _.each(this.scrollRestoreByName, function(scroll, name) {
+            var container = that.$el.find(".relationship-card-scroll[data-name='" + name + "']");
+            if (container.length && scroll) {
+                var nextTop = container[0].scrollHeight - scroll.height + scroll.top;
+                container[0].scrollTop = nextTop;
+            }
+        });
+        this.scrollRestoreByName = {};
+
+        _.each(this.searchByName, function(_value, name) {
+            that.applySearchFilter(name);
+        });
+    };
+
+    RelationshipCardsLayoutView.prototype.applySearchFilter = function(name) {
+        var rawQuery = (this.searchByName[name] || "").trim();
+        var query = rawQuery.toLowerCase();
+        var card = this.$el.find(".relationship-card[data-name='" + name + "']");
+        if (!card.length) {
+            return;
+        }
+        var items = card.find(".relationship-card-item");
+        var noMatch = card.find(".relationship-card-no-match");
+        if (!query) {
+            items.show();
+            noMatch.hide();
+            return;
+        }
+        var visibleCount = 0;
+        items.each(function() {
+            var searchText = ($(this).data("search") || "").toString();
+            if (searchText.includes(query)) {
+                $(this).show();
+                visibleCount += 1;
+            } else {
+                $(this).hide();
+            }
+        });
+        if (visibleCount === 0) {
+            noMatch.text("No record found for \"" + rawQuery + "\"").show();
+        } else {
+            noMatch.hide();
+        }
+    };
+
+    return RelationshipCardsLayoutView;
+});
diff --git a/dashboardv2/public/js/views/graph/RelationshipLayoutView.js b/dashboardv2/public/js/views/graph/RelationshipLayoutView.js
index a51fa7b25..35d04261a 100644
--- a/dashboardv2/public/js/views/graph/RelationshipLayoutView.js
+++ b/dashboardv2/public/js/views/graph/RelationshipLayoutView.js
@@ -40,7 +40,9 @@ define([
             template: RelationshipLayoutViewtmpl,
             className: "resizeGraph",
             /** Layout sub regions */
-            regions: {},
+            regions: {
+                relationshipCardsView: '[data-id="relationshipCardsView"]'
+            },
 
             /** ui selector cache */
             ui: {
@@ -48,11 +50,13 @@ define([
                 searchNode: '[data-id="searchNode"]',
                 relationshipViewToggle: 'input[name="relationshipViewToggle"]',
                 relationshipDetailTable: "[data-id='relationshipDetailTable']",
+                relationshipDetailTableContainer: ".relationship-detail-table",
                 relationshipSVG: "[data-id='relationshipSVG']",
                 relationshipDetailValue: "[data-id='relationshipDetailValue']",
                 zoomControl: "[data-id='zoomControl']",
                 boxClose: '[data-id="box-close"]',
-                noValueToggle: "[data-id='noValueToggle']"
+                noValueToggle: "[data-id='noValueToggle']",
+                relationshipCardsView: "[data-id='relationshipCardsView']"
             },
 
             /** ui events hash */
@@ -71,6 +75,7 @@ define([
                         inputType: this.ui.noValueToggle,
                         tableEl: this.ui.relationshipDetailValue
                     });
+                    this.updateCardsShowEmptyValues(e.currentTarget.checked);
                 };
                 return events;
             },
@@ -80,8 +85,44 @@ define([
              * @constructs
              */
             initialize: function(options) {
-                _.extend(this, _.pick(options, "entity", "entityName", "guid", "actionCallBack", "attributeDefs"));
+                _.extend(this, _.pick(options, "entity", "entityName", "guid", "actionCallBack", "attributeDefs", "referredEntities", "entityDefCollection"));
                 this.graphData = this.createData(this.entity);
+                this.relationshipCardCounts = {};
+                this.relationshipLoadedCounts = {};
+                this.cardsViewLoadInProgress = false;
+                
+                this.handleRelationshipDataUpdate = _.bind(function(payload) {
+                    var relationshipAttributes = payload && payload.data ? payload.data : payload;
+                    var relationshipCounts = payload && payload.counts ? payload.counts : this.relationshipCardCounts;
+                    var loadedCounts = payload && payload.loadedCounts ? payload.loadedCounts : this.relationshipLoadedCounts;
+                    var referredEntities = payload && payload.referredEntities ? payload.referredEntities : null;
+                    
+                    if (!relationshipAttributes) {
+                        return;
+                    }
+                    this.entity.relationshipAttributes = relationshipAttributes;
+                    this.relationshipCardCounts = relationshipCounts || {};
+                    this.relationshipLoadedCounts = loadedCounts || {};
+                    if (referredEntities) {
+                        this.referredEntities = _.extend({}, this.referredEntities, referredEntities);
+                    }
+                    this.graphData = this.createData(this.entity);
+                    if (!this.ui.relationshipViewToggle.is(':checked')) {
+                        this.$("svg").empty();
+                        if (this.graphData && _.isEmpty(this.graphData.links)) {
+                            this.noRelationship();
+                        } else if (this.graphData) {
+                            this.createGraph(this.graphData);
+                        }
+                    }
+                }, this);
+                this.handleRelationshipLoading = _.bind(function(isLoading) {
+                    if (isLoading) {
+                        this.$(".fontLoader").show();
+                    } else {
+                        this.$(".fontLoader").hide();
+                    }
+                }, this);
             },
             createData: function(entity) {
                 var that = this,
@@ -89,15 +130,22 @@ define([
                     nodes = {};
                 if (entity && entity.relationshipAttributes) {
                     _.each(entity.relationshipAttributes, function(obj, key) {
-                        if (!_.isEmpty(obj)) {
+                        var relationValue = obj;
+                        if (relationValue && relationValue.entities) {
+                            relationValue = relationValue.entities;
+                        }
+                        if (relationValue && !_.isArray(relationValue)) {
+                            relationValue = [relationValue];
+                        }
+                        if (!_.isEmpty(relationValue)) {
                             links.push({
                                 source: nodes[that.entity.typeName] ||
                                     (nodes[that.entity.typeName] = _.extend({ name: that.entity.typeName }, { value: entity })),
                                 target: nodes[key] ||
                                     (nodes[key] = _.extend({
                                         name: key
-                                    }, { value: obj })),
-                                value: obj
+                                    }, { value: relationValue })),
+                                value: relationValue
                             });
                         }
                     });
@@ -105,94 +153,147 @@ define([
                 return { nodes: nodes, links: links };
             },
             onRender: function() {
-                this.ui.zoomControl.hide();
-                this.$el.addClass("auto-height");
+                this.isRendered = true;
+
+                // Initialize: show card view by default (checked = Card)
+                this.ui.relationshipViewToggle.prop('checked', true);
+                this.relationshipViewToggle(true);
             },
             onShow: function(argument) {
-                if (this.graphData && _.isEmpty(this.graphData.links)) {
-                    this.noRelationship();
-                } else {
-                    this.createGraph(this.graphData);
+                // Always create graph on show if graph view is active
+                var isGraphView = !this.ui.relationshipViewToggle.is(':checked');
+                if (isGraphView) {
+                    if (this.graphData && _.isEmpty(this.graphData.links)) {
+                        this.noRelationship();
+                    } else if (this.graphData) {
+                        this.createGraph(this.graphData);
+                    }
                 }
                 this.createTable();
+                
+                this.ensureCardsView();
+            },
+            ensureCardsView: function(forceRefresh) {
+                var that = this;
+                
+                if (this.relationshipCardsViewInstance) {
+                    if (forceRefresh) {
+                        this.relationshipCardsViewInstance.cardData = {};
+                        this.relationshipCardsViewInstance.cardCounts = {};
+                        this.relationshipCardsViewInstance.fetchInitialCards();
+                    } else {
+                        var hasData = _.keys(this.relationshipCardsViewInstance.cardData || {}).length > 0;
+                        if (!hasData) {
+                            this.relationshipCardsViewInstance.fetchInitialCards();
+                        } else {
+                            this.relationshipCardsViewInstance.renderCards();
+                        }
+                    }
+                    return;
+                }
+                if (this.cardsViewLoadInProgress) {
+                    return;
+                }
+                this.cardsViewLoadInProgress = true;
+                require(['views/detail_page/RelationshipCardsLayoutView'], function(RelationshipCardsLayoutView) {
+                    try {
+                        if (!that.relationshipCardsView) {
+                            console.warn("[RelationshipLayoutView] Region not available");
+                            that.cardsViewLoadInProgress = false;
+                            return;
+                        }
+                        that.relationshipCardsViewInstance = new RelationshipCardsLayoutView({
+                            entity: that.entity,
+                            guid: that.guid,
+                            attributeDefs: that.attributeDefs,
+                            entityDefCollection: that.entityDefCollection,
+                            referredEntities: that.referredEntities || {},
+                            showEmptyValues: false,
+                            onDataLoaded: that.handleRelationshipDataUpdate,
+                            onDataLoading: that.handleRelationshipLoading
+                        });
+                        that.relationshipCardsView.show(that.relationshipCardsViewInstance);
+                    } catch (err) {
+                        console.error("[RelationshipLayoutView] Error showing cards view:", err);
+                    } finally {
+                        that.cardsViewLoadInProgress = false;
+                    }
+                }, function(err) {
+                    console.error("[RelationshipLayoutView] Failed to load RelationshipCardsLayoutView:", err);
+                    that.cardsViewLoadInProgress = false;
+                });
+            },
+            updateCardsShowEmptyValues: function(showEmptyValues) {
+                if (!this.relationshipCardsViewInstance) {
+                    return;
+                }
+                this.relationshipCardsViewInstance.showEmptyValues = !!showEmptyValues;
+                this.relationshipCardsViewInstance.renderCards();
             },
             noRelationship: function() {
                 this.$("svg").html('<text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">No relationship data found</text>');
             },
             toggleInformationSlider: function(options) {
-                if (options.open && !this.$(".relationship-details").hasClass("open")) {
-                    this.$(".relationship-details").addClass("open");
-                } else if (options.close && this.$(".relationship-details").hasClass("open")) {
-                    d3.selectAll("circle").attr("stroke", "none");
-                    this.$(".relationship-details").removeClass("open");
+                var panel = this.$(".relationship-node-details");
+                if (options && options.close) {
+                    panel.removeClass("slide-to-left").addClass("slide-from-left");
+                } else {
+                    if (panel.hasClass("slide-to-left")) {
+                        panel.removeClass("slide-to-left").addClass("slide-from-left");
+                    } else {
+                        panel.removeClass("slide-from-left").addClass("slide-to-left");
+                    }
                 }
             },
-            toggleBoxPanel: function(options) {
-                var el = options && options.el,
-                    nodeDetailToggler = options && options.nodeDetailToggler,
-                    currentTarget = options.currentTarget;
-                this.$el.find(".show-box-panel").removeClass("show-box-panel");
-                if (el && el.addClass) {
-                    el.addClass("show-box-panel");
-                }
-                this.$("circle.node-detail-highlight").removeClass("node-detail-highlight");
+            toggleBoxPanel: function() {
+                this.$(".relationship-node-details").removeClass("slide-to-left").addClass("slide-from-left");
             },
             searchNode: function(e) {
-                var $el = $(e.currentTarget);
-                this.updateRelationshipDetails(_.extend({}, $el.data(), { searchString: $el.val() }));
-            },
-            updateRelationshipDetails: function(options) {
-                var data = options.obj.value,
-                    typeName = data.typeName || options.obj.name,
-                    searchString = _.escape(options.searchString),
+                var searchString = $(e.currentTarget).val(),
                     listString = "",
+                    data = this.selectedNodeData,
+                    typeName = this.selectedNodeType,
+                    activeEntityColor = "#00b98b",
+                    deletedEntityColor = "#BB5838",
+                    defaultEntityColor = "#e0e0e0",
+                    normalizeEntity = function(entity) {
+                        if (!entity) {
+                            return entity;
+                        }
+                        if (_.isString(entity)) {
+                            entity = { guid: entity };
+                        }
+                        if (entity.guid && this.referredEntities && this.referredEntities[entity.guid]) {
+                            return _.extend({}, entity, this.referredEntities[entity.guid]);
+                        }
+                        return entity;
+                    }.bind(this),
+                    getdefault = function(options) {
+                        return "<pre class='entity-type-name' style='color:" + options.color + "'>" + options.name + "</pre>";
+                    },
+                    getWithButton = function(options) {
+                        var name = options.name,
+                            guid = options.options.guid,
+                            entityTypeButton = "";
+                        if (guid) {
+                            if (options.entity) {
+                                entityTypeButton = "<a href='#/detailPage/" + guid + "' class='entity-type-name' style='color:" + options.color + "'>" + name + "</a>";
+                            } else if (options.relationship) {
+                                entityTypeButton = "<a href='#/relationshipDetailPage/" + guid + "' class='entity-type-name' style='color:" + options.color + "'>" + name + "</a>";
+                            } else {
+                                entityTypeButton = "<a href='#/detailPage/" + guid + "' class='entity-type-name' style='color:" + options.color + "'>" + name + "</a>";
+                            }
+                        } else {
+                            entityTypeButton = "<pre class='entity-type-name' style='color:" + options.color + "'>" + name + "</pre>";
+                        }
+                        return entityTypeButton;
+                    },
                     getEntityTypelist = function(options) {
-                        var activeEntityColor = "#4a90e2",
-                            deletedEntityColor = "#BB5838",
-                            entityTypeHtml = "<pre>",
-                            getdefault = function(obj) {
-                                var options = obj.options,
-                                    status = Enums.entityStateReadOnly[options.entityStatus || options.status] ? " deleted-relation" : "",
-                                    guid = options.guid,
-                                    entityColor = obj.color,
-                                    name = obj.name,
-                                    typeName = options.typeName;
-                                if (typeName === "AtlasGlossaryTerm") {
-                                    return '<li class=' + status + '>' +
-                                        '<a style="color:' + entityColor + '" href="#!/glossary/' + guid + '?guid=' + guid + '&gType=term&viewType=term&fromView=entity">' + name + ' (' + typeName + ')</a>' +
-                                        '</li>';
-                                } else {
-                                    return "<li class=" + status + ">" +
-                                        "<a style='color:" + entityColor + "' href=#!/detailPage/" + guid + "?tabActive=relationship>" + name + " (" + typeName + ")</a>" +
-                                        "</li>";
-                                }
-                            },
-                            getWithButton = function(obj) {
-                                var options = obj.options,
-                                    status = Enums.entityStateReadOnly[options.entityStatus || options.status] ? " deleted-relation" : "",
-                                    guid = options.guid,
-                                    entityColor = obj.color,
-                                    name = obj.name,
-                                    typeName = options.typeName,
-                                    relationship = obj.relationship || false,
-                                    entity = obj.entity || false,
-                                    icon = '<i class="fa fa-trash"></i>',
-                                    title = "Deleted";
-                                if (relationship) {
-                                    icon = '<i class="fa fa-long-arrow-right"></i>';
-                                    status = Enums.entityStateReadOnly[options.relationshipStatus || options.status] ? "deleted-relation" : "";
-                                    title = "Relationship Deleted";
-                                }
-                                return "<li class=" + status + ">" +
-                                    "<a style='color:" + entityColor + "' href=#!/detailPage/" + options.guid + "?tabActive=relationship>" + _.escape(name) + " (" + options.typeName + ")</a>" +
-                                    '<button type="button" title="' + title + '" class="btn btn-sm deleteBtn deletedTableBtn btn-action ">' + icon + '</button>' +
-                                    "</li>";
-                            };
-
-                        var name = options.entityName ? options.entityName : Utils.getName(options, "displayText");
-                        if (options.entityStatus == "ACTIVE") {
+                        var name = options.entityName ? options.entityName : Utils.getName(options, "displayText"),
+                            entityTypeHtml = "";
+                        if (options.entityStatus == "ACTIVE" || options.status == "ACTIVE") {
                             if (options.relationshipStatus == "ACTIVE") {
-                                entityTypeHtml = getdefault({
+                                entityTypeHtml = getWithButton({
                                     color: activeEntityColor,
                                     options: options,
                                     name: name
@@ -228,25 +329,53 @@ define([
                     var entityTypeButton = getEntityTypelist(options);
                     return entityTypeButton;
                 };
+                var buildEntityObj = function(item) {
+                    var normalized = normalizeEntity(item);
+                    var ref = normalized && normalized.guid ? this.referredEntities && this.referredEntities[normalized.guid] : null;
+                    var displayText = (ref && (ref.displayText || (ref.attributes && ref.attributes.name))) ||
+                        normalized.displayText ||
+                        (normalized.attributes && normalized.attributes.name) ||
+                        normalized.qualifiedName ||
+                        normalized.guid ||
+                        "N/A";
+                    var typeName = normalized.typeName || (ref && ref.typeName) || this.selectedNodeType;
+                    return _.extend({}, ref, normalized, {
+                        entityName: displayText,
+                        typeName: typeName
+                    });
+                }.bind(this);
+                var buildListItem = function(item) {
+                    var name = item.entityName || Utils.getName(item, "displayText");
+                    var href = item.guid ? "#/detailPage/" + item.guid : "";
+                    var isDeleted = (item.entityStatus || item.status) == "DELETED";
+                    var color = isDeleted ? deletedEntityColor : activeEntityColor;
+                    var content = href
+                        ? "<a href='" + href + "' class='entity-type-name' style='color:" + color + "'>" + _.escape(name) + "</a>"
+                        : "<span class='entity-type-name' style='color:" + color + "'>" + _.escape(name) + "</span>";
+                    return "<li class='entity-list-item'>" + content + "</li>";
+                };
                 if (_.isArray(data)) {
+                    data = _.map(data, function(item) {
+                        return buildEntityObj(item);
+                    });
                     if (data.length > 1) {
                         this.ui.searchNode.show();
                     }
-                    _.each(_.sortBy(data, "displayText"), function(val) {
-                        var name = Utils.getName(val, "displayText"),
-                            valObj = _.extend({}, val, { entityName: name });
+                    _.each(_.sortBy(data, "entityName"), function(val) {
+                        var name = val.entityName || Utils.getName(val, "displayText");
                         if (searchString) {
-                            if (name.search(new RegExp(searchString, "i")) != -1) {
-                                listString += getElement(valObj);
+                            if (name.toLowerCase().includes(searchString.toLowerCase())) {
+                                listString += buildListItem(val);
                             } else {
                                 return;
                             }
                         } else {
-                            listString += getElement(valObj);
+                            listString += buildListItem(val);
                         }
                     });
                 } else {
-                    listString += getElement(data);
+                    data = buildEntityObj(data);
+                    listString += buildListItem(data);
                 }
                 this.$("[data-id='entityList']").html(listString);
             },
@@ -254,8 +383,8 @@ define([
                 //Ref - http://bl.ocks.org/fancellu/2c782394602a93921faff74e594d1bb1
 
                 var that = this,
-                    width = this.$("svg").width(),
-                    height = this.$("svg").height(),
+                    width = this.$("svg").width() || 1200,
+                    height = Math.max(this.$("svg").height() || 600, 600),
                     nodes = d3.values(data.nodes),
                     links = data.links;
 
@@ -263,11 +392,31 @@ define([
                     deletedEntityColor = "#BB5838",
                     defaultEntityColor = "#e0e0e0",
                     selectedNodeColor = "#4a90e2";
+                var getNodeCount = function(node) {
+                    if (!node) {
+                        return 0;
+                    }
+                    if (node.name === that.entity.typeName) {
+                        return 0;
+                    }
+                    if (that.relationshipLoadedCounts && _.has(that.relationshipLoadedCounts, node.name)) {
+                        var count = that.relationshipLoadedCounts[node.name];
+                        var parsedCount = _.isNumber(count) ? count : parseInt(count, 10);
+                        if (_.isFinite(parsedCount)) {
+                            return parsedCount;
+                        }
+                    }
+                    if (_.isArray(node.value)) {
+                        return node.value.length;
+                    }
+                    return node.value ? 1 : 0;
+                };
 
                 var svg = d3
                     .select(this.$("svg")[0])
                     .attr("viewBox", "0 0 " + width + " " + height)
-                    .attr("enable-background", "new 0 0 " + width + " " + height),
+                    .attr("enable-background", "new 0 0 " + width + " " + height)
+                    .style("min-height", "600px"),
                     node,
                     path;
 
@@ -298,47 +447,45 @@ define([
                     .attr("orient", "auto")
                     .attr("markerWidth", 6)
                     .attr("markerHeight", 6)
+                    .attr("xoverflow", "visible")
                     .append("svg:path")
-                    .attr("d", "M 0,-5 L 10 ,0 L 0,5")
+                    .attr("d", "M 0,-5 L 10,0 L 0,5")
                     .attr("fill", function(d) {
-                        return d == "deletedLink" ? deletedEntityColor : activeEntityColor;
+                        return d === "deletedLink" ? deletedEntityColor : activeEntityColor;
                     })
-                    .style("stroke", "none");
-
-                var forceLink = d3
-                    .forceLink()
-                    .id(function(d) {
-                        return d.id;
-                    })
-                    .distance(function(d) {
-                        return 100;
-                    })
-                    .strength(1);
+                    .attr("stroke", "none");
 
                 var simulation = d3
-                    .forceSimulation()
-                    .force("link", forceLink)
-                    .force("charge", d3.forceManyBody())
-                    .force("center", d3.forceCenter(width / 2, height / 2));
-
-                update();
+                    .forceSimulation(nodes)
+                    .force(
+                        "link",
+                        d3
+                            .forceLink(links)
+                            .id(function(d) {
+                                return d.name;
+                            })
+                            .distance(150)
+                    )
+                    .force("charge", d3.forceManyBody().strength(-300))
+                    .force("center", d3.forceCenter(width / 2, height / 2))
+                    .force("collision", d3.forceCollide().radius(50));
 
-                function update() {
                     path = container
-                        .append("svg:g")
+                    .append("g")
                         .selectAll("path")
                         .data(links)
                         .enter()
-                        .append("svg:path")
+                    .append("path")
                         .attr("class", "relatioship-link")
+                    .attr("marker-end", function(d) {
+                        return isAllEntityRelationDeleted({ data: d, type: "link" }) ? "url(#deletedLink)" : "url(#activeLink)";
+                    })
                         .attr("stroke", function(d) {
-                            return getPathColor({ data: d, type: "path" });
-                        })
-                        .attr("marker-end", function(d) {
-                            return "url(#" + (isAllEntityRelationDeleted({ data: d }) ? "deletedLink" : "activeLink") + ")";
+                        return isAllEntityRelationDeleted({ data: d, type: "link" }) ? deletedEntityColor : activeEntityColor;
                         });
 
                     node = container
+                    .append("g")
                         .selectAll(".node")
                         .data(nodes)
                         .enter()
@@ -365,70 +512,74 @@ define([
                             .drag()
                             .on("start", dragstarted)
                             .on("drag", dragged)
-                        );
-
-                    var circleContainer = node.append("g");
+                            .on("end", dragended)
+                    );
 
-                    circleContainer
-                        .append("circle")
-                        .attr("cx", 0)
-                        .attr("cy", 0)
-                        .attr("r", function(d) {
-                            d.radius = 25;
-                            return d.radius;
+                node.append("circle")
+                        .attr("r", function() {
+                        return 25;
                         })
                         .attr("fill", function(d) {
-                            if (d && d.value && d.value.guid == that.guid) {
-                                if (isAllEntityRelationDeleted({ data: d, type: "node" })) {
-                                    return deletedEntityColor;
-                                } else {
+                        if (d.name === that.entity.typeName) {
                                     return selectedNodeColor;
-                                }
-                            } else if (isAllEntityRelationDeleted({ data: d, type: "node" })) {
-                                return deletedEntityColor;
                             } else {
-                                return activeEntityColor;
+                            return isAllEntityRelationDeleted({ data: d, type: "node" }) ? deletedEntityColor : activeEntityColor;
                             }
                         })
-                        .attr("typename", function(d) {
-                            return d.name;
+                    .attr("stroke", "#fff")
+                    .attr("stroke-width", "2px")
+                    .style("cursor", "pointer")
+                    .on("click", function(d) {
+                        if (d && d.value && d.value.guid == that.guid) {
+                            return;
+                        }
+                        that.selectedNodeData = d.value;
+                        that.selectedNodeType = d.name;
+                        
+                        // Show the panel
+                        var panel = that.$(".relationship-node-details");
+                        panel.removeClass("slide-to-left").addClass("slide-from-left");
+                        
+                        // Trigger after a small delay to ensure DOM is ready
+                        setTimeout(function() {
+                            panel.removeClass("slide-from-left").addClass("slide-to-left");
+                            that.searchNode({ currentTarget: that.ui.searchNode });
+                        }, 10);
                         });
 
-                    circleContainer
-                        .append("text")
+                    node.append("text")
                         .attr("x", 0)
                         .attr("y", 0)
-                        .attr("dy", 25 - 17)
+                        .attr("dy", function() {
+                            return 25 - 17;
+                        })
                         .attr("text-anchor", "middle")
                         .style("font-family", "FontAwesome")
-                        .style("font-size", function(d) {
-                            return "25px";
-                        })
+                        .style("font-size", "25px")
+                        .attr("class", "relationship-node-icon")
                         .text(function(d) {
                             var iconObj = Enums.graphIcon[d.name];
                             if (iconObj && iconObj.textContent) {
                                 return iconObj.textContent;
-                            } else {
-                                if (d && _.isArray(d.value) && d.value.length > 1) {
-                                    return "\uf0c5";
-                                } else {
-                                    return "\uf016";
-                                }
                             }
+                            if (d && _.isArray(d.value) && d.value.length > 1) {
+                                return "\uf0c5";
+                            }
+                            return "\uf016";
                         })
-                        .attr("fill", function(d) {
-                            return "#fff";
-                        });
+                        .attr("fill", "#fff");
 
-                    var countBox = circleContainer.append("g");
+                    var countBox = node.append("g");
 
                     countBox
                         .append("circle")
                         .attr("cx", 18)
                         .attr("cy", -20)
+                        .attr("class", "relationship-node-count")
                         .attr("r", function(d) {
-                            if (_.isArray(d.value) && d.value.length > 1) {
-                                return 10;
+                            var count = getNodeCount(d);
+                            if (count > 1) {
+                                return 9;
                             }
                         });
 
@@ -438,44 +589,37 @@ define([
                         .attr("dy", -16)
                         .attr("text-anchor", "middle")
                         .attr("fill", defaultEntityColor)
+                        .attr("class", "relationship-node-count")
                         .text(function(d) {
-                            if (_.isArray(d.value) && d.value.length > 1) {
-                                return d.value.length;
+                            var count = getNodeCount(d);
+                            if (count > 1) {
+                                return count;
                             }
                         });
 
-                    node.append("text")
+                    node
+                        .append("text")
                         .attr("x", -15)
                         .attr("y", "35")
+                        .attr("class", "relationship-node-label")
                         .text(function(d) {
                             return d.name;
                         });
 
-                    simulation.nodes(nodes).on("tick", ticked);
-
-                    simulation.force("link").links(links);
-                }
-
-                function ticked() {
+                simulation.on("tick", function() {
                     path.attr("d", function(d) {
-                        var diffX = d.target.x - d.source.x,
-                            diffY = d.target.y - d.source.y,
-                            // Length of path from center of source node to center of target node
-                            pathLength = Math.sqrt(diffX * diffX + diffY * diffY),
-                            // x and y distances from center to outside edge of target node
-                            offsetX = (diffX * d.target.radius) / pathLength,
-                            offsetY = (diffY * d.target.radius) / pathLength;
-
-                        return "M" + d.source.x + "," + d.source.y + "A" + pathLength + "," + pathLength + " 0 0,1 " + (d.target.x - offsetX) + "," + (d.target.y - offsetY);
+                        var dx = d.target.x - d.source.x,
+                            dy = d.target.y - d.source.y,
+                            dr = Math.sqrt(dx * dx + dy * dy);
+                        return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
                     });
 
                     node.attr("transform", function(d) {
                         return "translate(" + d.x + "," + d.y + ")";
                     });
-                }
+                });
 
                 function dragstarted(d) {
-                    d3.event.sourceEvent.stopPropagation();
                     if (d && d.value && d.value.guid != that.guid) {
                         if (!d3.event.active) simulation.alphaTarget(0.3).restart();
                         d.fx = d.x;
@@ -490,6 +634,12 @@ define([
                     }
                 }
 
+                function dragended(d) {
+                    if (d && d.value && d.value.guid != that.guid) {
+                        if (!d3.event.active) simulation.alphaTarget(0);
+                    }
+                }
+
                 function getPathColor(options) {
                     return isAllEntityRelationDeleted(options) ? deletedEntityColor : activeEntityColor;
                 }
@@ -536,18 +686,58 @@ define([
                 });
             },
             relationshipViewToggle: function(checked) {
-                this.ui.relationshipDetailTable.toggleClass("visible invisible");
-                this.ui.relationshipSVG.toggleClass("visible invisible");
+                var that = this;
 
+                // In the original code: checked = Table, unchecked = Graph
+                // So we need to invert the logic
                 if (checked) {
+                    // Show card view (checked = Table)
+                    this.ui.relationshipSVG.addClass("invisible").hide();
+                    this.ui.relationshipDetailTableContainer.show();
                     this.ui.zoomControl.hide();
                     this.$el.addClass("auto-height");
+                    this.ui.relationshipDetailTable.hide();
+                    this.ui.relationshipDetailValue.hide();
+                    this.ui.relationshipCardsView.show();
+                    
+                    // Render card view if not already rendered
+                    this.ensureCardsView();
+                    
+                    // Force a re-render after a short delay to ensure DOM is ready
+                    setTimeout(function() {
+                        if (that.relationshipCardsViewInstance) {
+                            that.relationshipCardsViewInstance.renderCards();
+                        }
+                    }, 100);
                 } else {
+                    // Show graph view (unchecked = Graph)
+                    this.ui.relationshipSVG.removeClass("invisible").show();
+                    this.ui.relationshipDetailTableContainer.hide();
                     this.ui.zoomControl.show();
                     this.$el.removeClass("auto-height");
+                    this.ui.relationshipDetailTable.show();
+                    this.ui.relationshipDetailValue.show();
+                    this.ui.relationshipCardsView.hide();
+                    
+                    // Ensure graph is created if it hasn't been created yet
+                    if (this.graphData && !_.isEmpty(this.graphData.links)) {
+                        // Clear existing graph and recreate
+                        this.$("svg").empty();
+                        this.createGraph(this.graphData);
+                    } else if (this.graphData && _.isEmpty(this.graphData.links)) {
+                        this.noRelationship();
+                    }
+                }
+            },
+            
+            onDestroy: function() {
+                this.cardsViewLoadInProgress = false;
+                if (this.relationshipCardsViewInstance) {
+                    this.relationshipCardsViewInstance.destroy();
+                    this.relationshipCardsViewInstance = null;
                 }
             }
         }
     );
     return RelationshipLayoutView;
-});
\ No newline at end of file
+});