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

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


The following commit(s) were added to refs/heads/master by this push:
     new 911079f8f ATLAS-5306: Atlas React UI: SearchResult Table: 
Classification toolti… (#665)
911079f8f is described below

commit 911079f8f57118845bf74984726b1ece617aeb49
Author: Brijesh Bhalala <[email protected]>
AuthorDate: Thu Jun 11 17:38:25 2026 +0530

    ATLAS-5306: Atlas React UI: SearchResult Table: Classification toolti… 
(#665)
    
    * ATLAS-5306: Atlas React UI: SearchResult Table: Classification tooltip is 
missing parent/super-type name
    
    * ATLAS-5306: Atlas React UI: SearchResult Table: Classification tooltip is 
missing parent/super-type name
    
    * ATLAS-5306: Atlas React UI: SearchResult Table: Classification tooltip is 
missing parent/super-type name
---
 dashboard/src/components/DialogShowMoreLess.tsx    | 111 +++++++++++++--------
 .../__tests__/DialogShowMoreLess.test.tsx          |  25 +++++
 dashboard/src/views/SearchResult/SearchResult.tsx  |  11 +-
 .../SearchResult/__tests__/SearchResult.test.tsx   |  34 ++++++-
 4 files changed, 129 insertions(+), 52 deletions(-)

diff --git a/dashboard/src/components/DialogShowMoreLess.tsx 
b/dashboard/src/components/DialogShowMoreLess.tsx
index 03492d077..ebe35f9f2 100644
--- a/dashboard/src/components/DialogShowMoreLess.tsx
+++ b/dashboard/src/components/DialogShowMoreLess.tsx
@@ -16,7 +16,7 @@
  */
 
 import { LightTooltip } from "./muiComponents";
-import { Chip, IconButton, Menu, MenuItem, Typography } from "@mui/material";
+import { Chip, IconButton, Menu, MenuItem, Typography, Box } from 
"@mui/material";
 import { extractKeyValueFromEntity, isEmpty, serverError } from "@utils/Utils";
 import { useRef, useState } from "react";
 import ErrorRoundedIcon from "@mui/icons-material/ErrorRounded";
@@ -37,7 +37,8 @@ import { fetchGlossaryDetails } from 
"@redux/slice/glossaryDetailsSlice";
 import { fetchDetailPageData } from "@redux/slice/detailPageSlice";
 import { fetchGlossaryData } from "@redux/slice/glossarySlice";
 
-const CHIP_MAX_WIDTH = "200px";
+const CHIP_MAX_WIDTH = "6.25rem";
+const CLASSIFICATION = "Classification";
 const ITEM_HEIGHT = 48;
 
 export interface DialogShowMoreLessProps {
@@ -129,7 +130,7 @@ const DialogShowMoreLess = ({
    * classification is on this entity; propagated tags use another entityGuid.
    */
   const canShowDeleteOnClassificationChip = (tag: any) => {
-    if (colName !== "Classification") {
+    if (colName !== CLASSIFICATION) {
       return true;
     }
     if (!tag) {
@@ -155,7 +156,7 @@ const DialogShowMoreLess = ({
   const handleRemove = async (): Promise<void> => {
     try {
       setRemoveLoader(true);
-      if (colName == "Classification") {
+      if (colName == CLASSIFICATION) {
         await removeApiMethod(
           detailPage ? entity.guid : value.guid,
           currentValue.selectedValue
@@ -216,12 +217,11 @@ const DialogShowMoreLess = ({
       setOpenModal(false);
       toast.dismiss(toastId.current);
       toastId.current = toast.success(
-        `${colName} ${
-          colName == "Term" ? "association" : currentValue.selectedValue
+        `${colName} ${colName == "Term" ? "association" : 
currentValue.selectedValue
         } was removed successfully`
       );
       const isSchemaClassificationFlow =
-        colName === "Classification" &&
+        colName === CLASSIFICATION &&
         typeof onSchemaChildEntityRefresh === "function";
       if (!isEmpty(guid)) {
         if (!isEmpty(gType)) {
@@ -256,8 +256,8 @@ const DialogShowMoreLess = ({
   const checkSuperTypes = (classificationName: string) => {
     let tagObj = !isEmpty(classificationData.classificationDefs)
       ? classificationData.classificationDefs.find((obj: { name: string }) => {
-          return obj.name == classificationName;
-        })
+        return obj.name == classificationName;
+      })
       : {};
 
     return !isEmpty(tagObj?.superTypes)
@@ -268,7 +268,10 @@ const DialogShowMoreLess = ({
   };
 
   const getLabel = (label: string, optionalLabel?: string) => {
-    if (columnVal == "Classifications" || columnVal == "self") {
+    if (colName == CLASSIFICATION) {
+      return checkSuperTypes(label);
+    } else if (colName == "Propagated Classification") {
+      // Re-using checkSuperTypes since it does the same as getTagParentList
       return checkSuperTypes(label);
     } else {
       return label || optionalLabel;
@@ -280,7 +283,7 @@ const DialogShowMoreLess = ({
     text: string | undefined,
     data: any | undefined
   ) => {
-    if (colName == "Classification" || colName == "Propagated Classification") 
{
+    if (colName == CLASSIFICATION || colName == "Propagated Classification") {
       let keys = Array.from(searchParams.keys());
       for (let i = 0; i < keys.length; i++) {
         // if (keys[i] != "searchType") {
@@ -330,7 +333,7 @@ const DialogShowMoreLess = ({
   };
 
   const assignTitle = () => {
-    if (colName == "Classification") {
+    if (colName == CLASSIFICATION) {
       return "Add Classification";
     } else if (colName == "Term") {
       return "Add Term";
@@ -338,7 +341,7 @@ const DialogShowMoreLess = ({
   };
 
   const removeTitle = () => {
-    if (colName == "Classification") {
+    if (colName == CLASSIFICATION) {
       return "Remove Classification Assignment";
     } else if (colName == "Term") {
       return "Remove Term Assignment";
@@ -350,9 +353,18 @@ const DialogShowMoreLess = ({
   return (
     <>
       {value?.[columnVal]?.length > 0 ? (
-        <div
+        <Box
           className="tag-list"
-          style={{ flexWrap: isShowMoreLess ? "nowrap" : "wrap" }}
+          sx={
+            isShowMoreLess
+              ? {
+                display: "grid",
+                gridTemplateColumns: "minmax(2.1875rem, max-content) 
max-content max-content",
+                alignItems: "center",
+                width: "100%"
+              }
+              : { display: "flex", flexWrap: "wrap", alignItems: "center" }
+          }
         >
           {isShowMoreLess && (
             <LightTooltip
@@ -370,32 +382,36 @@ const DialogShowMoreLess = ({
                       value[columnVal][0][displayText],
                       optionalDisplayText,
                       (colName == "Term" || colName == "Category") &&
-                        value[columnVal][0]
+                      value[columnVal][0]
                     )}
                   </EllipsisText>
                 }
                 onDelete={
                   !isEmpty(removeApiMethod) &&
-                  canShowDeleteOnClassificationChip(value[columnVal][0])
+                    canShowDeleteOnClassificationChip(value[columnVal][0])
                     ? () => {
-                        handleDelete(value[columnVal][0][displayText]);
-                      }
+                      handleDelete(value[columnVal][0][displayText]);
+                    }
                     : undefined
                 }
                 size="small"
                 variant="outlined"
                 sx={{
                   "& .MuiChip-label": {
+                    overflow: "hidden",
+                    textOverflow: "ellipsis",
+                    whiteSpace: "nowrap",
                     display: "block",
-                    overflow: "ellipsis",
-                    maxWidth: "145px"
+                    minWidth: 0,
+                    flexShrink: 1
                   },
-
-                  maxWidth: CHIP_MAX_WIDTH
+                  maxWidth: CHIP_MAX_WIDTH,
+                  minWidth: 0,
+                  overflow: "hidden"
                 }}
                 clickable
                 data-cy="tagClick"
-              />{" "}
+              />
             </LightTooltip>
           )}
           {!isShowMoreLess &&
@@ -414,28 +430,30 @@ const DialogShowMoreLess = ({
                           obj[displayText] || obj,
                           optionalDisplayText,
                           (colName == "Term" || colName == "Category") &&
-                            value[columnVal][index]
+                          value[columnVal][index]
                         )}
                       </EllipsisText>
                     }
                     onDelete={
                       !isEmpty(removeApiMethod) &&
-                      canShowDeleteOnClassificationChip(obj)
+                        canShowDeleteOnClassificationChip(obj)
                         ? () => {
-                            handleDelete(obj[displayText] || obj);
-                          }
+                          handleDelete(obj[displayText] || obj);
+                        }
                         : undefined
                     }
                     size="small"
                     variant="outlined"
                     sx={{
                       "& .MuiChip-label": {
+                        overflow: "hidden",
+                        textOverflow: "ellipsis",
+                        whiteSpace: "nowrap",
                         display: "block",
-                        overflow: "ellipsis",
-                        maxWidth: "180px"
+                        minWidth: 0
                       },
-
-                      maxWidth: CHIP_MAX_WIDTH
+                      maxWidth: CHIP_MAX_WIDTH,
+                      minWidth: 0
                     }}
                     clickable
                   />
@@ -451,7 +469,7 @@ const DialogShowMoreLess = ({
                 onClick={handleClick}
                 aria-controls={open ? "long-menu" : undefined}
                 aria-expanded={open ? "true" : undefined}
-                aria-haspopup="true"
+                sx={{ flexShrink: 0, padding: "2px" }}
               >
                 <MoreHorizIcon />
               </IconButton>
@@ -464,7 +482,7 @@ const DialogShowMoreLess = ({
                 color="primary"
                 size="small"
                 onClick={() => {
-                  if (colName == "Classification") {
+                  if (colName == CLASSIFICATION) {
                     setTagModal(true);
                   } else if (colName == "Term") {
                     setTermModal(true);
@@ -474,6 +492,7 @@ const DialogShowMoreLess = ({
                     setAttributeModal(true);
                   }
                 }}
+                sx={{ flexShrink: 0, padding: "2px" }}
               >
                 <AddCircleOutlineIcon fontSize="small" />
               </IconButton>
@@ -509,17 +528,17 @@ const DialogShowMoreLess = ({
                               obj[displayText],
                               optionalDisplayText,
                               (colName == "Term" || colName == "Category") &&
-                                value[columnVal][index]
+                              value[columnVal][index]
                             )}
                           </EllipsisText>
                         }
                         className="chip-items"
                         onDelete={
                           !isEmpty(removeApiMethod) &&
-                          canShowDeleteOnClassificationChip(obj)
+                            canShowDeleteOnClassificationChip(obj)
                             ? () => {
-                                handleDelete(obj[displayText] || obj);
-                              }
+                              handleDelete(obj[displayText] || obj);
+                            }
                             : undefined
                         }
                         size="small"
@@ -527,11 +546,14 @@ const DialogShowMoreLess = ({
                         clickable
                         sx={{
                           "& .MuiChip-label": {
+                            overflow: "hidden",
+                            textOverflow: "ellipsis",
+                            whiteSpace: "nowrap",
                             display: "block",
-                            overflow: "ellipsis",
-                            maxWidth: "180px"
+                            minWidth: 0
                           },
-                          maxWidth: CHIP_MAX_WIDTH
+                          maxWidth: CHIP_MAX_WIDTH,
+                          minWidth: 0
                         }}
                       />
                     </LightTooltip>
@@ -540,7 +562,7 @@ const DialogShowMoreLess = ({
               }
             })}
           </Menu>
-        </div>
+        </Box>
       ) : (
         !readOnly && (
           <LightTooltip title={assignTitle()}>
@@ -549,7 +571,7 @@ const DialogShowMoreLess = ({
               color="primary"
               size="small"
               onClick={() => {
-                if (colName == "Classification") {
+                if (colName == CLASSIFICATION) {
                   setTagModal(true);
                 } else if (colName == "Term") {
                   setTermModal(true);
@@ -559,6 +581,7 @@ const DialogShowMoreLess = ({
                   setAttributeModal(true);
                 }
               }}
+              sx={{ flexShrink: 0, padding: "2px" }}
             >
               <AddCircleOutlineIcon fontSize="small" />
             </IconButton>
@@ -592,7 +615,7 @@ const DialogShowMoreLess = ({
         </CustomModal>
       )}
 
-      {tagModal && colName == "Classification" && (
+      {tagModal && colName == CLASSIFICATION && (
         <AddTag
           open={tagModal}
           isAdd={true}
diff --git a/dashboard/src/components/__tests__/DialogShowMoreLess.test.tsx 
b/dashboard/src/components/__tests__/DialogShowMoreLess.test.tsx
index fe30545e5..575eca7e7 100644
--- a/dashboard/src/components/__tests__/DialogShowMoreLess.test.tsx
+++ b/dashboard/src/components/__tests__/DialogShowMoreLess.test.tsx
@@ -28,6 +28,7 @@
 
 import React from 'react'
 import { render, screen, fireEvent, waitFor } from '@testing-library/react'
+import '@testing-library/jest-dom'
 import DialogShowMoreLess from '../DialogShowMoreLess'
 
 const toastSuccess = jest.fn()
@@ -45,6 +46,9 @@ jest.mock('../muiComponents', () => ({
 }))
 
 jest.mock('@mui/material', () => ({
+       Box: ({ children, className, sx }: any) => (
+               <div className={className} style={sx} 
data-testid="box">{children}</div>
+       ),
        Chip: ({ label, onDelete, className, sx, clickable, size, variant, 
color }: any) => (
                <div
                        data-testid="chip"
@@ -365,6 +369,27 @@ describe('DialogShowMoreLess', () => {
                        const chip = screen.getByText('PII@(a, 
b)').closest('[data-testid="chip"]')
                        expect(chip).toBeTruthy()
                })
+
+               it('applies truncation styles to classification chip', () => {
+                       render(
+                               <DialogShowMoreLess
+                                       value={{
+                                               guid: 'g1',
+                                               Classifications: [
+                                                       { name: 'PII', 
entityGuid: 'g1', entityStatus: 'ACTIVE' }
+                                               ]
+                                       }}
+                                       columnVal="Classifications"
+                                       colName="Classification"
+                                       displayText="name"
+                                       isShowMoreLess={true}
+                               />
+                       )
+
+                       const chip = screen.getByText('PII@(a, 
b)').closest('[data-testid="chip"]')
+                       expect(chip).toBeTruthy()
+                       expect(chip).toHaveStyle({ minWidth: 0 })
+               })
        })
 
        describe('Term rendering', () => {
diff --git a/dashboard/src/views/SearchResult/SearchResult.tsx 
b/dashboard/src/views/SearchResult/SearchResult.tsx
index 5de7ed7f1..f14ac32fb 100644
--- a/dashboard/src/views/SearchResult/SearchResult.tsx
+++ b/dashboard/src/views/SearchResult/SearchResult.tsx
@@ -362,8 +362,7 @@ const SearchResult = ({ classificationParams, 
glossaryTypeParams, hideFilters }:
             <LightTooltip title={name}>
               {entity.guid != "-1" ? (
                 <Link
-                  className={`entity-name nav-link text-decoration-none ${
-                    entityDef.status && entityStateReadOnly[entityDef.status]
+                  className={`entity-name nav-link text-decoration-none 
${entityDef.status && entityStateReadOnly[entityDef.status]
                       ? "text-red"
                       : "text-blue"
                   }`}
@@ -435,7 +434,8 @@ const SearchResult = ({ classificationParams, 
glossaryTypeParams, hideFilters }:
       accessorKey: "owner",
       cell: (info: any) => <span>{info.getValue()}</span>,
       header: "Owner",
-      show: true
+      show: true,
+      size: 100
     },
     {
       accessorFn: (row: any) => row.attributes.description,
@@ -468,7 +468,8 @@ const SearchResult = ({ classificationParams, 
glossaryTypeParams, hideFilters }:
         );
       },
       header: "Type",
-      show: true
+      show: true,
+      size: 100
     },
     {
       accessorFn: (row: any) => row.classificationNames[0],
@@ -1078,6 +1079,7 @@ const SearchResult = ({ classificationParams, 
glossaryTypeParams, hideFilters }:
         </Stack>
       )}
 
+      <div className="search-result-table-wrapper">
       <TableLayout
         fetchData={fetchSearchResult}
         data={
@@ -1143,6 +1145,7 @@ const SearchResult = ({ classificationParams, 
glossaryTypeParams, hideFilters }:
         showGoToPage={true}
         totalCount={totalCount}
       />
+      </div>
     </Stack>
   );
 };
diff --git a/dashboard/src/views/SearchResult/__tests__/SearchResult.test.tsx 
b/dashboard/src/views/SearchResult/__tests__/SearchResult.test.tsx
index 0f62bd223..398b362ee 100644
--- a/dashboard/src/views/SearchResult/__tests__/SearchResult.test.tsx
+++ b/dashboard/src/views/SearchResult/__tests__/SearchResult.test.tsx
@@ -23,7 +23,7 @@ import { MemoryRouter } from 'react-router-dom';
 import { configureStore } from '@reduxjs/toolkit';
 import { ThemeProvider, createTheme } from '@mui/material/styles';
 import SearchResult from '../SearchResult';
-import * as searchApiMethod from '@api/apiMethods/searchApiMethod';
+import * as searchApiMethod from '../../../api/apiMethods/searchApiMethod';
 import { toast } from 'react-toastify';
 
 const theme = createTheme();
@@ -41,7 +41,7 @@ jest.mock('@api/apiUrlLinks/commonApiUrl', () => ({
 }));
 
 // Mock API methods
-jest.mock('@api/apiMethods/searchApiMethod');
+jest.mock('../../../api/apiMethods/searchApiMethod');
 jest.mock('@api/apiMethods/classificationApiMethod', () => ({
   removeClassification: jest.fn()
 }));
@@ -259,14 +259,14 @@ jest.mock('@utils/Utils', () => {
         }
       }
       // Filter out any invalid entries
-      const validArr = arr.filter(item => item != null);
+      const validArr = arr.filter((item: any) => item != null);
       if (validArr.length === 0) return [];
       if (!Array.isArray(keys) || keys.length === 0) {
         const result = [...validArr];
         return Array.isArray(result) ? result : [];
       }
       try {
-        const sorted = [...validArr].sort((a, b) => {
+        const sorted = [...validArr].sort((a: any, b: any) => {
           if (!a || !b) return 0;
           for (const key of keys) {
             const aVal = a?.[key] || '';
@@ -1838,6 +1838,32 @@ describe('SearchResult', () => {
       }, { timeout: 15000 });
     }, 30000);
 
+    it('should render table within search-result-table-wrapper class', async 
() => {
+      await act(async () => {
+        renderWithProviders(<SearchResult />);
+      });
+
+      await waitFor(() => {
+        
expect(document.querySelector('.search-result-table-wrapper')).toBeInTheDocument();
+      }, { timeout: 15000 });
+    }, 30000);
+
+    it('should configure Owner and Type columns with specific sizes', async () 
=> {
+      await act(async () => {
+        renderWithProviders(<SearchResult />);
+      });
+
+      await waitFor(() => {
+        expect(document.querySelector('.table')).toBeInTheDocument();
+        const ownerColumn = capturedColumns.find((col: any) => col.header === 
'Owner');
+        expect(ownerColumn).toBeDefined();
+        expect(ownerColumn?.size).toBe(100);
+
+        const typeColumn = capturedColumns.find((col: any) => col.header === 
'Type');
+        expect(typeColumn).toBeDefined();
+        expect(typeColumn?.size).toBe(100);
+      }, { timeout: 15000 });
+    }, 30000);
 
     it('should show assign filters when classificationParams is present', 
async () => {
       await act(async () => {

Reply via email to