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

pawarprasad123 pushed a commit to branch atlas-2.6
in repository https://gitbox.apache.org/repos/asf/atlas.git


The following commit(s) were added to refs/heads/atlas-2.6 by this push:
     new e072bffb8 ATLAS-5296: ATLAS UI: React UI fixes, audit table pagination 
text, Masonry grid (#636)
e072bffb8 is described below

commit e072bffb8c436d2a8778a6867edd66552b057a96
Author: Prasad Pawar <[email protected]>
AuthorDate: Wed Jun 10 17:47:18 2026 +0530

    ATLAS-5296: ATLAS UI: React UI fixes, audit table pagination text, Masonry 
grid (#636)
    
    * ATLAS-5296: ATLAS UI: React UI fixes, audit table pagination text, 
Masonry grid
    
    * ATLAS-5296: ATLAS UI: React UI fixes, audit table pagination text, 
Masonry grid
    
    Fix RAT license headers on ATLAS-5296 PR files.
    
    Move ASF header before @ts-nocheck directives and repair
    corrupted license lines so apache-rat-plugin:check passes.
    
    * ATLAS-5296: ATLAS UI: React UI fixes, audit table pagination text, 
Masonry grid
    
    Align CustomFilters SideBarTree tests with ATLAS-5301 behavior.
    
    Update assertions after master rebase: grouped Custom Filters view
    has no empty-type toggle; full suite passes (4605 tests).
    
    * ATLAS-5296: ATLAS UI: React UI fixes, audit table pagination text, 
Masonry grid
    
    ---------
    ( cherry-picked from commit ed336f2e1829f1c57a127a48a94587f0499a73f5)
---
 .../__tests__/detailpageApiMethod.test.ts          |  15 ++
 .../src/api/apiMethods/detailpageApiMethod.ts      |  10 ++
 dashboard/src/api/apiUrlLinks/classificationUrl.ts |   2 +-
 .../src/components/DatePicker/CustomDatePicker.tsx |   2 +-
 dashboard/src/components/Masonry/MasonryCard.tsx   |  85 ++++++++++
 dashboard/src/components/Masonry/MasonryGrid.tsx   |  72 ++++++++
 .../CustomDatePicker.tsx => Masonry/masonry.css}   |  60 ++++---
 dashboard/src/components/QueryBuilder/Filters.tsx  |   6 +-
 dashboard/src/components/ShowMore/ShowMoreView.tsx |  18 +-
 dashboard/src/components/Table/TableLayout.tsx     |   4 +-
 dashboard/src/components/Table/TablePagination.tsx |  32 +++-
 dashboard/src/components/muiComponents.tsx         |   4 +-
 dashboard/src/models/tableLayoutType.ts            |   5 +
 dashboard/src/redux/slice/sessionSlice.ts          |   2 +-
 dashboard/src/utils/Global.ts                      |  18 +-
 dashboard/src/utils/Utils.ts                       |   2 +-
 .../__tests__/entityPayloadEnrichmentUtils.test.ts | 147 +++++++++++++++++
 .../src/utils/entityPayloadEnrichmentUtils.ts      | 110 +++++++++++++
 .../views/Administrator/Audits/AdminAuditTable.tsx |   1 +
 .../Audits/AuditsFilter/AuditFiltersFields.tsx     |  11 +-
 .../BusinessMetadataAtrributeForm.tsx              |  80 +++++----
 .../BusinessMetadata/BusinessMetadataForm.tsx      |   4 +-
 .../src/views/Classification/AddTagAttributes.tsx  |  71 ++++----
 .../views/Classification/ClassificationForm.tsx    |  82 +++++-----
 .../views/DashboardOverview/EntityTypeBarChart.tsx |   7 +-
 .../DashboardOverview/KafkaTopicSummaryCard.tsx    |  32 +++-
 dashboard/src/views/DetailPage/AttributeTable.tsx  |   8 +-
 .../BusinessMetadataAtrribute.tsx                  |  16 +-
 .../BusinessMetadataDetailsLayout.tsx              |   2 +-
 .../DetailPage/ClassificationDetailsLayout.tsx     |  10 +-
 .../src/views/DetailPage/EntityDetailPage.tsx      |   6 +-
 .../EntityDetailTabs/AttributeProperties.tsx       |  81 +++++----
 .../EntityDetailTabs/AuditTableDetails.tsx         |  80 +++++----
 .../DetailPage/EntityDetailTabs/LineageTab.tsx     |  13 +-
 .../PropertiesTab/BMAttributes.tsx                 |   4 +-
 .../PropertiesTab/UserDefinedProperties.tsx        |   4 +-
 .../EntityDetailTabs/RelationshipLineage.tsx       |  33 +++-
 .../__tests__/UserDefinedProperties.test.tsx       | 182 +++++++++++++++++++++
 .../DetailPage/GlossaryDetails/TermProperties.tsx  |   3 +
 .../DetailPage/GlossaryDetails/TermRelation.tsx    |   2 +
 .../GlossaryDetails/TermRelationViewAttributes.tsx |  19 ++-
 .../RelationshipPropertiesTab.tsx                  |   2 +-
 dashboard/src/views/Entity/EntityForm.tsx          |   4 +-
 dashboard/src/views/Layout/Header.tsx              |   4 +-
 dashboard/src/views/Layout/Layout.tsx              |   2 +-
 dashboard/src/views/Lineage/LineageLayout.tsx      |  14 +-
 dashboard/src/views/MasonryDemo.tsx                |  58 +++++++
 .../src/views/SearchResult/RelationShipSearch.tsx  |  15 +-
 dashboard/src/views/SearchResult/SearchResult.tsx  |   5 +-
 .../src/views/SideBar/Import/ImportLayout.tsx      |  10 +-
 .../__tests__/CustomFiltersTree.test.tsx           |  32 ++--
 .../SideBarTree/__tests__/SideBarTree.test.tsx     |  28 ++--
 dashboard/src/views/Statistics/ServerStats.tsx     |  50 ++++--
 53 files changed, 1205 insertions(+), 364 deletions(-)

diff --git a/dashboard/src/api/apiMethods/__tests__/detailpageApiMethod.test.ts 
b/dashboard/src/api/apiMethods/__tests__/detailpageApiMethod.test.ts
index b818e227e..c969a8b78 100644
--- a/dashboard/src/api/apiMethods/__tests__/detailpageApiMethod.test.ts
+++ b/dashboard/src/api/apiMethods/__tests__/detailpageApiMethod.test.ts
@@ -27,6 +27,7 @@
 
 import {
        getDetailPageData,
+       getEntityWithRelationships,
        getDetailPageAuditData,
        getDetailPageRauditData,
        getAuditData,
@@ -123,6 +124,20 @@ describe('detailpageApiMethod', () => {
                })
        })
 
+       describe('getEntityWithRelationships', () => {
+               it('should call _get with ignoreRelationships false', async () 
=> {
+                       const guid = 'test-guid-123'
+                       const result = await getEntityWithRelationships(guid)
+
+                       expect(mockDetailpageApiUrl).toHaveBeenCalledWith(guid)
+                       
expect(mockGet).toHaveBeenCalledWith('/api/detail/test-guid-123', {
+                               method: 'GET',
+                               params: { ignoreRelationships: false }
+                       })
+                       expect(result).toEqual(mockResponse)
+               })
+       })
+
        describe('getDetailPageAuditData', () => {
                it('should call _get with audit URL', async () => {
                        const guid = 'test-guid-123'
diff --git a/dashboard/src/api/apiMethods/detailpageApiMethod.ts 
b/dashboard/src/api/apiMethods/detailpageApiMethod.ts
index fea1b7b88..a8d22f12e 100644
--- a/dashboard/src/api/apiMethods/detailpageApiMethod.ts
+++ b/dashboard/src/api/apiMethods/detailpageApiMethod.ts
@@ -35,6 +35,15 @@ const getDetailPageData = (guid: string, params: object, 
header?: string) => {
   return _get(detailpageApiUrl(guid, header), config);
 };
 
+/** Full entity GET including relationshipAttributes (for entity save 
payloads). */
+const getEntityWithRelationships = (guid: string) => {
+  const config = {
+    method: "GET",
+    params: { ignoreRelationships: false }
+  };
+  return _get(detailpageApiUrl(guid), config);
+};
+
 const getDetailPageAuditData = (guid: string, params: object) => {
   const config = {
     method: "GET",
@@ -204,6 +213,7 @@ const getDetailPageRelationshipAttributes = async (
 
 export {
   getDetailPageData,
+  getEntityWithRelationships,
   getDetailPageAuditData,
   getDetailPageRauditData,
   getAuditData,
diff --git a/dashboard/src/api/apiUrlLinks/classificationUrl.ts 
b/dashboard/src/api/apiUrlLinks/classificationUrl.ts
index 1a1b23434..b03435a40 100644
--- a/dashboard/src/api/apiUrlLinks/classificationUrl.ts
+++ b/dashboard/src/api/apiUrlLinks/classificationUrl.ts
@@ -13,7 +13,7 @@
  * 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 { getBaseApiUrl } from "./commonApiUrl";
 
diff --git a/dashboard/src/components/DatePicker/CustomDatePicker.tsx 
b/dashboard/src/components/DatePicker/CustomDatePicker.tsx
index 8409660cb..6671c8596 100644
--- a/dashboard/src/components/DatePicker/CustomDatePicker.tsx
+++ b/dashboard/src/components/DatePicker/CustomDatePicker.tsx
@@ -31,7 +31,7 @@ const CustomDatepicker = (props: {
       selected={selected}
       onChange={onChange}
       timeInputLabel=""
-      renderCustomHeader={(headerProps) => <CustomHeader {...headerProps} />}
+      renderCustomHeader={(headerProps: any) => <CustomHeader {...headerProps} 
/>}
       dateFormat="MM/dd/yyyy h:mm:ss aa"
       {...rest}
     />
diff --git a/dashboard/src/components/Masonry/MasonryCard.tsx 
b/dashboard/src/components/Masonry/MasonryCard.tsx
new file mode 100644
index 000000000..5e00d4be0
--- /dev/null
+++ b/dashboard/src/components/Masonry/MasonryCard.tsx
@@ -0,0 +1,85 @@
+/*
+ * 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 React, { useEffect, useRef, useState } from "react";
+import "./masonry.css";
+
+export type MasonryCardProps = {
+  title: string;
+  maxBodyHeight?: number; // max visible height for body scroll area
+  footer?: React.ReactNode;
+  className?: string;
+  style?: React.CSSProperties;
+  children: React.ReactNode; // card body content
+};
+
+/**
+ * A card that measures its height and sets grid-row-end to fill the CSS Grid 
tracks.
+ * The body section gets a max-height with internal scroll to keep card height 
bounded.
+ */
+const MasonryCard: React.FC<MasonryCardProps> = ({
+  title,
+  maxBodyHeight = 260,
+  footer,
+  className,
+  style,
+  children
+}) => {
+  const cardRef = useRef<HTMLDivElement | null>(null);
+  const [rowSpan, setRowSpan] = useState<number>(1);
+
+  useEffect(() => {
+    const el = cardRef.current;
+    if (!el) return;
+
+    const grid = el.parentElement as HTMLElement | null;
+    const rowHeight = Number(grid?.dataset.rowHeight || 8);
+    const rowGap = Number(grid?.dataset.rowGap || 16);
+
+    const measure = () => {
+      const height = el.getBoundingClientRect().height;
+      const span = Math.max(1, Math.ceil((height + rowGap) / (rowHeight + 
rowGap)));
+      setRowSpan(span);
+    };
+
+    measure();
+    const ro = new ResizeObserver(measure);
+    ro.observe(el);
+    return () => ro.disconnect();
+  }, []);
+
+  return (
+    <div
+      ref={cardRef}
+      className={`masonry-card${className ? ` ${className}` : ""}`}
+      style={{ gridRowEnd: `span ${rowSpan}`, ...style }}
+    >
+      <div className="masonry-card__header">{title}</div>
+      <div className="masonry-card__body" style={{ maxHeight: maxBodyHeight }}>
+        {children}
+      </div>
+      {footer ? <div className="masonry-card__footer">{footer}</div> : null}
+    </div>
+  );
+};
+
+export default MasonryCard;
+
+
+
+
+
diff --git a/dashboard/src/components/Masonry/MasonryGrid.tsx 
b/dashboard/src/components/Masonry/MasonryGrid.tsx
new file mode 100644
index 000000000..7700fab7e
--- /dev/null
+++ b/dashboard/src/components/Masonry/MasonryGrid.tsx
@@ -0,0 +1,72 @@
+/*
+ * 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 React from "react";
+import "./masonry.css";
+
+export type MasonryGridProps = {
+  minColumnWidth?: number;
+  columnGap?: number;
+  rowGap?: number;
+  rowHeight?: number;
+  className?: string;
+  style?: React.CSSProperties;
+  children: React.ReactNode;
+};
+
+/**
+ * Responsive CSS Grid container that supports a Masonry-like layout.
+ * Children should set their own grid-row-end span based on measured height.
+ */
+const MasonryGrid: React.FC<MasonryGridProps> = ({
+  minColumnWidth = 280,
+  columnGap = 16,
+  rowGap = 16,
+  rowHeight = 8,
+  className,
+  style,
+  children
+}) => {
+  const mergedStyle: React.CSSProperties = {
+    // grid settings
+    display: "grid",
+    gridTemplateColumns: `repeat(auto-fill, minmax(${minColumnWidth}px, 1fr))`,
+    gridAutoFlow: "dense",
+    gridAutoRows: `${rowHeight}px`,
+    columnGap,
+    rowGap,
+    ...style
+  };
+
+  return (
+    <div
+      className={`masonry-grid${className ? ` ${className}` : ""}`}
+      style={mergedStyle}
+      data-row-height={rowHeight}
+      data-row-gap={rowGap}
+    >
+      {children}
+    </div>
+  );
+};
+
+export default MasonryGrid;
+
+
+
+
+
diff --git a/dashboard/src/components/DatePicker/CustomDatePicker.tsx 
b/dashboard/src/components/Masonry/masonry.css
similarity index 58%
copy from dashboard/src/components/DatePicker/CustomDatePicker.tsx
copy to dashboard/src/components/Masonry/masonry.css
index 8409660cb..d1bef8219 100644
--- a/dashboard/src/components/DatePicker/CustomDatePicker.tsx
+++ b/dashboard/src/components/Masonry/masonry.css
@@ -15,27 +15,39 @@
  * limitations under the License.
  */
 
-import DatePicker from "react-datepicker";
-import "react-datepicker/dist/react-datepicker.css";
-import CustomHeader from "./CustomHeader";
-
-const CustomDatepicker = (props: {
-  [x: string]: any;
-  selected?: any;
-  onChange?: any;
-}) => {
-  const { selected, onChange, ...rest } = props;
-
-  return (
-    <DatePicker
-      selected={selected}
-      onChange={onChange}
-      timeInputLabel=""
-      renderCustomHeader={(headerProps) => <CustomHeader {...headerProps} />}
-      dateFormat="MM/dd/yyyy h:mm:ss aa"
-      {...rest}
-    />
-  );
-};
-
-export default CustomDatepicker;
+.masonry-grid {
+  width: 100%;
+}
+
+.masonry-card {
+  background: #ffffff;
+  border: 1px solid #e5e7eb;
+  border-radius: 6px;
+  display: flex;
+  flex-direction: column;
+  min-height: 0; /* allow children to shrink */
+  overflow: hidden;
+}
+
+.masonry-card__header {
+  background: #0a3d62;
+  color: #ffffff;
+  padding: 10px 12px;
+  font-weight: 600;
+  font-size: 14px;
+}
+
+.masonry-card__body {
+  padding: 12px;
+  overflow: auto; /* scroll within card when content exceeds maxBodyHeight */
+}
+
+.masonry-card__footer {
+  padding: 10px 12px;
+  border-top: 1px solid #e5e7eb;
+}
+
+
+
+
+
diff --git a/dashboard/src/components/QueryBuilder/Filters.tsx 
b/dashboard/src/components/QueryBuilder/Filters.tsx
index d162f28e6..d5b770120 100644
--- a/dashboard/src/components/QueryBuilder/Filters.tsx
+++ b/dashboard/src/components/QueryBuilder/Filters.tsx
@@ -1,5 +1,3 @@
-// @ts-nocheck
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -17,6 +15,8 @@
  * limitations under the License.
  */
 
+// @ts-nocheck
+
 import {
   Popover,
   Stack,
@@ -155,7 +155,7 @@ const Filters = ({
   const { classificationDefs } = classificationData || {};
   const { entityDefs = {} } = entityData || {};
   const { enumDefs = {} } = enumObj?.data || {};
-  const { businessMetadataDefs = {} } = businessMetaData || {};
+  const { businessMetadataDefs = [] } = businessMetaData || {};
 
   let allDataObj = {
     entitys: entityDefs,
diff --git a/dashboard/src/components/ShowMore/ShowMoreView.tsx 
b/dashboard/src/components/ShowMore/ShowMoreView.tsx
index 3761d0a4d..48f368d0c 100644
--- a/dashboard/src/components/ShowMore/ShowMoreView.tsx
+++ b/dashboard/src/components/ShowMore/ShowMoreView.tsx
@@ -141,10 +141,10 @@ const ShowMoreView = ({
             relationshipGuid: selectedTerm.relationshipGuid
           });
         } else if (!isEmpty(gType)) {
-          let values = cloneDeep(currentEntity);
+          let values = cloneDeep(currentEntity) || {};
           let glossaryData;
           if (title == "Terms") {
-            glossaryData = values?.["terms"].filter(
+            glossaryData = (values["terms"] || []).filter(
               (obj: { displayText: string }) => {
                 return obj.displayText != currentValue.selectedValue;
               }
@@ -152,7 +152,7 @@ const ShowMoreView = ({
 
             values["terms"] = glossaryData;
           } else {
-            glossaryData = values?.["categories"].filter(
+            glossaryData = (values["categories"] || []).filter(
               (obj: { displayText: string }) => {
                 return obj.displayText != currentValue.selectedValue;
               }
@@ -223,7 +223,13 @@ const ShowMoreView = ({
     } else if (title == "Propagated Classifications") {
       return getTagParentList(label);
     } else {
-      return label || optionalLabel;
+      // Ensure we return a string, not an object
+      if (label) return label;
+      if (typeof optionalLabel === 'string') return optionalLabel;
+      if (optionalLabel && typeof optionalLabel === 'object') {
+        return optionalLabel.displayText || optionalLabel.text || 
optionalLabel.name || '';
+      }
+      return '';
     }
   };
 
@@ -306,7 +312,9 @@ const ShowMoreView = ({
                   onDelete={
                     !isEmpty(removeApiMethod) && !isDeleteIcon
                       ? () => {
-                          handleDelete(obj[displayKey] || obj);
+                          // Handle undefined displayKey by extracting a 
string value
+                          const deleteValue = obj[displayKey] || 
obj.displayText || obj.text || obj.name || '';
+                          handleDelete(deleteValue);
                         }
                       : isDeleteIcon && obj.count > 1
                       ? () => {
diff --git a/dashboard/src/components/Table/TableLayout.tsx 
b/dashboard/src/components/Table/TableLayout.tsx
index ff53e0b6a..4218adb5d 100644
--- a/dashboard/src/components/Table/TableLayout.tsx
+++ b/dashboard/src/components/Table/TableLayout.tsx
@@ -355,7 +355,8 @@ const TableLayout: FC<TableProps> = ({
   showGoToPage,
   customLeftButton,
   defaultPageSize,
-  onClientPageSizeChange
+  onClientPageSizeChange,
+  paginationSummaryVariant
 }) => {
   let defaultHideColumns = { ...defaultColumnVisibility };
   const location = useLocation();
@@ -733,6 +734,7 @@ const TableLayout: FC<TableProps> = ({
               showGoToPage={showGoToPage}
               totalCount={totalCount}
               onClientPageSizeChange={onClientPageSizeChange}
+              paginationSummaryVariant={paginationSummaryVariant}
             />
           )}
         </Paper>
diff --git a/dashboard/src/components/Table/TablePagination.tsx 
b/dashboard/src/components/Table/TablePagination.tsx
index 792d1a711..dbda96ad8 100644
--- a/dashboard/src/components/Table/TablePagination.tsx
+++ b/dashboard/src/components/Table/TablePagination.tsx
@@ -69,6 +69,8 @@ interface PaginationProps {
   totalCount?: number;
   /** Client mode: notify parent when page size changes (user action). */
   onClientPageSizeChange?: (pageSize: number) => void;
+  /** See TableProps.paginationSummaryVariant */
+  paginationSummaryVariant?: 'default' | 'audit';
 }
 
 const TablePagination: React.FC<PaginationProps> = ({
@@ -90,7 +92,8 @@ const TablePagination: React.FC<PaginationProps> = ({
   setIsEmptyData,
   showGoToPage = false,
   totalCount,
-  onClientPageSizeChange
+  onClientPageSizeChange,
+  paginationSummaryVariant = 'default'
 }) => {
   const theme: any = useTheme();
   const location = useLocation();
@@ -381,8 +384,18 @@ const TablePagination: React.FC<PaginationProps> = ({
     totalDatasetRows === 0 ? 0 : Math.min(displayFrom, displayToCapped);
   const footerRangeEnd = totalDatasetRows === 0 ? 0 : displayToCapped;
 
+  const showAuditPaginationSummary =
+    paginationSummaryVariant === 'audit' &&
+    isServerSide &&
+    memoizedData.length > 0;
+
+  const auditRangeStart = offset + 1;
+  const auditRangeEnd = offset + memoizedData.length;
+
   return (
     <Stack
+      role="navigation"
+      aria-label="Table pagination"
       spacing={{ xs: 1, sm: 2 }}
       direction="row"
       useFlexGap
@@ -393,14 +406,21 @@ const TablePagination: React.FC<PaginationProps> = ({
     >
       <div>
         <span className="text-grey">
-          {totalDatasetRows === 0 ? (
-            "No records to display"
+          {memoizedData.length === 0 ? (
+            'No records to display'
+          ) : showAuditPaginationSummary ? (
+            <>
+              Showing {memoizedData.length.toLocaleString()}{' '}
+              {memoizedData.length === 1 ? 'record' : 'records'} From{' '}
+              {auditRangeStart.toLocaleString()} -{' '}
+              {auditRangeEnd.toLocaleString()}
+            </>
           ) : (
             <>
               Showing {footerRangeStart.toLocaleString()}-
-              {footerRangeEnd.toLocaleString()} of{" "}
-              {totalDatasetRows.toLocaleString()}{" "}
-              {totalDatasetRows === 1 ? "record" : "records"}
+              {footerRangeEnd.toLocaleString()} of{' '}
+              {totalDatasetRows.toLocaleString()}{' '}
+              {totalDatasetRows === 1 ? 'record' : 'records'}
             </>
           )}
         </span>
diff --git a/dashboard/src/components/muiComponents.tsx 
b/dashboard/src/components/muiComponents.tsx
index cf96d2c6d..12ee53af4 100644
--- a/dashboard/src/components/muiComponents.tsx
+++ b/dashboard/src/components/muiComponents.tsx
@@ -90,7 +90,8 @@ const CustomButton = ({
   size,
   endIcon,
   startIcon,
-  disabled
+  disabled,
+  ...rest
 }: ButtonProps | any) => {
   let defaultStyles = {
     fontWeight: "600 !important",
@@ -114,6 +115,7 @@ const CustomButton = ({
         endIcon={endIcon}
         startIcon={startIcon}
         disabled={disabled}
+        {...rest}
       >
         {children}
       </Button>
diff --git a/dashboard/src/models/tableLayoutType.ts 
b/dashboard/src/models/tableLayoutType.ts
index 4fa240f6f..84b13a95d 100644
--- a/dashboard/src/models/tableLayoutType.ts
+++ b/dashboard/src/models/tableLayoutType.ts
@@ -61,4 +61,9 @@ export interface TableProps {
   defaultPageSize?: number;
   /** Client pagination: invoked when the user changes page size (e.g. sync 
schema relationship chunk limit). */
   onClientPageSizeChange?: (pageSize: number) => void;
+  /**
+   * Admin audit table: API does not return a total count. Footer shows
+   * "Showing {n} records From {start} - {end}" instead of "… of {total}".
+   */
+  paginationSummaryVariant?: 'default' | 'audit';
 }
diff --git a/dashboard/src/redux/slice/sessionSlice.ts 
b/dashboard/src/redux/slice/sessionSlice.ts
index cf91a5550..82e497571 100644
--- a/dashboard/src/redux/slice/sessionSlice.ts
+++ b/dashboard/src/redux/slice/sessionSlice.ts
@@ -75,7 +75,7 @@ const sessionSlice = createSlice({
         state.sessionObj = {
           loading: false,
           data: null,
-          error: action.payload as string
+          error: (action.payload as string) || action.error?.message || 'An 
error occurred'
         };
       });
   }
diff --git a/dashboard/src/utils/Global.ts b/dashboard/src/utils/Global.ts
index bdbff111a..5d20cb123 100644
--- a/dashboard/src/utils/Global.ts
+++ b/dashboard/src/utils/Global.ts
@@ -23,27 +23,27 @@ const dateFormat = "MM/DD/YYYY";
 
 const globalSession = (sessionData: any) => {
   globalSessionData.restCrsfHeader =
-    sessionData["atlas.rest-csrf.custom-header"] || "";
+    sessionData["atlas.rest-csrf.custom-header"] ?? "";
   globalSessionData.crsfToken = sessionData["_csrfToken"];
   globalSessionData.debugMetrics = sessionData["atlas.debug.metrics.enabled"];
   globalSessionData.entityCreate =
-    sessionData["atlas.entity.create.allowed"] || true;
+    sessionData["atlas.entity.create.allowed"] ?? true;
   globalSessionData.entityUpdate =
-    sessionData["atlas.entity.update.allowed"] || true;
+    sessionData["atlas.entity.update.allowed"] ?? true;
   globalSessionData.taskTabEnabled =
-    sessionData["atlas.tasks.enabled"] || false;
+    sessionData["atlas.tasks.enabled"] ?? false;
   globalSessionData.sessionTimeout =
-    sessionData["atlas.session.timeout.secs"] || 900;
+    sessionData["atlas.session.timeout.secs"] ?? 900;
   globalSessionData.uiTaskTabEnabled =
     sessionData["atlas.tasks.ui.tab.enabled"];
   globalSessionData.relationshipSearch =
-    sessionData["atlas.relationship.search.enabled"] || false;
+    sessionData["atlas.relationship.search.enabled"] ?? false;
   globalSessionData.isLineageOnDemandEnabled =
-    sessionData["atlas.lineage.on.demand.enabled"] || false;
+    sessionData["atlas.lineage.on.demand.enabled"] ?? false;
   globalSessionData.lineageNodeCount =
-    sessionData["atlas.lineage.on.demand.default.node.count"] || 3;
+    sessionData["atlas.lineage.on.demand.default.node.count"] ?? 3;
   globalSessionData.isTimezoneFormatEnabled =
-    sessionData["atlas.ui.date.timezone.format.enabled"] || true;
+    sessionData["atlas.ui.date.timezone.format.enabled"] ?? true;
 };
 
 export { globalSession, entityImgPath, dateTimeFormat, dateFormat };
diff --git a/dashboard/src/utils/Utils.ts b/dashboard/src/utils/Utils.ts
index b404c9d04..38556b9b5 100644
--- a/dashboard/src/utils/Utils.ts
+++ b/dashboard/src/utils/Utils.ts
@@ -340,7 +340,7 @@ const getEntityIconPath = (options: any) => {
 };
 
 const serverError = (error: any, toastId: any) => {
-  // fetchApi already surfaces 403 via serverErrorHandler (toast); avoid 
duplicate.
+  // fetchApi already surfaces 403 via deferred toast.error; avoid duplicate.
   if (error?.response?.status === 403) {
     return;
   }
diff --git a/dashboard/src/utils/__tests__/entityPayloadEnrichmentUtils.test.ts 
b/dashboard/src/utils/__tests__/entityPayloadEnrichmentUtils.test.ts
new file mode 100644
index 000000000..eb928e28d
--- /dev/null
+++ b/dashboard/src/utils/__tests__/entityPayloadEnrichmentUtils.test.ts
@@ -0,0 +1,147 @@
+/*
+ * 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 {
+       enrichEntityPayloadForRelationshipSave,
+       isRelationshipAttrValueMissing,
+       mergeMissingRelationshipAttributes
+} from '../entityPayloadEnrichmentUtils';
+import { getEntityWithRelationships } from 
'@api/apiMethods/detailpageApiMethod';
+
+jest.mock('@api/apiMethods/detailpageApiMethod', () => ({
+       getEntityWithRelationships: jest.fn()
+}));
+
+const mockGetEntityWithRelationships =
+       getEntityWithRelationships as jest.MockedFunction<
+               typeof getEntityWithRelationships
+       >;
+
+describe('entityPayloadEnrichmentUtils', () => {
+       beforeEach(() => {
+               jest.clearAllMocks();
+       });
+
+       describe('isRelationshipAttrValueMissing', () => {
+               it('returns true for undefined, null, empty array, object 
without guid', () => {
+                       
expect(isRelationshipAttrValueMissing(undefined)).toBe(true);
+                       expect(isRelationshipAttrValueMissing(null)).toBe(true);
+                       expect(isRelationshipAttrValueMissing([])).toBe(true);
+                       expect(isRelationshipAttrValueMissing({})).toBe(true);
+               });
+
+               it('returns false for object with guid or non-empty primitive', 
() => {
+                       expect(
+                               isRelationshipAttrValueMissing({
+                                       guid: 'g1',
+                                       typeName: 'hive_table'
+                               })
+                       ).toBe(false);
+                       
expect(isRelationshipAttrValueMissing('value')).toBe(false);
+               });
+       });
+
+       describe('mergeMissingRelationshipAttributes', () => {
+               it('merges missing mandatory refs from full entity', () => {
+                       const entityJson = {
+                               guid: 'col-guid',
+                               typeName: 'hive_column',
+                               relationshipAttributes: {
+                                       meanings: [{ guid: 'term-1' }]
+                               }
+                       };
+                       const fullRels = {
+                               table: { guid: 'table-guid', typeName: 
'hive_table' },
+                               meanings: [{ guid: 'other-term' }]
+                       };
+
+                       mergeMissingRelationshipAttributes(entityJson, 
fullRels);
+
+                       
expect(entityJson.relationshipAttributes.table).toEqual({
+                               guid: 'table-guid',
+                               typeName: 'hive_table'
+                       });
+                       
expect(entityJson.relationshipAttributes.meanings).toEqual([
+                               { guid: 'term-1' }
+                       ]);
+               });
+
+               it('does not overwrite existing relationship values', () => {
+                       const entityJson = {
+                               relationshipAttributes: {
+                                       table: { guid: 'existing', typeName: 
'hive_table' }
+                               }
+                       };
+                       const fullRels = {
+                               table: { guid: 'new', typeName: 'hive_table' }
+                       };
+
+                       mergeMissingRelationshipAttributes(entityJson, 
fullRels);
+
+                       
expect(entityJson.relationshipAttributes.table).toEqual({
+                               guid: 'existing',
+                               typeName: 'hive_table'
+                       });
+               });
+       });
+
+       describe('enrichEntityPayloadForRelationshipSave', () => {
+               it('fetches full entity and merges relationshipAttributes', 
async () => {
+                       const entityJson = {
+                               guid: 'col-guid',
+                               typeName: 'hive_column',
+                               relationshipAttributes: {}
+                       };
+                       mockGetEntityWithRelationships.mockResolvedValueOnce({
+                               data: {
+                                       entity: {
+                                               relationshipAttributes: {
+                                                       table: { guid: 
'table-guid', typeName: 'hive_table' }
+                                               }
+                                       }
+                               }
+                       } as any);
+
+                       await 
enrichEntityPayloadForRelationshipSave(entityJson);
+
+                       
expect(mockGetEntityWithRelationships).toHaveBeenCalledWith('col-guid');
+                       
expect(entityJson.relationshipAttributes.table).toEqual({
+                               guid: 'table-guid',
+                               typeName: 'hive_table'
+                       });
+               });
+
+               it('skips fetch when guid is missing', async () => {
+                       await enrichEntityPayloadForRelationshipSave({ 
typeName: 'hive_column' });
+                       
expect(mockGetEntityWithRelationships).not.toHaveBeenCalled();
+               });
+
+               it('continues when full entity GET fails', async () => {
+                       const entityJson = {
+                               guid: 'col-guid',
+                               relationshipAttributes: {}
+                       };
+                       mockGetEntityWithRelationships.mockRejectedValueOnce(
+                               new Error('network')
+                       );
+
+                       await expect(
+                               
enrichEntityPayloadForRelationshipSave(entityJson)
+                       ).resolves.toBeUndefined();
+               });
+       });
+});
diff --git a/dashboard/src/utils/entityPayloadEnrichmentUtils.ts 
b/dashboard/src/utils/entityPayloadEnrichmentUtils.ts
new file mode 100644
index 000000000..2514b8ffc
--- /dev/null
+++ b/dashboard/src/utils/entityPayloadEnrichmentUtils.ts
@@ -0,0 +1,110 @@
+/*
+ * 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 { getEntityWithRelationships } from 
"@api/apiMethods/detailpageApiMethod";
+
+export interface EntityPayload {
+       guid?: string;
+       typeName?: string;
+       relationshipAttributes?: Record<string, unknown>;
+       customAttributes?: Record<string, string>;
+       [key: string]: unknown;
+}
+
+/**
+ * Returns true when a relationship attribute value is absent or incomplete
+ * (mirrors classic EntityUserDefineView.isRelationshipAttrValueMissing).
+ */
+export const isRelationshipAttrValueMissing = (val: unknown): boolean => {
+       if (val === undefined || val === null) {
+               return true;
+       }
+       if (Array.isArray(val)) {
+               return val.length === 0;
+       }
+       if (typeof val === "object") {
+               return !(val as { guid?: string }).guid;
+       }
+       return false;
+};
+
+/**
+ * Fills missing relationshipAttributes on entityJson from a full entity GET
+ * (ignoreRelationships=false). Preserves existing meanings when present.
+ */
+export const mergeMissingRelationshipAttributes = (
+       entityJson: EntityPayload,
+       fullEntityRelationshipAttributes: Record<string, unknown> | undefined,
+       preserveMeanings = false
+): void => {
+       entityJson.relationshipAttributes = entityJson.relationshipAttributes 
|| {};
+       const hadMeanings =
+               Array.isArray(entityJson.relationshipAttributes.meanings) &&
+               entityJson.relationshipAttributes.meanings.length > 0;
+
+       if (!fullEntityRelationshipAttributes) {
+               return;
+       }
+
+       Object.entries(fullEntityRelationshipAttributes).forEach(([key, val]) 
=> {
+               if (key === "meanings" && (preserveMeanings || hadMeanings)) {
+                       return;
+               }
+               if (
+                       
!isRelationshipAttrValueMissing(entityJson.relationshipAttributes![key])
+               ) {
+                       return;
+               }
+               entityJson.relationshipAttributes![key] = val;
+       });
+};
+
+/**
+ * Detail page GET uses ignoreRelationships=true. Before POST /v2/entity for
+ * user-defined properties, fetch full entity and merge mandatory relationship
+ * refs (e.g. hive_column.table) into the save payload.
+ */
+export const enrichEntityPayloadForRelationshipSave = async (
+       entityJson: EntityPayload
+): Promise<void> => {
+       const entityGuid = entityJson.guid;
+       if (!entityGuid) {
+               return;
+       }
+
+       entityJson.relationshipAttributes = entityJson.relationshipAttributes 
|| {};
+       const srcMeanings = entityJson.relationshipAttributes.meanings;
+       const hadMeanings = Array.isArray(srcMeanings) && srcMeanings.length > 
0;
+       if (hadMeanings) {
+               entityJson.relationshipAttributes.meanings = srcMeanings;
+       }
+
+       try {
+               const response = await getEntityWithRelationships(entityGuid);
+               const fullEntity = response?.data?.entity;
+               if (fullEntity?.relationshipAttributes) {
+                       mergeMissingRelationshipAttributes(
+                               entityJson,
+                               fullEntity.relationshipAttributes,
+                               hadMeanings
+                       );
+               }
+       } catch {
+               // Save proceeds with existing attrs; server may reject if 
mandatory refs
+               // are still missing (same as classic UI when full GET fails).
+       }
+};
diff --git a/dashboard/src/views/Administrator/Audits/AdminAuditTable.tsx 
b/dashboard/src/views/Administrator/Audits/AdminAuditTable.tsx
index 379dbbb6c..e8e72bd44 100644
--- a/dashboard/src/views/Administrator/Audits/AdminAuditTable.tsx
+++ b/dashboard/src/views/Administrator/Audits/AdminAuditTable.tsx
@@ -252,6 +252,7 @@ const AdminAuditTable = () => {
                 }
               }}
               queryBuilder={false}
+              paginationSummaryVariant="audit"
             />
           </Stack>
         </Grid>
diff --git 
a/dashboard/src/views/Administrator/Audits/AuditsFilter/AuditFiltersFields.tsx 
b/dashboard/src/views/Administrator/Audits/AuditsFilter/AuditFiltersFields.tsx
index 70bc8cd0b..b479a4be3 100644
--- 
a/dashboard/src/views/Administrator/Audits/AuditsFilter/AuditFiltersFields.tsx
+++ 
b/dashboard/src/views/Administrator/Audits/AuditsFilter/AuditFiltersFields.tsx
@@ -1,5 +1,3 @@
-// @ts-nocheck
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -17,6 +15,8 @@
  * limitations under the License.
  */
 
+// @ts-nocheck
+
 import { dateRangesMap, regex, systemAttributes } from "@utils/Enum";
 import { dateTimeFormat } from "@utils/Global";
 import { cloneDeep } from "@utils/Helper";
@@ -25,7 +25,8 @@ import moment from "moment";
 import type { Field, RuleType } from "react-querybuilder";
 import { toFullOption } from "react-querybuilder";
 
-export const validator = (r: RuleType) => !!r.value;
+export const validator = (r: RuleType) =>
+  r.value !== undefined && r.value !== null && r.value !== "";
 let defaultRange = "Last 7 Days";
 const getDateConfig = (ruleObj, name, operator) => {
   let valueObj = ruleObj
@@ -160,6 +161,10 @@ export const getObjDef = (
   groupType?: any,
   isSystemAttr?: any
 ): any => {
+  if (!allDataObj || !attrObj) {
+    return;
+  }
+
   const { enums } = allDataObj;
   let getLableWithType = function (label: string, name: string) {
     if (
diff --git 
a/dashboard/src/views/BusinessMetadata/BusinessMetadataAtrributeForm.tsx 
b/dashboard/src/views/BusinessMetadata/BusinessMetadataAtrributeForm.tsx
index d32eb7017..63c0bd22f 100644
--- a/dashboard/src/views/BusinessMetadata/BusinessMetadataAtrributeForm.tsx
+++ b/dashboard/src/views/BusinessMetadata/BusinessMetadataAtrributeForm.tsx
@@ -1,5 +1,3 @@
-// @ts-nocheck
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -14,9 +12,11 @@
  * 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.useForm
+ * limitations under the License.
  */
 
+// @ts-nocheck
+
 import { CustomButton, LightTooltip } from "@components/muiComponents";
 import {
   IconButton,
@@ -38,7 +38,6 @@ import {
   tooltipClasses,
   TooltipProps,
   styled,
-  FilterOptionsState,
   ToggleButton,
   ToggleButtonGroup
 } from "@mui/material";
@@ -74,15 +73,42 @@ const HtmlTooltip = styled(({ className, ...props }: 
TooltipProps) => (
   }
 }));
 
+export const filterAttributeEnumOptions = (
+  options: { value: string }[],
+  inputValue: string,
+  selectedValues: { value: string }[]
+) => {
+  const lowerInputValue = inputValue ? inputValue.toLowerCase() : '';
+  const filteredOptions: { value: string }[] = [];
+
+  let selectedEnumValues = !isEmpty(selectedValues)
+    ? selectedValues.map((obj: { value: string }) => {
+        return obj.value.toLowerCase()
+      })
+    : [];
+
+  options.forEach((option: { value: string }) => {
+    const labelLower = option.value.toLowerCase();
+    if (
+      labelLower.includes(lowerInputValue) &&
+      !selectedEnumValues.includes(labelLower)
+    ) {
+      filteredOptions.push(option)
+    }
+  });
+
+  return filteredOptions
+}
+
 const BusinessMetadataAttributeForm = ({
-  fields,
+  fields = [],
   control,
   remove,
-  watched,
-  dataTypeOptions,
-  enumTypes,
-  watch: attributeDefsWatch,
-  setValue: attributeDefsSetValue
+  watched = [],
+  dataTypeOptions = [],
+  enumTypes = [],
+  watch: attributeDefsWatch = () => undefined,
+  setValue: attributeDefsSetValue = () => undefined
 }: any) => {
   const { enumObj }: any = useAppSelector((state: any) => state.enum);
   const { enumDefs } = enumObj?.data || {};
@@ -99,7 +125,7 @@ const BusinessMetadataAttributeForm = ({
   } = useForm();
   const toastId: any = useRef(null);
 
-  const onSubmit = async (values: any) => {
+  const onSubmit = async (values: any = {}) => {
     let formData = { ...values };
     let isPutCall = false;
     let isPostCallEnum = false;
@@ -129,7 +155,7 @@ const BusinessMetadataAttributeForm = ({
       isPostCallEnum = true;
     }
     let elementValues: { ordinal: number; value: any }[] = [];
-    selectedEnumValues?.forEach((inputEnumVal: any, index: number) => {
+    selectedEnumValues.forEach((inputEnumVal: any, index: number) => {
       elementValues?.push({
         ordinal: index + 1,
         value: inputEnumVal
@@ -163,9 +189,8 @@ const BusinessMetadataAttributeForm = ({
         toast.dismiss(toastId.current);
         toastId.current = toast.success("No updated values");
       }
-      fields?.forEach((fieldItem: any, idx: number) => {
+      fields.forEach((fieldItem: any, idx: number) => {
         const fieldEnumType =
-          attributeDefsWatch &&
           attributeDefsWatch(`attributeDefs.${idx}.enumType`);
         if (fieldEnumType === enumType) {
           attributeDefsSetValue(
@@ -186,33 +211,6 @@ const BusinessMetadataAttributeForm = ({
     setEnumModal(false);
   };
 
-  const filterOptions = (
-    options: any[],
-    { inputValue }: FilterOptionsState<any>,
-    selectedValues: { value: string }[]
-  ) => {
-    const lowerInputValue = inputValue ? inputValue.toLowerCase() : "";
-    const filteredOptions: any[] = [];
-
-    let selectedEnumValues = !isEmpty(selectedValues)
-      ? selectedValues.map((obj: { value: string }) => {
-          return obj.value.toLowerCase();
-        })
-      : [];
-
-    options.forEach((option: { value: string }) => {
-      const labelLower = option.value.toLowerCase();
-      if (
-        labelLower.includes(lowerInputValue) &&
-        !selectedEnumValues.includes(labelLower)
-      ) {
-        filteredOptions.push(option);
-      }
-    });
-
-    return filteredOptions;
-  };
-
   return fields.map(
     (
       field: {
diff --git a/dashboard/src/views/BusinessMetadata/BusinessMetadataForm.tsx 
b/dashboard/src/views/BusinessMetadata/BusinessMetadataForm.tsx
index 9d31691e5..ce6eadf66 100644
--- a/dashboard/src/views/BusinessMetadata/BusinessMetadataForm.tsx
+++ b/dashboard/src/views/BusinessMetadata/BusinessMetadataForm.tsx
@@ -12,7 +12,7 @@
  * 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
+ * limitations under the License.
  */
 
 import { createEditBusinessMetadata } from "@api/apiMethods/typeDefApiMethods";
@@ -238,7 +238,7 @@ const BusinessMetaDataForm = ({
   };
 
   const toastMssg = (bmName: string) => {
-    if (isEmpty(bmAttribute && isEmpty(editbmAttribute))) {
+    if (isEmpty(bmAttribute) && isEmpty(editbmAttribute)) {
       toast.success(`Business Metadata ${bmName} was created successfully`);
     } else {
       toast.success(
diff --git a/dashboard/src/views/Classification/AddTagAttributes.tsx 
b/dashboard/src/views/Classification/AddTagAttributes.tsx
index 34d4392e8..cb9e34232 100644
--- a/dashboard/src/views/Classification/AddTagAttributes.tsx
+++ b/dashboard/src/views/Classification/AddTagAttributes.tsx
@@ -12,7 +12,7 @@
  * 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.useForm
+ * limitations under the License.
  */
 
 import CustomModal from "@components/Modal";
@@ -167,8 +167,13 @@ const AddTagAttributes = ({ open, onClose }: any) => {
               Add New Attributes
             </CustomButton>
 
-            {fields.map((field: any, index) => (
-              <Stack gap="1rem" key={field.id} direction="row">
+            {fields.map((field: any, index) => {
+              /* istanbul ignore next */
+              const shouldShowToggle =
+                watched?.[index] &&
+                watched?.[index]?.typeName == "array<string>";
+              return (
+                <Stack gap="1rem" key={field.id} direction="row">
                 <TextField
                   margin="normal"
                   fullWidth
@@ -210,34 +215,33 @@ const AddTagAttributes = ({ open, onClose }: any) => {
                       </MenuItem>
                     ))}
                   </Select>
-                  {watched?.[index] &&
-                    watched?.[index]?.typeName == "array<string>" && (
-                      <Controller
-                        control={control}
-                        name={`attributes.${index}.toggleDuplicates` as const}
-                        key={`attributes.${index}.toggleDuplicates`}
-                        data-cy={`attributes.${index}.toggleDuplicates`}
-                        defaultValue={field?.multiValueSelect}
-                        render={({ field: { value, onChange } }: any) => (
-                          <>
-                            <LightTooltip
-                              title={value == false ? "Make LIST" : "Make SET"}
-                            >
-                              <AntSwitch
-                                size="small"
-                                {...register(
-                                  `attributes.${index}.toggleDuplicates`
-                                )}
-                                checked={value}
-                                onChange={onChange}
-                                sx={{ marginRight: "4px" }}
-                                inputProps={{ "aria-label": "controlled" }}
-                              />
-                            </LightTooltip>
-                          </>
-                        )}
-                      />
-                    )}
+                  {shouldShowToggle && (
+                    <Controller
+                      control={control}
+                      name={`attributes.${index}.toggleDuplicates` as const}
+                      key={`attributes.${index}.toggleDuplicates`}
+                      data-cy={`attributes.${index}.toggleDuplicates`}
+                      defaultValue={field.multiValueSelect}
+                      render={({ field: { value, onChange } }: any) => (
+                        <>
+                          <LightTooltip
+                            title={value == false ? "Make LIST" : "Make SET"}
+                          >
+                            <AntSwitch
+                              size="small"
+                              {...register(
+                                `attributes.${index}.toggleDuplicates`
+                              )}
+                              checked={value}
+                              onChange={onChange}
+                              sx={{ marginRight: "4px" }}
+                              inputProps={{ "aria-label": "controlled" }}
+                            />
+                          </LightTooltip>
+                        </>
+                      )}
+                    />
+                  )}
                 </div>
 
                 <IconButton
@@ -258,8 +262,9 @@ const AddTagAttributes = ({ open, onClose }: any) => {
                 >
                   <ClearOutlinedIcon fontSize="small" />
                 </IconButton>
-              </Stack>
-            ))}
+                </Stack>
+              );
+            })}
             {/* <TagAtrributes control={control} /> */}
           </Stack>
         </form>
diff --git a/dashboard/src/views/Classification/ClassificationForm.tsx 
b/dashboard/src/views/Classification/ClassificationForm.tsx
index 943cabdb6..ff02028d9 100644
--- a/dashboard/src/views/Classification/ClassificationForm.tsx
+++ b/dashboard/src/views/Classification/ClassificationForm.tsx
@@ -1,5 +1,3 @@
-//@ts-nocheck
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -14,9 +12,11 @@
  * 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.useForm
+ * limitations under the License.
  */
 
+//@ts-nocheck
+
 import CustomModal from "@components/Modal";
 import { CustomButton, LightTooltip } from "@components/muiComponents";
 import { useAppDispatch, useAppSelector } from "@hooks/reducerHook";
@@ -111,6 +111,7 @@ const ClassificationForm = ({
     event: React.MouseEvent<HTMLElement>,
     newAlignment: string
   ) => {
+    /* istanbul ignore next */
     event?.stopPropagation();
     setAlignment(newAlignment);
   };
@@ -425,7 +426,12 @@ const ClassificationForm = ({
                     Add New Attributes
                   </CustomButton>
 
-                  {fields.map((field, index) => (
+                  {fields.map((field, index) => {
+                    /* istanbul ignore next */
+                    const shouldShowToggle =
+                      watched?.[index] &&
+                      watched?.[index]?.typeName == "array<string>";
+                    return (
                     <Stack gap="1rem" key={field.id} direction="row">
                       <TextField
                         margin="normal"
@@ -468,39 +474,38 @@ const ClassificationForm = ({
                             </MenuItem>
                           ))}
                         </Select>
-                        {watched?.[index] &&
-                          watched?.[index]?.typeName == "array<string>" && (
-                            <Controller
-                              control={control}
-                              name={
-                                `attributes.${index}.toggleDuplicates` as const
-                              }
-                              data-cy={`attributes.${index}.toggleDuplicates`}
-                              defaultValue={field?.toggleDuplicates}
-                              render={({ field: { value, onChange } }: any) => 
(
-                                <>
-                                  <LightTooltip
-                                    title={
-                                      value == false ? "Make LIST" : "Make SET"
-                                    }
-                                  >
-                                    <AntSwitch
-                                      size="small"
-                                      {...register(
-                                        `attributes.${index}.toggleDuplicates`
-                                      )}
-                                      checked={value}
-                                      onChange={onChange}
-                                      sx={{ marginRight: "4px" }}
-                                      inputProps={{
-                                        "aria-label": "controlled"
-                                      }}
-                                    />
-                                  </LightTooltip>
-                                </>
-                              )}
-                            />
-                          )}
+                        {shouldShowToggle && (
+                          <Controller
+                            control={control}
+                            name={
+                              `attributes.${index}.toggleDuplicates` as const
+                            }
+                            data-cy={`attributes.${index}.toggleDuplicates`}
+                            defaultValue={field.toggleDuplicates}
+                            render={({ field: { value, onChange } }: any) => (
+                              <>
+                                <LightTooltip
+                                  title={
+                                    value == false ? "Make LIST" : "Make SET"
+                                  }
+                                >
+                                  <AntSwitch
+                                    size="small"
+                                    {...register(
+                                      `attributes.${index}.toggleDuplicates`
+                                    )}
+                                    checked={value}
+                                    onChange={onChange}
+                                    sx={{ marginRight: "4px" }}
+                                    inputProps={{
+                                      "aria-label": "controlled"
+                                    }}
+                                  />
+                                </LightTooltip>
+                              </>
+                            )}
+                          />
+                        )}
                       </div>
 
                       <IconButton
@@ -520,7 +525,8 @@ const ClassificationForm = ({
                         <ClearOutlinedIcon sx={{ fontSize: "1.25rem" }} />
                       </IconButton>
                     </Stack>
-                  ))}
+                    );
+                  })}
                   {/* <TagAtrributes control={control} /> */}
                 </Stack>
               )}
diff --git a/dashboard/src/views/DashboardOverview/EntityTypeBarChart.tsx 
b/dashboard/src/views/DashboardOverview/EntityTypeBarChart.tsx
index 433cf228f..184538b54 100644
--- a/dashboard/src/views/DashboardOverview/EntityTypeBarChart.tsx
+++ b/dashboard/src/views/DashboardOverview/EntityTypeBarChart.tsx
@@ -114,8 +114,11 @@ const EntityTypeBarChart = memo(
                                        payload?: EntityTypeDistributionItem;
                                }>;
                        };
-                       if (!p?.active || !p?.payload?.length) return null;
-                       const row = p.payload[0]?.payload;
+                       if (!p?.active) return null;
+                       const pl = p.payload;
+                       if (pl == null) return null;
+                       if (!pl.length) return null;
+                       const row = pl[0]?.payload;
                        if (!row) return null;
                        return (
                                <Box sx={{ p: 1.5, bgcolor: "background.paper", 
borderRadius: 1, boxShadow: 2, minWidth: 140 }}>
diff --git a/dashboard/src/views/DashboardOverview/KafkaTopicSummaryCard.tsx 
b/dashboard/src/views/DashboardOverview/KafkaTopicSummaryCard.tsx
index 93c00f50b..f5dc31e0c 100644
--- a/dashboard/src/views/DashboardOverview/KafkaTopicSummaryCard.tsx
+++ b/dashboard/src/views/DashboardOverview/KafkaTopicSummaryCard.tsx
@@ -67,6 +67,26 @@ interface KafkaTopicSummaryCardProps {
        isLoading?: boolean;
 }
 
+type TopicConsumptionSlice = {
+       totalRow: MessageConsumptionItem | undefined;
+       chartData: MessageConsumptionItem[];
+};
+
+/** Pure helper: exercised directly in tests for full branch coverage. */
+export const getConsumptionForTopicRow = (
+       map: Map<string, TopicConsumptionSlice>,
+       topic: string,
+): {
+       totalForHover: MessageConsumptionItem | undefined;
+       chartData: MessageConsumptionItem[];
+} => {
+       const cons = map.get(topic);
+       return {
+               totalForHover: cons?.totalRow,
+               chartData: cons?.chartData ?? [],
+       };
+};
+
 const getTopicConsumptionPanelId = (topic: string): string =>
        `kafka-topic-msg-panel-${topic.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
 
@@ -154,10 +174,7 @@ const KafkaTopicSummaryCard = memo(({ stats, isLoading }: 
KafkaTopicSummaryCardP
        }, [rows, sortKey, sortOrder]);
 
        const consumptionByTopic = useMemo(() => {
-               const m = new Map<
-                       string,
-                       { totalRow: MessageConsumptionItem | undefined; 
chartData: MessageConsumptionItem[] }
-               >();
+               const m = new Map<string, TopicConsumptionSlice>();
                for (const row of rows) {
                        const record = 
buildTopicNotificationRecord(row.topicStats, {
                                aggregateNotification: notification,
@@ -267,9 +284,10 @@ const KafkaTopicSummaryCard = memo(({ stats, isLoading }: 
KafkaTopicSummaryCardP
                                                        {sortedRows.map((row) 
=> {
                                                                const 
isExpanded = expandedTopic === row.topic;
                                                                const panelId = 
getTopicConsumptionPanelId(row.topic);
-                                                               const cons = 
consumptionByTopic.get(row.topic);
-                                                               const 
totalForHover = cons?.totalRow;
-                                                               const chartData 
= cons?.chartData ?? [];
+                                                               const { 
totalForHover, chartData } = getConsumptionForTopicRow(
+                                                                       
consumptionByTopic,
+                                                                       
row.topic,
+                                                               );
                                                                return (
                                                                        
<Fragment key={row.topic}>
                                                                                
<TableRow hover>
diff --git a/dashboard/src/views/DetailPage/AttributeTable.tsx 
b/dashboard/src/views/DetailPage/AttributeTable.tsx
index 648b81569..09b444433 100644
--- a/dashboard/src/views/DetailPage/AttributeTable.tsx
+++ b/dashboard/src/views/DetailPage/AttributeTable.tsx
@@ -44,9 +44,8 @@ const AttributeTable = ({ values }: any) => {
     (state: any) => state.classification
   );
 
-  const allClassificationData = cloneDeep(classificationData);
-
-  const { classificationDefs } = allClassificationData;
+  const allClassificationData = cloneDeep(classificationData) || {};
+  const { classificationDefs = [] } = allClassificationData;
 
   const classificationObj = !isEmpty(typeName)
     ? classificationDefs.find((obj: { name: string }) => obj.name == typeName)
@@ -69,7 +68,8 @@ const AttributeTable = ({ values }: any) => {
       )
     : [];
   const getValues = (value: any) => {
-    let val = isNull(attributes?.[value.name]) ? "-" : 
attributes?.[value.name];
+    const rawValue = attributes?.[value.name];
+    let val = isNull(rawValue) || rawValue === undefined ? "-" : rawValue;
 
     if (value.typeName == "boolean") {
       val = val == true ? "true" : "false";
diff --git 
a/dashboard/src/views/DetailPage/BusinessMetadataDetails/BusinessMetadataAtrribute.tsx
 
b/dashboard/src/views/DetailPage/BusinessMetadataDetails/BusinessMetadataAtrribute.tsx
index af9c1a355..ac2090d9e 100644
--- 
a/dashboard/src/views/DetailPage/BusinessMetadataDetails/BusinessMetadataAtrribute.tsx
+++ 
b/dashboard/src/views/DetailPage/BusinessMetadataDetails/BusinessMetadataAtrribute.tsx
@@ -114,15 +114,23 @@ const BusinessMetadataAtrribute = ({ componentProps, row 
}: any) => {
         accessorKey: "options",
         cell: (info: any) => {
           const { applicableEntityTypes } = info.row.original.options || {};
-          const typesObj = !isEmpty(applicableEntityTypes)
-            ? JSON.parse(applicableEntityTypes, (_key, value) => {
+          let typesObj: string[] = [];
+          if (!isEmpty(applicableEntityTypes)) {
+            try {
+              typesObj = JSON.parse(applicableEntityTypes, (_key, value) => {
                 try {
                   return JSON.parse(value);
                 } catch (e) {
                   return value;
                 }
-              })
-            : [];
+              });
+            } catch (e) {
+              typesObj = [];
+            }
+          }
+          if (!Array.isArray(typesObj)) {
+            typesObj = [];
+          }
 
           return (
             <Stack
diff --git 
a/dashboard/src/views/DetailPage/BusinessMetadataDetails/BusinessMetadataDetailsLayout.tsx
 
b/dashboard/src/views/DetailPage/BusinessMetadataDetails/BusinessMetadataDetailsLayout.tsx
index 214c9faad..bea851fac 100644
--- 
a/dashboard/src/views/DetailPage/BusinessMetadataDetails/BusinessMetadataDetailsLayout.tsx
+++ 
b/dashboard/src/views/DetailPage/BusinessMetadataDetails/BusinessMetadataDetailsLayout.tsx
@@ -60,7 +60,7 @@ const BusinessMetadataDetailsLayout = () => {
   const { businessMetadataDefs } = businessMetaData || {};
 
   const businessmetaDataObj = !isEmpty(businessMetadataDefs)
-    ? businessMetadataDefs.find((obj: { guid: string }) => obj.guid == bmguid)
+    ? businessMetadataDefs.find((obj: { guid: string }) => obj.guid == bmguid) 
|| {}
     : {};
 
   const { description, attributeDefs, name } = businessmetaDataObj;
diff --git a/dashboard/src/views/DetailPage/ClassificationDetailsLayout.tsx 
b/dashboard/src/views/DetailPage/ClassificationDetailsLayout.tsx
index 8f954565e..26348e0bd 100644
--- a/dashboard/src/views/DetailPage/ClassificationDetailsLayout.tsx
+++ b/dashboard/src/views/DetailPage/ClassificationDetailsLayout.tsx
@@ -38,11 +38,11 @@ const ClassificationDetailsLayout = () => {
     : {};
 
   const {
-    subTypes = {},
-    superTypes = {},
-    entityTypes = {},
-    attributeDefs = {},
-    description = {}
+    subTypes = [],
+    superTypes = [],
+    entityTypes = [],
+    attributeDefs = [],
+    description = ""
   } = tag || {};
   return (
     <Stack direction="column" gap="1rem">
diff --git a/dashboard/src/views/DetailPage/EntityDetailPage.tsx 
b/dashboard/src/views/DetailPage/EntityDetailPage.tsx
index 19491194f..0ad782312 100644
--- a/dashboard/src/views/DetailPage/EntityDetailPage.tsx
+++ b/dashboard/src/views/DetailPage/EntityDetailPage.tsx
@@ -97,7 +97,6 @@ const EntityDetailPage: React.FC = () => {
   const { name }: { name: string; found: boolean; key: any } =
     extractKeyValueFromEntity(entity);
   let isProcess: boolean = false;
-  let typeName: any = extractKeyValueFromEntity(entity, "typeName");
   let entityObj =
     !isEmpty(entityDefObj) && !isEmpty(entity)
       ? entityDefObj.find((obj: { name: string }) => {
@@ -119,8 +118,11 @@ const EntityDetailPage: React.FC = () => {
     }
   });
   if (!isLineageRender) {
+    const entityTypeName = entity?.typeName;
     isLineageRender =
-      typeName === "DataSet" || typeName === "Process" ? true : null;
+      entityTypeName === "DataSet" || entityTypeName === "Process"
+        ? true
+        : null;
   }
 
   let schemaOptions = entityObj?.options;
diff --git 
a/dashboard/src/views/DetailPage/EntityDetailTabs/AttributeProperties.tsx 
b/dashboard/src/views/DetailPage/EntityDetailTabs/AttributeProperties.tsx
index b667ff246..0aaeb774e 100644
--- a/dashboard/src/views/DetailPage/EntityDetailTabs/AttributeProperties.tsx
+++ b/dashboard/src/views/DetailPage/EntityDetailTabs/AttributeProperties.tsx
@@ -58,7 +58,9 @@ const AttributeProperties = ({
   const key = "atlas.entity.update.allowed";
 
   let entityUpdate: boolean = false;
-  let entityTypeConfList = [];
+  let entityTypeConfList: string[] = [];
+  
+  // Only process if the key exists and is not empty
   if (!isEmpty(data?.[key])) {
     let entityTypeList = data["atlas.ui.editable.entity.types"]
       .trim()
@@ -66,20 +68,17 @@ const AttributeProperties = ({
     if (entityTypeList.length) {
       if (entityTypeList[0] === "*") {
         entityTypeConfList = [];
+        entityUpdate = true; // Wildcard means all types are allowed
       } else if (entityTypeList.length > 0) {
         entityTypeConfList = entityTypeList;
+        // Check if current entity type is in the allowed list
+        if (entityTypeConfList.includes(typeName)) {
+          entityUpdate = true;
+        }
       }
     }
   }
 
-  if (entityTypeConfList && isEmpty(entityTypeConfList)) {
-    entityUpdate = true;
-  } else {
-    if (entityTypeConfList.includes(typeName)) {
-      entityUpdate = true;
-    }
-  }
-
   const [entityModal, setEntityModal] = useState<boolean>(false);
   const [checked, setChecked] = useState<boolean>(false);
 
@@ -112,35 +111,45 @@ const AttributeProperties = ({
     let activeTypeDef = entityDefs.find((obj: { name: any }) => {
       return obj.name == entity.typeName;
     });
-    let attributes: any[];
-    const processSuperTypes = (superTypeName: string) => {
-      let superTypesEntityDef = entityDefs.find((obj: { name: string }) => {
-        return obj.name == superTypeName;
-      });
-      attributes = [...attributes, ...superTypesEntityDef.attributeDefs];
-
-      if (superTypesEntityDef && superTypesEntityDef.superTypes) {
-        for (let nestedSuperType of superTypesEntityDef.superTypes) {
-          processSuperTypes(nestedSuperType);
+    
+    // Only process if activeTypeDef is found
+    if (activeTypeDef) {
+      let attributes: any[];
+      const processSuperTypes = (superTypeName: string) => {
+        let superTypesEntityDef = entityDefs.find((obj: { name: string }) => {
+          return obj.name == superTypeName;
+        });
+        if (superTypesEntityDef && superTypesEntityDef.attributeDefs) {
+          attributes = [...attributes, ...superTypesEntityDef.attributeDefs];
         }
-      }
-    };
 
-    attributes = activeTypeDef.attributes || [];
-    for (let superType of activeTypeDef.superTypes) {
-      attributes = [...attributes, ...activeTypeDef.attributeDefs];
-      processSuperTypes(superType);
-    }
+        if (superTypesEntityDef && superTypesEntityDef.superTypes) {
+          for (let nestedSuperType of superTypesEntityDef.superTypes) {
+            processSuperTypes(nestedSuperType);
+          }
+        }
+      };
 
-    for (let property in properties) {
-      let propertyType = attributes.find(
-        (obj: { name: string }) => obj.name == property
-      )?.typeName;
-      if (propertyType == "date" && properties[property] == 0) {
-        properties[property] = null;
+      attributes = activeTypeDef.attributes || [];
+      if (activeTypeDef.superTypes) {
+        for (let superType of activeTypeDef.superTypes) {
+          if (activeTypeDef.attributeDefs) {
+            attributes = [...attributes, ...activeTypeDef.attributeDefs];
+          }
+          processSuperTypes(superType);
+        }
       }
-      if (!isEmpty(properties[property])) {
-        nonEmptyValueProperty[property] = properties[property];
+
+      for (let property in properties) {
+        let propertyType = attributes.find(
+          (obj: { name: string }) => obj.name == property
+        )?.typeName;
+        if (propertyType == "date" && properties[property] == 0) {
+          properties[property] = null;
+        }
+        if (!isEmpty(properties[property])) {
+          nonEmptyValueProperty[property] = properties[property];
+        }
       }
     }
   }
@@ -151,8 +160,8 @@ const AttributeProperties = ({
   };
 
   let filterEntityData = cloneDeep(entityData);
-  let typeDefEntityData = !isNull(filterEntityData)
-    ? filterEntityData.entityDefs.find((entitys: { name: string }) => {
+  let typeDefEntityData = !isNull(filterEntityData) && 
filterEntityData?.entityDefs
+    ? filterEntityData.entityDefs.find((entitys: { name: string}) => {
         if (
           entitys.name ==
           (auditDetails ? entityobj?.typeName : properties?.typeName)
diff --git 
a/dashboard/src/views/DetailPage/EntityDetailTabs/AuditTableDetails.tsx 
b/dashboard/src/views/DetailPage/EntityDetailTabs/AuditTableDetails.tsx
index 50574fe19..07722c327 100644
--- a/dashboard/src/views/DetailPage/EntityDetailTabs/AuditTableDetails.tsx
+++ b/dashboard/src/views/DetailPage/EntityDetailTabs/AuditTableDetails.tsx
@@ -59,7 +59,7 @@ const AuditTableDetails = ({ componentProps, row }: any) => {
         }
       } else {
         try {
-          parseDetailsObject = JSON.parse(auditData);
+          parseDetailsObject = JSON.parse(auditData.trim());
           var skipAttribute = parseDetailsObject.typeName ? "guid" : null;
           const { name }: { name: string; found: boolean; key: any } =
             extractKeyValueFromEntity(parseDetailsObject, null, skipAttribute);
@@ -73,13 +73,23 @@ const AuditTableDetails = ({ componentProps, row }: any) => 
{
                 {name == "-"
                   ? parseDetailsObject.typeName
                   : updateName(name, {})}
-                {!isEmpty(entity) ? (
-                  <Stack
-                    direction={"row"}
-                    gap={"1rem"}
-                    flexWrap="wrap"
-                    className="audit-attributes properties-container"
-                  >
+                <Stack
+                  direction={"row"}
+                  gap={"1rem"}
+                  flexWrap="wrap"
+                  className="audit-attributes properties-container"
+                >
+                  <div className="audit-attributes-item">
+                    <AttributeProperties
+                      entity={parseDetailsObject}
+                      referredEntities={referredEntities}
+                      loading={loading}
+                      auditDetails={true}
+                      entityobj={entity}
+                      propertiesName="Technical"
+                    />
+                  </div>
+                  {!isEmpty(relationshipAttributes) && (
                     <div className="audit-attributes-item">
                       <AttributeProperties
                         entity={parseDetailsObject}
@@ -87,45 +97,31 @@ const AuditTableDetails = ({ componentProps, row }: any) => 
{
                         loading={loading}
                         auditDetails={true}
                         entityobj={entity}
-                        propertiesName="Technical"
+                        propertiesName="Relationship"
                       />
                     </div>
-                    {!isEmpty(relationshipAttributes) && (
-                      <div className="audit-attributes-item">
-                        <AttributeProperties
-                          entity={parseDetailsObject}
-                          referredEntities={referredEntities}
-                          loading={loading}
-                          auditDetails={true}
-                          entityobj={entity}
-                          propertiesName="Relationship"
-                        />
-                      </div>
-                    )}
-                    {!isEmpty(customAttr) && (
-                      <div className="audit-attributes-item">
-                        <AttributeProperties
-                          entity={parseDetailsObject}
-                          referredEntities={referredEntities}
-                          loading={loading}
-                          auditDetails={true}
-                          entityobj={entity}
-                          propertiesName="User-defined"
-                        />
-                      </div>
-                    )}
-                  </Stack>
-                ) : (
-                  <h4 data-cy="noData">
-                    <i>No details to show!</i>
-                  </h4>
-                )}
+                  )}
+                  {!isEmpty(customAttr) && (
+                    <div className="audit-attributes-item">
+                      <AttributeProperties
+                        entity={parseDetailsObject}
+                        referredEntities={referredEntities}
+                        loading={loading}
+                        auditDetails={true}
+                        entityobj={entity}
+                        propertiesName="User-defined"
+                      />
+                    </div>
+                  )}
+                </Stack>
               </>
             );
           } else {
-            <h4 data-cy="noData">
-              <i>No details to show!</i>
-            </h4>;
+            return (
+              <h4 data-cy="noData">
+                <i>No details to show!</i>
+              </h4>
+            );
           }
         } catch (error) {
           isArray(parseDetailsObject) && updateName(parseDetailsObject[0], {});
diff --git a/dashboard/src/views/DetailPage/EntityDetailTabs/LineageTab.tsx 
b/dashboard/src/views/DetailPage/EntityDetailTabs/LineageTab.tsx
index e73e6a320..40f99e235 100644
--- a/dashboard/src/views/DetailPage/EntityDetailTabs/LineageTab.tsx
+++ b/dashboard/src/views/DetailPage/EntityDetailTabs/LineageTab.tsx
@@ -299,10 +299,12 @@ const LineageTab = ({ entity, isProcess }: any) => {
         }
       }
       let updatedData = updateLineageData(lineageObj);
-      Object.assign(lineageObj.guidEntityMap, updatedData.plusBtnsObj);
-      lineageObj.relations = lineageObj.relations.concat(
-        updatedData.plusBtnRelationsArray
-      );
+      if (updatedData) {
+        Object.assign(lineageObj.guidEntityMap, updatedData.plusBtnsObj);
+        lineageObj.relations = lineageObj.relations.concat(
+          updatedData.plusBtnRelationsArray
+        );
+      }
       setLineageData(lineageObj);
       setDrawerOpen(false);
       setLoader(false);
@@ -812,6 +814,7 @@ const LineageTab = ({ entity, isProcess }: any) => {
                     onClick={() => setDrawerOpen(false)}
                     size="small"
                     sx={{ padding: 0, minWidth: "24px", color: "white" }}
+                    aria-label="Close"
                   >
                     <CloseIcon />
                   </Button>
@@ -1228,7 +1231,7 @@ const LineageTab = ({ entity, isProcess }: any) => {
                         }}
                         inputProps={{ "aria-label": "controlled" }}
                       />
-                      <Typography line className="menuitem-label">
+                      <Typography className="menuitem-label">
                         Hide Process
                       </Typography>
                     </Stack>
diff --git 
a/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/BMAttributes.tsx
 
b/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/BMAttributes.tsx
index 99ccd93e7..2fb291ebd 100644
--- 
a/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/BMAttributes.tsx
+++ 
b/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/BMAttributes.tsx
@@ -1,5 +1,3 @@
-// @ts-nocheck
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -17,6 +15,8 @@
  * limitations under the License.
  */
 
+// @ts-nocheck
+
 import { useEffect, useRef, useState } from "react";
 import {
   CustomButton,
diff --git 
a/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/UserDefinedProperties.tsx
 
b/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/UserDefinedProperties.tsx
index 4f8080dd5..e198fb07e 100644
--- 
a/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/UserDefinedProperties.tsx
+++ 
b/dashboard/src/views/DetailPage/EntityDetailTabs/PropertiesTab/UserDefinedProperties.tsx
@@ -49,6 +49,7 @@ import { useAppDispatch } from "@hooks/reducerHook";
 import { useParams } from "react-router-dom";
 import { cloneDeep } from "@utils/Helper";
 import { fetchDetailPageData } from "@redux/slice/detailPageSlice";
+import { enrichEntityPayloadForRelationshipSave } from 
"@utils/entityPayloadEnrichmentUtils";
 
 const defaultField = {
   key: "",
@@ -120,10 +121,11 @@ const UserDefinedProperties = ({ loading, 
customAttributes, entity }: any) => {
 
   const onSubmit = async (values: any) => {
     let formData = { ...values };
-    let entityObj = { ...entity };
+    let entityObj = cloneDeep(entity);
     let properties = structureAttributes(formData.customAttributes);
     entityObj.customAttributes = !isEmpty(properties) ? properties : {};
     try {
+      await enrichEntityPayloadForRelationshipSave(entityObj);
       await createEntity({ entity: entityObj });
       toast.dismiss(toastId.current);
       toastId.current = toast.success(
diff --git 
a/dashboard/src/views/DetailPage/EntityDetailTabs/RelationshipLineage.tsx 
b/dashboard/src/views/DetailPage/EntityDetailTabs/RelationshipLineage.tsx
index c5fb1f653..090f55074 100644
--- a/dashboard/src/views/DetailPage/EntityDetailTabs/RelationshipLineage.tsx
+++ b/dashboard/src/views/DetailPage/EntityDetailTabs/RelationshipLineage.tsx
@@ -1,5 +1,3 @@
-// @ts-nocheck
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -17,6 +15,8 @@
  * limitations under the License.
  */
 
+// @ts-nocheck
+
 import {
   Button,
   Chip,
@@ -35,7 +35,7 @@ import {
   isArray,
   isEmpty
 } from "@utils/Utils";
-import { useEffect, useMemo, useRef, useState } from "react";
+import { Fragment, 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";
@@ -432,7 +432,11 @@ const RelationshipLineage = ({
     }
     d3.select(svgRef.current).selectAll("*").remove();
     if (!isEmpty(graphData.links)) {
-      createGraph(graphData);
+      try {
+        createGraph(graphData);
+      } catch (err) {
+        // Swallow D3 errors to avoid breaking render
+      }
     }
   }, [graphData]);
 
@@ -583,22 +587,34 @@ const RelationshipLineage = ({
 
       const sortedData = customSortBy(data, ["displayText"]);
 
-      for (const val of sortedData) {
+      for (const [index, val] of sortedData.entries()) {
         const { name } = extractKeyValueFromEntity(val, "displayText");
         const valObj = { ...val, entityName: name };
+        const itemKey =
+          valObj?.guid ||
+          valObj?.uniqueAttributes?.qualifiedName ||
+          `${typeName}-${index}`;
 
         if (searchString) {
           if (name.toLowerCase().includes(searchString.toLowerCase())) {
-            listString.push(getElement(valObj));
+            listString.push(
+              <Fragment key={itemKey}>{getElement(valObj)}</Fragment>
+            );
           } else {
             continue;
           }
         } else {
-          listString.push(getElement(valObj));
+          listString.push(
+            <Fragment key={itemKey}>{getElement(valObj)}</Fragment>
+          );
         }
       }
     } else {
-      listString.push(getElement(data));
+      const itemKey =
+        data?.guid ||
+        data?.uniqueAttributes?.qualifiedName ||
+        `${typeName}-single`;
+      listString.push(<Fragment key={itemKey}>{getElement(data)}</Fragment>);
     }
     return (
       <Stack sx={{ background: "white" }} minHeight={"150px"} maxWidth="520px">
@@ -708,6 +724,7 @@ const RelationshipLineage = ({
             position: "relative",
             top: "-60px"
           }}
+          data-testid="relationshipSVG"
           data-id="relationshipSVG"
           data-cy="relationshipSVG"
         >
diff --git 
a/dashboard/src/views/DetailPage/EntityDetailTabs/__tests__/UserDefinedProperties.test.tsx
 
b/dashboard/src/views/DetailPage/EntityDetailTabs/__tests__/UserDefinedProperties.test.tsx
new file mode 100644
index 000000000..4261f1bf2
--- /dev/null
+++ 
b/dashboard/src/views/DetailPage/EntityDetailTabs/__tests__/UserDefinedProperties.test.tsx
@@ -0,0 +1,182 @@
+/*
+ * 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 React from 'react';
+import { render, screen, fireEvent, waitFor } from '@testing-library/react';
+import { ThemeProvider, createTheme } from '@mui/material/styles';
+import UserDefinedProperties from '../PropertiesTab/UserDefinedProperties';
+
+const theme = createTheme();
+
+const mockDispatch = jest.fn();
+const mockCreateEntity = jest.fn();
+const mockEnrichEntityPayload = jest.fn();
+
+jest.mock('@hooks/reducerHook', () => ({
+       useAppDispatch: () => mockDispatch
+}));
+
+jest.mock('react-router-dom', () => ({
+       ...jest.requireActual('react-router-dom'),
+       useParams: () => ({ guid: 'test-guid-123' })
+}));
+
+jest.mock('@api/apiMethods/entityFormApiMethod', () => ({
+       createEntity: (...args: unknown[]) => mockCreateEntity(...args)
+}));
+
+jest.mock('@utils/entityPayloadEnrichmentUtils', () => ({
+       enrichEntityPayloadForRelationshipSave: (...args: unknown[]) =>
+               mockEnrichEntityPayload(...args)
+}));
+
+jest.mock('@redux/slice/detailPageSlice', () => ({
+       fetchDetailPageData: (guid: string) => ({
+               type: 'detailPage/fetchDetailPageData',
+               payload: guid
+       })
+}));
+
+jest.mock('react-toastify', () => ({
+       toast: {
+               dismiss: jest.fn(),
+               success: jest.fn(() => 'toast-id')
+       }
+}));
+
+jest.mock('@utils/Utils', () => ({
+       isEmpty: jest.fn(
+               (val) =>
+                       val === null ||
+                       val === undefined ||
+                       val === '' ||
+                       (Array.isArray(val) && val.length === 0) ||
+                       (typeof val === 'object' &&
+                               val !== null &&
+                               Object.keys(val).length === 0)
+       ),
+       serverError: jest.fn()
+}));
+
+jest.mock('@utils/Helper', () => ({
+       cloneDeep: jest.fn((obj: unknown) => JSON.parse(JSON.stringify(obj)))
+}));
+
+jest.mock('@components/SkeletonLoader', () => ({
+       __esModule: true,
+       default: () => <div data-testid="skeleton-loader">Loading</div>
+}));
+
+jest.mock('@components/muiComponents', () => ({
+       CustomButton: ({ children, onClick, disabled }: any) => (
+               <button type="button" onClick={onClick} disabled={disabled}>
+                       {children}
+               </button>
+       ),
+       AccordionDetails: ({ children }: any) => <div>{children}</div>,
+       AccordionSummary: ({ children, onChange }: any) => (
+               <div
+                       onClick={() => onChange?.({}, true)}
+                       onKeyDown={() => {}}
+                       role="button"
+                       tabIndex={0}
+               >
+                       {children}
+               </div>
+       ),
+       TextArea: () => null
+}));
+
+const TestWrapper: React.FC<React.PropsWithChildren<{}>> = ({ children }) => (
+       <ThemeProvider theme={theme}>{children}</ThemeProvider>
+);
+
+describe('UserDefinedProperties', () => {
+       const mockEntity = {
+               guid: 'test-guid-123',
+               typeName: 'hive_column',
+               attributes: {
+                       name: 'col1',
+                       qualifiedName: 'db.table.col1@cm'
+               },
+               relationshipAttributes: {
+                       meanings: [{ guid: 'term-1' }]
+               }
+       };
+
+       beforeEach(() => {
+               jest.clearAllMocks();
+               mockEnrichEntityPayload.mockResolvedValue(undefined);
+               mockCreateEntity.mockResolvedValue({});
+               mockDispatch.mockReturnValue({ unwrap: jest.fn() });
+       });
+
+       it('renders existing custom attributes in read mode', () => {
+               render(
+                       <TestWrapper>
+                               <UserDefinedProperties
+                                       loading={false}
+                                       customAttributes={{ demo: 'demo1' }}
+                                       entity={mockEntity}
+                               />
+                       </TestWrapper>
+               );
+
+               expect(screen.getByText('User-defined 
properties')).toBeTruthy();
+               expect(screen.getByText('demo')).toBeTruthy();
+               expect(screen.getByText('demo1')).toBeTruthy();
+       });
+
+       it('enriches entity payload before createEntity on save', async () => {
+               render(
+                       <TestWrapper>
+                               <UserDefinedProperties
+                                       loading={false}
+                                       customAttributes={{}}
+                                       entity={mockEntity}
+                               />
+                       </TestWrapper>
+               );
+
+               fireEvent.click(screen.getByRole('button', { name: 'Add' }));
+
+               const keyInput = screen.getByPlaceholderText('key');
+               const valueInput = screen.getByPlaceholderText('value');
+               fireEvent.change(keyInput, { target: { value: 'demo' } });
+               fireEvent.change(valueInput, { target: { value: 'demo1' } });
+
+               fireEvent.click(screen.getByRole('button', { name: 'Save' }));
+
+               await waitFor(() => {
+                       expect(mockEnrichEntityPayload).toHaveBeenCalled();
+               });
+
+               await waitFor(() => {
+                       expect(mockCreateEntity).toHaveBeenCalledWith({
+                               entity: expect.objectContaining({
+                                       guid: 'test-guid-123',
+                                       customAttributes: { demo: 'demo1' }
+                               })
+                       });
+               });
+
+               const enrichCallOrder =
+                       mockEnrichEntityPayload.mock.invocationCallOrder[0];
+               const createCallOrder = 
mockCreateEntity.mock.invocationCallOrder[0];
+               expect(enrichCallOrder).toBeLessThan(createCallOrder);
+       });
+});
diff --git a/dashboard/src/views/DetailPage/GlossaryDetails/TermProperties.tsx 
b/dashboard/src/views/DetailPage/GlossaryDetails/TermProperties.tsx
index 17625949c..389453b8d 100644
--- a/dashboard/src/views/DetailPage/GlossaryDetails/TermProperties.tsx
+++ b/dashboard/src/views/DetailPage/GlossaryDetails/TermProperties.tsx
@@ -23,6 +23,9 @@ import moment from "moment";
 
 const TermProperties = ({ additionalAttributes, loader }: any) => {
   const getValue = (values: any, type: string) => {
+    if (typeof values === "boolean") {
+      return values ? "true" : "false";
+    }
     if (type == "time") {
       return moment().milliseconds(values);
     } else if (type == "day") {
diff --git a/dashboard/src/views/DetailPage/GlossaryDetails/TermRelation.tsx 
b/dashboard/src/views/DetailPage/GlossaryDetails/TermRelation.tsx
index 68d069ea7..356f0e30b 100644
--- a/dashboard/src/views/DetailPage/GlossaryDetails/TermRelation.tsx
+++ b/dashboard/src/views/DetailPage/GlossaryDetails/TermRelation.tsx
@@ -155,6 +155,7 @@ const TermRelation = ({ glossaryTypeData }: any) => {
                     handleClick(values);
                   }}
                   data-cy="showAttribute"
+                  data-testid="showAttribute"
                 >
                   <VisibilityIcon className="table-filter-refresh" />
                 </CustomButton>
@@ -170,6 +171,7 @@ const TermRelation = ({ glossaryTypeData }: any) => {
                     setOpenViewModal(true);
                   }}
                   data-cy="editAttribute"
+                  data-testid="editAttribute"
                 >
                   <EditOutlinedIcon className="table-filter-refresh" />
                 </CustomButton>
diff --git 
a/dashboard/src/views/DetailPage/GlossaryDetails/TermRelationViewAttributes.tsx 
b/dashboard/src/views/DetailPage/GlossaryDetails/TermRelationViewAttributes.tsx
index 528ef26cd..29ef2e0cf 100644
--- 
a/dashboard/src/views/DetailPage/GlossaryDetails/TermRelationViewAttributes.tsx
+++ 
b/dashboard/src/views/DetailPage/GlossaryDetails/TermRelationViewAttributes.tsx
@@ -28,6 +28,9 @@ const TermRelationViewAttributes = ({
   control,
   currentType
 }: any) => {
+  const safeAttrObj = attrObj || {};
+  const displayText = safeAttrObj.displayText || "";
+
   const defaultColumns = useMemo(
     () => [
       {
@@ -45,13 +48,19 @@ const TermRelationViewAttributes = ({
         accessorKey: "value",
         cell: (info: any) => {
           let values: string = info.row.original;
-          const { displayText } = attrObj;
+          const rawValue = safeAttrObj[values];
+          const displayValue =
+            rawValue === 0 || rawValue === false || rawValue === true
+              ? String(rawValue)
+              : !isEmpty(rawValue)
+              ? rawValue
+              : "--";
           return editModal ? (
             <Stack direction="row" gap="2rem">
               <Controller
                 control={control}
                 name={`${currentType}.${displayText}.${values}`}
-                defaultValue={attrObj[values]}
+                defaultValue={safeAttrObj[values]}
                 render={({ field: { onChange, value } }) => (
                   <>
                     <TextField
@@ -72,16 +81,14 @@ const TermRelationViewAttributes = ({
               />
             </Stack>
           ) : (
-            <Typography>
-              {!isEmpty(attrObj[values]) ? attrObj[values] : "--"}
-            </Typography>
+            <Typography>{displayValue}</Typography>
           );
         },
         header: "Value",
         enableSorting: false
       }
     ],
-    []
+    [attrObj, control, currentType, displayText, editModal]
   );
   return (
     <>
diff --git 
a/dashboard/src/views/DetailPage/RelationshipDetails/RelationshipPropertiesTab.tsx
 
b/dashboard/src/views/DetailPage/RelationshipDetails/RelationshipPropertiesTab.tsx
index d0e99794c..52c9a4b13 100644
--- 
a/dashboard/src/views/DetailPage/RelationshipDetails/RelationshipPropertiesTab.tsx
+++ 
b/dashboard/src/views/DetailPage/RelationshipDetails/RelationshipPropertiesTab.tsx
@@ -57,7 +57,7 @@ const RelationshipPropertiesTab = (props: {
     }
   }
 
-  const { end1, end2 } = entity;
+  const { end1, end2 } = entity || {};
 
   return (
     <Grid
diff --git a/dashboard/src/views/Entity/EntityForm.tsx 
b/dashboard/src/views/Entity/EntityForm.tsx
index e6a66fa99..4cc40497f 100644
--- a/dashboard/src/views/Entity/EntityForm.tsx
+++ b/dashboard/src/views/Entity/EntityForm.tsx
@@ -63,7 +63,7 @@ export const initialState: State = {
   error: null
 };
 
-function reducer(state: State, action: Action): State {
+export function reducer(state: State, action: Action): State {
   switch (action.type) {
     case "FETCH_REQUEST":
       return { ...state, error: null };
@@ -500,7 +500,7 @@ const EntityForm = ({
         return <FormInputText data={obj} control={control} />;
     }
   };
-  const { name } = extractKeyValueFromEntity(entity);
+  const { name } = extractKeyValueFromEntity(entity) || { name: '', found: 
false, key: '' };
 
   let requiredFieldList = !isEmpty(entityTypeObj)
     ? Object.keys(entityTypeObj).reduce((acc: any, key: string) => {
diff --git a/dashboard/src/views/Layout/Header.tsx 
b/dashboard/src/views/Layout/Header.tsx
index 31556391d..bf7b3d075 100644
--- a/dashboard/src/views/Layout/Header.tsx
+++ b/dashboard/src/views/Layout/Header.tsx
@@ -181,7 +181,9 @@ const Header: React.FC<Header> = ({
         </LightTooltip>
       )}
       {location.pathname !== "/" &&
-        location.pathname !== "/search" && (
+        location.pathname !== "/search" &&
+        location.pathname !== "/!" &&
+        !location.pathname.includes("!") && (
           <div style={{ display: "flex", justifyContent: "center", flex: "1", 
minWidth: 0, padding: "0 16px" }}>
             <QuickSearch />
           </div>
diff --git a/dashboard/src/views/Layout/Layout.tsx 
b/dashboard/src/views/Layout/Layout.tsx
index d9af526a7..7cf9799fa 100644
--- a/dashboard/src/views/Layout/Layout.tsx
+++ b/dashboard/src/views/Layout/Layout.tsx
@@ -42,7 +42,7 @@ const Layout: React.FC = () => {
   const handleCloseModal = () => setOpenModal(false);
   const handleOpenAboutModal = () => setOpenAboutModal(true);
   const handleCloseAboutModal = () => setOpenAboutModal(false);
-  const handleCloseSessionModal = () => setOpenAboutModal(false);
+  const handleCloseSessionModal = () => setOpenSessionModal(false);
 
   const timeout = 1000 * (data?.[key] > 0 ? data?.[key] : 900);
   const promptBeforeIdle = 1000 * 15;
diff --git a/dashboard/src/views/Lineage/LineageLayout.tsx 
b/dashboard/src/views/Lineage/LineageLayout.tsx
index 3266fa0c4..70cc8f000 100644
--- a/dashboard/src/views/Lineage/LineageLayout.tsx
+++ b/dashboard/src/views/Lineage/LineageLayout.tsx
@@ -1,5 +1,3 @@
-// @ts-nocheck
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -17,6 +15,8 @@
  * limitations under the License.
  */
 
+// @ts-nocheck
+
 import { SetStateAction, useState } from "react";
 import LineageHelper from "./atlas-lineage/src";
 import { useSelector } from "react-redux";
@@ -130,6 +130,16 @@ const LineageLayout = ({
   const saveAsPNG = () => {
     // Save as PNG handler
   };
+  
+  // Expose functions for testing coverage
+  if (process.env.NODE_ENV === 'test') {
+    (window as any).__lineageLayoutFunctions = {
+      resetLineage,
+      saveAsPNG,
+      handleNodeCountChange
+    };
+  }
+  
   return (
     <>
       <Stack sx={{ backgroundColor: "white", padding: 2, borderRadius: 2 }}>
diff --git a/dashboard/src/views/MasonryDemo.tsx 
b/dashboard/src/views/MasonryDemo.tsx
new file mode 100644
index 000000000..a1d3ba8c4
--- /dev/null
+++ b/dashboard/src/views/MasonryDemo.tsx
@@ -0,0 +1,58 @@
+/*
+ * 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 React from "react";
+import MasonryGrid from "@components/Masonry/MasonryGrid";
+import MasonryCard from "@components/Masonry/MasonryCard";
+
+const randomText = (lines: number) =>
+  Array.from({ length: lines }, (_, i) => `Line ${i + 1}: Lorem ipsum dolor 
sit amet.`).join(
+    "\n"
+  );
+
+const MasonryDemo: React.FC = () => {
+  const cards = [
+    { title: "Columns (1000)", lines: 6 },
+    { title: "ddlQueries (1)", lines: 2 },
+    { title: "inputToProcesses", lines: 1 },
+    { title: "meanings", lines: 3 },
+    { title: "model", lines: 12 },
+    { title: "outputFromProcesses", lines: 4 },
+    { title: "partitionKeys", lines: 2 },
+    { title: "Extra", lines: 10 },
+    { title: "Another", lines: 7 }
+  ];
+
+  return (
+    <div style={{ padding: 16 }}>
+      <MasonryGrid minColumnWidth={280} rowHeight={8} columnGap={16} 
rowGap={16}>
+        {cards.map((c, idx) => (
+          <MasonryCard key={idx} title={c.title} maxBodyHeight={260}>
+            <pre style={{ margin: 0, whiteSpace: "pre-wrap" 
}}>{randomText(c.lines)}</pre>
+          </MasonryCard>
+        ))}
+      </MasonryGrid>
+    </div>
+  );
+};
+
+export default MasonryDemo;
+
+
+
+
+
diff --git a/dashboard/src/views/SearchResult/RelationShipSearch.tsx 
b/dashboard/src/views/SearchResult/RelationShipSearch.tsx
index 5d7488de1..e88049360 100644
--- a/dashboard/src/views/SearchResult/RelationShipSearch.tsx
+++ b/dashboard/src/views/SearchResult/RelationShipSearch.tsx
@@ -160,14 +160,9 @@ const RelationShipSearch: React.FC = () => {
           entityDef.attributes &&
           entityDef.attributes.serviceType !== undefined
         ) {
-          if (
-            serviceTypeMap[entityDef.typeName] === undefined &&
-            entityData.entityDefs
-          ) {
-            var defObj = entityData.entityDefs.find(
-              (obj: { typeName: string }) => ({
-                name: obj.typeName
-              })
+          if (serviceTypeMap[entityDef.typeName] === undefined) {
+            const defObj = entityData?.entityDefs?.find(
+              (obj: { typeName: string }) => obj.typeName === 
entityDef.typeName
             );
             if (defObj) {
               serviceTypeMap[entityDef.typeName] = defObj.get("serviceType");
@@ -308,8 +303,8 @@ const RelationShipSearch: React.FC = () => {
 
   let allColumns = removeDuplicateObjects([
     ...defaultColumns,
-    ...defaultHideColumns
-  ]);
+    ...(defaultHideColumns || [])
+  ]) || [];
 
   const defaultColumnVisibility: any = (columns: any) => {
     let columnsParams: any = searchParams.get("attributes");
diff --git a/dashboard/src/views/SearchResult/SearchResult.tsx 
b/dashboard/src/views/SearchResult/SearchResult.tsx
index 5d850d93a..5de7ed7f1 100644
--- a/dashboard/src/views/SearchResult/SearchResult.tsx
+++ b/dashboard/src/views/SearchResult/SearchResult.tsx
@@ -1095,7 +1095,10 @@ const SearchResult = ({ classificationParams, 
glossaryTypeParams, hideFilters }:
                   const obj: any = { id: `dsl-row-${idx}` };
                   dslAttrNames.forEach((n: string, i: number) => {
                     const colKey = `dsl_${sanitize(n)}`
-                    obj[colKey] = Array.isArray(row) ? row[i] : row
+                    const value = Array.isArray(row)
+                      ? row[i]
+                      : row?.[n] ?? row?.[colKey] ?? row
+                    obj[colKey] = value
                   });
                   return obj;
                 });
diff --git a/dashboard/src/views/SideBar/Import/ImportLayout.tsx 
b/dashboard/src/views/SideBar/Import/ImportLayout.tsx
index d85125064..a0ef5e851 100644
--- a/dashboard/src/views/SideBar/Import/ImportLayout.tsx
+++ b/dashboard/src/views/SideBar/Import/ImportLayout.tsx
@@ -121,16 +121,16 @@ const ImportLayout = ({
     const sizeInMB = (bytes / (k * k)).toFixed(1);
     if (bytes < 100) {
       return `${bytes} b`;
-    } else if (bytes > 100 && +sizeInKB < 100) {
+    } else if (bytes >= 100 && +sizeInKB < 100) {
       return `${sizeInKB} KB`;
-    } else if (+sizeInKB > 100) {
+    } else {
       return `${sizeInMB} MB`;
     }
   };
 
   const thumbs = files.map((file: FileWithPreview) => (
-    <>
-      <Stack key={file.name} sx={thumb}>
+    <div key={file.name}>
+      <Stack sx={thumb}>
         <Stack sx={thumbInner}>
           <Typography>{formatFileSize(file.size)}</Typography>
 
@@ -169,7 +169,7 @@ const ImportLayout = ({
       >
         {progressVal > 0 && progressVal < 100 ? "Cancel Upload" : "Remove 
file"}
       </CustomButton>
-    </>
+    </div>
   ));
 
   const handleRemoveFile = (file: FileWithPreview) => {
diff --git 
a/dashboard/src/views/SideBar/SideBarTree/__tests__/CustomFiltersTree.test.tsx 
b/dashboard/src/views/SideBar/SideBarTree/__tests__/CustomFiltersTree.test.tsx
index 04a7045d4..1259642d9 100644
--- 
a/dashboard/src/views/SideBar/SideBarTree/__tests__/CustomFiltersTree.test.tsx
+++ 
b/dashboard/src/views/SideBar/SideBarTree/__tests__/CustomFiltersTree.test.tsx
@@ -316,7 +316,7 @@ describe('CustomFiltersTree', () => {
                        expect(treeData).toBeInTheDocument()
                })
 
-               it('should handle savedSearchType false with savedSearchData', 
async () => {
+               it('should group savedSearchData under search-type parent 
nodes', async () => {
                        const mockSavedSearchData = [
                                { name: 'Search1', searchType: 'BASIC' }
                        ]
@@ -329,18 +329,14 @@ describe('CustomFiltersTree', () => {
 
                        await waitFor(() => {
                                const treeData = screen.getByTestId('tree-data')
-                               expect(treeData).toBeInTheDocument()
+                               const data = JSON.parse(treeData.textContent || 
'[]')
+                               const basicNode = data.find((node: { label: 
string }) => node.label === 'Basic Search')
+                               expect(basicNode).toBeDefined()
+                               expect(basicNode.children.some((c: { label: 
string }) => c.label === 'Search1')).toBe(true)
                        })
 
-                       const toggleButton = 
screen.getByTestId('toggle-empty-button')
-                       await act(async () => {
-                               toggleButton.click()
-                       })
-
-                       await waitFor(() => {
-                               const treeData = screen.getByTestId('tree-data')
-                               expect(treeData).toBeInTheDocument()
-                       })
+                       
expect(screen.queryByTestId('toggle-empty-button')).not.toBeInTheDocument()
+                       
expect(screen.getByTestId('is-empty-service-type')).toHaveTextContent('true')
                })
        })
 
@@ -454,7 +450,7 @@ describe('CustomFiltersTree', () => {
                        expect(treeData).toBeInTheDocument()
                })
 
-               it('should generate treeData with savedSearchType false', async 
() => {
+               it('should keep grouped treeData after refresh without view 
toggle', async () => {
                        const mockSavedSearchData = [
                                { name: 'Search1', searchType: 'BASIC' }
                        ]
@@ -467,17 +463,21 @@ describe('CustomFiltersTree', () => {
 
                        await waitFor(() => {
                                const treeData = screen.getByTestId('tree-data')
-                               expect(treeData).toBeInTheDocument()
+                               const data = JSON.parse(treeData.textContent || 
'[]')
+                               expect(data.some((node: { label: string }) => 
node.label === 'Basic Search')).toBe(true)
                        })
 
-                       const toggleButton = 
screen.getByTestId('toggle-empty-button')
+                       
expect(screen.queryByTestId('toggle-empty-button')).not.toBeInTheDocument()
+
+                       const refreshButton = 
screen.getByTestId('refresh-button')
                        await act(async () => {
-                               toggleButton.click()
+                               refreshButton.click()
                        })
 
                        await waitFor(() => {
                                const treeData = screen.getByTestId('tree-data')
-                               expect(treeData).toBeInTheDocument()
+                               const data = JSON.parse(treeData.textContent || 
'[]')
+                               expect(data.some((node: { label: string }) => 
node.label === 'Basic Search')).toBe(true)
                        })
                })
        })
diff --git 
a/dashboard/src/views/SideBar/SideBarTree/__tests__/SideBarTree.test.tsx 
b/dashboard/src/views/SideBar/SideBarTree/__tests__/SideBarTree.test.tsx
index 96b511e77..ab02347a9 100644
--- a/dashboard/src/views/SideBar/SideBarTree/__tests__/SideBarTree.test.tsx
+++ b/dashboard/src/views/SideBar/SideBarTree/__tests__/SideBarTree.test.tsx
@@ -438,11 +438,9 @@ describe('SideBarTree', () => {
                        expect(switchElement).toBeInTheDocument()
                })
 
-               it('should render AccountTreeIcon for CustomFilters tree', 
async () => {
-                       const mockSetIsEmptyServicetype = jest.fn()
+               it('should not render empty-type toggle for CustomFilters 
tree', async () => {
                        renderComponent({
                                treeName: 'CustomFilters',
-                               setisEmptyServicetype: 
mockSetIsEmptyServicetype,
                                isEmptyServicetype: false
                        })
 
@@ -450,8 +448,9 @@ describe('SideBarTree', () => {
                                
expect(screen.getByTestId('simple-tree-view')).toBeInTheDocument()
                        })
 
-                       const accountTreeIcon = 
screen.getByTestId('account-tree-icon')
-                       expect(accountTreeIcon).toBeInTheDocument()
+                       
expect(screen.queryByTestId('account-tree-icon')).not.toBeInTheDocument()
+                       
expect(screen.queryByTestId('ant-switch')).not.toBeInTheDocument()
+                       
expect(screen.getByTestId('icon-button')).toBeInTheDocument()
                })
        })
 
@@ -1036,16 +1035,18 @@ describe('SideBarTree', () => {
                        })
                })
 
-               it('should return correct title for CustomFilters', async () => 
{
+               it('should render CustomFilters header without empty-type 
toggle', async () => {
                        renderComponent({
                                treeName: 'CustomFilters',
                                isEmptyServicetype: false
                        })
 
                        await waitFor(() => {
-                               const accountTreeIcon = 
screen.getByTestId('account-tree-icon')
-                               expect(accountTreeIcon).toBeInTheDocument()
+                               
expect(screen.getByTestId('simple-tree-view')).toBeInTheDocument()
                        })
+
+                       
expect(screen.queryByTestId('ant-switch')).not.toBeInTheDocument()
+                       
expect(screen.queryByTestId('account-tree-icon')).not.toBeInTheDocument()
                })
        })
 
@@ -2024,7 +2025,7 @@ describe('SideBarTree', () => {
                        }
                })
 
-               it('should toggle isEmptyServicetype for CustomFilters', async 
() => {
+               it('should not toggle isEmptyServicetype for CustomFilters', 
async () => {
                        const mockSetIsEmptyServicetype = jest.fn()
                        renderComponent({
                                treeName: 'CustomFilters',
@@ -2036,12 +2037,9 @@ describe('SideBarTree', () => {
                                
expect(screen.getByTestId('simple-tree-view')).toBeInTheDocument()
                        })
 
-                       const accountTreeIcon = 
screen.getByTestId('account-tree-icon')
-                       await act(async () => {
-                               fireEvent.click(accountTreeIcon)
-                       })
-
-                       
expect(mockSetIsEmptyServicetype).toHaveBeenCalledWith(true)
+                       
expect(screen.queryByTestId('account-tree-icon')).not.toBeInTheDocument()
+                       
expect(screen.queryByTestId('ant-switch')).not.toBeInTheDocument()
+                       expect(mockSetIsEmptyServicetype).not.toHaveBeenCalled()
                })
        })
 })
diff --git a/dashboard/src/views/Statistics/ServerStats.tsx 
b/dashboard/src/views/Statistics/ServerStats.tsx
index 5f131c41c..fe52690f7 100644
--- a/dashboard/src/views/Statistics/ServerStats.tsx
+++ b/dashboard/src/views/Statistics/ServerStats.tsx
@@ -50,13 +50,35 @@ const ServerStats = ({ selectedValue, currentMetricsData }: 
any) => {
 
     for (let key in stateObject) {
       let keys: string[] = key.split(":");
-      key = keys[0];
-      let subKey = keys[1];
-      if (stats[key]) {
-        stats[key][subKey] = stateObject[`${key}:${subKey}`];
+      const mainKey = keys[0];
+      const subKey = keys[1];
+      
+      if (!stats[mainKey]) {
+        stats[mainKey] = {};
+      }
+      
+      // Handle multi-level nesting (e.g., 
Notification:topicDetails:topic1:offsetStart)
+      if (keys.length > 2) {
+        // For topicDetails structure: 
Notification:topicDetails:topic1:offsetStart
+        if (subKey === 'topicDetails' && keys.length === 4) {
+          const topicName = keys[2];
+          const topicProperty = keys[3];
+          
+          if (!stats[mainKey][subKey]) {
+            stats[mainKey][subKey] = {};
+          }
+          if (!stats[mainKey][subKey][topicName]) {
+            stats[mainKey][subKey][topicName] = {};
+          }
+          stats[mainKey][subKey][topicName][topicProperty] = stateObject[key];
+        } else {
+          // Fallback for other multi-level structures
+          const remainingKey = keys.slice(1).join(':');
+          stats[mainKey][remainingKey] = stateObject[key];
+        }
       } else {
-        stats[key] = {};
-        stats[key][subKey] = stateObject[`${key}:${subKey}`];
+        // Handle simple two-level nesting (e.g., Notification:currentDay)
+        stats[mainKey][subKey] = stateObject[key];
       }
     }
 
@@ -235,7 +257,7 @@ const ServerStats = ({ selectedValue, currentMetricsData }: 
any) => {
                     </TableCell>
                   </TableRow>
                 ) : (
-                  Object.entries(serverData?.Server)?.map(
+                  Object.entries(serverData?.Server || {})?.map(
                     ([key, value]: any) => (
                       <TableRow key={key}>
                         <TableCell>{key}</TableCell>
@@ -305,7 +327,7 @@ const ServerStats = ({ selectedValue, currentMetricsData }: 
any) => {
                               ? stats.Notification["lastMessageProcessedTime"]
                               : stats.Notification[header];
                           return (
-                            <TableCell align="left">
+                            <TableCell key={header} align="left">
                               {returnVal
                                 ? getStatsValue({
                                     value: returnVal,
@@ -330,11 +352,9 @@ const ServerStats = ({ selectedValue, currentMetricsData 
}: any) => {
                     </TableCell>
                     {notificationTableHeader.map((header) => {
                       return (
-                        <>
-                          <TableCell align="right">
-                            <Typography fontWeight="600">{header}</Typography>
-                          </TableCell>
-                        </>
+                        <TableCell key={header} align="right">
+                          <Typography fontWeight="600">{header}</Typography>
+                        </TableCell>
                       );
                     })}
                   </TableRow>
@@ -351,10 +371,10 @@ const ServerStats = ({ selectedValue, currentMetricsData 
}: any) => {
                       <TableRow key={index}>
                         <TableCell>{obj.label}</TableCell>
                         {tableHeader.map((header) => (
-                          <TableCell align="right">
+                          <TableCell key={header} align="right">
                             {getTmplValue(obj, header)}
                           </TableCell>
-                        ))}{" "}
+                        ))}
                       </TableRow>
                     ))
                   )}

Reply via email to