diff --git a/package.json b/package.json index d32bfa0e..44ed9d60 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "react-hook-form": "^7.43.7", "react-markdown": "^8.0.3", "react-select": "^5.6.1", - "react-tooltip": "^4.4.3", + "react-tooltip": "^5.10.5", "redis": "^4.6.5", "remark-breaks": "^3.0.2", "remark-gfm": "^3.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 905f5b9f..20ef2841 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -101,8 +101,8 @@ dependencies: specifier: ^5.6.1 version: 5.7.0(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0) react-tooltip: - specifier: ^4.4.3 - version: 4.5.1(react-dom@18.2.0)(react@18.2.0) + specifier: ^5.10.5 + version: 5.10.5(react-dom@18.2.0)(react@18.2.0) redis: specifier: ^4.6.5 version: 4.6.5 @@ -3163,6 +3163,10 @@ packages: resolution: {integrity: sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==} dev: true + /classnames@2.3.2: + resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==} + dev: false + /cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -7330,17 +7334,16 @@ packages: tslib: 2.5.0 dev: false - /react-tooltip@4.5.1(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Zo+CSFUGXar1uV+bgXFFDe7VeS2iByeIp5rTgTcc2HqtuOS5D76QapejNNfx320MCY91TlhTQat36KGFTqgcvw==} - engines: {npm: '>=6.13'} + /react-tooltip@5.10.5(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-3bi4UtoPSdaQh0R17B3vMPhNFiATpAbXIV8AqlHqrrIdqo33OJyxuPHtgborw3KXVQ5a6iyyAmCY8ztjUB4CrA==} peerDependencies: - react: '>=16.0.0' - react-dom: '>=16.0.0' + react: '>=16.14.0' + react-dom: '>=16.14.0' dependencies: - prop-types: 15.8.1 + '@floating-ui/dom': 1.2.1 + classnames: 2.3.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - uuid: 7.0.3 dev: false /react-transition-group@4.4.5(react-dom@18.2.0)(react@18.2.0): @@ -8424,11 +8427,6 @@ packages: engines: {node: '>= 0.4.0'} dev: false - /uuid@7.0.3: - resolution: {integrity: sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==} - hasBin: true - dev: false - /uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true diff --git a/src/client/components/AppStatus/AppStatus.tsx b/src/client/components/AppStatus/AppStatus.tsx index d687a9bc..c08d9559 100644 --- a/src/client/components/AppStatus/AppStatus.tsx +++ b/src/client/components/AppStatus/AppStatus.tsx @@ -1,10 +1,11 @@ import clsx from 'clsx'; import React from 'react'; +import { Tooltip } from 'react-tooltip'; import * as AppTypes from '../../core/types'; import styles from './AppStatus.module.scss'; export const AppStatus: React.FC<{ status: AppTypes.AppStatus; lite?: boolean }> = ({ status, lite }) => { - const formattedStatus = `${status[0]}${status.substring(1, status.length).toLowerCase()}`; + const formattedStatus = `${status[0]?.toUpperCase()}${status.substring(1, status.length).toLowerCase()}`; const classes = clsx('status-dot status-gray', { 'status-dot-animated status-green': status === 'running', @@ -12,9 +13,16 @@ export const AppStatus: React.FC<{ status: AppTypes.AppStatus; lite?: boolean }> }); return ( -
- - {!lite && {formattedStatus}} -
+ <> + {lite && ( + + {formattedStatus} + + )} +
+ + {!lite && {formattedStatus}} +
+ ); }; diff --git a/src/client/components/AppTile/AppTile.tsx b/src/client/components/AppTile/AppTile.tsx index 8f9cdd73..e8e44580 100644 --- a/src/client/components/AppTile/AppTile.tsx +++ b/src/client/components/AppTile/AppTile.tsx @@ -1,6 +1,7 @@ import Link from 'next/link'; import React from 'react'; import { IconDownload } from '@tabler/icons-react'; +import { Tooltip } from 'react-tooltip'; import { AppStatus } from '../AppStatus'; import { AppLogo } from '../AppLogo/AppLogo'; import { limitText } from '../../modules/AppStore/helpers/table.helpers'; @@ -30,9 +31,12 @@ export const AppTile: React.FC<{ app: AppTileInfo; status: AppStatusEnum; update {updateAvailable && ( -
- -
+ <> + Update available +
+ +
+ )} diff --git a/src/client/components/Layout/Layout.tsx b/src/client/components/Layout/Layout.tsx index 7e41962b..c8b28d39 100644 --- a/src/client/components/Layout/Layout.tsx +++ b/src/client/components/Layout/Layout.tsx @@ -2,7 +2,6 @@ import Head from 'next/head'; import Link from 'next/link'; import React, { useEffect } from 'react'; import clsx from 'clsx'; -import ReactTooltip from 'react-tooltip'; import semver from 'semver'; import { useRouter } from 'next/router'; import { Header } from '../ui/Header'; @@ -61,7 +60,6 @@ export const Layout: React.FC = ({ children, breadcrumbs, title, actions {`${title} - Tipi`} -
diff --git a/src/client/components/ui/Header/Header.test.tsx b/src/client/components/ui/Header/Header.test.tsx index e87cd9d7..a09158b3 100644 --- a/src/client/components/ui/Header/Header.test.tsx +++ b/src/client/components/ui/Header/Header.test.tsx @@ -5,8 +5,7 @@ import { Header } from './Header'; describe('Header', () => { it('renders without crashing', () => { - const { container } = render(
); - expect(container).toBeInTheDocument(); + render(
); }); it('renders the brand logo', () => { @@ -16,22 +15,22 @@ describe('Header', () => { }); it('renders the dark mode toggle', () => { - const { container } = render(
); - const darkModeToggle = container.querySelector('[data-tip="Dark mode"]'); + render(
); + const darkModeToggle = screen.getByTestId('dark-mode-toggle'); expect(darkModeToggle).toContainElement(screen.getByTestId('icon-moon')); }); it('renders the light mode toggle', () => { - const { container } = render(
); - const lightModeToggle = container.querySelector('[data-tip="Light mode"]'); + render(
); + const lightModeToggle = screen.getByTestId('light-mode-toggle'); expect(lightModeToggle).toContainElement(screen.getByTestId('icon-sun')); }); it('Should toggle the dark mode on click of the dark mode toggle', () => { const { result } = renderHook(() => useUIStore()); - const { container } = render(
); - const darkModeToggle = container.querySelector('[data-tip="Dark mode"]'); + render(
); + const darkModeToggle = screen.getByTestId('dark-mode-toggle'); fireEvent.click(darkModeToggle as Element); expect(result.current.darkMode).toBe(true); @@ -40,8 +39,8 @@ describe('Header', () => { it('Should toggle the dark mode on click of the light mode toggle', () => { const { result } = renderHook(() => useUIStore()); - const { container } = render(
); - const lightModeToggle = container.querySelector('[data-tip="Light mode"]'); + render(
); + const lightModeToggle = screen.getByTestId('light-mode-toggle'); fireEvent.click(lightModeToggle as Element); expect(result.current.darkMode).toBe(false); @@ -49,8 +48,8 @@ describe('Header', () => { it('Should remove the token from local storage on logout', async () => { localStorage.setItem('token', 'token'); - const { container } = render(
); - const logoutButton = container.querySelector('[data-tip="Log out"]'); + render(
); + const logoutButton = screen.getByTestId('logout-button'); fireEvent.click(logoutButton as Element); await waitFor(() => { diff --git a/src/client/components/ui/Header/Header.tsx b/src/client/components/ui/Header/Header.tsx index 904e7191..b2963391 100644 --- a/src/client/components/ui/Header/Header.tsx +++ b/src/client/components/ui/Header/Header.tsx @@ -4,6 +4,7 @@ import Image from 'next/image'; import clsx from 'clsx'; import Link from 'next/link'; import { useRouter } from 'next/router'; +import { Tooltip } from 'react-tooltip'; import { getUrl } from '../../../core/helpers/url-helpers'; import { useUIStore } from '../../../state/uiStore'; import { NavBar } from '../NavBar'; @@ -62,14 +63,17 @@ export const Header: React.FC = ({ isUpdateAvailable }) => {
-
-
setDarkMode(true)} role="button" aria-hidden="true" className="nav-link px-0 hide-theme-dark cursor-pointer" data-tip="Dark mode"> +
+ Dark mode +
setDarkMode(true)} role="button" aria-hidden="true" className="darkMode nav-link px-0 hide-theme-dark cursor-pointer" data-testid="dark-mode-toggle">
-
setDarkMode(false)} aria-hidden="true" className="nav-link px-0 hide-theme-light cursor-pointer" data-tip="Light mode"> + Light mode +
setDarkMode(false)} aria-hidden="true" className="lightMode nav-link px-0 hide-theme-light cursor-pointer" data-testid="light-mode-toggle">
-
logout.mutate()} tabIndex={0} onKeyPress={() => logout.mutate()} role="button" className="nav-link px-0 cursor-pointer" data-tip="Log out"> + Log out +
logout.mutate()} tabIndex={0} onKeyPress={() => logout.mutate()} role="button" className="logOut nav-link px-0 cursor-pointer" data-testid="logout-button">
diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 77f2b1f3..3e8a1043 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -4,6 +4,7 @@ import type { AppProps } from 'next/app'; import Head from 'next/head'; import '../client/styles/global.css'; import '../client/styles/global.scss'; +import 'react-tooltip/dist/react-tooltip.css'; import { useUIStore } from '../client/state/uiStore'; import { ToastProvider } from '../client/components/hoc/ToastProvider'; import { StatusProvider } from '../client/components/hoc/StatusProvider';