Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions dashboard/src/components/GlobalSearch/AdvancedSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -394,9 +394,8 @@ const AdvancedSearch: React.FC<AdvancedSearchPropsType> = ({
variant="outlined"
color="success"
aria-label="reset"
primary={true}
size="small"
onClick={(e: Event) => {
onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();
handleClearValue();
}}
Expand Down
5 changes: 2 additions & 3 deletions dashboard/src/components/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ export const CustomModal: React.FC<CustomModalProps> = ({
variant="outlined"
color="primary"
disabled={isLoading}
onClick={(e: Event) => {
onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();
if (isLoading) {
return;
Expand All @@ -196,7 +196,6 @@ export const CustomModal: React.FC<CustomModalProps> = ({
? "Action in progress, please wait"
: "Confirm dialog action"
}
primary={true}
disabled={primaryDisabled}
sx={{
minWidth: isLoading ? 88 : undefined,
Expand Down Expand Up @@ -232,7 +231,7 @@ export const CustomModal: React.FC<CustomModalProps> = ({
/>
) : undefined
}
onClick={(e: Event) => {
onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();
if (isLoading) {
return;
Expand Down
6 changes: 2 additions & 4 deletions dashboard/src/components/ShowMore/ShowMoreDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,7 @@ const ShowMoreDrawer = ({
variant="text"
color="primary"
aria-label="save"
primary={true}
onClick={(e: Event) => {
onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();
dispatch(toggleDrawer());
}}
Expand All @@ -132,8 +131,7 @@ const ShowMoreDrawer = ({
variant="text"
color="primary"
aria-label="close"
primary={true}
onClick={(e: Event) => {
onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();
dispatch(toggleDrawer());
}}
Expand Down
97 changes: 96 additions & 1 deletion dashboard/src/components/__tests__/muiComponents.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@
*/

import React from 'react'
import { render, screen, fireEvent } from '@testing-library/react'
import { render, screen, fireEvent, act } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import {
CustomButton,
LightTooltip,
OverflowTooltip,
LinkTab,
Accordion,
AccordionSummary,
Expand Down Expand Up @@ -69,6 +70,100 @@ describe('muiComponents', () => {
expect(screen.getByText('Tooltip Child')).toBeTruthy()
})

describe('OverflowTooltip', () => {
Comment thread
Brijesh619 marked this conversation as resolved.
let triggerResize: any
const originalResizeObserver = global.ResizeObserver

beforeAll(() => {
global.ResizeObserver = class {
constructor(callback: any) {
triggerResize = callback
}
observe = jest.fn()
unobserve = jest.fn()
disconnect = jest.fn()
} as any
})

afterAll(() => {
global.ResizeObserver = originalResizeObserver
})

it('renders OverflowTooltip children', () => {
render(
<OverflowTooltip title="overflow tip">
<span>Overflow Child</span>
</OverflowTooltip>
)
expect(screen.getByText('Overflow Child')).toBeTruthy()
})

it('disables tooltip when not overflowed', async () => {
render(
<OverflowTooltip title="overflow tip">
<span data-testid="short-text">Short</span>
</OverflowTooltip>
)
const span = screen.getByTestId('short-text').parentElement!

// Mock no overflow
Object.defineProperty(span, 'scrollWidth', { configurable: true, value: 100 })
Object.defineProperty(span, 'clientWidth', { configurable: true, value: 100 })

act(() => {
if (triggerResize) triggerResize()
})

fireEvent.mouseOver(span)

// Tooltip should not be in the document
expect(screen.queryByText('overflow tip')).not.toBeInTheDocument()
})

it('enables tooltip on resize if overflow occurs', async () => {
render(
<OverflowTooltip title="overflow tip">
<span data-testid="resize-text">Will be long</span>
</OverflowTooltip>
)
const span = screen.getByTestId('resize-text').parentElement!

// Mock overflow condition
Object.defineProperty(span, 'scrollWidth', { configurable: true, value: 200 })
Object.defineProperty(span, 'clientWidth', { configurable: true, value: 100 })

// Trigger resize observer callback
act(() => {
if (triggerResize) triggerResize()
})

fireEvent.mouseOver(span)

// Tooltip should appear
expect(await screen.findByText('overflow tip')).toBeInTheDocument()
})

it('enables tooltip for subpixel overflow where clientWidth matches scrollWidth', async () => {
render(
<OverflowTooltip title="subpixel tip">
<span data-testid="subpixel-text">Subpixel</span>
</OverflowTooltip>
)
const span = screen.getByTestId('subpixel-text').parentElement!

// Mock subpixel overflow condition (scrollWidth matches clientWidth, but rect is smaller)
Object.defineProperty(span, 'scrollWidth', { configurable: true, value: 100 })
Object.defineProperty(span, 'clientWidth', { configurable: true, value: 100 })
span.getBoundingClientRect = jest.fn(() => ({ width: 99.5 } as DOMRect))

// Trigger hover to fire the onMouseEnter checkOverflow logic
fireEvent.mouseEnter(span)
fireEvent.mouseOver(span)

expect(await screen.findByText('subpixel tip')).toBeInTheDocument()
})
})

it('prevents default navigation in LinkTab', async () => {
const preventDefault = jest.fn()
render(
Expand Down
134 changes: 87 additions & 47 deletions dashboard/src/components/muiComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ import Switch from "@mui/material/Switch";
import Divider from "@mui/material/Divider";
import IconButton from "@mui/material/IconButton";
import ListItemIcon from "@mui/material/ListItemIcon";
import React from "react";
import Menu from "@mui/material/Menu";
import MenuItem from "@mui/material/MenuItem";
import Button from "@mui/material/Button";
import Button, { ButtonProps } from "@mui/material/Button";
import DialogTitle from "@mui/material/DialogTitle";
import DialogContent from "@mui/material/DialogContent";
import DialogActions from "@mui/material/DialogActions";
Expand All @@ -51,6 +52,8 @@ import MuiAccordionSummary, {
AccordionSummaryProps
} from "@mui/material/AccordionSummary";
import MuiAccordionDetails from "@mui/material/AccordionDetails";
import { TooltipProps } from "@mui/material/Tooltip";
import { SxProps, Theme } from "@mui/material/styles";

const LightTooltip = styled(({ className, ...props }: any) => (
<Tooltip
Expand All @@ -68,58 +71,94 @@ const LightTooltip = styled(({ className, ...props }: any) => (
}
}));

interface ButtonProps {
children?: any;
variant?: string;
color: string;
onClick: any;
sx?: any;
size?: string;
endIcon?: any;
startIcon?: any;
className?: string;
disabled?: boolean;

interface OverflowTooltipProps extends Omit<TooltipProps, "children"> {
children: React.ReactElement;
wrapperSx?: SxProps<Theme>;
wrapperClassName?: string;
}

const OverflowTooltip = ({ title, children, wrapperSx, wrapperClassName, ...props }: OverflowTooltipProps) => {
const textElementRef = React.useRef<HTMLElement>(null);
const [isOverflowed, setIsOverflowed] = React.useState(false);

const checkOverflow = React.useCallback(() => {
if (textElementRef.current) {
const el = textElementRef.current;
setIsOverflowed(
el.scrollWidth > el.clientWidth ||
el.scrollWidth > el.getBoundingClientRect().width
);
}
}, []);

React.useEffect(() => {
checkOverflow();
const element = textElementRef.current;
if (element) {
const resizeObserver = new ResizeObserver(() => checkOverflow());
resizeObserver.observe(element);
return () => resizeObserver.disconnect();
}
}, [title, checkOverflow]);

const child = (
<Box
component="span"
ref={textElementRef}
className={wrapperClassName}
sx={{
display: "inline-flex",
minWidth: 0,
width: "100%",
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
...wrapperSx
}}
onMouseEnter={checkOverflow}
>
{children}
</Box>
);

return (
<LightTooltip
title={title}
disableHoverListener={!isOverflowed}
disableFocusListener={!isOverflowed}
disableTouchListener={!isOverflowed}
{...props}
>
{child}
</LightTooltip>
);
};

const ButtonWrapper = styled(Box)({
display: "inline-flex"
});

const StyledButton = styled(Button)(({ variant }) => ({
fontWeight: "600",
letterSpacing: "0",
fontSize: "0.875rem",
cursor: "pointer",
minWidth: "unset",
...(variant === "outlined" && { border: "1px solid #dddddd" })
}));

const CustomButton = ({
children,
variant,
color,
sx: customStyles = {},
onClick,
size,
endIcon,
startIcon,
disabled,
sx,
...rest
}: ButtonProps | any) => {
let defaultStyles = {
fontWeight: "600 !important",
letterSpacing: "0 !important",
fontSize: "0.875rem !important",
cursor: "pointer !important",
minWidth: "unset !important",
...(variant == "outlined" && { border: "1px solid #dddddd !important" })
};

let mergedStyle = { ...defaultStyles, ...customStyles };

}: ButtonProps) => {
return (
<Box component="span" sx={{ display: 'inline-flex' }}>
<Button
variant={variant}
color={color}
sx={mergedStyle}
onClick={onClick}
size={size}
endIcon={endIcon}
startIcon={startIcon}
disabled={disabled}
{...rest}
>
<ButtonWrapper component="span">
<StyledButton sx={sx} {...rest}>
{children}
</Button>
</Box>
</StyledButton>
</ButtonWrapper>
);
};

Expand Down Expand Up @@ -202,5 +241,6 @@ export {
CustomButton,
Accordion,
AccordionSummary,
AccordionDetails
AccordionDetails,
OverflowTooltip
};
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ const BusinessMetaDataForm = ({
<CustomButton
variant="outlined"
color="primary"
onClick={(_e: Event) => {
onClick={(_e: React.MouseEvent<HTMLButtonElement>) => {
setForm(false);
setBMAttribute({});
dispatchState(setEditBMAttribute({}));
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/views/BusinessMetadata/EnumCreateUpdate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ const EnumCreateUpdate = ({
size="small"
data-cy="clearButton"
color="primary"
onClick={(_e: Event) => {
onClick={(_e: React.MouseEvent<HTMLButtonElement>) => {
reset({ enumType: "", enumValues: [] });
}}
disabled={
Expand Down
Loading
Loading