Skip to content

Commit

Permalink
B
Browse files Browse the repository at this point in the history
Create TooltipOnTruncate Component
  • Loading branch information
FeimeiChen committed Oct 5, 2024
1 parent 1a2e6c7 commit 1bfb43f
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 17 deletions.
21 changes: 12 additions & 9 deletions ui/src/components/table/groupings-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import GroupingPathCell from '@/components/table/table-element/grouping-path-cel
import Link from 'next/link';
import { useLocalStorage } from 'usehooks-ts';
import { GroupingPath } from '@/lib/types';
import TooltipOnTruncate from '@/components/table/table-element/tooltip-on-truncate';

const pageSize = parseInt(process.env.NEXT_PUBLIC_PAGE_SIZE as string);

Expand Down Expand Up @@ -109,15 +110,17 @@ const GroupingsTable = ({ groupingPaths }: { groupingPaths: GroupingPath[] }) =>
)}
</div>
{cell.column.id === 'description' && (
<div
className={`${
columnCount === 3
? 'truncate sm:max-w-[calc(6ch+1em)] md:max-w-[calc(40ch+1em)]'
: 'truncate'
}`}
>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</div>
<TooltipOnTruncate value={String(cell.getValue() as string)}>
<div
className={`${
columnCount === 3
? 'truncate sm:max-w-[calc(6ch+1em)] md:max-w-[calc(40ch+1em)]'
: 'truncate'
}`}
>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</div>
</TooltipOnTruncate>
)}
{cell.column.id === 'path' && (
<GroupingPathCell path={cell.row.getValue('path')} />
Expand Down
22 changes: 14 additions & 8 deletions ui/src/components/table/table-element/grouping-path-cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ClipboardIcon } from 'lucide-react';
import { Input } from '@/components/ui/input';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
import { useState } from 'react';
import TooltipOnTruncate from '@/components/table/table-element/tooltip-on-truncate';

const GroupingPathCell = ({ path }: { path: string }) => {
const [tooltipContent, setTooltipContent] = useState('copy');
Expand All @@ -22,13 +23,15 @@ const GroupingPathCell = ({ path }: { path: string }) => {

return (
<div className="flex items-center w-full outline outline-1 rounded h-6 m-1">
<Input
id="dataInput"
value={path}
readOnly
className="flex-1 h-6 text-input-text-grey text-[0.875rem]
border-none rounded-none w-[161px] truncate"
/>
<TooltipOnTruncate value={path}>
<Input
id="dataInput"
value={path}
readOnly
className="flex-1 h-6 text-input-text-grey text-[0.875rem]
border-none rounded-none w-full truncate"
/>
</TooltipOnTruncate>

<TooltipProvider>
<Tooltip open={tooltipVisible} onOpenChange={setTooltipVisible}>
Expand All @@ -39,7 +42,10 @@ const GroupingPathCell = ({ path }: { path: string }) => {
justify-center hover:bg-green-blue h-6 p-2 transition ease-in-out duration-150"
data-testid="clipboard-button"
>
<ClipboardIcon className="group-hover:text-white h-4 w-4 text-gray-600" data-testid="clipboard-icon" />
<ClipboardIcon
className="group-hover:text-white h-4 w-4 text-gray-600"
data-testid="clipboard-icon"
/>
</button>
</TooltipTrigger>
<TooltipContent>
Expand Down
36 changes: 36 additions & 0 deletions ui/src/components/table/table-element/tooltip-on-truncate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
'use client';
import React, { useEffect, useState, useRef } from 'react';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';

const TooltipOnTruncate = ({ children, value }: { children: React.ReactNode; value: string }) => {
const [isTruncated, setIsTruncated] = useState(false);
const ref = useRef<HTMLButtonElement>(null);

useEffect(() => {
const checkIsTruncated = () => {
if (ref.current) {
setIsTruncated(ref.current.scrollWidth > ref.current.clientWidth);
}
};
checkIsTruncated();
window.addEventListener('resize', checkIsTruncated);
return () => window.removeEventListener('resize', checkIsTruncated);
}, []);

return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild ref={ref}>
{children}
</TooltipTrigger>
{isTruncated && (
<TooltipContent className="max-w-[190px] max-h-[180px] text-center whitespace-normal break-words bg-black text-white">
<p data-testid="tooltip-on-truncate">{value}</p>
</TooltipContent>
)}
</Tooltip>
</TooltipProvider>
);
};

export default TooltipOnTruncate;
20 changes: 20 additions & 0 deletions ui/tests/components/table/groupings-table.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,24 @@ describe('GroupingsTable', () => {
await checkPageContent('Last', mockData.length - pageSize, mockData.length - 1);
await checkPageContent('Previous', mockData.length - pageSize * 2, mockData.length - pageSize - 1);
});
it('should show tooltip if description content is truncated', async () => {
Object.defineProperties(HTMLElement.prototype, {
scrollWidth: { get: () => 500, configurable: true },
clientWidth: { get: () => 30, configurable: true }
});
render(<GroupingsTable groupingPaths={mockData} />);
const firstButton = screen.getByText('First');

fireEvent.click(firstButton);

const description = screen.getByText('Test Description 0');
await waitFor(async () => {
await userEvent.hover(description);
});

// Wait for the tooltip to appear
await waitFor(() => {
expect(screen.getAllByTestId('tooltip-on-truncate')[0]).toBeInTheDocument();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,24 @@ describe('GroupingPathCell', () => {
{ timeout: 2000 }
);
});

it('should show tooltip if content is truncated', async () => {
Object.defineProperties(HTMLElement.prototype, {
scrollWidth: { get: () => 500, configurable: true },
clientWidth: { get: () => 30, configurable: true }
});
render(<GroupingPathCell path={path} />);

const inputElement = screen.getByRole('textbox');
expect(inputElement).toHaveValue(path);

await waitFor(async () => {
await userEvent.hover(inputElement);
});

// Wait for the tooltip to appear
await waitFor(() => {
expect(screen.getAllByTestId('tooltip-on-truncate')[0]).toBeInTheDocument();
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import TooltipOnTruncate from '@/components/table/table-element/tooltip-on-truncate';

describe('TooltipOnTruncate component', () => {
it('should show tooltip if content is truncated', async () => {
Object.defineProperties(HTMLElement.prototype, {
scrollWidth: { get: () => 500, configurable: true },
clientWidth: { get: () => 30, configurable: true }
});
render(
<TooltipOnTruncate value="Truncated Text">
<button>Truncated Text</button>
</TooltipOnTruncate>
);
const button = screen.getByRole('button');
await waitFor(async () => {
await userEvent.hover(button);
});

// Wait for the tooltip to appear
await waitFor(() => {
expect(screen.getAllByTestId('tooltip-on-truncate')[0]).toBeInTheDocument();
});
});

it('should not show tooltip if content is not truncated', async () => {
Object.defineProperties(HTMLElement.prototype, {
scrollWidth: { get: () => 30, configurable: true },
clientWidth: { get: () => 500, configurable: true }
});
render(
<TooltipOnTruncate value="Truncated Text">
<button>Truncated Text</button>
</TooltipOnTruncate>
);
const button = screen.getByRole('button');

await waitFor(async () => {
await userEvent.hover(button);
});

await waitFor(() => {
expect(screen.queryByTestId('tooltip-on-truncate')).not.toBeInTheDocument();
});
});
});

0 comments on commit 1bfb43f

Please sign in to comment.