From 1bfb43fd0e5ffc1ee9b879e9ee7aa4a2a197d9c7 Mon Sep 17 00:00:00 2001
From: FeimeiChen <54688836+FeimeiChen@users.noreply.github.com>
Date: Fri, 4 Oct 2024 12:55:31 -1000
Subject: [PATCH] B
Create TooltipOnTruncate Component
---
ui/src/components/table/groupings-table.tsx | 21 +++++----
.../table-element/grouping-path-cell.tsx | 22 +++++----
.../table-element/tooltip-on-truncate.tsx | 36 ++++++++++++++
.../components/table/groupings-table.test.tsx | 20 ++++++++
.../table-element/grouping-path-cell.test.tsx | 20 ++++++++
.../tooltip-on-truncate.test.tsx | 47 +++++++++++++++++++
6 files changed, 149 insertions(+), 17 deletions(-)
create mode 100644 ui/src/components/table/table-element/tooltip-on-truncate.tsx
create mode 100644 ui/tests/components/table/table-element/tooltip-on-truncate.test.tsx
diff --git a/ui/src/components/table/groupings-table.tsx b/ui/src/components/table/groupings-table.tsx
index 82e561cc..cb3df24b 100644
--- a/ui/src/components/table/groupings-table.tsx
+++ b/ui/src/components/table/groupings-table.tsx
@@ -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);
@@ -109,15 +110,17 @@ const GroupingsTable = ({ groupingPaths }: { groupingPaths: GroupingPath[] }) =>
)}
{cell.column.id === 'description' && (
-
- {flexRender(cell.column.columnDef.cell, cell.getContext())}
-
+
+
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
+
+
)}
{cell.column.id === 'path' && (
diff --git a/ui/src/components/table/table-element/grouping-path-cell.tsx b/ui/src/components/table/table-element/grouping-path-cell.tsx
index c08b218c..b3ce74ef 100644
--- a/ui/src/components/table/table-element/grouping-path-cell.tsx
+++ b/ui/src/components/table/table-element/grouping-path-cell.tsx
@@ -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');
@@ -22,13 +23,15 @@ const GroupingPathCell = ({ path }: { path: string }) => {
return (
-
+
+
+
@@ -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"
>
-
+
diff --git a/ui/src/components/table/table-element/tooltip-on-truncate.tsx b/ui/src/components/table/table-element/tooltip-on-truncate.tsx
new file mode 100644
index 00000000..a4104546
--- /dev/null
+++ b/ui/src/components/table/table-element/tooltip-on-truncate.tsx
@@ -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(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 (
+
+
+
+ {children}
+
+ {isTruncated && (
+
+ {value}
+
+ )}
+
+
+ );
+};
+
+export default TooltipOnTruncate;
diff --git a/ui/tests/components/table/groupings-table.test.tsx b/ui/tests/components/table/groupings-table.test.tsx
index 164630ba..02ac6b03 100644
--- a/ui/tests/components/table/groupings-table.test.tsx
+++ b/ui/tests/components/table/groupings-table.test.tsx
@@ -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();
+ 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();
+ });
+ });
});
diff --git a/ui/tests/components/table/table-element/grouping-path-cell.test.tsx b/ui/tests/components/table/table-element/grouping-path-cell.test.tsx
index 61177ab9..1a44ee22 100644
--- a/ui/tests/components/table/table-element/grouping-path-cell.test.tsx
+++ b/ui/tests/components/table/table-element/grouping-path-cell.test.tsx
@@ -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();
+
+ 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();
+ });
+ });
});
diff --git a/ui/tests/components/table/table-element/tooltip-on-truncate.test.tsx b/ui/tests/components/table/table-element/tooltip-on-truncate.test.tsx
new file mode 100644
index 00000000..61d00449
--- /dev/null
+++ b/ui/tests/components/table/table-element/tooltip-on-truncate.test.tsx
@@ -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(
+
+
+
+ );
+ 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(
+
+
+
+ );
+ const button = screen.getByRole('button');
+
+ await waitFor(async () => {
+ await userEvent.hover(button);
+ });
+
+ await waitFor(() => {
+ expect(screen.queryByTestId('tooltip-on-truncate')).not.toBeInTheDocument();
+ });
+ });
+});