From 6e1dca60dddb8d9e3457c8b077e8713b88e5154c Mon Sep 17 00:00:00 2001 From: Jethary Rader <66035149+jerader@users.noreply.github.com> Date: Mon, 22 Jul 2024 14:21:59 -0400 Subject: [PATCH] feat(components, app, labware-library): migrate to react-router-dom v6.24.1 (#15699) closes AUTH-564 --- app/package.json | 2 +- app/src/App/DesktopApp.tsx | 60 ++++++------ app/src/App/DesktopAppFallback.tsx | 6 +- app/src/App/OnDeviceDisplayApp.tsx | 30 +++--- app/src/App/__tests__/Navbar.test.tsx | 10 +- app/src/App/types.ts | 1 - app/src/atoms/buttons/BackButton.tsx | 6 +- .../buttons/__tests__/BackButton.test.tsx | 16 ++-- app/src/index.tsx | 8 +- .../CardButton/__tests__/CardButton.test.tsx | 10 +- app/src/molecules/CardButton/index.tsx | 6 +- .../__tests__/Breadcrumbs.test.tsx | 47 ++++++--- app/src/organisms/Breadcrumbs/index.tsx | 9 +- .../__tests__/CalibrationTaskList.test.tsx | 42 ++++---- .../organisms/CalibrationTaskList/index.tsx | 8 +- .../__tests__/ChangePipette.test.tsx | 8 +- app/src/organisms/ChangePipette/index.tsx | 6 +- .../__tests__/ChooseProtocolSlideout.test.tsx | 6 +- .../ChooseProtocolSlideout/index.tsx | 6 +- .../__tests__/ChooseRobotSlideout.test.tsx | 6 +- .../__tests__/FileCard.test.tsx | 6 +- .../ChooseRobotToRunProtocolSlideout.test.tsx | 6 +- .../index.tsx | 8 +- .../DeckConfigurationDiscardChangesModal.tsx | 6 +- ...kConfigurationDiscardChangesModal.test.tsx | 10 +- .../HistoricalProtocolRunOverflowMenu.tsx | 6 +- .../Devices/ProtocolRun/ProtocolRunHeader.tsx | 16 ++-- .../__tests__/LabwareListItem.test.tsx | 6 +- .../__tests__/OffDeckLabwareList.test.tsx | 6 +- .../__tests__/SetupLabware.test.tsx | 6 +- .../__tests__/SetupLabwareList.test.tsx | 6 +- .../__tests__/SetupLabwareMap.test.tsx | 6 +- .../SetupLabwarePositionCheck.test.tsx | 6 +- .../ChooseModuleToConfigureModal.tsx | 6 +- .../__tests__/SetupModulesMap.test.tsx | 6 +- .../__tests__/BackToTopButton.test.tsx | 6 +- .../__tests__/ProtocolRunHeader.test.tsx | 10 +- app/src/organisms/Devices/RobotCard.tsx | 6 +- .../Devices/RobotOverviewOverflowMenu.tsx | 6 +- .../AdvancedTabSlideouts/DeviceResetModal.tsx | 6 +- .../RenameRobotSlideout.tsx | 8 +- .../organisms/Devices/RobotStatusHeader.tsx | 6 +- .../__tests__/InstrumentInfo.test.tsx | 4 +- app/src/organisms/InstrumentInfo/index.tsx | 8 +- .../AttachedInstrumentMountItem.tsx | 13 ++- .../ModuleCard/__tests__/ModuleCard.test.tsx | 8 ++ app/src/organisms/ModuleCard/index.tsx | 6 +- .../organisms/Navigation/NavigationMenu.tsx | 6 +- .../__tests__/NavigationMenu.test.tsx | 10 +- .../AlternativeSecurityTypeModal.tsx | 6 +- .../NetworkSettings/DisplayWifiList.tsx | 6 +- .../NetworkSettings/WifiConnectionDetails.tsx | 6 +- .../AlternativeSecurityTypeModal.test.tsx | 10 +- .../__tests__/DisplayWifiList.test.tsx | 10 +- .../SelectAuthenticationType.test.tsx | 8 +- .../__tests__/WifiConnectionDetails.test.tsx | 10 +- .../NameRobot/ConfirmRobotName.tsx | 6 +- .../__tests__/ConfirmRobotName.test.tsx | 10 +- .../RobotDashboard/RecentRunProtocolCard.tsx | 8 +- .../__tests__/RecentRunProtocolCard.test.tsx | 10 +- .../RunningProtocol/ConfirmCancelRunModal.tsx | 8 +- .../RunningProtocol/RunFailedModal.tsx | 6 +- .../__tests__/ConfirmCancelRunModal.test.tsx | 10 +- .../__tests__/RunFailedModal.test.tsx | 10 +- .../ProtocolAnalysisFailure.test.tsx | 6 +- .../__tests__/ProtocolDetails.test.tsx | 6 +- .../__tests__/LabwareMapViewModal.test.tsx | 6 +- .../ProtocolSetupModulesAndDeck/index.tsx | 13 ++- .../AnalysisFailedModal.tsx | 6 +- .../__tests__/AnalysisFailedModal.test.tsx | 12 +-- .../ProtocolSetupParameters.test.tsx | 12 +-- .../ProtocolSetupParameters/index.tsx | 6 +- .../ProtocolsLanding/ProtocolCard.tsx | 6 +- .../ProtocolsLanding/ProtocolOverflowMenu.tsx | 6 +- .../QuickTransferFlow/SummaryAndSettings.tsx | 8 +- .../__tests__/SummaryAndSettings.test.tsx | 8 +- app/src/organisms/QuickTransferFlow/index.tsx | 6 +- .../__tests__/WifiConnectionDetails.test.tsx | 4 +- .../RobotSystemVersionModal.tsx | 6 +- .../RobotSystemVersionModal.test.tsx | 6 +- .../SendProtocolToFlexSlideout.test.tsx | 6 +- .../__tests__/UpdateAppModal.test.tsx | 4 +- app/src/organisms/UpdateAppModal/index.tsx | 6 +- .../AppSettings/__test__/AppSettings.test.tsx | 8 +- app/src/pages/AppSettings/index.tsx | 8 +- .../DisplayConnectionStatus.tsx | 6 +- .../pages/ConnectViaEthernet/TitleHeader.tsx | 6 +- .../DisplayConnectionStatus.test.tsx | 10 +- .../__tests__/TitleHeader.test.tsx | 10 +- .../_tests__/ConnectedViaUSB.test.tsx | 12 +-- app/src/pages/ConnectViaUSB/index.tsx | 8 +- .../__tests__/DeckConfiguration.test.tsx | 6 +- app/src/pages/DeckConfiguration/index.tsx | 6 +- .../__tests__/CalibrationDashboard.test.tsx | 11 ++- .../Devices/CalibrationDashboard/index.tsx | 4 +- .../__tests__/DeviceDetails.test.tsx | 10 +- app/src/pages/Devices/DeviceDetails/index.tsx | 8 +- .../__tests__/ProtocolRunDetails.test.tsx | 11 ++- .../Devices/ProtocolRunDetails/index.tsx | 20 ++-- .../__tests__/RobotSettings.test.tsx | 18 ++-- app/src/pages/Devices/RobotSettings/index.tsx | 12 ++- .../__tests__/EmergencyStop.test.tsx | 10 +- app/src/pages/EmergencyStop/index.tsx | 6 +- .../__tests__/InstrumentDetail.test.tsx | 2 +- .../__tests__/InstrumentsDashboard.test.tsx | 34 ++++--- .../NameRobot/__tests__/NameRobot.test.tsx | 10 +- app/src/pages/NameRobot/index.tsx | 10 +- .../__tests__/NetworkSetupMenu.test.tsx | 14 +-- .../ProtocolDashboard/LongPressModal.tsx | 6 +- .../ProtocolDashboard/PinnedProtocol.tsx | 6 +- .../pages/ProtocolDashboard/ProtocolCard.tsx | 6 +- .../__tests__/PinnedProtocol.test.tsx | 10 +- .../__tests__/ProtocolCard.test.tsx | 10 +- .../__tests__/ProtocolDetails.test.tsx | 8 +- app/src/pages/ProtocolDetails/index.tsx | 16 ++-- .../__tests__/ProtocolSetup.test.tsx | 22 ++--- app/src/pages/ProtocolSetup/index.tsx | 12 ++- .../ProtocolDetails/ProtocolTimeline.tsx | 4 +- .../__tests__/ProtocolDetails.test.tsx | 12 +-- .../pages/Protocols/ProtocolDetails/index.tsx | 8 +- .../DeleteTransferConfirmationModal.tsx | 8 +- .../QuickTransferDashboard/LongPressModal.tsx | 6 +- .../QuickTransferDashboard/PinnedTransfer.tsx | 6 +- .../QuickTransferCard.tsx | 6 +- .../DeleteTransferConfirmationModal.test.tsx | 8 +- .../__tests__/PinnedTransfer.test.tsx | 10 +- .../__tests__/QuickTransferCard.test.tsx | 10 +- .../pages/QuickTransferDashboard/index.tsx | 8 +- .../__tests__/QuickTransferDetails.test.tsx | 11 ++- app/src/pages/QuickTransferDetails/index.tsx | 10 +- .../__tests__/RobotDashboard.test.tsx | 8 +- app/src/pages/RunSummary/index.tsx | 10 +- .../__tests__/RunningProtocol.test.tsx | 8 +- app/src/pages/RunningProtocol/index.tsx | 4 +- app/src/pages/UpdateRobot/UpdateRobot.tsx | 12 ++- .../UpdateRobotDuringOnboarding.tsx | 8 +- .../pages/Welcome/__tests__/Welcome.test.tsx | 12 +-- app/src/pages/Welcome/index.tsx | 6 +- app/src/redux/reducer.ts | 14 +-- app/src/redux/store.ts | 11 +-- app/src/redux/types.ts | 3 +- components/package.json | 5 +- components/src/index.ts | 1 - components/src/lists/ListItem.tsx | 92 ------------------ components/src/lists/index.ts | 1 - components/src/structure/PageTabs.tsx | 46 --------- components/src/structure/index.ts | 1 - components/src/tabbedNav/index.ts | 7 -- labware-library/package.json | 3 +- labware-library/src/components/App/index.tsx | 5 +- .../components/Sidebar/FilterManufacturer.tsx | 16 ++-- labware-library/src/components/ui/Link.tsx | 16 +--- labware-library/src/definitions.tsx | 24 ++--- labware-library/src/filters.tsx | 4 +- labware-library/src/index.tsx | 10 +- package.json | 1 - .../src/containers/ConnectedNav.tsx | 4 +- .../src/containers}/NavTab.tsx | 8 +- .../src/containers}/OutsideLinkTab.tsx | 6 +- .../src/containers}/TabbedNavBar.tsx | 0 .../src/containers}/navbar.module.css | 2 +- yarn.lock | 96 ++----------------- 162 files changed, 722 insertions(+), 944 deletions(-) delete mode 100644 components/src/lists/ListItem.tsx delete mode 100644 components/src/structure/PageTabs.tsx delete mode 100644 components/src/tabbedNav/index.ts rename {components/src/tabbedNav => protocol-designer/src/containers}/NavTab.tsx (90%) rename {components/src/tabbedNav => protocol-designer/src/containers}/OutsideLinkTab.tsx (92%) rename {components/src/tabbedNav => protocol-designer/src/containers}/TabbedNavBar.tsx (100%) rename {components/src/tabbedNav => protocol-designer/src/containers}/navbar.module.css (96%) diff --git a/app/package.json b/app/package.json index 2108a9dff65..43a1869b186 100644 --- a/app/package.json +++ b/app/package.json @@ -53,7 +53,7 @@ "react-intersection-observer": "^8.33.1", "react-markdown": "9.0.1", "react-redux": "8.1.2", - "react-router-dom": "5.3.4", + "react-router-dom": "6.24.1", "react-select": "5.4.0", "react-simple-keyboard": "^3.7.0", "react-viewport-list": "6.3.0", diff --git a/app/src/App/DesktopApp.tsx b/app/src/App/DesktopApp.tsx index 910f9a9895d..ab0b91f7c9c 100644 --- a/app/src/App/DesktopApp.tsx +++ b/app/src/App/DesktopApp.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { Redirect, Route, Switch, useRouteMatch } from 'react-router-dom' +import { Navigate, Route, Routes, useMatch } from 'react-router-dom' import { ErrorBoundary } from 'react-error-boundary' import { I18nextProvider } from 'react-i18next' @@ -48,20 +48,17 @@ export const DesktopApp = (): JSX.Element => { const desktopRoutes: RouteProps[] = [ { Component: ProtocolsLanding, - exact: true, name: 'Protocols', navLinkTo: '/protocols', path: '/protocols', }, { Component: ProtocolDetails, - exact: true, name: 'Protocol Details', path: '/protocols/:protocolKey', }, { Component: ProtocolTimeline, - exact: true, name: 'Protocol Timeline', path: '/protocols/:protocolKey/timeline', }, @@ -73,26 +70,22 @@ export const DesktopApp = (): JSX.Element => { }, { Component: DevicesLanding, - exact: true, name: 'Devices', navLinkTo: '/devices', path: '/devices', }, { Component: DeviceDetails, - exact: true, name: 'Device', path: '/devices/:robotName', }, { Component: RobotSettings, - exact: true, name: 'Robot Settings', path: '/devices/:robotName/robot-settings/:robotSettingsTab?', }, { Component: CalibrationDashboard, - exact: true, name: 'Calibration Dashboard', path: '/devices/:robotName/robot-settings/calibration/dashboard', }, @@ -103,7 +96,6 @@ export const DesktopApp = (): JSX.Element => { }, { Component: AppSettings, - exact: true, name: 'App Settings', path: '/app-settings/:appSettingsTab?', }, @@ -123,33 +115,37 @@ export const DesktopApp = (): JSX.Element => { > - - {desktopRoutes.map( - ({ Component, exact, path }: RouteProps) => { - return ( - - - + + {desktopRoutes.map(({ Component, path }: RouteProps) => { + return ( + + - - + + + + - - - ) - } - )} - - + > + } + path={path} + /> + ) + })} + } /> + @@ -162,7 +158,7 @@ export const DesktopApp = (): JSX.Element => { } function RobotControlTakeover(): JSX.Element | null { - const deviceRouteMatch = useRouteMatch({ path: '/devices/:robotName' }) + const deviceRouteMatch = useMatch('/devices/:robotName') const params = deviceRouteMatch?.params as DesktopRouteParams const robotName = params?.robotName const robot = useRobot(robotName) diff --git a/app/src/App/DesktopAppFallback.tsx b/app/src/App/DesktopAppFallback.tsx index 03c5c367b3c..30525606b23 100644 --- a/app/src/App/DesktopAppFallback.tsx +++ b/app/src/App/DesktopAppFallback.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useDispatch } from 'react-redux' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { useTrackEvent, ANALYTICS_DESKTOP_APP_ERROR } from '../redux/analytics' @@ -26,14 +26,14 @@ export function DesktopAppFallback({ error }: FallbackProps): JSX.Element { const { t } = useTranslation('app_settings') const trackEvent = useTrackEvent() const dispatch = useDispatch() - const history = useHistory() + const navigate = useNavigate() const handleReloadClick = (): void => { trackEvent({ name: ANALYTICS_DESKTOP_APP_ERROR, properties: { errorMessage: error.message }, }) // route to the root page and initiate an electron browser window reload via app-shell - history.push('/') + navigate('/', { replace: true }) dispatch(reloadUi(error.message as string)) } diff --git a/app/src/App/OnDeviceDisplayApp.tsx b/app/src/App/OnDeviceDisplayApp.tsx index 61c039b06b8..ae0e0a1d933 100644 --- a/app/src/App/OnDeviceDisplayApp.tsx +++ b/app/src/App/OnDeviceDisplayApp.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useDispatch, useSelector } from 'react-redux' -import { Switch, Route, Redirect } from 'react-router-dom' +import { Routes, Route, Navigate } from 'react-router-dom' import { css } from 'styled-components' import { ErrorBoundary } from 'react-error-boundary' @@ -252,23 +252,31 @@ export function OnDeviceDisplayAppRoutes(): JSX.Element { ` return ( - + {ON_DEVICE_DISPLAY_PATHS.map(path => ( - - - - {getPathComponent(path)} - - + + + {getPathComponent(path)} + + } + /> ))} - {targetPath != null && } - + {targetPath != null && ( + } /> + )} + ) } function TopLevelRedirects(): JSX.Element | null { const currentRunRoute = useCurrentRunRoute() - return currentRunRoute != null ? : null + return currentRunRoute != null ? ( + } /> + ) : null } function ProtocolReceiptToasts(): null { diff --git a/app/src/App/__tests__/Navbar.test.tsx b/app/src/App/__tests__/Navbar.test.tsx index c5ec4661226..db7eedc744b 100644 --- a/app/src/App/__tests__/Navbar.test.tsx +++ b/app/src/App/__tests__/Navbar.test.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { describe, it } from 'vitest' import { screen, render } from '@testing-library/react' -import { StaticRouter } from 'react-router-dom' +import { MemoryRouter } from 'react-router-dom' import { Navbar } from '../Navbar' @@ -16,9 +16,9 @@ const ROUTE_PROPS: RouteProps[] = [ describe('Navbar', () => { it('should render a NavbarLink for every nav location', () => { render( - + - + ) screen.getByRole('link', { name: 'foo' }) screen.getByRole('link', { name: 'bar' }) @@ -26,9 +26,9 @@ describe('Navbar', () => { }) it('should render logo, settings, and help', () => { render( - + - + ) screen.getByRole('img', { name: 'opentrons logo' }) screen.getByTestId('Navbar_settingsLink') diff --git a/app/src/App/types.ts b/app/src/App/types.ts index 7896158f8fe..b75f19aedb7 100644 --- a/app/src/App/types.ts +++ b/app/src/App/types.ts @@ -6,7 +6,6 @@ export interface RouteProps { * drop developed components into slots held by placeholder div components */ Component: React.FC - exact?: boolean /** * a route/page name to render in the nav bar */ diff --git a/app/src/atoms/buttons/BackButton.tsx b/app/src/atoms/buttons/BackButton.tsx index 1395c03ab8f..05df2fd800b 100644 --- a/app/src/atoms/buttons/BackButton.tsx +++ b/app/src/atoms/buttons/BackButton.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { ALIGN_CENTER, @@ -16,7 +16,7 @@ export function BackButton({ onClick, children, }: React.HTMLProps): JSX.Element { - const history = useHistory() + const navigate = useNavigate() const { t } = useTranslation('shared') return ( @@ -28,7 +28,7 @@ export function BackButton({ onClick != null ? onClick : () => { - history.goBack() + navigate(-1) } } > diff --git a/app/src/atoms/buttons/__tests__/BackButton.test.tsx b/app/src/atoms/buttons/__tests__/BackButton.test.tsx index e1c2ae3e68f..7b1595d0b83 100644 --- a/app/src/atoms/buttons/__tests__/BackButton.test.tsx +++ b/app/src/atoms/buttons/__tests__/BackButton.test.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import { fireEvent, screen } from '@testing-library/react' import { describe, it, expect, vi } from 'vitest' import '@testing-library/jest-dom/vitest' -import { MemoryRouter, Route, Switch } from 'react-router-dom' +import { MemoryRouter, Route, Routes } from 'react-router-dom' import { renderWithProviders } from '../../../__testing-utils__' @@ -16,14 +16,10 @@ const render = (props?: React.HTMLProps) => { initialIndex={1} > - - - this is the current page - - - this is the previous page - - + + this is the current page>} /> + this is the previous page>} /> + , { i18nInstance: i18n } )[0] @@ -49,7 +45,7 @@ describe('BackButton', () => { expect(screen.queryByText('this is the previous page')).toBeNull() }) - it('goes back one page in history on click if no on click handler provided', () => { + it('goes back one page in navigate on click if no on click handler provided', () => { render() screen.getByText('this is the current page') diff --git a/app/src/index.tsx b/app/src/index.tsx index e37435c9aba..b8fe832abdc 100644 --- a/app/src/index.tsx +++ b/app/src/index.tsx @@ -2,15 +2,13 @@ import React from 'react' import ReactDom from 'react-dom/client' import { Provider } from 'react-redux' - -import { ConnectedRouter } from 'connected-react-router' +import { BrowserRouter } from 'react-router-dom' import { ApiClientProvider } from '@opentrons/react-api-client' import { createLogger } from './logger' import { uiInitialized } from './redux/shell' -import { history } from './redux/reducer' import { store } from './redux/store' import '../src/atoms/SoftwareKeyboard/AlphanumericKeyboard' @@ -34,10 +32,10 @@ if (container == null) throw new Error('Failed to find the root element') const root = ReactDom.createRoot(container) root.render( - + - + ) diff --git a/app/src/molecules/CardButton/__tests__/CardButton.test.tsx b/app/src/molecules/CardButton/__tests__/CardButton.test.tsx index 80d17c32d08..04a841ccc23 100644 --- a/app/src/molecules/CardButton/__tests__/CardButton.test.tsx +++ b/app/src/molecules/CardButton/__tests__/CardButton.test.tsx @@ -7,15 +7,15 @@ import { COLORS } from '@opentrons/components' import { renderWithProviders } from '../../../__testing-utils__' import { i18n } from '../../../i18n' import { CardButton } from '..' -import type * as ReactRouterDom from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const reactRouterDom = await importOriginal() + const reactRouterDom = await importOriginal() return { ...reactRouterDom, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) @@ -65,6 +65,6 @@ describe('CardButton', () => { render(props) const button = screen.getByRole('button') fireEvent.click(button) - expect(mockPush).toHaveBeenCalledWith('/mockPath') + expect(mockNavigate).toHaveBeenCalledWith('/mockPath') }) }) diff --git a/app/src/molecules/CardButton/index.tsx b/app/src/molecules/CardButton/index.tsx index a07753c240d..1181985f772 100644 --- a/app/src/molecules/CardButton/index.tsx +++ b/app/src/molecules/CardButton/index.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { css } from 'styled-components' import { ALIGN_CENTER, @@ -76,12 +76,12 @@ interface CardButtonProps { export function CardButton(props: CardButtonProps): JSX.Element { const { title, iconName, description, destinationPath, disabled } = props - const history = useHistory() + const navigate = useNavigate() return ( { - history.push(destinationPath) + navigate(destinationPath) }} width="100%" css={CARD_BUTTON_STYLE} diff --git a/app/src/organisms/Breadcrumbs/__tests__/Breadcrumbs.test.tsx b/app/src/organisms/Breadcrumbs/__tests__/Breadcrumbs.test.tsx index 688a3d8a9f1..bd06ebcd9df 100644 --- a/app/src/organisms/Breadcrumbs/__tests__/Breadcrumbs.test.tsx +++ b/app/src/organisms/Breadcrumbs/__tests__/Breadcrumbs.test.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { MemoryRouter, Route, Switch } from 'react-router-dom' +import { MemoryRouter, Route, Routes } from 'react-router-dom' import { when } from 'vitest-when' import { describe, it, expect, beforeEach, vi } from 'vitest' @@ -34,20 +34,37 @@ const PROTOCOL_NAME = 'a protocol for otie' const render = (path = '/') => { return renderWithProviders( - - - - device details path matched - - - - protocol run details path matched - - - - protocol details path matched - - + + + + device details path matched + > + } + /> + + + + protocol run details path matched + > + } + /> + + + + protocol details path matched + > + } + /> + , { i18nInstance: i18n, diff --git a/app/src/organisms/Breadcrumbs/index.tsx b/app/src/organisms/Breadcrumbs/index.tsx index f7f43ae3745..e760cf8beb4 100644 --- a/app/src/organisms/Breadcrumbs/index.tsx +++ b/app/src/organisms/Breadcrumbs/index.tsx @@ -71,8 +71,9 @@ const CrumbLinkInactive = styled(Flex)` function BreadcrumbsComponent(): JSX.Element | null { const { t } = useTranslation('top_navigation') const isOnDevice = useSelector(getIsOnDevice) - const { protocolKey, robotName, runId } = useParams() - + const { protocolKey, robotName, runId } = useParams< + keyof DesktopRouteParams + >() as DesktopRouteParams const runCreatedAtTimestamp = useRunCreatedAtTimestamp(runId) const storedProtocol = useSelector((state: State) => @@ -148,7 +149,9 @@ function BreadcrumbsComponent(): JSX.Element | null { } export function Breadcrumbs(): JSX.Element | null { - const { robotName } = useParams() + const { robotName } = useParams< + keyof DesktopRouteParams + >() as DesktopRouteParams const robot = useRobot(robotName) return ( diff --git a/app/src/organisms/CalibrationTaskList/__tests__/CalibrationTaskList.test.tsx b/app/src/organisms/CalibrationTaskList/__tests__/CalibrationTaskList.test.tsx index 8ad8fe61ce6..2c3e27b43df 100644 --- a/app/src/organisms/CalibrationTaskList/__tests__/CalibrationTaskList.test.tsx +++ b/app/src/organisms/CalibrationTaskList/__tests__/CalibrationTaskList.test.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { StaticRouter } from 'react-router-dom' +import { MemoryRouter } from 'react-router-dom' import { vi, it, describe, expect, beforeEach, afterEach } from 'vitest' import { fireEvent, screen } from '@testing-library/react' @@ -30,7 +30,7 @@ vi.mock('../../ProtocolUpload/hooks') const render = (robotName: string = 'otie') => { return renderWithProviders( - + { deckCalLauncher={mockDeckCalLauncher} exitBeforeDeckConfigCompletion={false} /> - , + , { i18nInstance: i18n, } @@ -82,7 +82,7 @@ describe('CalibrationTaskList', () => { // Complete screen will only render if a wizard has been launched fireEvent.click(screen.getByText('Calibrate')) rerender( - + { deckCalLauncher={mockDeckCalLauncher} exitBeforeDeckConfigCompletion={false} /> - + ) expect(screen.getByText('Calibrations complete!')).toBeTruthy() }) @@ -108,7 +108,7 @@ describe('CalibrationTaskList', () => { screen.getByText('Right Mount') fireEvent.click(screen.getByText('Calibrate')) rerender( - + { deckCalLauncher={mockDeckCalLauncher} exitBeforeDeckConfigCompletion={false} /> - + ) expect(screen.getByText('Calibrations complete!')).toBeTruthy() }) @@ -133,7 +133,7 @@ describe('CalibrationTaskList', () => { screen.getByText('Right Mount') fireEvent.click(screen.getByText('Calibrate')) rerender( - + { deckCalLauncher={mockDeckCalLauncher} exitBeforeDeckConfigCompletion={false} /> - + ) expect(screen.getByText('Calibrations complete!')).toBeTruthy() }) @@ -158,7 +158,7 @@ describe('CalibrationTaskList', () => { screen.getByText('Right Mount') fireEvent.click(screen.getByText('Calibrate')) rerender( - + { deckCalLauncher={mockDeckCalLauncher} exitBeforeDeckConfigCompletion={false} /> - + ) expect(screen.getByText('Calibrations complete!')).toBeTruthy() }) @@ -182,7 +182,7 @@ describe('CalibrationTaskList', () => { expect(recalibrateLinks).toHaveLength(3) fireEvent.click(recalibrateLinks[2]) rerender( - + { deckCalLauncher={mockDeckCalLauncher} exitBeforeDeckConfigCompletion={false} /> - + ) expect(screen.getByText('Calibrations complete!')).toBeTruthy() }) @@ -206,7 +206,7 @@ describe('CalibrationTaskList', () => { expect(recalibrateLinks).toHaveLength(3) fireEvent.click(recalibrateLinks[0]) rerender( - + { deckCalLauncher={mockDeckCalLauncher} exitBeforeDeckConfigCompletion={false} /> - + ) expect(screen.getByText('Calibrations complete!')).toBeTruthy() }) @@ -228,7 +228,7 @@ describe('CalibrationTaskList', () => { const recalibrateLink = screen.getByText('Recalibrate') fireEvent.click(recalibrateLink) rerender( - + { deckCalLauncher={mockDeckCalLauncher} exitBeforeDeckConfigCompletion={true} /> - + ) expect(screen.getByText('Using current calibrations.')).toBeTruthy() }) @@ -253,7 +253,7 @@ describe('CalibrationTaskList', () => { fireEvent.click(calibrateButtons[0]) expect(mockDeckCalLauncher).not.toHaveBeenCalled() rerender( - + { deckCalLauncher={mockDeckCalLauncher} exitBeforeDeckConfigCompletion={false} /> - + ) const recalibrateLinks = screen.getAllByText('Recalibrate') expect(recalibrateLinks).toHaveLength(1) // only deck's recalibration link should be shown @@ -281,7 +281,7 @@ describe('CalibrationTaskList', () => { fireEvent.click(calibrateButtons[0]) expect(mockTipLengthCalLauncher).not.toHaveBeenCalled() rerender( - + { deckCalLauncher={mockDeckCalLauncher} exitBeforeDeckConfigCompletion={false} /> - + ) fireEvent.click(screen.getByText('Left Mount')) const recalibrateLinks = screen.getAllByText('Recalibrate') diff --git a/app/src/organisms/CalibrationTaskList/index.tsx b/app/src/organisms/CalibrationTaskList/index.tsx index d3011a8d573..301a6d1e2b8 100644 --- a/app/src/organisms/CalibrationTaskList/index.tsx +++ b/app/src/organisms/CalibrationTaskList/index.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { css } from 'styled-components' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { ALIGN_CENTER, @@ -55,7 +55,7 @@ export function CalibrationTaskList({ setShowCompletionScreen, ] = React.useState(false) const { t } = useTranslation(['robot_calibration', 'device_settings']) - const history = useHistory() + const navigate = useNavigate() const { activeIndex, taskList, taskListStatus } = useCalibrationTaskList( pipOffsetCalLauncher, tipLengthCalLauncher, @@ -111,7 +111,7 @@ export function CalibrationTaskList({ { - history.push(`/devices/${robotName}/robot-settings/calibration`) + navigate(`/devices/${robotName}/robot-settings/calibration`) }} fullPage backgroundColor={COLORS.grey10} @@ -145,7 +145,7 @@ export function CalibrationTaskList({ { - history.push(`/devices/${robotName}/robot-settings/calibration`) + navigate(`/devices/${robotName}/robot-settings/calibration`) }} > {t('device_settings:done')} diff --git a/app/src/organisms/ChangePipette/__tests__/ChangePipette.test.tsx b/app/src/organisms/ChangePipette/__tests__/ChangePipette.test.tsx index 47277d64b76..40b2174194b 100644 --- a/app/src/organisms/ChangePipette/__tests__/ChangePipette.test.tsx +++ b/app/src/organisms/ChangePipette/__tests__/ChangePipette.test.tsx @@ -21,18 +21,18 @@ import { ExitModal } from '../ExitModal' import { ConfirmPipette } from '../ConfirmPipette' import { ChangePipette } from '..' -import type { useHistory } from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' import type { PipetteNameSpecs } from '@opentrons/shared-data' import type { AttachedPipette } from '../../../redux/pipettes/types' import type { DispatchApiRequestType } from '../../../redux/robot-api' -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush }), + useNavigate: () => mockNavigate, } }) diff --git a/app/src/organisms/ChangePipette/index.tsx b/app/src/organisms/ChangePipette/index.tsx index de19bf2f353..a241ed2dd8c 100644 --- a/app/src/organisms/ChangePipette/index.tsx +++ b/app/src/organisms/ChangePipette/index.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import capitalize from 'lodash/capitalize' import { useSelector, useDispatch } from 'react-redux' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { getPipetteNameSpecs } from '@opentrons/shared-data' import { SPACING, TYPOGRAPHY, LegacyStyledText } from '@opentrons/components' @@ -57,7 +57,7 @@ interface Props { export function ChangePipette(props: Props): JSX.Element | null { const { robotName, mount, closeModal } = props const { t } = useTranslation(['change_pipette', 'shared']) - const history = useHistory() + const navigate = useNavigate() const dispatch = useDispatch() const finalRequestId = React.useRef(null) const [dispatchApiRequests] = useDispatchApiRequests(dispatchedAction => { @@ -267,7 +267,7 @@ export function ChangePipette(props: Props): JSX.Element | null { const toCalDashboard = (): void => { dispatchApiRequests(home(robotName, ROBOT)) closeModal() - history.push(`/devices/${robotName}/robot-settings/calibration/dashboard`) + navigate(`/devices/${robotName}/robot-settings/calibration/dashboard`) } exitWizardHeader = diff --git a/app/src/organisms/ChooseProtocolSlideout/__tests__/ChooseProtocolSlideout.test.tsx b/app/src/organisms/ChooseProtocolSlideout/__tests__/ChooseProtocolSlideout.test.tsx index 0b812ae060c..af2ce216663 100644 --- a/app/src/organisms/ChooseProtocolSlideout/__tests__/ChooseProtocolSlideout.test.tsx +++ b/app/src/organisms/ChooseProtocolSlideout/__tests__/ChooseProtocolSlideout.test.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { vi, it, describe, expect, beforeEach } from 'vitest' -import { StaticRouter } from 'react-router-dom' +import { MemoryRouter } from 'react-router-dom' import { fireEvent, screen, waitFor } from '@testing-library/react' import { simpleAnalysisFileFixture } from '@opentrons/api-client' @@ -27,9 +27,9 @@ vi.mock('../../../resources/useNotifyDataReady') const render = (props: React.ComponentProps) => { return renderWithProviders( - + - , + , { i18nInstance: i18n, } diff --git a/app/src/organisms/ChooseProtocolSlideout/index.tsx b/app/src/organisms/ChooseProtocolSlideout/index.tsx index 7a63ebe2ed6..cd82b1a48ba 100644 --- a/app/src/organisms/ChooseProtocolSlideout/index.tsx +++ b/app/src/organisms/ChooseProtocolSlideout/index.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import first from 'lodash/first' import { Trans, useTranslation } from 'react-i18next' -import { Link, NavLink, useHistory } from 'react-router-dom' +import { Link, NavLink, useNavigate } from 'react-router-dom' import { useSelector } from 'react-redux' import { css } from 'styled-components' @@ -89,7 +89,7 @@ export function ChooseProtocolSlideoutComponent( props: ChooseProtocolSlideoutProps ): JSX.Element | null { const { t } = useTranslation(['device_details', 'shared']) - const history = useHistory() + const navigate = useNavigate() const logger = useLogger(new URL('', import.meta.url).pathname) const [targetProps, tooltipProps] = useTooltip() const [targetPropsHover, tooltipPropsHover] = useHoverTooltip() @@ -190,7 +190,7 @@ export function ChooseProtocolSlideoutComponent( name: 'createProtocolRecordResponse', properties: { success: true }, }) - history.push(`/devices/${name}/protocol-runs/${runData.id}`) + navigate(`/devices/${name}/protocol-runs/${runData.id}`) }, onError: (error: Error) => { trackCreateProtocolRunEvent({ diff --git a/app/src/organisms/ChooseRobotSlideout/__tests__/ChooseRobotSlideout.test.tsx b/app/src/organisms/ChooseRobotSlideout/__tests__/ChooseRobotSlideout.test.tsx index 4d5a6667190..41dff450fb0 100644 --- a/app/src/organisms/ChooseRobotSlideout/__tests__/ChooseRobotSlideout.test.tsx +++ b/app/src/organisms/ChooseRobotSlideout/__tests__/ChooseRobotSlideout.test.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { vi, it, describe, expect, beforeEach } from 'vitest' -import { StaticRouter } from 'react-router-dom' +import { MemoryRouter } from 'react-router-dom' import { fireEvent, screen } from '@testing-library/react' import { OT2_ROBOT_TYPE } from '@opentrons/shared-data' @@ -30,9 +30,9 @@ vi.mock('../../../redux/networking') vi.mock('../../../resources/useNotifyDataReady') const render = (props: React.ComponentProps) => { return renderWithProviders( - + - , + , { i18nInstance: i18n, } diff --git a/app/src/organisms/ChooseRobotSlideout/__tests__/FileCard.test.tsx b/app/src/organisms/ChooseRobotSlideout/__tests__/FileCard.test.tsx index b9649386090..0370fc68e09 100644 --- a/app/src/organisms/ChooseRobotSlideout/__tests__/FileCard.test.tsx +++ b/app/src/organisms/ChooseRobotSlideout/__tests__/FileCard.test.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { vi, it, describe, expect } from 'vitest' -import { StaticRouter } from 'react-router-dom' +import { MemoryRouter } from 'react-router-dom' import { fireEvent, screen } from '@testing-library/react' import { renderWithProviders } from '../../../__testing-utils__' @@ -16,9 +16,9 @@ vi.mock('../../../resources/useNotifyDataReady') vi.mock('../../../redux/config') const render = (props: React.ComponentProps) => { return renderWithProviders( - + - , + , { i18nInstance: i18n, } diff --git a/app/src/organisms/ChooseRobotToRunProtocolSlideout/__tests__/ChooseRobotToRunProtocolSlideout.test.tsx b/app/src/organisms/ChooseRobotToRunProtocolSlideout/__tests__/ChooseRobotToRunProtocolSlideout.test.tsx index 6085ff5636d..6216e7d1ae9 100644 --- a/app/src/organisms/ChooseRobotToRunProtocolSlideout/__tests__/ChooseRobotToRunProtocolSlideout.test.tsx +++ b/app/src/organisms/ChooseRobotToRunProtocolSlideout/__tests__/ChooseRobotToRunProtocolSlideout.test.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { vi, it, describe, expect, beforeEach, afterEach } from 'vitest' -import { StaticRouter } from 'react-router-dom' +import { MemoryRouter } from 'react-router-dom' import { fireEvent, screen, waitFor } from '@testing-library/react' import { when } from 'vitest-when' @@ -51,9 +51,9 @@ const render = ( props: React.ComponentProps ) => { return renderWithProviders( - + - , + , { i18nInstance: i18n, } diff --git a/app/src/organisms/ChooseRobotToRunProtocolSlideout/index.tsx b/app/src/organisms/ChooseRobotToRunProtocolSlideout/index.tsx index e1a77129761..49cbb7d8217 100644 --- a/app/src/organisms/ChooseRobotToRunProtocolSlideout/index.tsx +++ b/app/src/organisms/ChooseRobotToRunProtocolSlideout/index.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import first from 'lodash/first' import { useTranslation } from 'react-i18next' import { useSelector } from 'react-redux' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { Icon, @@ -50,7 +50,7 @@ export function ChooseRobotToRunProtocolSlideoutComponent( ): JSX.Element | null { const { t } = useTranslation(['protocol_details', 'shared', 'app_settings']) const { storedProtocolData, showSlideout, onCloseClick } = props - const history = useHistory() + const navigate = useNavigate() const [shouldApplyOffsets, setShouldApplyOffsets] = React.useState( true ) @@ -112,9 +112,7 @@ export function ChooseRobotToRunProtocolSlideoutComponent( name: 'createProtocolRecordResponse', properties: { success: true }, }) - history.push( - `/devices/${selectedRobot.name}/protocol-runs/${runData.id}` - ) + navigate(`/devices/${selectedRobot.name}/protocol-runs/${runData.id}`) } }, onError: (error: Error) => { diff --git a/app/src/organisms/DeviceDetailsDeckConfiguration/DeckConfigurationDiscardChangesModal.tsx b/app/src/organisms/DeviceDetailsDeckConfiguration/DeckConfigurationDiscardChangesModal.tsx index 1d58f2b6f4f..03fa0608e38 100644 --- a/app/src/organisms/DeviceDetailsDeckConfiguration/DeckConfigurationDiscardChangesModal.tsx +++ b/app/src/organisms/DeviceDetailsDeckConfiguration/DeckConfigurationDiscardChangesModal.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { DIRECTION_COLUMN, @@ -23,14 +23,14 @@ export function DeckConfigurationDiscardChangesModal({ setShowConfirmationModal, }: DeckConfigurationDiscardChangesModalProps): JSX.Element { const { t } = useTranslation('device_details') - const history = useHistory() + const navigate = useNavigate() const modalHeader: ModalHeaderBaseProps = { title: t('changes_will_be_lost'), } const handleDiscard = (): void => { setShowConfirmationModal(false) - history.goBack() + navigate(-1) } return ( diff --git a/app/src/organisms/DeviceDetailsDeckConfiguration/__tests__/DeckConfigurationDiscardChangesModal.test.tsx b/app/src/organisms/DeviceDetailsDeckConfiguration/__tests__/DeckConfigurationDiscardChangesModal.test.tsx index 0461f81496b..8b2d6c409d4 100644 --- a/app/src/organisms/DeviceDetailsDeckConfiguration/__tests__/DeckConfigurationDiscardChangesModal.test.tsx +++ b/app/src/organisms/DeviceDetailsDeckConfiguration/__tests__/DeckConfigurationDiscardChangesModal.test.tsx @@ -5,16 +5,16 @@ import { describe, it, beforeEach, vi, expect } from 'vitest' import { renderWithProviders } from '../../../__testing-utils__' import { i18n } from '../../../i18n' import { DeckConfigurationDiscardChangesModal } from '../DeckConfigurationDiscardChangesModal' -import type { useHistory } from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' const mockFunc = vi.fn() -const mockGoBack = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ goBack: mockGoBack }), + useNavigate: () => mockNavigate, } }) @@ -51,7 +51,7 @@ describe('DeckConfigurationDiscardChangesModal', () => { render(props) fireEvent.click(screen.getByText('Discard changes')) expect(mockFunc).toHaveBeenCalledWith(false) - expect(mockGoBack).toHaveBeenCalled() + expect(mockNavigate).toHaveBeenCalled() }) it('should call a mock function when tapping continue editing button', () => { diff --git a/app/src/organisms/Devices/HistoricalProtocolRunOverflowMenu.tsx b/app/src/organisms/Devices/HistoricalProtocolRunOverflowMenu.tsx index 49eab67c57f..b72b70c8bcf 100644 --- a/app/src/organisms/Devices/HistoricalProtocolRunOverflowMenu.tsx +++ b/app/src/organisms/Devices/HistoricalProtocolRunOverflowMenu.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { useSelector } from 'react-redux' import { useTranslation } from 'react-i18next' -import { NavLink, useHistory } from 'react-router-dom' +import { NavLink, useNavigate } from 'react-router-dom' import { Flex, @@ -103,7 +103,7 @@ interface MenuDropdownProps extends HistoricalProtocolRunOverflowMenuProps { } function MenuDropdown(props: MenuDropdownProps): JSX.Element { const { t } = useTranslation('device_details') - const history = useHistory() + const navigate = useNavigate() const { runId, @@ -121,7 +121,7 @@ function MenuDropdown(props: MenuDropdownProps): JSX.Element { ) const [targetProps, tooltipProps] = useHoverTooltip() const onResetSuccess = (createRunResponse: Run): void => { - history.push( + navigate( `/devices/${robotName}/protocol-runs/${createRunResponse.data.id}/run-preview` ) } diff --git a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader.tsx b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader.tsx index 42b86e3d4d1..9b090a67259 100644 --- a/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader.tsx +++ b/app/src/organisms/Devices/ProtocolRun/ProtocolRunHeader.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' import { useSelector } from 'react-redux' -import { Link, useHistory } from 'react-router-dom' +import { Link, useNavigate } from 'react-router-dom' import { RUN_STATUS_IDLE, @@ -139,7 +139,7 @@ export function ProtocolRunHeader({ makeHandleJumpToStep, }: ProtocolRunHeaderProps): JSX.Element | null { const { t } = useTranslation(['run_details', 'shared']) - const history = useHistory() + const navigate = useNavigate() const host = useHost() const createdAtTimestamp = useRunCreatedAtTimestamp(runId) const { @@ -228,9 +228,9 @@ export function ProtocolRunHeader({ React.useEffect(() => { if (protocolData != null && !isRobotViewable) { - history.push(`/devices`) + navigate('/devices') } - }, [protocolData, isRobotViewable, history]) + }, [protocolData, isRobotViewable, navigate]) // Side effects dependent on the current run state. React.useEffect(() => { @@ -254,7 +254,7 @@ export function ProtocolRunHeader({ // redirect to new run after successful reset const onResetSuccess = (createRunResponse: Run): void => { - history.push( + navigate( `/devices/${robotName}/protocol-runs/${createRunResponse.data.id}/run-preview` ) } @@ -577,7 +577,7 @@ function ActionButton(props: ActionButtonProps): JSX.Element { isFixtureMismatch, isResetRunLoadingRef, } = props - const history = useHistory() + const navigate = useNavigate() const { t } = useTranslation(['run_details', 'shared']) const attachedModules = useModulesQuery({ @@ -597,7 +597,7 @@ function ActionButton(props: ActionButtonProps): JSX.Element { } = useRunControls(runId, (createRunResponse: Run): void => // redirect to new run after successful reset { - history.push( + navigate( `/devices/${robotName}/protocol-runs/${createRunResponse.data.id}/run-preview` ) } @@ -726,7 +726,7 @@ function ActionButton(props: ActionButtonProps): JSX.Element { confirmAttachment() } else { play() - history.push(`/devices/${robotName}/protocol-runs/${runId}/run-preview`) + navigate(`/devices/${robotName}/protocol-runs/${runId}/run-preview`) trackProtocolRunEvent({ name: runStatus === RUN_STATUS_IDLE diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/LabwareListItem.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/LabwareListItem.test.tsx index 4b7d3ae79b9..108439c1262 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/LabwareListItem.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/LabwareListItem.test.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { fireEvent, screen } from '@testing-library/react' import { describe, it, beforeEach, vi, expect } from 'vitest' -import { StaticRouter } from 'react-router-dom' +import { MemoryRouter } from 'react-router-dom' import { opentrons96PcrAdapterV1 } from '@opentrons/shared-data' import { useCreateLiveCommandMutation } from '@opentrons/react-api-client' @@ -68,9 +68,9 @@ const mockNickName = 'nickName' const render = (props: React.ComponentProps) => { return renderWithProviders( - + - , + , { i18nInstance: i18n, } diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/OffDeckLabwareList.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/OffDeckLabwareList.test.tsx index 0fbe91a3265..59487246732 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/OffDeckLabwareList.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/OffDeckLabwareList.test.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { StaticRouter } from 'react-router-dom' +import { MemoryRouter } from 'react-router-dom' import { screen } from '@testing-library/react' import { describe, it, beforeEach, vi, expect } from 'vitest' @@ -13,9 +13,9 @@ vi.mock('../LabwareListItem') const render = (props: React.ComponentProps) => { return renderWithProviders( - + - , + , { i18nInstance: i18n, } diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/SetupLabware.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/SetupLabware.test.tsx index 0e19191306d..d6a6ab4b05e 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/SetupLabware.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/SetupLabware.test.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { StaticRouter } from 'react-router-dom' +import { MemoryRouter } from 'react-router-dom' import { fireEvent, screen } from '@testing-library/react' import { describe, it, beforeEach, vi, afterEach, expect } from 'vitest' import { when } from 'vitest-when' @@ -36,7 +36,7 @@ const RUN_ID = '1' const render = () => { return renderWithProviders( - + { expandStep={vi.fn()} nextStep={'liquid_setup_step'} /> - , + , { i18nInstance: i18n, } diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/SetupLabwareList.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/SetupLabwareList.test.tsx index 34a402b1baa..4228c517134 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/SetupLabwareList.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/SetupLabwareList.test.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { StaticRouter } from 'react-router-dom' +import { MemoryRouter } from 'react-router-dom' import { describe, it, beforeEach, vi } from 'vitest' import { screen } from '@testing-library/react' @@ -17,9 +17,9 @@ const protocolWithTC = (multiple_tipacks_with_tc as unknown) as CompletedProtoco const render = (props: React.ComponentProps) => { return renderWithProviders( - + - , + , { i18nInstance: i18n, } diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/SetupLabwareMap.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/SetupLabwareMap.test.tsx index a9fe5d6d1fc..2f305f90dab 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/SetupLabwareMap.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/SetupLabwareMap.test.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { when } from 'vitest-when' -import { StaticRouter } from 'react-router-dom' +import { MemoryRouter } from 'react-router-dom' import { describe, it, beforeEach, vi, afterEach, expect } from 'vitest' import { screen } from '@testing-library/react' @@ -86,9 +86,9 @@ const mockTCModule = { const render = (props: React.ComponentProps) => { return renderWithProviders( - + - , + , { i18nInstance: i18n, } diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLabwarePositionCheck/__tests__/SetupLabwarePositionCheck.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLabwarePositionCheck/__tests__/SetupLabwarePositionCheck.test.tsx index 98bfe60da4a..0bf4aaebbfc 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLabwarePositionCheck/__tests__/SetupLabwarePositionCheck.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLabwarePositionCheck/__tests__/SetupLabwarePositionCheck.test.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { when } from 'vitest-when' -import { StaticRouter } from 'react-router-dom' +import { MemoryRouter } from 'react-router-dom' import { screen, fireEvent } from '@testing-library/react' import { describe, it, beforeEach, vi, expect, afterEach } from 'vitest' @@ -43,13 +43,13 @@ const RUN_ID = '1' const render = () => { return renderWithProviders( - + - , + , { i18nInstance: i18n, } diff --git a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/ChooseModuleToConfigureModal.tsx b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/ChooseModuleToConfigureModal.tsx index 10eaee47a41..79066ce7398 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/ChooseModuleToConfigureModal.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupModuleAndDeck/ChooseModuleToConfigureModal.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { createPortal } from 'react-dom' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { useModulesQuery } from '@opentrons/react-api-client' import { ALIGN_CENTER, @@ -193,13 +193,13 @@ function NoUnconfiguredModules(props: NoUnconfiguredModulesProps): JSX.Element { robotName, } = props const { t } = useTranslation('protocol_setup') - const history = useHistory() + const navigate = useNavigate() const { closeCurrentRun } = useCloseCurrentRun() const handleCancelRun = (): void => { closeCurrentRun() } const handleNavigateToDeviceDetails = (): void => { - history.push(`/devices/${robotName}`) + navigate(`/devices/${robotName}`) } const exitButton = isOnDevice ? ( ) => { return renderWithProviders( - + - , + , { i18nInstance: i18n, } diff --git a/app/src/organisms/Devices/ProtocolRun/__tests__/BackToTopButton.test.tsx b/app/src/organisms/Devices/ProtocolRun/__tests__/BackToTopButton.test.tsx index 4113d2c131c..65c5f106f1a 100644 --- a/app/src/organisms/Devices/ProtocolRun/__tests__/BackToTopButton.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/__tests__/BackToTopButton.test.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { fireEvent, screen } from '@testing-library/react' import { when } from 'vitest-when' -import { StaticRouter } from 'react-router-dom' +import { MemoryRouter } from 'react-router-dom' import { describe, it, beforeEach, vi, afterEach, expect } from 'vitest' import { renderWithProviders } from '../../../../__testing-utils__' @@ -25,14 +25,14 @@ const ROBOT_SERIAL_NUMBER = 'OT123' const render = () => { return renderWithProviders( - + - , + , { i18nInstance: i18n, } diff --git a/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunHeader.test.tsx b/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunHeader.test.tsx index 0ae4fd544bb..b090b284a34 100644 --- a/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunHeader.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/__tests__/ProtocolRunHeader.test.tsx @@ -98,19 +98,19 @@ import { } from '../../../ErrorRecoveryFlows' import type { UseQueryResult } from 'react-query' -import type * as ReactRouterDom from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' import type { Mock } from 'vitest' import type * as OpentronsSharedData from '@opentrons/shared-data' import type * as OpentronsComponents from '@opentrons/components' import type * as OpentronsApiClient from '@opentrons/api-client' -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const reactRouterDom = await importOriginal() + const reactRouterDom = await importOriginal() return { ...reactRouterDom, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) @@ -945,7 +945,7 @@ describe('ProtocolRunHeader', () => { vi.mocked(useIsRobotViewable).mockReturnValue(false) render() await waitFor(() => { - expect(mockPush).toHaveBeenCalledWith('/devices') + expect(mockNavigate).toHaveBeenCalledWith('/devices') }) }) diff --git a/app/src/organisms/Devices/RobotCard.tsx b/app/src/organisms/Devices/RobotCard.tsx index 5910ea8e8cc..d92ea790435 100644 --- a/app/src/organisms/Devices/RobotCard.tsx +++ b/app/src/organisms/Devices/RobotCard.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { useSelector } from 'react-redux' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { ALIGN_START, @@ -54,7 +54,7 @@ interface RobotCardProps { export function RobotCard(props: RobotCardProps): JSX.Element | null { const { robot } = props const { name: robotName, local } = robot - const history = useHistory() + const navigate = useNavigate() const robotModel = useSelector((state: State) => getRobotModelByName(state, robotName) ) @@ -71,7 +71,7 @@ export function RobotCard(props: RobotCardProps): JSX.Element | null { padding={SPACING.spacing16} position={POSITION_RELATIVE} onClick={() => { - history.push(`/devices/${robotName}`) + navigate(`/devices/${robotName}`) }} > { - history.push(`/devices/${robot.name}/robot-settings`) + navigate(`/devices/${robot.name}/robot-settings`) }} disabled={ robot == null || diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/DeviceResetModal.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/DeviceResetModal.tsx index e2e429d2507..25386016168 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/DeviceResetModal.tsx +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/DeviceResetModal.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import { useSelector } from 'react-redux' import { useTranslation } from 'react-i18next' import last from 'lodash/last' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { AlertPrimaryButton, @@ -46,7 +46,7 @@ export function DeviceResetModal({ resetOptions, }: DeviceResetModalProps): JSX.Element { const { t } = useTranslation(['device_settings', 'shared', 'branded']) - const history = useHistory() + const navigate = useNavigate() const [dispatchRequest, requestIds] = useDispatchApiRequest() const isFlex = useIsFlex(robotName) const resetRequestStatus = useSelector((state: State) => { @@ -79,7 +79,7 @@ export function DeviceResetModal({ } } dispatchRequest(resetConfig(robotName, resetOptions)) - history.push(`/devices/`) + navigate('/devices/') } } diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/RenameRobotSlideout.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/RenameRobotSlideout.tsx index 5c68bdceabd..4774249d1f7 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/RenameRobotSlideout.tsx +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/AdvancedTabSlideouts/RenameRobotSlideout.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useSelector, useDispatch } from 'react-redux' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { useForm, Controller } from 'react-hook-form' import { useTranslation } from 'react-i18next' import { @@ -57,7 +57,7 @@ export function RenameRobotSlideout({ ) const isFlex = useIsFlex(robotName) const trackEvent = useTrackEvent() - const history = useHistory() + const navigate = useNavigate() const dispatch = useDispatch() const connectableRobots = useSelector((state: State) => getConnectableRobots(state) @@ -136,10 +136,10 @@ export function RenameRobotSlideout({ const { updateRobotName } = useUpdateRobotNameMutation({ onSuccess: (data: UpdatedRobotName) => { // TODO: 6/10/2022 kj for the robot name, we need to use GET: /server/name - // data.name != null && history.push(`/devices/${data.name}/robot-settings`) + // data.name != null && navigate(`/devices/${data.name}/robot-settings`) // TODO 6/9/2022 kj this is a temporary fix to avoid the issue // https://github.com/Opentrons/opentrons/issues/10709 - data.name != null && history.push(`/devices`) + data.name != null && navigate('/devices') dispatch(removeRobot(previousRobotName)) }, onError: (error: Error) => { diff --git a/app/src/organisms/Devices/RobotStatusHeader.tsx b/app/src/organisms/Devices/RobotStatusHeader.tsx index 32ef7c4da90..6516c7910c7 100644 --- a/app/src/organisms/Devices/RobotStatusHeader.tsx +++ b/app/src/organisms/Devices/RobotStatusHeader.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' import { useSelector, useDispatch } from 'react-redux' -import { Link, useHistory } from 'react-router-dom' +import { Link, useNavigate } from 'react-router-dom' import styled from 'styled-components' import { useProtocolQuery } from '@opentrons/react-api-client' @@ -58,7 +58,7 @@ export function RobotStatusHeader(props: RobotStatusHeaderProps): JSX.Element { 'device_settings', 'run_details', ]) - const history = useHistory() + const navigate = useNavigate() const [targetProps, tooltipProps] = useHoverTooltip() const dispatch = useDispatch() @@ -187,7 +187,7 @@ export function RobotStatusHeader(props: RobotStatusHeaderProps): JSX.Element { {...targetProps} marginRight={SPACING.spacing8} onClick={() => { - history.push(`/devices/${name}/robot-settings/networking`) + navigate(`/devices/${name}/robot-settings/networking`) }} > { const reactRouterDom = await importOriginal() return { ...reactRouterDom, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) diff --git a/app/src/organisms/InstrumentInfo/index.tsx b/app/src/organisms/InstrumentInfo/index.tsx index d87491a21bf..ea7599dde76 100644 --- a/app/src/organisms/InstrumentInfo/index.tsx +++ b/app/src/organisms/InstrumentInfo/index.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { BORDERS, COLORS, @@ -35,7 +35,7 @@ interface InstrumentInfoProps { export const InstrumentInfo = (props: InstrumentInfoProps): JSX.Element => { const { t, i18n } = useTranslation('instruments_dashboard') const { instrument } = props - const history = useHistory() + const navigate = useNavigate() const [wizardProps, setWizardProps] = React.useState< | React.ComponentProps | React.ComponentProps @@ -66,7 +66,7 @@ export const InstrumentInfo = (props: InstrumentInfoProps): JSX.Element => { ...sharedGripperWizardProps, flowType: GRIPPER_FLOW_TYPES.DETACH, onComplete: () => { - history.goBack() + navigate(-1) }, } : { @@ -74,7 +74,7 @@ export const InstrumentInfo = (props: InstrumentInfoProps): JSX.Element => { setWizardProps(null) }, onComplete: () => { - history.goBack() + navigate(-1) }, mount: instrument.mount as PipetteMount, selectedPipette: is96Channel diff --git a/app/src/organisms/InstrumentMountItem/AttachedInstrumentMountItem.tsx b/app/src/organisms/InstrumentMountItem/AttachedInstrumentMountItem.tsx index 1811fbaf706..d56a1af86ae 100644 --- a/app/src/organisms/InstrumentMountItem/AttachedInstrumentMountItem.tsx +++ b/app/src/organisms/InstrumentMountItem/AttachedInstrumentMountItem.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { SINGLE_MOUNT_PIPETTES } from '@opentrons/shared-data' @@ -33,8 +33,7 @@ interface AttachedInstrumentMountItemProps { export function AttachedInstrumentMountItem( props: AttachedInstrumentMountItemProps ): JSX.Element { - const history = useHistory() - console.log(history) + const navigate = useNavigate() const { mount, attachedInstrument, setWizardProps } = props const [showChoosePipetteModal, setShowChoosePipetteModal] = React.useState( @@ -53,8 +52,8 @@ export function AttachedInstrumentMountItem( flowType: GRIPPER_FLOW_TYPES.ATTACH, attachedGripper: attachedInstrument, onComplete: () => { - history.push( - attachedInstrument == null ? `/instruments` : `/instrument/${mount}` + navigate( + attachedInstrument == null ? '/instruments' : `/instrument/${mount}` ) }, closeFlow: () => { @@ -62,7 +61,7 @@ export function AttachedInstrumentMountItem( }, }) } else { - history.push(`/instruments/${mount}`) + navigate(`/instruments/${mount}`) } } @@ -101,7 +100,7 @@ export function AttachedInstrumentMountItem( setShowChoosePipetteModal(false) }, onComplete: () => { - history.push( + navigate( attachedInstrument == null ? `/instruments` : `/instrument/${mount}` diff --git a/app/src/organisms/ModuleCard/__tests__/ModuleCard.test.tsx b/app/src/organisms/ModuleCard/__tests__/ModuleCard.test.tsx index 8c6dbcfd025..4dc583d6c9d 100644 --- a/app/src/organisms/ModuleCard/__tests__/ModuleCard.test.tsx +++ b/app/src/organisms/ModuleCard/__tests__/ModuleCard.test.tsx @@ -37,6 +37,7 @@ import { FirmwareUpdateFailedModal } from '../FirmwareUpdateFailedModal' import { ErrorInfo } from '../ErrorInfo' import { ModuleCard } from '..' +import type { NavigateFunction } from 'react-router-dom' import type { HeaterShakerModule, MagneticModule, @@ -57,6 +58,13 @@ vi.mock('../../../redux/robot-api') vi.mock('../../../organisms/ToasterOven') vi.mock('../../../organisms/Devices/hooks') vi.mock('../../../resources/devices/hooks/useIsEstopNotDisengaged') +vi.mock('react-router-dom', async importOriginal => { + const actual = await importOriginal() + return { + ...actual, + useNavigate: () => vi.fn(), + } +}) const mockMagneticModuleHub = { id: 'magdeck_id', diff --git a/app/src/organisms/ModuleCard/index.tsx b/app/src/organisms/ModuleCard/index.tsx index c6f9b27ee9f..c3d78ddf730 100644 --- a/app/src/organisms/ModuleCard/index.tsx +++ b/app/src/organisms/ModuleCard/index.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { Trans, useTranslation } from 'react-i18next' import { useDispatch, useSelector } from 'react-redux' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { ALIGN_START, @@ -126,11 +126,11 @@ export const ModuleCard = (props: ModuleCardProps): JSX.Element | null => { const [showCalModal, setShowCalModal] = React.useState(false) const [targetProps, tooltipProps] = useHoverTooltip() - const history = useHistory() + const navigate = useNavigate() const runStatus = useCurrentRunStatus({ onSettled: data => { if (data == null) { - history.push('/upload') + navigate('/upload') } }, }) diff --git a/app/src/organisms/Navigation/NavigationMenu.tsx b/app/src/organisms/Navigation/NavigationMenu.tsx index 4c579f5b9ce..3b4f10752e8 100644 --- a/app/src/organisms/Navigation/NavigationMenu.tsx +++ b/app/src/organisms/Navigation/NavigationMenu.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import { createPortal } from 'react-dom' import { useDispatch } from 'react-redux' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { ALIGN_CENTER, @@ -39,7 +39,7 @@ export function NavigationMenu(props: NavigationMenuProps): JSX.Element { setShowRestartRobotConfirmationModal, ] = React.useState(false) - const history = useHistory() + const navigate = useNavigate() const handleRestart = (): void => { setShowRestartRobotConfirmationModal(true) @@ -97,7 +97,7 @@ export function NavigationMenu(props: NavigationMenuProps): JSX.Element { { - history.push('/deck-configuration') + navigate('/deck-configuration') }} > diff --git a/app/src/organisms/Navigation/__tests__/NavigationMenu.test.tsx b/app/src/organisms/Navigation/__tests__/NavigationMenu.test.tsx index 1c85aa47861..52f18c32306 100644 --- a/app/src/organisms/Navigation/__tests__/NavigationMenu.test.tsx +++ b/app/src/organisms/Navigation/__tests__/NavigationMenu.test.tsx @@ -9,19 +9,19 @@ import { useLights } from '../../Devices/hooks' import { RestartRobotConfirmationModal } from '../RestartRobotConfirmationModal' import { NavigationMenu } from '../NavigationMenu' -import type { useHistory } from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' vi.mock('../../../redux/robot-admin') vi.mock('../../../redux/robot-controls') vi.mock('../../Devices/hooks') vi.mock('../RestartRobotConfirmationModal') -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) @@ -97,6 +97,6 @@ describe('NavigationMenu', () => { it('should call a mock function when tapping deck configuration', () => { render(props) fireEvent.click(screen.getByText('Deck configuration')) - expect(mockPush).toHaveBeenCalledWith('/deck-configuration') + expect(mockNavigate).toHaveBeenCalledWith('/deck-configuration') }) }) diff --git a/app/src/organisms/NetworkSettings/AlternativeSecurityTypeModal.tsx b/app/src/organisms/NetworkSettings/AlternativeSecurityTypeModal.tsx index 50a9a05b074..b4a532f095b 100644 --- a/app/src/organisms/NetworkSettings/AlternativeSecurityTypeModal.tsx +++ b/app/src/organisms/NetworkSettings/AlternativeSecurityTypeModal.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { COLORS, @@ -27,7 +27,7 @@ export function AlternativeSecurityTypeModal({ setShowAlternativeSecurityTypeModal, }: AlternativeSecurityTypeModalProps): JSX.Element { const { t } = useTranslation(['device_settings', 'branded']) - const history = useHistory() + const navigate = useNavigate() const modalHeader: ModalHeaderBaseProps = { title: t('alternative_security_types'), hasExitIcon: true, @@ -37,7 +37,7 @@ export function AlternativeSecurityTypeModal({ } const handleClick = (): void => { setShowAlternativeSecurityTypeModal(false) - history.push('/network-setup/usb') + navigate('/network-setup/usb') } return ( diff --git a/app/src/organisms/NetworkSettings/DisplayWifiList.tsx b/app/src/organisms/NetworkSettings/DisplayWifiList.tsx index 137391618c5..2925a47f392 100644 --- a/app/src/organisms/NetworkSettings/DisplayWifiList.tsx +++ b/app/src/organisms/NetworkSettings/DisplayWifiList.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { css } from 'styled-components' import { @@ -73,7 +73,7 @@ export function DisplayWifiList({ isHeader = false, }: DisplayWifiListProps): JSX.Element { const { t } = useTranslation('device_settings') - const history = useHistory() + const navigate = useNavigate() return ( <> @@ -81,7 +81,7 @@ export function DisplayWifiList({ { - history.push('/network-setup') + navigate('/network-setup') }} /> ) : null} diff --git a/app/src/organisms/NetworkSettings/WifiConnectionDetails.tsx b/app/src/organisms/NetworkSettings/WifiConnectionDetails.tsx index 97f264dc556..ec95615c4e5 100644 --- a/app/src/organisms/NetworkSettings/WifiConnectionDetails.tsx +++ b/app/src/organisms/NetworkSettings/WifiConnectionDetails.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' import { useDispatch, useSelector } from 'react-redux' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { ALIGN_CENTER, @@ -37,7 +37,7 @@ export function WifiConnectionDetails({ authType, }: WifiConnectionDetailsProps): JSX.Element { const { i18n, t } = useTranslation(['device_settings', 'shared']) - const history = useHistory() + const navigate = useNavigate() const localRobot = useSelector(getLocalRobot) const robotName = localRobot?.name != null ? localRobot.name : 'no name' const dispatch = useDispatch() @@ -95,7 +95,7 @@ export function WifiConnectionDetails({ flex="1" buttonText={i18n.format(t('continue'), 'capitalize')} onClick={() => { - history.push('/robot-settings/update-robot-during-onboarding') + navigate('/robot-settings/update-robot-during-onboarding') }} /> diff --git a/app/src/organisms/NetworkSettings/__tests__/AlternativeSecurityTypeModal.test.tsx b/app/src/organisms/NetworkSettings/__tests__/AlternativeSecurityTypeModal.test.tsx index d838c397942..ee23afbee84 100644 --- a/app/src/organisms/NetworkSettings/__tests__/AlternativeSecurityTypeModal.test.tsx +++ b/app/src/organisms/NetworkSettings/__tests__/AlternativeSecurityTypeModal.test.tsx @@ -6,15 +6,15 @@ import { renderWithProviders } from '../../../__testing-utils__' import { i18n } from '../../../i18n' import { AlternativeSecurityTypeModal } from '../AlternativeSecurityTypeModal' -import type { useHistory } from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' const mockFunc = vi.fn() -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) @@ -55,6 +55,6 @@ describe('AlternativeSecurityTypeModal', () => { const button = screen.getByText('Connect via USB') fireEvent.click(button) expect(mockFunc).toHaveBeenCalled() - expect(mockPush).toHaveBeenCalledWith('/network-setup/usb') + expect(mockNavigate).toHaveBeenCalledWith('/network-setup/usb') }) }) diff --git a/app/src/organisms/NetworkSettings/__tests__/DisplayWifiList.test.tsx b/app/src/organisms/NetworkSettings/__tests__/DisplayWifiList.test.tsx index 04920134dee..2a901ee1850 100644 --- a/app/src/organisms/NetworkSettings/__tests__/DisplayWifiList.test.tsx +++ b/app/src/organisms/NetworkSettings/__tests__/DisplayWifiList.test.tsx @@ -8,9 +8,9 @@ import * as Fixtures from '../../../redux/networking/__fixtures__' import { DisplaySearchNetwork } from '../DisplaySearchNetwork' import { DisplayWifiList } from '../DisplayWifiList' -import type { useHistory } from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' -const mockPush = vi.fn() +const mockNavigate = vi.fn() const mockWifiList = [ { ...Fixtures.mockWifiNetwork, ssid: 'foo', active: true }, { ...Fixtures.mockWifiNetwork, ssid: 'bar' }, @@ -24,10 +24,10 @@ vi.mock('../../../redux/networking/selectors') vi.mock('../../../redux/discovery/selectors') vi.mock('../DisplaySearchNetwork') vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) @@ -76,7 +76,7 @@ describe('DisplayWifiList', () => { render(props) const button = screen.getByLabelText('back-button') fireEvent.click(button) - expect(mockPush).toHaveBeenCalledWith('/network-setup') + expect(mockNavigate).toHaveBeenCalledWith('/network-setup') }) it('should call mock function when tapping tapping a ssid', () => { diff --git a/app/src/organisms/NetworkSettings/__tests__/SelectAuthenticationType.test.tsx b/app/src/organisms/NetworkSettings/__tests__/SelectAuthenticationType.test.tsx index 2028e100991..d014f2b5316 100644 --- a/app/src/organisms/NetworkSettings/__tests__/SelectAuthenticationType.test.tsx +++ b/app/src/organisms/NetworkSettings/__tests__/SelectAuthenticationType.test.tsx @@ -11,9 +11,9 @@ import { AlternativeSecurityTypeModal } from '../AlternativeSecurityTypeModal' import { SelectAuthenticationType } from '../SelectAuthenticationType' import { SetWifiCred } from '../SetWifiCred' -import type { useHistory } from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' -const mockPush = vi.fn() +const mockNavigate = vi.fn() const mockSetSelectedAuthType = vi.fn() vi.mock('../SetWifiCred') @@ -22,10 +22,10 @@ vi.mock('../../../redux/discovery/selectors') vi.mock('../AlternativeSecurityTypeModal') vi.mock('../../RobotSettingsDashboard/NetworkSettings/hooks') vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) diff --git a/app/src/organisms/NetworkSettings/__tests__/WifiConnectionDetails.test.tsx b/app/src/organisms/NetworkSettings/__tests__/WifiConnectionDetails.test.tsx index 479f8c65ab0..3c5427d3426 100644 --- a/app/src/organisms/NetworkSettings/__tests__/WifiConnectionDetails.test.tsx +++ b/app/src/organisms/NetworkSettings/__tests__/WifiConnectionDetails.test.tsx @@ -11,19 +11,19 @@ import * as Fixtures from '../../../redux/networking/__fixtures__' import { NetworkDetailsModal } from '../../RobotSettingsDashboard/NetworkSettings/NetworkDetailsModal' import { WifiConnectionDetails } from '../WifiConnectionDetails' -import type { useHistory } from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' vi.mock('../../../resources/networking/hooks') vi.mock('../../../redux/networking') vi.mock('../../../redux/discovery/selectors') vi.mock('../../RobotSettingsDashboard/NetworkSettings/NetworkDetailsModal') -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) @@ -88,7 +88,7 @@ describe('WifiConnectionDetails', () => { it('when clicking Check for updates button, should call mock function', () => { render(props) fireEvent.click(screen.getByText('Continue')) - expect(mockPush).toHaveBeenCalledWith( + expect(mockNavigate).toHaveBeenCalledWith( '/robot-settings/update-robot-during-onboarding' ) }) diff --git a/app/src/organisms/OnDeviceDisplay/NameRobot/ConfirmRobotName.tsx b/app/src/organisms/OnDeviceDisplay/NameRobot/ConfirmRobotName.tsx index 449d31105f0..ebcb54f1f69 100644 --- a/app/src/organisms/OnDeviceDisplay/NameRobot/ConfirmRobotName.tsx +++ b/app/src/organisms/OnDeviceDisplay/NameRobot/ConfirmRobotName.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { @@ -27,10 +27,10 @@ export function ConfirmRobotName({ robotName, }: ConfirmRobotNameProps): JSX.Element { const { t } = useTranslation('device_settings') - const history = useHistory() + const navigate = useNavigate() const handleClick = (): void => { - history.push('/dashboard') + navigate('/dashboard') } return ( <> diff --git a/app/src/organisms/OnDeviceDisplay/NameRobot/__tests__/ConfirmRobotName.test.tsx b/app/src/organisms/OnDeviceDisplay/NameRobot/__tests__/ConfirmRobotName.test.tsx index 5b6966ff0a6..d33230a6424 100644 --- a/app/src/organisms/OnDeviceDisplay/NameRobot/__tests__/ConfirmRobotName.test.tsx +++ b/app/src/organisms/OnDeviceDisplay/NameRobot/__tests__/ConfirmRobotName.test.tsx @@ -7,15 +7,15 @@ import { renderWithProviders } from '../../../../__testing-utils__' import { i18n } from '../../../../i18n' import { ConfirmRobotName } from '../ConfirmRobotName' -import type { useHistory } from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) @@ -49,6 +49,6 @@ describe('ConfirmRobotName', () => { render(props) const button = screen.getByText('Finish setup') fireEvent.click(button) - expect(mockPush).toBeCalledWith('/dashboard') + expect(mockNavigate).toBeCalledWith('/dashboard') }) }) diff --git a/app/src/organisms/OnDeviceDisplay/RobotDashboard/RecentRunProtocolCard.tsx b/app/src/organisms/OnDeviceDisplay/RobotDashboard/RecentRunProtocolCard.tsx index 29ad4a159cd..f3c218a8392 100644 --- a/app/src/organisms/OnDeviceDisplay/RobotDashboard/RecentRunProtocolCard.tsx +++ b/app/src/organisms/OnDeviceDisplay/RobotDashboard/RecentRunProtocolCard.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { css } from 'styled-components' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { formatDistance } from 'date-fns' import last from 'lodash/last' @@ -81,7 +81,7 @@ export function ProtocolWithLastRun({ isLoading: isLookingForHardware, conflictedSlots, } = useMissingProtocolHardware(protocolData.id) - const history = useHistory() + const navigate = useNavigate() const isOk = 'ok' in runData ? !(runData?.ok === false) : true const isReadyToBeReRun = isOk && missingProtocolHardware.length === 0 const chipText = useRerunnableStatusText( @@ -93,7 +93,7 @@ export function ProtocolWithLastRun({ // TODO(BC, 08/29/23): reintroduce this analytics event when we refactor the hook to fetch data lazily (performance concern) // const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runData.id) const onResetSuccess = (createRunResponse: Run): void => { - history.push(`runs/${createRunResponse.data.id}/setup`) + navigate(`runs/${createRunResponse.data.id}/setup`) } const { cloneRun } = useCloneRun(runData.id, onResetSuccess) const robotInitStatus = useRobotInitializationStatus() @@ -147,7 +147,7 @@ export function ProtocolWithLastRun({ const handleCardClick = (): void => { setShowSpinner(true) if (hasRunTimeParameters) { - history.push(`/protocols/${protocolId}`) + navigate(`/protocols/${protocolId}`) } else { cloneRun() trackEvent({ diff --git a/app/src/organisms/OnDeviceDisplay/RobotDashboard/__tests__/RecentRunProtocolCard.test.tsx b/app/src/organisms/OnDeviceDisplay/RobotDashboard/__tests__/RecentRunProtocolCard.test.tsx index 25e040583a7..6d82103955b 100644 --- a/app/src/organisms/OnDeviceDisplay/RobotDashboard/__tests__/RecentRunProtocolCard.test.tsx +++ b/app/src/organisms/OnDeviceDisplay/RobotDashboard/__tests__/RecentRunProtocolCard.test.tsx @@ -33,16 +33,16 @@ import { INIT_STATUS, } from '../../../../resources/health/hooks' -import type { useHistory } from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' import type { ProtocolHardware } from '../../../../pages/Protocols/hooks' -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) @@ -292,6 +292,6 @@ describe('RecentRunProtocolCard', () => { render(props) const button = screen.getByLabelText('RecentRunProtocolCard') fireEvent.click(button) - expect(mockPush).toBeCalledWith('/protocols/mockProtocolId') + expect(mockNavigate).toBeCalledWith('/protocols/mockProtocolId') }) }) diff --git a/app/src/organisms/OnDeviceDisplay/RunningProtocol/ConfirmCancelRunModal.tsx b/app/src/organisms/OnDeviceDisplay/RunningProtocol/ConfirmCancelRunModal.tsx index 8bd583f7a74..76efff81b8b 100644 --- a/app/src/organisms/OnDeviceDisplay/RunningProtocol/ConfirmCancelRunModal.tsx +++ b/app/src/organisms/OnDeviceDisplay/RunningProtocol/ConfirmCancelRunModal.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { useSelector } from 'react-redux' import { RUN_STATUS_STOPPED } from '@opentrons/api-client' @@ -50,7 +50,7 @@ export function ConfirmCancelRunModal({ const localRobot = useSelector(getLocalRobot) const robotName = localRobot?.name ?? '' const { trackProtocolRunEvent } = useTrackProtocolRunEvent(runId, robotName) - const history = useHistory() + const navigate = useNavigate() const [isCanceling, setIsCanceling] = React.useState(false) const modalHeader: ModalHeaderBaseProps = { @@ -75,9 +75,9 @@ export function ConfirmCancelRunModal({ dismissCurrentRun(runId) if (!isActiveRun) { if (protocolId != null) { - history.push(`/protocols/${protocolId}`) + navigate(`/protocols/${protocolId}`) } else { - history.push(`/protocols`) + navigate('/protocols') } } } diff --git a/app/src/organisms/OnDeviceDisplay/RunningProtocol/RunFailedModal.tsx b/app/src/organisms/OnDeviceDisplay/RunningProtocol/RunFailedModal.tsx index d4e0b056b5a..c4db8a35360 100644 --- a/app/src/organisms/OnDeviceDisplay/RunningProtocol/RunFailedModal.tsx +++ b/app/src/organisms/OnDeviceDisplay/RunningProtocol/RunFailedModal.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { css } from 'styled-components' import { @@ -34,7 +34,7 @@ export function RunFailedModal({ errors, }: RunFailedModalProps): JSX.Element | null { const { t, i18n } = useTranslation(['run_details', 'shared', 'branded']) - const history = useHistory() + const navigate = useNavigate() const { stopRun } = useStopRunMutation() const [isCanceling, setIsCanceling] = React.useState(false) @@ -53,7 +53,7 @@ export function RunFailedModal({ // ToDo do we need to track this event? // If need, runCancel or runFailure something // trackProtocolRunEvent({ name: 'runCancel' }) - history.push('/dashboard') + navigate('/dashboard') }, onError: () => { setIsCanceling(false) diff --git a/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/ConfirmCancelRunModal.test.tsx b/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/ConfirmCancelRunModal.test.tsx index 36e23a35df6..9ae25e466f4 100644 --- a/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/ConfirmCancelRunModal.test.tsx +++ b/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/ConfirmCancelRunModal.test.tsx @@ -20,7 +20,7 @@ import { mockConnectedRobot } from '../../../../redux/discovery/__fixtures__' import { ConfirmCancelRunModal } from '../ConfirmCancelRunModal' import { CancelingRunModal } from '../CancelingRunModal' -import type { useHistory } from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' vi.mock('@opentrons/react-api-client') vi.mock('../../../../organisms/Devices/hooks') @@ -29,7 +29,7 @@ vi.mock('../../../../redux/analytics') vi.mock('../../../ProtocolUpload/hooks') vi.mock('../CancelingRunModal') vi.mock('../../../../redux/discovery') -const mockPush = vi.fn() +const mockNavigate = vi.fn() const mockStopRun = vi.fn() const mockDismissCurrentRun = vi.fn() const mockTrackEvent = vi.fn() @@ -38,10 +38,10 @@ const mockTrackProtocolRunEvent = vi.fn( ) vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) @@ -150,6 +150,6 @@ describe('ConfirmCancelRunModal', () => { expect(mockDismissCurrentRun).toHaveBeenCalled() expect(mockTrackProtocolRunEvent).toHaveBeenCalled() - expect(mockPush).toHaveBeenCalledWith('/protocols') + expect(mockNavigate).toHaveBeenCalledWith('/protocols') }) }) diff --git a/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/RunFailedModal.test.tsx b/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/RunFailedModal.test.tsx index 9634879ee44..b57a09cc8aa 100644 --- a/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/RunFailedModal.test.tsx +++ b/app/src/organisms/OnDeviceDisplay/RunningProtocol/__tests__/RunFailedModal.test.tsx @@ -9,13 +9,13 @@ import { renderWithProviders } from '../../../../__testing-utils__' import { i18n } from '../../../../i18n' import { RunFailedModal } from '../RunFailedModal' -import type { useHistory } from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' vi.mock('@opentrons/react-api-client') const RUN_ID = 'mock_runID' const mockFn = vi.fn() -const mockPush = vi.fn() +const mockNavigate = vi.fn() const mockErrors = [ { id: 'd0245210-dfb9-4f1c-8ad0-3416b603a7ba', @@ -74,10 +74,10 @@ const mockErrors = [ const mockStopRun = vi.fn((_runId, opts) => opts.onSuccess()) vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) @@ -123,6 +123,6 @@ describe('RunFailedModal', () => { const button = screen.getByText('Close') fireEvent.click(button) expect(mockStopRun).toHaveBeenCalled() - expect(mockPush).toHaveBeenCalledWith('/dashboard') + expect(mockNavigate).toHaveBeenCalledWith('/dashboard') }) }) diff --git a/app/src/organisms/ProtocolAnalysisFailure/__tests__/ProtocolAnalysisFailure.test.tsx b/app/src/organisms/ProtocolAnalysisFailure/__tests__/ProtocolAnalysisFailure.test.tsx index a2b0d712d54..86f0feb7373 100644 --- a/app/src/organisms/ProtocolAnalysisFailure/__tests__/ProtocolAnalysisFailure.test.tsx +++ b/app/src/organisms/ProtocolAnalysisFailure/__tests__/ProtocolAnalysisFailure.test.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { StaticRouter } from 'react-router-dom' +import { MemoryRouter } from 'react-router-dom' import { fireEvent, screen } from '@testing-library/react' import { describe, it, expect } from 'vitest' @@ -13,7 +13,7 @@ const render = ( props: Partial> = {} ) => { return renderWithProviders( - + - , + , { i18nInstance: i18n, } diff --git a/app/src/organisms/ProtocolDetails/__tests__/ProtocolDetails.test.tsx b/app/src/organisms/ProtocolDetails/__tests__/ProtocolDetails.test.tsx index 130c3ceedbd..140cf3f6373 100644 --- a/app/src/organisms/ProtocolDetails/__tests__/ProtocolDetails.test.tsx +++ b/app/src/organisms/ProtocolDetails/__tests__/ProtocolDetails.test.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { act, screen, waitFor } from '@testing-library/react' -import { StaticRouter } from 'react-router-dom' +import { MemoryRouter } from 'react-router-dom' import { describe, it, beforeEach, vi, expect, afterEach } from 'vitest' import { renderWithProviders } from '../../../__testing-utils__' @@ -40,9 +40,9 @@ const render = ( props: Partial> = {} ) => { return renderWithProviders( - + - , + , { i18nInstance: i18n, } diff --git a/app/src/organisms/ProtocolSetupLabware/__tests__/LabwareMapViewModal.test.tsx b/app/src/organisms/ProtocolSetupLabware/__tests__/LabwareMapViewModal.test.tsx index 8a76e5703fe..04b4df83d09 100644 --- a/app/src/organisms/ProtocolSetupLabware/__tests__/LabwareMapViewModal.test.tsx +++ b/app/src/organisms/ProtocolSetupLabware/__tests__/LabwareMapViewModal.test.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { StaticRouter } from 'react-router-dom' +import { MemoryRouter } from 'react-router-dom' import { when } from 'vitest-when' import { fireEvent, screen } from '@testing-library/react' import { describe, it, vi, beforeEach, afterEach, expect } from 'vitest' @@ -53,9 +53,9 @@ vi.mock('@opentrons/components', async importOriginal => { const render = (props: React.ComponentProps) => { return renderWithProviders( - + - , + , { i18nInstance: i18n, } diff --git a/app/src/organisms/ProtocolSetupModulesAndDeck/index.tsx b/app/src/organisms/ProtocolSetupModulesAndDeck/index.tsx index 6e4986ae0bf..349faeff2b6 100644 --- a/app/src/organisms/ProtocolSetupModulesAndDeck/index.tsx +++ b/app/src/organisms/ProtocolSetupModulesAndDeck/index.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { createPortal } from 'react-dom' import { useTranslation } from 'react-i18next' - +import { useNavigate } from 'react-router-dom' import { COLORS, DIRECTION_COLUMN, @@ -14,6 +14,7 @@ import { FLEX_ROBOT_TYPE, getDeckDefFromRobotType, } from '@opentrons/shared-data' +import { RUN_STATUS_STOPPED } from '@opentrons/api-client' import { getTopPortalEl } from '../../App/portal' import { FloatingActionButton } from '../../atoms/buttons' @@ -22,6 +23,7 @@ import { ChildNavigation } from '../../organisms/ChildNavigation' import { useAttachedModules } from '../../organisms/Devices/hooks' import { getProtocolModulesInfo } from '../../organisms/Devices/ProtocolRun/utils/getProtocolModulesInfo' import { useMostRecentCompletedAnalysis } from '../../organisms/LabwarePositionCheck/useMostRecentCompletedAnalysis' +import { useRunStatus } from '../RunTimeControl/hooks' import { getAttachedProtocolModuleMatches, getUnmatchedModulesForProtocol, @@ -34,9 +36,6 @@ import { useNotifyDeckConfigurationQuery } from '../../resources/deck_configurat import type { CutoutId, CutoutFixtureId } from '@opentrons/shared-data' import type { SetupScreens } from '../../pages/ProtocolSetup' -import { useRunStatus } from '../RunTimeControl/hooks' -import { RUN_STATUS_STOPPED } from '@opentrons/api-client' -import { useHistory } from 'react-router-dom' const ATTACHED_MODULE_POLL_MS = 5000 const DECK_CONFIG_POLL_MS = 5000 @@ -58,13 +57,13 @@ export function ProtocolSetupModulesAndDeck({ setProvidedFixtureOptions, }: ProtocolSetupModulesAndDeckProps): JSX.Element { const { i18n, t } = useTranslation('protocol_setup') - const history = useHistory() + const navigate = useNavigate() const runStatus = useRunStatus(runId) React.useEffect(() => { if (runStatus === RUN_STATUS_STOPPED) { - history.push('/protocols') + navigate('/protocols') } - }, [runStatus, history]) + }, [runStatus, navigate]) const [ showSetupInstructionsModal, setShowSetupInstructionsModal, diff --git a/app/src/organisms/ProtocolSetupParameters/AnalysisFailedModal.tsx b/app/src/organisms/ProtocolSetupParameters/AnalysisFailedModal.tsx index 82195197903..3fba85759a6 100644 --- a/app/src/organisms/ProtocolSetupParameters/AnalysisFailedModal.tsx +++ b/app/src/organisms/ProtocolSetupParameters/AnalysisFailedModal.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { BORDERS, COLORS, @@ -27,7 +27,7 @@ export function AnalysisFailedModal({ setShowAnalysisFailedModal, }: AnalysisFailedModalProps): JSX.Element { const { t } = useTranslation('protocol_setup') - const history = useHistory() + const navigate = useNavigate() const modalHeader: ModalHeaderBaseProps = { title: t('protocol_analysis_failed'), iconName: 'information', @@ -36,7 +36,7 @@ export function AnalysisFailedModal({ } const handleRestartSetup = (): void => { - history.push(protocolId != null ? `/protocols/${protocolId}` : '/protocols') + navigate(protocolId != null ? `/protocols/${protocolId}` : '/protocols') } return ( diff --git a/app/src/organisms/ProtocolSetupParameters/__tests__/AnalysisFailedModal.test.tsx b/app/src/organisms/ProtocolSetupParameters/__tests__/AnalysisFailedModal.test.tsx index 143f6d92feb..2f0be95f26d 100644 --- a/app/src/organisms/ProtocolSetupParameters/__tests__/AnalysisFailedModal.test.tsx +++ b/app/src/organisms/ProtocolSetupParameters/__tests__/AnalysisFailedModal.test.tsx @@ -5,17 +5,17 @@ import { fireEvent, screen } from '@testing-library/react' import { renderWithProviders } from '../../../__testing-utils__' import { i18n } from '../../../i18n' import { AnalysisFailedModal } from '../AnalysisFailedModal' -import type * as ReactRouterDom from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' -const mockPush = vi.fn() +const mockNavigate = vi.fn() const PROTOCOL_ID = 'mockId' const mockSetShowAnalysisFailedModal = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const reactRouterDom = await importOriginal() + const reactRouterDom = await importOriginal() return { ...reactRouterDom, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) @@ -58,12 +58,12 @@ describe('AnalysisFailedModal', () => { it('should call a mock function when tapping restart setup button', () => { render(props) fireEvent.click(screen.getByText('Restart setup')) - expect(mockPush).toHaveBeenCalledWith(`/protocols/${PROTOCOL_ID}`) + expect(mockNavigate).toHaveBeenCalledWith(`/protocols/${PROTOCOL_ID}`) }) it('should push to protocols dashboard when tapping restart setup button and protocol ID is null', () => { render({ ...props, protocolId: null }) fireEvent.click(screen.getByText('Restart setup')) - expect(mockPush).toHaveBeenCalledWith('/protocols') + expect(mockNavigate).toHaveBeenCalledWith('/protocols') }) }) diff --git a/app/src/organisms/ProtocolSetupParameters/__tests__/ProtocolSetupParameters.test.tsx b/app/src/organisms/ProtocolSetupParameters/__tests__/ProtocolSetupParameters.test.tsx index 13bf4664f7b..a80d8565748 100644 --- a/app/src/organisms/ProtocolSetupParameters/__tests__/ProtocolSetupParameters.test.tsx +++ b/app/src/organisms/ProtocolSetupParameters/__tests__/ProtocolSetupParameters.test.tsx @@ -20,11 +20,11 @@ import { useToaster } from '../../ToasterOven' import { useFeatureFlag } from '../../../redux/config' import { ProtocolSetupParameters } from '..' -import type * as ReactRouterDom from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' import type { HostConfig } from '@opentrons/api-client' import type { CompletedProtocolAnalysis } from '@opentrons/shared-data' -const mockGoBack = vi.fn() +const mockNavigate = vi.fn() vi.mock('../ChooseEnum') vi.mock('../ChooseNumber') @@ -34,10 +34,10 @@ vi.mock('../../ToasterOven') vi.mock('@opentrons/react-api-client') vi.mock('../../LabwarePositionCheck/useMostRecentCompletedAnalysis') vi.mock('react-router-dom', async importOriginal => { - const reactRouterDom = await importOriginal() + const reactRouterDom = await importOriginal() return { ...reactRouterDom, - useHistory: () => ({ goBack: mockGoBack } as any), + useNavigate: () => mockNavigate, } }) vi.mock('../../../redux/config') @@ -147,10 +147,10 @@ describe('ProtocolSetupParameters', () => { screen.getByText('CSV File') }) - it('renders the back icon and calls useHistory', () => { + it('renders the back icon and calls useNavigate', () => { render(props) fireEvent.click(screen.getAllByRole('button')[0]) - expect(mockGoBack).toHaveBeenCalled() + expect(mockNavigate).toHaveBeenCalled() }) it('renders the confirm values button and clicking on it creates a run', () => { diff --git a/app/src/organisms/ProtocolSetupParameters/index.tsx b/app/src/organisms/ProtocolSetupParameters/index.tsx index 7fd9d50faa1..66cad283b6c 100644 --- a/app/src/organisms/ProtocolSetupParameters/index.tsx +++ b/app/src/organisms/ProtocolSetupParameters/index.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { useCreateProtocolAnalysisMutation, useCreateRunMutation, @@ -58,7 +58,7 @@ export function ProtocolSetupParameters({ }: ProtocolSetupParametersProps): JSX.Element { const { t } = useTranslation('protocol_setup') const enableCsvFile = useFeatureFlag('enableCsvFile') - const history = useHistory() + const navigate = useNavigate() const host = useHost() const queryClient = useQueryClient() const [ @@ -263,7 +263,7 @@ export function ProtocolSetupParameters({ { - history.goBack() + navigate(-1) }} onClickButton={handleConfirmValues} buttonText={t('confirm_values')} diff --git a/app/src/organisms/ProtocolsLanding/ProtocolCard.tsx b/app/src/organisms/ProtocolsLanding/ProtocolCard.tsx index 874826e6abf..53411434f29 100644 --- a/app/src/organisms/ProtocolsLanding/ProtocolCard.tsx +++ b/app/src/organisms/ProtocolsLanding/ProtocolCard.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import { format } from 'date-fns' import { useTranslation } from 'react-i18next' import { useSelector } from 'react-redux' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { ErrorBoundary } from 'react-error-boundary' import { @@ -60,7 +60,7 @@ interface ProtocolCardProps { storedProtocolData: StoredProtocolData } export function ProtocolCard(props: ProtocolCardProps): JSX.Element | null { - const history = useHistory() + const navigate = useNavigate() const { handleRunProtocol, handleSendProtocolToFlex, @@ -101,7 +101,7 @@ export function ProtocolCard(props: ProtocolCardProps): JSX.Element | null { padding={SPACING.spacing16} position="relative" onClick={() => { - history.push(`/protocols/${protocolKey}`) + navigate(`/protocols/${protocolKey}`) }} > diff --git a/app/src/organisms/ProtocolsLanding/ProtocolOverflowMenu.tsx b/app/src/organisms/ProtocolsLanding/ProtocolOverflowMenu.tsx index d64dd0f46dd..9412939d23f 100644 --- a/app/src/organisms/ProtocolsLanding/ProtocolOverflowMenu.tsx +++ b/app/src/organisms/ProtocolsLanding/ProtocolOverflowMenu.tsx @@ -3,7 +3,7 @@ import { css } from 'styled-components' import { createPortal } from 'react-dom' import { useTranslation } from 'react-i18next' import { useDispatch } from 'react-redux' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { Flex, @@ -62,7 +62,7 @@ export function ProtocolOverflowMenu( setShowOverflowMenu, } = useMenuHandleClickOutside() const dispatch = useDispatch() - const history = useHistory() + const navigate = useNavigate() const trackEvent = useTrackEvent() const { confirm: confirmDeleteProtocol, @@ -114,7 +114,7 @@ export function ProtocolOverflowMenu( } const handleClickTimeline: React.MouseEventHandler = e => { e.preventDefault() - history.push(`/protocols/${protocolKey}/timeline`) + navigate(`/protocols/${protocolKey}/timeline`) setShowOverflowMenu(prevShowOverflowMenu => !prevShowOverflowMenu) } return ( diff --git a/app/src/organisms/QuickTransferFlow/SummaryAndSettings.tsx b/app/src/organisms/QuickTransferFlow/SummaryAndSettings.tsx index 676e00eb4f3..44cfd13f5eb 100644 --- a/app/src/organisms/QuickTransferFlow/SummaryAndSettings.tsx +++ b/app/src/organisms/QuickTransferFlow/SummaryAndSettings.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { useQueryClient } from 'react-query' import { Flex, @@ -39,7 +39,7 @@ export function SummaryAndSettings( props: SummaryAndSettingsProps ): JSX.Element | null { const { exitButtonProps, state: wizardFlowState } = props - const history = useHistory() + const navigate = useNavigate() const queryClient = useQueryClient() const host = useHost() const { t } = useTranslation(['quick_transfer', 'shared']) @@ -76,7 +76,7 @@ export function SummaryAndSettings( queryClient.invalidateQueries([host, 'runs']).catch((e: Error) => { console.error(`error invalidating runs query: ${e.message}`) }) - history.push(`/runs/${data.data.id}/setup`) + navigate(`/runs/${data.data.id}/setup`) }, }, host @@ -92,7 +92,7 @@ export function SummaryAndSettings( files: [protocolFile], protocolKind: 'quick-transfer', }).then(() => { - history.push('/quick-transfer') + navigate('/quick-transfer') }) } diff --git a/app/src/organisms/QuickTransferFlow/__tests__/SummaryAndSettings.test.tsx b/app/src/organisms/QuickTransferFlow/__tests__/SummaryAndSettings.test.tsx index 9635b05eb03..a6cfc429cb1 100644 --- a/app/src/organisms/QuickTransferFlow/__tests__/SummaryAndSettings.test.tsx +++ b/app/src/organisms/QuickTransferFlow/__tests__/SummaryAndSettings.test.tsx @@ -12,15 +12,15 @@ import { i18n } from '../../../i18n' import { SummaryAndSettings } from '../SummaryAndSettings' import { NameQuickTransfer } from '../NameQuickTransfer' import { Overview } from '../Overview' -import type * as ReactRouterDom from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const reactRouterDom = await importOriginal() + const reactRouterDom = await importOriginal() return { ...reactRouterDom, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) vi.mock('../Overview') diff --git a/app/src/organisms/QuickTransferFlow/index.tsx b/app/src/organisms/QuickTransferFlow/index.tsx index 9749d2cecb1..6b589ca0b45 100644 --- a/app/src/organisms/QuickTransferFlow/index.tsx +++ b/app/src/organisms/QuickTransferFlow/index.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { useConditionalConfirm, @@ -25,7 +25,7 @@ const QUICK_TRANSFER_WIZARD_STEPS = 8 const initialQuickTransferState: QuickTransferWizardState = {} export const QuickTransferFlow = (): JSX.Element => { - const history = useHistory() + const navigate = useNavigate() const { i18n, t } = useTranslation(['quick_transfer', 'shared']) const [state, dispatch] = React.useReducer( quickTransferWizardReducer, @@ -38,7 +38,7 @@ export const QuickTransferFlow = (): JSX.Element => { showConfirmation: showConfirmExit, cancel: cancelExit, } = useConditionalConfirm(() => { - history.push('/quick-transfer') + navigate('/quick-transfer') }, true) const exitButtonProps: React.ComponentProps = { diff --git a/app/src/organisms/RobotSettingsDashboard/NetworkSettings/__tests__/WifiConnectionDetails.test.tsx b/app/src/organisms/RobotSettingsDashboard/NetworkSettings/__tests__/WifiConnectionDetails.test.tsx index a8ec836d044..02da87250d3 100644 --- a/app/src/organisms/RobotSettingsDashboard/NetworkSettings/__tests__/WifiConnectionDetails.test.tsx +++ b/app/src/organisms/RobotSettingsDashboard/NetworkSettings/__tests__/WifiConnectionDetails.test.tsx @@ -17,12 +17,12 @@ vi.mock('../../../../redux/discovery') vi.mock('../../../../redux/networking') vi.mock('../NetworkDetailsModal') -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { const reactRouterDom = await importOriginal() return { ...reactRouterDom, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) diff --git a/app/src/organisms/RobotSettingsDashboard/RobotSystemVersionModal.tsx b/app/src/organisms/RobotSettingsDashboard/RobotSystemVersionModal.tsx index 703f252c82e..9b6467af878 100644 --- a/app/src/organisms/RobotSettingsDashboard/RobotSystemVersionModal.tsx +++ b/app/src/organisms/RobotSettingsDashboard/RobotSystemVersionModal.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { DIRECTION_COLUMN, @@ -29,7 +29,7 @@ export function RobotSystemVersionModal({ setShowModal, }: RobotSystemVersionModalProps): JSX.Element { const { t } = useTranslation(['device_settings', 'shared']) - const history = useHistory() + const navigate = useNavigate() const modalHeader: ModalHeaderBaseProps = { title: t('robot_system_version_available', { @@ -68,7 +68,7 @@ export function RobotSystemVersionModal({ { - history.push('/robot-settings/update-robot') + navigate('/robot-settings/update-robot') }} buttonText={t('shared:update')} /> diff --git a/app/src/organisms/RobotSettingsDashboard/__tests__/RobotSystemVersionModal.test.tsx b/app/src/organisms/RobotSettingsDashboard/__tests__/RobotSystemVersionModal.test.tsx index 6e6f4780e0d..887b36c332b 100644 --- a/app/src/organisms/RobotSettingsDashboard/__tests__/RobotSystemVersionModal.test.tsx +++ b/app/src/organisms/RobotSettingsDashboard/__tests__/RobotSystemVersionModal.test.tsx @@ -9,13 +9,13 @@ import { RobotSystemVersionModal } from '../RobotSystemVersionModal' import type * as Dom from 'react-router-dom' const mockFn = vi.fn() -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { const reactRouterDom = await importOriginal() return { ...reactRouterDom, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) @@ -52,7 +52,7 @@ describe('RobotSystemVersionModal', () => { it('should close the modal when tapping remind me later', () => { render(props) fireEvent.click(screen.getByText('Update')) - expect(mockPush).toHaveBeenCalledWith('/robot-settings/update-robot') + expect(mockNavigate).toHaveBeenCalledWith('/robot-settings/update-robot') }) it('should call the mock function when tapping update', () => { diff --git a/app/src/organisms/SendProtocolToFlexSlideout/__tests__/SendProtocolToFlexSlideout.test.tsx b/app/src/organisms/SendProtocolToFlexSlideout/__tests__/SendProtocolToFlexSlideout.test.tsx index 9f5279aa18f..cd3ab48d411 100644 --- a/app/src/organisms/SendProtocolToFlexSlideout/__tests__/SendProtocolToFlexSlideout.test.tsx +++ b/app/src/organisms/SendProtocolToFlexSlideout/__tests__/SendProtocolToFlexSlideout.test.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import { fireEvent, screen } from '@testing-library/react' import { describe, it, expect, vi, beforeEach } from 'vitest' import '@testing-library/jest-dom/vitest' -import { StaticRouter } from 'react-router-dom' +import { MemoryRouter } from 'react-router-dom' import { mockOT3HealthResponse, @@ -57,9 +57,9 @@ const render = ( props: React.ComponentProps ) => { return renderWithProviders( - + - , + , { i18nInstance: i18n, } diff --git a/app/src/organisms/UpdateAppModal/__tests__/UpdateAppModal.test.tsx b/app/src/organisms/UpdateAppModal/__tests__/UpdateAppModal.test.tsx index 95681e4a661..761cb07f0f8 100644 --- a/app/src/organisms/UpdateAppModal/__tests__/UpdateAppModal.test.tsx +++ b/app/src/organisms/UpdateAppModal/__tests__/UpdateAppModal.test.tsx @@ -27,9 +27,7 @@ vi.mock('react-router-dom', async importOriginal => { const actual = await importOriginal() return { ...actual, - useHistory: () => ({ - push: vi.fn(), - }), + useNavigate: () => vi.fn(), } }) diff --git a/app/src/organisms/UpdateAppModal/index.tsx b/app/src/organisms/UpdateAppModal/index.tsx index be41d6ed597..431bc144a31 100644 --- a/app/src/organisms/UpdateAppModal/index.tsx +++ b/app/src/organisms/UpdateAppModal/index.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { useSelector, useDispatch } from 'react-redux' import styled, { css } from 'styled-components' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { @@ -96,7 +96,7 @@ export function UpdateAppModal(props: UpdateAppModalProps): JSX.Element { } = updateState const releaseNotes = updateInfo?.releaseNotes const { t } = useTranslation(['app_settings', 'branded']) - const history = useHistory() + const navigate = useNavigate() const { removeActiveAppUpdateToast } = useRemoveActiveAppUpdateToast() const availableAppUpdateVersion = useSelector(getAvailableShellUpdate) ?? '' @@ -104,7 +104,7 @@ export function UpdateAppModal(props: UpdateAppModalProps): JSX.Element { setTimeout(() => dispatch(applyShellUpdate()), RESTART_APP_AFTER_TIME) const handleRemindMeLaterClick = (): void => { - history.push('/app-settings/general') + navigate('/app-settings/general') closeModal(true) } diff --git a/app/src/pages/AppSettings/__test__/AppSettings.test.tsx b/app/src/pages/AppSettings/__test__/AppSettings.test.tsx index bc8942c85f9..fecd160e0e2 100644 --- a/app/src/pages/AppSettings/__test__/AppSettings.test.tsx +++ b/app/src/pages/AppSettings/__test__/AppSettings.test.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { vi, describe, beforeEach, it, expect, afterEach } from 'vitest' import { Route } from 'react-router' -import { MemoryRouter } from 'react-router-dom' +import { MemoryRouter, Routes } from 'react-router-dom' import { renderWithProviders } from '../../../__testing-utils__' @@ -22,9 +22,9 @@ vi.mock('../../../organisms/AppSettings/FeatureFlags') const render = (path = '/'): ReturnType => { return renderWithProviders( - - - + + } /> + , { i18nInstance: i18n, diff --git a/app/src/pages/AppSettings/index.tsx b/app/src/pages/AppSettings/index.tsx index 0cfe5872885..61b5f619c96 100644 --- a/app/src/pages/AppSettings/index.tsx +++ b/app/src/pages/AppSettings/index.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' import { useSelector } from 'react-redux' -import { Redirect, useParams } from 'react-router-dom' +import { Navigate, useParams } from 'react-router-dom' import { ALIGN_START, @@ -28,7 +28,9 @@ import type { DesktopRouteParams, AppSettingsTab } from '../../App/types' export function AppSettings(): JSX.Element { const { t } = useTranslation('app_settings') const devToolsOn = useSelector(Config.getDevtoolsEnabled) - const { appSettingsTab } = useParams() + const { appSettingsTab } = useParams< + keyof DesktopRouteParams + >() as DesktopRouteParams const appSettingsContentByTab: { [K in AppSettingsTab]: JSX.Element @@ -41,7 +43,7 @@ export function AppSettings(): JSX.Element { const appSettingsContent = appSettingsContentByTab[appSettingsTab] ?? ( // default to the general tab if no tab or nonexistent tab is passed as a param - + ) return ( diff --git a/app/src/pages/ConnectViaEthernet/DisplayConnectionStatus.tsx b/app/src/pages/ConnectViaEthernet/DisplayConnectionStatus.tsx index 6e2ef24d5b3..177599adb5b 100644 --- a/app/src/pages/ConnectViaEthernet/DisplayConnectionStatus.tsx +++ b/app/src/pages/ConnectViaEthernet/DisplayConnectionStatus.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { ALIGN_CENTER, @@ -28,7 +28,7 @@ export function DisplayConnectionStatus({ setShowNetworkDetailsModal, }: DisplayConnectionStatusProps): JSX.Element { const { i18n, t } = useTranslation(['device_settings', 'shared']) - const history = useHistory() + const navigate = useNavigate() return ( @@ -94,7 +94,7 @@ export function DisplayConnectionStatus({ flex="1" buttonText={i18n.format(t('shared:continue'), 'capitalize')} onClick={() => { - history.push('/robot-settings/update-robot-during-onboarding') + navigate('/robot-settings/update-robot-during-onboarding') }} /> ) : null} diff --git a/app/src/pages/ConnectViaEthernet/TitleHeader.tsx b/app/src/pages/ConnectViaEthernet/TitleHeader.tsx index 40c3bf27fe8..c837499c22b 100644 --- a/app/src/pages/ConnectViaEthernet/TitleHeader.tsx +++ b/app/src/pages/ConnectViaEthernet/TitleHeader.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { ALIGN_CENTER, @@ -21,7 +21,7 @@ interface TitleHeaderProps { // Note (kj:05/12/2023) This might be a component later export function TitleHeader({ title }: TitleHeaderProps): JSX.Element { - const history = useHistory() + const navigate = useNavigate() return ( { - history.push('/network-setup') + navigate('/network-setup') }} data-testid={`${title}_header_back_button`} > diff --git a/app/src/pages/ConnectViaEthernet/__tests__/DisplayConnectionStatus.test.tsx b/app/src/pages/ConnectViaEthernet/__tests__/DisplayConnectionStatus.test.tsx index 76c195f3ff6..92864b2a1d0 100644 --- a/app/src/pages/ConnectViaEthernet/__tests__/DisplayConnectionStatus.test.tsx +++ b/app/src/pages/ConnectViaEthernet/__tests__/DisplayConnectionStatus.test.tsx @@ -6,15 +6,15 @@ import { renderWithProviders } from '../../../__testing-utils__' import { i18n } from '../../../i18n' import { DisplayConnectionStatus } from '../../../pages/ConnectViaEthernet/DisplayConnectionStatus' -import type * as ReactRouterDom from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' const mockFunc = vi.fn() -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) @@ -70,7 +70,7 @@ describe('DisplayConnectionStatus', () => { it('should call a mock push when tapping continue button', () => { render(props) fireEvent.click(screen.getByText('Continue')) - expect(mockPush).toHaveBeenCalledWith( + expect(mockNavigate).toHaveBeenCalledWith( '/robot-settings/update-robot-during-onboarding' ) }) diff --git a/app/src/pages/ConnectViaEthernet/__tests__/TitleHeader.test.tsx b/app/src/pages/ConnectViaEthernet/__tests__/TitleHeader.test.tsx index 67921d8203c..14575779736 100644 --- a/app/src/pages/ConnectViaEthernet/__tests__/TitleHeader.test.tsx +++ b/app/src/pages/ConnectViaEthernet/__tests__/TitleHeader.test.tsx @@ -5,14 +5,14 @@ import { fireEvent, screen } from '@testing-library/react' import { renderWithProviders } from '../../../__testing-utils__' import { TitleHeader } from '../../../pages/ConnectViaEthernet/TitleHeader' -import type * as ReactRouterDom from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) @@ -38,6 +38,6 @@ describe('TitleHeader', () => { it('should call a mock function when tapping back button', () => { render(props) fireEvent.click(screen.getByTestId('Ethernet_header_back_button')) - expect(mockPush).toHaveBeenCalledWith('/network-setup') + expect(mockNavigate).toHaveBeenCalledWith('/network-setup') }) }) diff --git a/app/src/pages/ConnectViaUSB/_tests__/ConnectedViaUSB.test.tsx b/app/src/pages/ConnectViaUSB/_tests__/ConnectedViaUSB.test.tsx index 16bc9bb98bf..79647ac1fb8 100644 --- a/app/src/pages/ConnectViaUSB/_tests__/ConnectedViaUSB.test.tsx +++ b/app/src/pages/ConnectViaUSB/_tests__/ConnectedViaUSB.test.tsx @@ -11,15 +11,15 @@ import { ConnectViaUSB } from '../../../pages/ConnectViaUSB' import type { UseQueryResult } from 'react-query' import type { ActiveConnections } from '@opentrons/api-client' -import type * as ReactRouterDom from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) vi.mock('@opentrons/react-api-client') @@ -58,7 +58,7 @@ describe('ConnectViaUSB', () => { it('should call a mock function when tapping back button', () => { const [{ getByRole }] = render() fireEvent.click(getByRole('button')) - expect(mockPush).toHaveBeenCalledWith('/network-setup') + expect(mockNavigate).toHaveBeenCalledWith('/network-setup') }) it('should render successful connection text and button', () => { @@ -81,6 +81,6 @@ describe('ConnectViaUSB', () => { const [{ getByText }] = render() const button = getByText('Continue') fireEvent.click(button) - expect(mockPush).toHaveBeenCalledWith('/emergency-stop') + expect(mockNavigate).toHaveBeenCalledWith('/emergency-stop') }) }) diff --git a/app/src/pages/ConnectViaUSB/index.tsx b/app/src/pages/ConnectViaUSB/index.tsx index a28b97af85c..a802d36d891 100644 --- a/app/src/pages/ConnectViaUSB/index.tsx +++ b/app/src/pages/ConnectViaUSB/index.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { ALIGN_CENTER, BORDERS, @@ -23,7 +23,7 @@ import { MediumButton } from '../../atoms/buttons' export function ConnectViaUSB(): JSX.Element { const { i18n, t } = useTranslation(['device_settings', 'shared', 'branded']) - const history = useHistory() + const navigate = useNavigate() // TODO(bh, 2023-5-31): active connections from /system/connected isn't exactly the right way to monitor for a usb connection - // the system-server tracks active connections by authorization token, which is valid for 2 hours // another option is to report an active usb connection by monitoring usb port traffic (discovery-client polls health from the desktop app) @@ -50,7 +50,7 @@ export function ConnectViaUSB(): JSX.Element { { - history.push('/network-setup') + navigate('/network-setup') }} position={POSITION_ABSOLUTE} > @@ -104,7 +104,7 @@ export function ConnectViaUSB(): JSX.Element { { - history.push('/emergency-stop') + navigate('/emergency-stop') }} /> diff --git a/app/src/pages/DeckConfiguration/__tests__/DeckConfiguration.test.tsx b/app/src/pages/DeckConfiguration/__tests__/DeckConfiguration.test.tsx index d0fab1277b0..1e34e917eca 100644 --- a/app/src/pages/DeckConfiguration/__tests__/DeckConfiguration.test.tsx +++ b/app/src/pages/DeckConfiguration/__tests__/DeckConfiguration.test.tsx @@ -20,15 +20,15 @@ import { import type { UseQueryResult } from 'react-query' import type { DeckConfiguration } from '@opentrons/shared-data' import type * as Components from '@opentrons/components' -import type * as ReactRouterDom from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' const mockUpdateDeckConfiguration = vi.fn() const mockGoBack = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ goBack: mockGoBack } as any), + useNavigate: () => mockGoBack, } }) vi.mock('@opentrons/components', async importOriginal => { diff --git a/app/src/pages/DeckConfiguration/index.tsx b/app/src/pages/DeckConfiguration/index.tsx index f520b825177..ef27e81bc0a 100644 --- a/app/src/pages/DeckConfiguration/index.tsx +++ b/app/src/pages/DeckConfiguration/index.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { createPortal } from 'react-dom' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { DeckConfigurator, @@ -28,7 +28,7 @@ export function DeckConfigurationEditor(): JSX.Element { 'devices_landing', 'shared', ]) - const history = useHistory() + const navigate = useNavigate() const [ showSetupInstructionsModal, setShowSetupInstructionsModal, @@ -49,7 +49,7 @@ export function DeckConfigurationEditor(): JSX.Element { const deckConfig = useNotifyDeckConfigurationQuery().data ?? [] const handleClickConfirm = (): void => { - history.goBack() + navigate(-1) } const secondaryButtonProps: React.ComponentProps = { diff --git a/app/src/pages/Devices/CalibrationDashboard/__tests__/CalibrationDashboard.test.tsx b/app/src/pages/Devices/CalibrationDashboard/__tests__/CalibrationDashboard.test.tsx index 1c46e097c41..7039e9836b5 100644 --- a/app/src/pages/Devices/CalibrationDashboard/__tests__/CalibrationDashboard.test.tsx +++ b/app/src/pages/Devices/CalibrationDashboard/__tests__/CalibrationDashboard.test.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { vi, describe, it, beforeEach } from 'vitest' import { screen } from '@testing-library/react' -import { MemoryRouter, Route } from 'react-router-dom' +import { MemoryRouter, Route, Routes } from 'react-router-dom' import { renderWithProviders } from '../../../../__testing-utils__' import { i18n } from '../../../../i18n' @@ -27,9 +27,12 @@ vi.mock('../../../../resources/runs') const render = (path = '/') => { return renderWithProviders( - - - + + } + /> + , { i18nInstance: i18n, diff --git a/app/src/pages/Devices/CalibrationDashboard/index.tsx b/app/src/pages/Devices/CalibrationDashboard/index.tsx index bcdd71cc31c..b875918c25e 100644 --- a/app/src/pages/Devices/CalibrationDashboard/index.tsx +++ b/app/src/pages/Devices/CalibrationDashboard/index.tsx @@ -12,7 +12,9 @@ import { useRobot } from '../../../organisms/Devices/hooks' import type { DesktopRouteParams } from '../../../App/types' export function CalibrationDashboard(): JSX.Element { - const { robotName } = useParams() + const { robotName } = useParams< + keyof DesktopRouteParams + >() as DesktopRouteParams const robot = useRobot(robotName) const [ dashboardOffsetCalLauncher, diff --git a/app/src/pages/Devices/DeviceDetails/__tests__/DeviceDetails.test.tsx b/app/src/pages/Devices/DeviceDetails/__tests__/DeviceDetails.test.tsx index 6c20bf55094..7c45cf32baa 100644 --- a/app/src/pages/Devices/DeviceDetails/__tests__/DeviceDetails.test.tsx +++ b/app/src/pages/Devices/DeviceDetails/__tests__/DeviceDetails.test.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import { vi, it, describe, expect, beforeEach } from 'vitest' import { when } from 'vitest-when' import { screen } from '@testing-library/react' -import { MemoryRouter, Route } from 'react-router-dom' +import { MemoryRouter, Route, Routes } from 'react-router-dom' import { renderWithProviders } from '../../../../__testing-utils__' @@ -29,10 +29,10 @@ vi.mock('../../../../redux/discovery') const render = (path = '/') => { return renderWithProviders( - - - - devices page + + } /> + devices page>} /> + , { i18nInstance: i18n, diff --git a/app/src/pages/Devices/DeviceDetails/index.tsx b/app/src/pages/Devices/DeviceDetails/index.tsx index 048a9921220..962dd229d87 100644 --- a/app/src/pages/Devices/DeviceDetails/index.tsx +++ b/app/src/pages/Devices/DeviceDetails/index.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useSelector } from 'react-redux' -import { Redirect, useParams } from 'react-router-dom' +import { Navigate, useParams } from 'react-router-dom' import { ApiHostProvider } from '@opentrons/react-api-client' @@ -12,7 +12,9 @@ import { DeviceDetailsComponent } from './DeviceDetailsComponent' import type { DesktopRouteParams } from '../../../App/types' export function DeviceDetails(): JSX.Element | null { - const { robotName } = useParams() + const { robotName } = useParams< + keyof DesktopRouteParams + >() as DesktopRouteParams const robot = useRobot(robotName) const isScanning = useSelector(getScanning) @@ -30,6 +32,6 @@ export function DeviceDetails(): JSX.Element | null { ) : ( - + ) } diff --git a/app/src/pages/Devices/ProtocolRunDetails/__tests__/ProtocolRunDetails.test.tsx b/app/src/pages/Devices/ProtocolRunDetails/__tests__/ProtocolRunDetails.test.tsx index 23d9e3494c1..a5a1df6d218 100644 --- a/app/src/pages/Devices/ProtocolRunDetails/__tests__/ProtocolRunDetails.test.tsx +++ b/app/src/pages/Devices/ProtocolRunDetails/__tests__/ProtocolRunDetails.test.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { vi, it, describe, expect, beforeEach, afterEach } from 'vitest' -import { Route, MemoryRouter } from 'react-router-dom' +import { Route, MemoryRouter, Routes } from 'react-router-dom' import { fireEvent, screen } from '@testing-library/react' import { renderWithProviders } from '../../../../__testing-utils__' @@ -61,9 +61,12 @@ const mockMagneticModule = { const render = (path = '/') => { return renderWithProviders( - - - + + } + /> + , { i18nInstance: i18n, diff --git a/app/src/pages/Devices/ProtocolRunDetails/index.tsx b/app/src/pages/Devices/ProtocolRunDetails/index.tsx index 8fdec56aeaf..e77841ec980 100644 --- a/app/src/pages/Devices/ProtocolRunDetails/index.tsx +++ b/app/src/pages/Devices/ProtocolRunDetails/index.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import isEmpty from 'lodash/isEmpty' import { useTranslation } from 'react-i18next' import { useDispatch } from 'react-redux' -import { NavLink, Redirect, useParams } from 'react-router-dom' +import { NavLink, Navigate, useParams } from 'react-router-dom' import styled, { css } from 'styled-components' import { @@ -125,11 +125,9 @@ function RoundTab({ } export function ProtocolRunDetails(): JSX.Element | null { - const { - robotName, - runId, - protocolRunDetailsTab, - } = useParams() + const { robotName, runId, protocolRunDetailsTab } = useParams< + keyof DesktopRouteParams + >() as DesktopRouteParams const dispatch = useDispatch() const robot = useRobot(robotName) @@ -224,7 +222,8 @@ function PageContents(props: PageContentsProps): JSX.Element { protocolRunDetailsTab ] ?? ( // default to the setup tab if no tab or nonexistent tab is passed as a param - + + ) return ( @@ -277,7 +276,7 @@ const SetupTab = (props: SetupTabProps): JSX.Element | null => { /> {currentRunId !== runId ? ( // redirect to run preview if not current run - ) : null} @@ -305,7 +304,7 @@ const ParametersTab = (props: ParametersTabProps): JSX.Element | null => { tabName={t('parameters')} /> {disabled ? ( - ) : null} @@ -346,7 +345,8 @@ const ModuleControlsTab = ( /> {disabled ? ( // redirect to run preview if not current run - ) : null} diff --git a/app/src/pages/Devices/RobotSettings/__tests__/RobotSettings.test.tsx b/app/src/pages/Devices/RobotSettings/__tests__/RobotSettings.test.tsx index a9ce14f4f5b..23b55dc1c84 100644 --- a/app/src/pages/Devices/RobotSettings/__tests__/RobotSettings.test.tsx +++ b/app/src/pages/Devices/RobotSettings/__tests__/RobotSettings.test.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { vi, it, describe, expect, beforeEach, afterEach } from 'vitest' import { fireEvent, screen } from '@testing-library/react' -import { Route, MemoryRouter } from 'react-router-dom' +import { Route, MemoryRouter, Routes } from 'react-router-dom' import { renderWithProviders } from '../../../../__testing-utils__' import { i18n } from '../../../../i18n' @@ -30,12 +30,16 @@ vi.mock('../../../../redux/robot-update') const render = (path = '/') => { return renderWithProviders( - - - - - mock device details - + + } + /> + mock device details} + /> + , { i18nInstance: i18n, diff --git a/app/src/pages/Devices/RobotSettings/index.tsx b/app/src/pages/Devices/RobotSettings/index.tsx index b93fc441d74..b3b7580377b 100644 --- a/app/src/pages/Devices/RobotSettings/index.tsx +++ b/app/src/pages/Devices/RobotSettings/index.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { Redirect, useParams } from 'react-router-dom' +import { useParams, Navigate } from 'react-router-dom' import { BORDERS, @@ -40,7 +40,9 @@ import type { DesktopRouteParams, RobotSettingsTab } from '../../../App/types' export function RobotSettings(): JSX.Element | null { const { t } = useTranslation('device_settings') - const { robotName, robotSettingsTab } = useParams() + const { robotName, robotSettingsTab } = useParams< + keyof DesktopRouteParams + >() as DesktopRouteParams const robot = useRobot(robotName) const isCalibrationDisabled = robot?.status !== CONNECTABLE const isPrivacyDisabled = robot?.status === UNREACHABLE @@ -87,7 +89,7 @@ export function RobotSettings(): JSX.Element | null { (robot?.status === REACHABLE && robot?.serverHealthStatus !== 'ok')) && robotUpdateSession == null ) { - return + return } const cannotViewCalibration = robotSettingsTab === 'calibration' && isCalibrationDisabled @@ -95,12 +97,12 @@ export function RobotSettings(): JSX.Element | null { robotSettingsTab === 'feature-flags' && !devToolsOn const cannotViewPrivacy = robotSettingsTab === 'privacy' && isPrivacyDisabled if (cannotViewCalibration || cannotViewFeatureFlags || cannotViewPrivacy) { - return + return } const robotSettingsContent = robotSettingsContentByTab[robotSettingsTab] ?? ( // default to the calibration tab if no tab or nonexistent tab is passed as a param - + ) return ( diff --git a/app/src/pages/EmergencyStop/__tests__/EmergencyStop.test.tsx b/app/src/pages/EmergencyStop/__tests__/EmergencyStop.test.tsx index bbfee8eb376..6e34f86c218 100644 --- a/app/src/pages/EmergencyStop/__tests__/EmergencyStop.test.tsx +++ b/app/src/pages/EmergencyStop/__tests__/EmergencyStop.test.tsx @@ -7,7 +7,7 @@ import { renderWithProviders } from '../../../__testing-utils__' import { i18n } from '../../../i18n' import { EmergencyStop } from '..' -import type * as ReactRouterDom from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' vi.mock('@opentrons/react-api-client') @@ -19,12 +19,12 @@ const mockDisconnectedEstop = { rightEstopPhysicalStatus: 'notPresent', }, } as any -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) @@ -85,6 +85,6 @@ describe('EmergencyStop', () => { } as any) render() fireEvent.click(screen.getByRole('button')) - expect(mockPush).toHaveBeenCalledWith('/robot-settings/rename-robot') + expect(mockNavigate).toHaveBeenCalledWith('/robot-settings/rename-robot') }) }) diff --git a/app/src/pages/EmergencyStop/index.tsx b/app/src/pages/EmergencyStop/index.tsx index c0d430ce12a..b5419ec5790 100644 --- a/app/src/pages/EmergencyStop/index.tsx +++ b/app/src/pages/EmergencyStop/index.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { ALIGN_CENTER, @@ -25,7 +25,7 @@ const ESTOP_STATUS_REFETCH_INTERVAL_MS = 10000 export function EmergencyStop(): JSX.Element { const { i18n, t } = useTranslation(['device_settings', 'shared']) - const history = useHistory() + const navigate = useNavigate() // Note here the touchscreen app is using status since status is linked to EstopPhysicalStatuses // left notPresent + right disengaged => disengaged @@ -102,7 +102,7 @@ export function EmergencyStop(): JSX.Element { buttonText={i18n.format(t('shared:continue'), 'capitalize')} disabled={!isEstopConnected} onClick={() => { - history.push('/robot-settings/rename-robot') + navigate('/robot-settings/rename-robot') }} /> diff --git a/app/src/pages/InstrumentDetail/__tests__/InstrumentDetail.test.tsx b/app/src/pages/InstrumentDetail/__tests__/InstrumentDetail.test.tsx index af9489f2c6c..6b92a5ab9be 100644 --- a/app/src/pages/InstrumentDetail/__tests__/InstrumentDetail.test.tsx +++ b/app/src/pages/InstrumentDetail/__tests__/InstrumentDetail.test.tsx @@ -19,7 +19,7 @@ import type { Instruments } from '@opentrons/api-client' vi.mock('@opentrons/react-api-client') vi.mock('react-router-dom', () => ({ useParams: vi.fn(), - useHistory: vi.fn(), + useNavigate: vi.fn(), })) vi.mock('../../../resources/instruments/hooks') vi.mock('../../../resources/robot-settings/hooks') diff --git a/app/src/pages/InstrumentsDashboard/__tests__/InstrumentsDashboard.test.tsx b/app/src/pages/InstrumentsDashboard/__tests__/InstrumentsDashboard.test.tsx index 06e040bbe39..18b6d2cfb9c 100644 --- a/app/src/pages/InstrumentsDashboard/__tests__/InstrumentsDashboard.test.tsx +++ b/app/src/pages/InstrumentsDashboard/__tests__/InstrumentsDashboard.test.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { Route, MemoryRouter } from 'react-router-dom' +import { Route, MemoryRouter, Routes } from 'react-router-dom' import { fireEvent, screen } from '@testing-library/react' import { renderWithProviders } from '../../../__testing-utils__' import { vi, describe, it, afterEach, beforeEach, expect } from 'vitest' @@ -93,18 +93,16 @@ vi.mock('../../../organisms/PipetteWizardFlows') vi.mock('../../../organisms/PipetteWizardFlows/ChoosePipette') vi.mock('../../../organisms/Navigation') -const render = () => { +const render = (path = '/') => { return renderWithProviders( - - - - - - - + + + } /> + } /> + , { i18nInstance: i18n } - ) + )[0] } describe('InstrumentsDashboard', () => { @@ -119,7 +117,7 @@ describe('InstrumentsDashboard', () => { vi.resetAllMocks() }) it('should render mount info for all attached mounts', () => { - render() + render('/instruments') screen.getByText('left Mount') screen.getByText('Flex 1-Channel 1000 μL') screen.getByText('right Mount') @@ -128,7 +126,7 @@ describe('InstrumentsDashboard', () => { screen.getByText('Flex Gripper') }) it('should route to left mount detail when instrument attached and clicked', () => { - render() + render('/instruments') fireEvent.click(screen.getByText('left Mount')) screen.getByText('serial number') screen.getByText(mockLeftPipetteData.serialNumber) @@ -139,7 +137,7 @@ describe('InstrumentsDashboard', () => { ) }) it('should route to right mount detail when instrument attached and clicked', () => { - render() + render('/instruments') fireEvent.click(screen.getByText('right Mount')) screen.getByText('serial number') screen.getByText(mockRightPipetteData.serialNumber) @@ -150,7 +148,7 @@ describe('InstrumentsDashboard', () => { ) }) it('should route to extension mount detail when instrument attached and clicked', () => { - render() + render('/instruments') fireEvent.click(screen.getByText('extension Mount')) screen.getByText('serial number') screen.getByText(mockGripperData.serialNumber) @@ -159,7 +157,7 @@ describe('InstrumentsDashboard', () => { vi.mocked(useInstrumentsQuery).mockReturnValue({ data: { data: [] }, } as any) - render() + render('/instruments') fireEvent.click(screen.getByText('left Mount')) expect(vi.mocked(ChoosePipette)).toHaveBeenCalled() }) @@ -167,7 +165,7 @@ describe('InstrumentsDashboard', () => { vi.mocked(useInstrumentsQuery).mockReturnValue({ data: { data: [] }, } as any) - render() + render('/instruments') fireEvent.click(screen.getByText('right Mount')) expect(vi.mocked(ChoosePipette)).toHaveBeenCalled() }) @@ -175,7 +173,7 @@ describe('InstrumentsDashboard', () => { vi.mocked(useInstrumentsQuery).mockReturnValue({ data: { data: [] }, } as any) - render() + render('/instruments') fireEvent.click(screen.getByText('extension Mount')) expect(vi.mocked(GripperWizardFlows)).toHaveBeenCalled() }) @@ -185,7 +183,7 @@ describe('InstrumentsDashboard', () => { data: [mock96ChannelData, mockGripperData], }, } as any) - render() + render('/instruments') screen.getByText('Left+Right Mounts') screen.getByText('extension Mount') }) diff --git a/app/src/pages/NameRobot/__tests__/NameRobot.test.tsx b/app/src/pages/NameRobot/__tests__/NameRobot.test.tsx index c7b9b546645..a91c108a527 100644 --- a/app/src/pages/NameRobot/__tests__/NameRobot.test.tsx +++ b/app/src/pages/NameRobot/__tests__/NameRobot.test.tsx @@ -19,20 +19,20 @@ import { } from '../../../redux/discovery/__fixtures__' import { NameRobot } from '..' -import type * as ReactRouterDom from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' vi.mock('../../../redux/discovery/selectors') vi.mock('../../../redux/config') vi.mock('../../../redux/analytics') vi.mock('../../../organisms/RobotSettingsDashboard/NetworkSettings/hooks') -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) @@ -142,6 +142,6 @@ describe('NameRobot', () => { vi.mocked(useIsUnboxingFlowOngoing).mockReturnValue(false) render() fireEvent.click(screen.getByTestId('name_back_button')) - expect(mockPush).toHaveBeenCalledWith('/robot-settings') + expect(mockNavigate).toHaveBeenCalledWith('/robot-settings') }) }) diff --git a/app/src/pages/NameRobot/index.tsx b/app/src/pages/NameRobot/index.tsx index eeed5b819e5..bd6f2180853 100644 --- a/app/src/pages/NameRobot/index.tsx +++ b/app/src/pages/NameRobot/index.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import { Controller, useForm } from 'react-hook-form' import { useTranslation } from 'react-i18next' import { useSelector, useDispatch } from 'react-redux' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { ALIGN_CENTER, @@ -47,7 +47,7 @@ interface FormValues { export function NameRobot(): JSX.Element { const { t } = useTranslation(['device_settings', 'shared']) - const history = useHistory() + const navigate = useNavigate() const trackEvent = useTrackEvent() const localRobot = useSelector(getLocalRobot) const ipAddress = localRobot?.ip @@ -143,7 +143,7 @@ export function NameRobot(): JSX.Element { if (data.name != null) { setNewName(data.name) if (!isUnboxingFlowOngoing) { - history.push('/robot-settings') + navigate('/robot-settings') } else { setIsShowConfirmRobotName(true) } @@ -198,9 +198,9 @@ export function NameRobot(): JSX.Element { data-testid="name_back_button" onClick={() => { if (isUnboxingFlowOngoing) { - history.push('/emergency-stop') + navigate('/emergency-stop') } else { - history.push('/robot-settings') + navigate('/robot-settings') } }} > diff --git a/app/src/pages/NetworkSetupMenu/__tests__/NetworkSetupMenu.test.tsx b/app/src/pages/NetworkSetupMenu/__tests__/NetworkSetupMenu.test.tsx index f2febd1a32d..73f9312cc3c 100644 --- a/app/src/pages/NetworkSetupMenu/__tests__/NetworkSetupMenu.test.tsx +++ b/app/src/pages/NetworkSetupMenu/__tests__/NetworkSetupMenu.test.tsx @@ -6,15 +6,15 @@ import { renderWithProviders } from '../../../__testing-utils__' import { i18n } from '../../../i18n' import { NetworkSetupMenu } from '..' -import type * as ReactRouterDom from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) @@ -53,10 +53,10 @@ describe('NetworkSetupMenu', () => { const ethernetButton = screen.getByText('Ethernet') const usbButton = screen.getByText('USB') fireEvent.click(wifiButton) - expect(mockPush).toHaveBeenCalledWith('/network-setup/wifi') + expect(mockNavigate).toHaveBeenCalledWith('/network-setup/wifi') fireEvent.click(ethernetButton) - expect(mockPush).toHaveBeenCalledWith('/network-setup/ethernet') + expect(mockNavigate).toHaveBeenCalledWith('/network-setup/ethernet') fireEvent.click(usbButton) - expect(mockPush).toHaveBeenCalledWith('/network-setup/usb') + expect(mockNavigate).toHaveBeenCalledWith('/network-setup/usb') }) }) diff --git a/app/src/pages/ProtocolDashboard/LongPressModal.tsx b/app/src/pages/ProtocolDashboard/LongPressModal.tsx index a3287360b42..535b754259e 100644 --- a/app/src/pages/ProtocolDashboard/LongPressModal.tsx +++ b/app/src/pages/ProtocolDashboard/LongPressModal.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useDispatch, useSelector } from 'react-redux' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { Flex, Icon, SPACING, LegacyStyledText } from '@opentrons/components' import { useCreateRunMutation } from '@opentrons/react-api-client' @@ -28,7 +28,7 @@ export function LongPressModal({ setShowDeleteConfirmationModal, setTargetProtocolId, }: LongPressModalProps): JSX.Element { - const history = useHistory() + const navigate = useNavigate() let pinnedProtocolIds = useSelector(getPinnedProtocolIds) ?? [] const { i18n, t } = useTranslation(['protocol_info', 'shared']) const dispatch = useDispatch() @@ -49,7 +49,7 @@ export function LongPressModal({ const createRunUse = useCreateRunMutation({ onSuccess: data => { const runId: string = data.data.id - history.push(`/runs/${runId}/setup`) + navigate(`/runs/${runId}/setup`) }, }) const createRun = diff --git a/app/src/pages/ProtocolDashboard/PinnedProtocol.tsx b/app/src/pages/ProtocolDashboard/PinnedProtocol.tsx index d5e4a8c7347..6824a67d232 100644 --- a/app/src/pages/ProtocolDashboard/PinnedProtocol.tsx +++ b/app/src/pages/ProtocolDashboard/PinnedProtocol.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { formatDistance } from 'date-fns' import styled, { css } from 'styled-components' @@ -83,7 +83,7 @@ export function PinnedProtocol(props: PinnedProtocolProps): JSX.Element { isRequiredCSV = false, } = props const cardSize = size ?? 'full' - const history = useHistory() + const navigate = useNavigate() const longpress = useLongPress() const protocolName = protocol.metadata.protocolName ?? protocol.files[0].name const { t } = useTranslation('protocol_info') @@ -96,7 +96,7 @@ export function PinnedProtocol(props: PinnedProtocolProps): JSX.Element { protocolId: string ): void => { if (!longpress.isLongPressed) { - history.push(`/protocols/${protocolId}`) + navigate(`/protocols/${protocolId}`) } } React.useEffect(() => { diff --git a/app/src/pages/ProtocolDashboard/ProtocolCard.tsx b/app/src/pages/ProtocolDashboard/ProtocolCard.tsx index a210a46139b..f6acd4ed098 100644 --- a/app/src/pages/ProtocolDashboard/ProtocolCard.tsx +++ b/app/src/pages/ProtocolDashboard/ProtocolCard.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { Trans, useTranslation } from 'react-i18next' import { useQueryClient } from 'react-query' import { formatDistance } from 'date-fns' @@ -59,7 +59,7 @@ export function ProtocolCard(props: ProtocolCardProps): JSX.Element { setTargetProtocolId, setIsRequiredCSV, } = props - const history = useHistory() + const navigate = useNavigate() const [showIcon, setShowIcon] = React.useState(false) const [ showFailedAnalysisModal, @@ -120,7 +120,7 @@ export function ProtocolCard(props: ProtocolCardProps): JSX.Element { if (isFailedAnalysis) { setShowFailedAnalysisModal(true) } else if (!longpress.isLongPressed) { - history.push(`/protocols/${protocolId}`) + navigate(`/protocols/${protocolId}`) } } diff --git a/app/src/pages/ProtocolDashboard/__tests__/PinnedProtocol.test.tsx b/app/src/pages/ProtocolDashboard/__tests__/PinnedProtocol.test.tsx index e1e2125c88a..15cc38baefe 100644 --- a/app/src/pages/ProtocolDashboard/__tests__/PinnedProtocol.test.tsx +++ b/app/src/pages/ProtocolDashboard/__tests__/PinnedProtocol.test.tsx @@ -12,15 +12,15 @@ import { PinnedProtocol } from '../PinnedProtocol' import type { Chip } from '@opentrons/components' import type { ProtocolResource } from '@opentrons/shared-data' -import type * as ReactRouterDom from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) vi.mock('@opentrons/components', async importOriginal => { @@ -119,7 +119,7 @@ describe('Pinned Protocol', () => { render(props) const name = screen.getByText('yay mock protocol') fireEvent.click(name) - expect(mockPush).toHaveBeenCalledWith('/protocols/mockProtocol1') + expect(mockNavigate).toHaveBeenCalledWith('/protocols/mockProtocol1') }) it('should display modal after long click', async () => { diff --git a/app/src/pages/ProtocolDashboard/__tests__/ProtocolCard.test.tsx b/app/src/pages/ProtocolDashboard/__tests__/ProtocolCard.test.tsx index 6ad885d780e..0e792cb8d70 100644 --- a/app/src/pages/ProtocolDashboard/__tests__/ProtocolCard.test.tsx +++ b/app/src/pages/ProtocolDashboard/__tests__/ProtocolCard.test.tsx @@ -14,7 +14,7 @@ import { i18n } from '../../../i18n' import { useFeatureFlag } from '../../../redux/config' import { ProtocolCard } from '../ProtocolCard' -import type * as ReactRouterDom from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' import type { UseQueryResult } from 'react-query' import type { CompletedProtocolAnalysis, @@ -22,13 +22,13 @@ import type { } from '@opentrons/shared-data' import type { Chip } from '@opentrons/components' -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) vi.mock('@opentrons/react-api-client') @@ -115,7 +115,7 @@ describe('ProtocolCard', () => { const card = screen.getByTestId('protocol_card') expect(card).toHaveStyle(`background-color: ${COLORS.grey35}`) fireEvent.click(name) - expect(mockPush).toHaveBeenCalledWith('/protocols/mockProtocol1') + expect(mockNavigate).toHaveBeenCalledWith('/protocols/mockProtocol1') }) it('should display the analysis failed error modal when clicking on the protocol', () => { diff --git a/app/src/pages/ProtocolDetails/__tests__/ProtocolDetails.test.tsx b/app/src/pages/ProtocolDetails/__tests__/ProtocolDetails.test.tsx index d4166d6a004..443677f7ae6 100644 --- a/app/src/pages/ProtocolDetails/__tests__/ProtocolDetails.test.tsx +++ b/app/src/pages/ProtocolDetails/__tests__/ProtocolDetails.test.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import { vi, it, describe, expect, beforeEach, afterEach } from 'vitest' import { fireEvent, screen, waitFor } from '@testing-library/react' import { when } from 'vitest-when' -import { Route, MemoryRouter } from 'react-router-dom' +import { Route, MemoryRouter, Routes } from 'react-router-dom' import '@testing-library/jest-dom/vitest' import { renderWithProviders } from '../../../__testing-utils__' import { deleteProtocol, deleteRun, getProtocol } from '@opentrons/api-client' @@ -81,9 +81,9 @@ const MOCK_DATA = { const render = (path = '/protocols/fakeProtocolId') => { return renderWithProviders( - - - + + } /> + , { i18nInstance: i18n, diff --git a/app/src/pages/ProtocolDetails/index.tsx b/app/src/pages/ProtocolDetails/index.tsx index 6567f15e91b..cb7d979ea6f 100644 --- a/app/src/pages/ProtocolDetails/index.tsx +++ b/app/src/pages/ProtocolDetails/index.tsx @@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next' import { useQueryClient } from 'react-query' import { deleteProtocol, deleteRun, getProtocol } from '@opentrons/api-client' import { useDispatch, useSelector } from 'react-redux' -import { useHistory, useParams } from 'react-router-dom' +import { useNavigate, useParams } from 'react-router-dom' import { ALIGN_CENTER, BORDERS, @@ -80,7 +80,7 @@ const ProtocolHeader = ({ isScrolled, isProtocolFetching, }: ProtocolHeaderProps): JSX.Element => { - const history = useHistory() + const navigate = useNavigate() const { t } = useTranslation(['protocol_info, protocol_details', 'shared']) const [truncate, setTruncate] = React.useState(true) const [startSetup, setStartSetup] = React.useState(false) @@ -115,7 +115,7 @@ const ProtocolHeader = ({ paddingLeft="0rem" paddingRight={SPACING.spacing24} onClick={() => { - history.push('/protocols') + navigate('/protocols') }} width="3rem" > @@ -309,7 +309,9 @@ export function ProtocolDetails(): JSX.Element | null { 'shared', ]) const enableCsvFile = useFeatureFlag('enableCsvFile') - const { protocolId } = useParams() + const { protocolId } = useParams< + keyof OnDeviceRouteParams + >() as OnDeviceRouteParams const { missingProtocolHardware, conflictedSlots, @@ -318,7 +320,7 @@ export function ProtocolDetails(): JSX.Element | null { const runTimeParameters = useRunTimeParameters(protocolId) const dispatch = useDispatch() - const history = useHistory() + const navigate = useNavigate() const host = useHost() const { makeSnackbar } = useToaster() const [showParameters, setShowParameters] = React.useState(false) @@ -426,11 +428,11 @@ export function ProtocolDetails(): JSX.Element | null { ) .then(() => deleteProtocol(host, protocolId)) .then(() => { - history.push('/protocols') + navigate('/protocols') }) .catch((e: Error) => { console.error(`error deleting resources: ${e.message}`) - history.push('/protocols') + navigate('/protocols') }) } else { console.error( diff --git a/app/src/pages/ProtocolSetup/__tests__/ProtocolSetup.test.tsx b/app/src/pages/ProtocolSetup/__tests__/ProtocolSetup.test.tsx index 30cfe51c947..1be58ae82f8 100644 --- a/app/src/pages/ProtocolSetup/__tests__/ProtocolSetup.test.tsx +++ b/app/src/pages/ProtocolSetup/__tests__/ProtocolSetup.test.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { Route, MemoryRouter } from 'react-router-dom' +import { Route, MemoryRouter, Routes } from 'react-router-dom' import { fireEvent, screen } from '@testing-library/react' import { when } from 'vitest-when' import { vi, it, describe, expect, beforeEach, afterEach } from 'vitest' @@ -60,7 +60,7 @@ import { useNotifyDeckConfigurationQuery } from '../../../resources/deck_configu import type { UseQueryResult } from 'react-query' import type * as SharedData from '@opentrons/shared-data' -import type * as ReactRouterDom from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' // Mock IntersectionObserver class IntersectionObserver { observe = vi.fn() @@ -74,7 +74,7 @@ Object.defineProperty(window, 'IntersectionObserver', { value: IntersectionObserver, }) -let mockHistoryPush = vi.fn() +let mockNavigate = vi.fn() vi.mock('@opentrons/shared-data', async importOriginal => { const sharedData = await importOriginal() @@ -85,12 +85,10 @@ vi.mock('@opentrons/shared-data', async importOriginal => { }) vi.mock('react-router-dom', async importOriginal => { - const reactRouterDom = await importOriginal() + const reactRouterDom = await importOriginal() return { ...reactRouterDom, - useHistory: () => ({ - push: mockHistoryPush, - }), + useNavigate: () => mockNavigate, } }) @@ -118,9 +116,9 @@ vi.mock('../../../resources/deck_configuration') const render = (path = '/') => { return renderWithProviders( - - - + + } /> + , { i18nInstance: i18n, @@ -193,7 +191,7 @@ describe('ProtocolSetup', () => { let mockLaunchLPC = vi.fn() beforeEach(() => { mockLaunchLPC = vi.fn() - mockHistoryPush = vi.fn() + mockNavigate = vi.fn() vi.mocked(useLPCDisabledReason).mockReturnValue(null) vi.mocked(useAttachedModules).mockReturnValue([]) vi.mocked(useModuleCalibrationStatus).mockReturnValue({ complete: true }) @@ -430,6 +428,6 @@ describe('ProtocolSetup', () => { it('should redirect to the protocols page when a run is stopped', () => { vi.mocked(useRunStatus).mockReturnValue(RUN_STATUS_STOPPED) render(`/runs/${RUN_ID}/setup/`) - expect(mockHistoryPush).toHaveBeenCalledWith('/protocols') + expect(mockNavigate).toHaveBeenCalledWith('/protocols') }) }) diff --git a/app/src/pages/ProtocolSetup/index.tsx b/app/src/pages/ProtocolSetup/index.tsx index 02ab6990070..8954e7d0b01 100644 --- a/app/src/pages/ProtocolSetup/index.tsx +++ b/app/src/pages/ProtocolSetup/index.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import last from 'lodash/last' import { useSelector } from 'react-redux' import { useTranslation } from 'react-i18next' -import { useHistory, useParams } from 'react-router-dom' +import { useNavigate, useParams } from 'react-router-dom' import first from 'lodash/first' import { css } from 'styled-components' @@ -282,7 +282,7 @@ function PrepareToRun({ runRecord, }: PrepareToRunProps): JSX.Element { const { t, i18n } = useTranslation(['protocol_setup', 'shared']) - const history = useHistory() + const navigate = useNavigate() const { makeSnackbar } = useToaster() const scrollRef = React.useRef(null) const [isScrolled, setIsScrolled] = React.useState(false) @@ -323,7 +323,7 @@ function PrepareToRun({ const runStatus = useRunStatus(runId) if (runStatus === RUN_STATUS_STOPPED) { - history.push('/protocols') + navigate('/protocols') } React.useEffect(() => { @@ -339,7 +339,7 @@ function PrepareToRun({ const onConfirmCancelClose = (): void => { setShowConfirmCancelModal(false) - history.goBack() + navigate(-1) } const protocolHasModules = @@ -832,7 +832,9 @@ export type SetupScreens = | 'view only parameters' export function ProtocolSetup(): JSX.Element { - const { runId } = useParams() + const { runId } = useParams< + keyof OnDeviceRouteParams + >() as OnDeviceRouteParams const { data: runRecord } = useNotifyRunQuery(runId, { staleTime: Infinity }) const { analysisErrors } = useProtocolAnalysisErrors(runId) const localRobot = useSelector(getLocalRobot) diff --git a/app/src/pages/Protocols/ProtocolDetails/ProtocolTimeline.tsx b/app/src/pages/Protocols/ProtocolDetails/ProtocolTimeline.tsx index e537b8b4b76..b8511ad4f87 100644 --- a/app/src/pages/Protocols/ProtocolDetails/ProtocolTimeline.tsx +++ b/app/src/pages/Protocols/ProtocolDetails/ProtocolTimeline.tsx @@ -12,7 +12,9 @@ import type { Dispatch, State } from '../../../redux/types' import type { DesktopRouteParams } from '../../../App/types' export function ProtocolTimeline(): JSX.Element { - const { protocolKey } = useParams() + const { protocolKey } = useParams< + keyof DesktopRouteParams + >() as DesktopRouteParams const dispatch = useDispatch() const storedProtocol = useSelector((state: State) => getStoredProtocol(state, protocolKey) diff --git a/app/src/pages/Protocols/ProtocolDetails/__tests__/ProtocolDetails.test.tsx b/app/src/pages/Protocols/ProtocolDetails/__tests__/ProtocolDetails.test.tsx index bb0a4d8f5e4..27e728dd844 100644 --- a/app/src/pages/Protocols/ProtocolDetails/__tests__/ProtocolDetails.test.tsx +++ b/app/src/pages/Protocols/ProtocolDetails/__tests__/ProtocolDetails.test.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { vi, it, describe, expect, beforeEach, afterEach } from 'vitest' import { screen } from '@testing-library/react' -import { Route, MemoryRouter } from 'react-router-dom' +import { Route, MemoryRouter, Routes } from 'react-router-dom' import { when } from 'vitest-when' import { renderWithProviders } from '../../../../__testing-utils__' @@ -34,12 +34,10 @@ const MOCK_STATE: State = { const render = (path = '/') => { return renderWithProviders( - - - - - protocols - + + } /> + protocols} /> + , { i18nInstance: i18n, diff --git a/app/src/pages/Protocols/ProtocolDetails/index.tsx b/app/src/pages/Protocols/ProtocolDetails/index.tsx index dc834092c5f..a75e3457540 100644 --- a/app/src/pages/Protocols/ProtocolDetails/index.tsx +++ b/app/src/pages/Protocols/ProtocolDetails/index.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { useParams, Redirect } from 'react-router-dom' +import { useParams, Navigate } from 'react-router-dom' import { useDispatch, useSelector } from 'react-redux' import { @@ -12,7 +12,9 @@ import type { Dispatch, State } from '../../../redux/types' import type { DesktopRouteParams } from '../../../App/types' export function ProtocolDetails(): JSX.Element { - const { protocolKey } = useParams() + const { protocolKey } = useParams< + keyof DesktopRouteParams + >() as DesktopRouteParams const dispatch = useDispatch() const storedProtocol = useSelector((state: State) => @@ -26,6 +28,6 @@ export function ProtocolDetails(): JSX.Element { return storedProtocol != null ? ( ) : ( - + ) } diff --git a/app/src/pages/QuickTransferDashboard/DeleteTransferConfirmationModal.tsx b/app/src/pages/QuickTransferDashboard/DeleteTransferConfirmationModal.tsx index 9916a576c1f..3bf006598b1 100644 --- a/app/src/pages/QuickTransferDashboard/DeleteTransferConfirmationModal.tsx +++ b/app/src/pages/QuickTransferDashboard/DeleteTransferConfirmationModal.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { useQueryClient } from 'react-query' import { useTranslation } from 'react-i18next' import styled from 'styled-components' @@ -35,7 +35,7 @@ export function DeleteTransferConfirmationModal({ setShowDeleteConfirmationModal, }: DeleteTransferConfirmationModalProps): JSX.Element { const { i18n, t } = useTranslation(['quick_transfer', 'shared']) - const history = useHistory() + const navigate = useNavigate() const { makeSnackbar } = useToaster() const [showIcon, setShowIcon] = React.useState(false) const modalHeader: ModalHeaderBaseProps = { @@ -77,11 +77,11 @@ export function DeleteTransferConfirmationModal({ .then(() => { setShowIcon(false) setShowDeleteConfirmationModal(false) - history.push('/quick-transfer') + navigate('/quick-transfer') makeSnackbar(t('deleted_transfer') as string) }) .catch((e: Error) => { - history.push('/quick-transfer') + navigate('/quick-transfer') console.error(`error deleting resources: ${e.message}`) }) } else { diff --git a/app/src/pages/QuickTransferDashboard/LongPressModal.tsx b/app/src/pages/QuickTransferDashboard/LongPressModal.tsx index 0cdc777287d..b856d1296cf 100644 --- a/app/src/pages/QuickTransferDashboard/LongPressModal.tsx +++ b/app/src/pages/QuickTransferDashboard/LongPressModal.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useDispatch, useSelector } from 'react-redux' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { Flex, Icon, SPACING, LegacyStyledText } from '@opentrons/components' import { useCreateRunMutation } from '@opentrons/react-api-client' @@ -31,7 +31,7 @@ export function LongPressModal({ setShowDeleteConfirmationModal, setTargetTransferId, }: LongPressModalProps): JSX.Element { - const history = useHistory() + const navigate = useNavigate() let pinnedQuickTransferIds = useSelector(getPinnedQuickTransferIds) ?? [] const { i18n, t } = useTranslation(['quick_transfer', 'shared']) const dispatch = useDispatch() @@ -44,7 +44,7 @@ export function LongPressModal({ const { createRun } = useCreateRunMutation({ onSuccess: data => { const runId: string = data.data.id - history.push(`/runs/${runId}/setup`) + navigate(`/runs/${runId}/setup`) }, }) diff --git a/app/src/pages/QuickTransferDashboard/PinnedTransfer.tsx b/app/src/pages/QuickTransferDashboard/PinnedTransfer.tsx index 2ac60006813..cafcaa299a5 100644 --- a/app/src/pages/QuickTransferDashboard/PinnedTransfer.tsx +++ b/app/src/pages/QuickTransferDashboard/PinnedTransfer.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import styled, { css } from 'styled-components' import { @@ -71,7 +71,7 @@ export function PinnedTransfer(props: { setTargetTransferId, } = props const cardSize = props.cardSize ?? 'full' - const history = useHistory() + const navigate = useNavigate() const longpress = useLongPress() const transferName = transfer.metadata.protocolName ?? transfer.files[0].name @@ -80,7 +80,7 @@ export function PinnedTransfer(props: { transferId: string ): void => { if (!longpress.isLongPressed) { - history.push(`/quick-transfer/${transferId}`) + navigate(`/quick-transfer/${transferId}`) } } React.useEffect(() => { diff --git a/app/src/pages/QuickTransferDashboard/QuickTransferCard.tsx b/app/src/pages/QuickTransferDashboard/QuickTransferCard.tsx index 25b6983f9a2..7f273f30658 100644 --- a/app/src/pages/QuickTransferDashboard/QuickTransferCard.tsx +++ b/app/src/pages/QuickTransferDashboard/QuickTransferCard.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { Trans, useTranslation } from 'react-i18next' import { useQueryClient } from 'react-query' import last from 'lodash/last' @@ -53,7 +53,7 @@ export function QuickTransferCard(props: { setShowDeleteConfirmationModal, setTargetTransferId, } = props - const history = useHistory() + const navigate = useNavigate() const [showIcon, setShowIcon] = React.useState(false) const [ showFailedAnalysisModal, @@ -108,7 +108,7 @@ export function QuickTransferCard(props: { if (isFailedAnalysis) { setShowFailedAnalysisModal(true) } else if (!longpress.isLongPressed) { - history.push(`/quick-transfer/${transferId}`) + navigate(`/quick-transfer/${transferId}`) } } diff --git a/app/src/pages/QuickTransferDashboard/__tests__/DeleteTransferConfirmationModal.test.tsx b/app/src/pages/QuickTransferDashboard/__tests__/DeleteTransferConfirmationModal.test.tsx index 7715f6efff8..177eb93a691 100644 --- a/app/src/pages/QuickTransferDashboard/__tests__/DeleteTransferConfirmationModal.test.tsx +++ b/app/src/pages/QuickTransferDashboard/__tests__/DeleteTransferConfirmationModal.test.tsx @@ -11,19 +11,19 @@ import { i18n } from '../../../i18n' import { useToaster } from '../../../organisms/ToasterOven' import { DeleteTransferConfirmationModal } from '../DeleteTransferConfirmationModal' -import type * as ReactRouterDom from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' import type { HostConfig } from '@opentrons/api-client' -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('@opentrons/api-client') vi.mock('@opentrons/react-api-client') vi.mock('../../../organisms/ToasterOven') vi.mock('react-router-dom', async importOriginal => { - const reactRouterDom = await importOriginal() + const reactRouterDom = await importOriginal() return { ...reactRouterDom, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) diff --git a/app/src/pages/QuickTransferDashboard/__tests__/PinnedTransfer.test.tsx b/app/src/pages/QuickTransferDashboard/__tests__/PinnedTransfer.test.tsx index 5ae26b3f1da..28588dbccb1 100644 --- a/app/src/pages/QuickTransferDashboard/__tests__/PinnedTransfer.test.tsx +++ b/app/src/pages/QuickTransferDashboard/__tests__/PinnedTransfer.test.tsx @@ -8,15 +8,15 @@ import { i18n } from '../../../i18n' import { PinnedTransfer } from '../PinnedTransfer' import type { ProtocolResource } from '@opentrons/shared-data' -import type * as ReactRouterDom from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) @@ -63,7 +63,7 @@ describe('Pinned Transfer', () => { render() const name = screen.getByText('yay mock transfer') fireEvent.click(name) - expect(mockPush).toHaveBeenCalledWith('/quick-transfer/mockTransfer1') + expect(mockNavigate).toHaveBeenCalledWith('/quick-transfer/mockTransfer1') }) it('should display modal after long click', async () => { diff --git a/app/src/pages/QuickTransferDashboard/__tests__/QuickTransferCard.test.tsx b/app/src/pages/QuickTransferDashboard/__tests__/QuickTransferCard.test.tsx index de3a23700d9..6853233b08f 100644 --- a/app/src/pages/QuickTransferDashboard/__tests__/QuickTransferCard.test.tsx +++ b/app/src/pages/QuickTransferDashboard/__tests__/QuickTransferCard.test.tsx @@ -11,20 +11,20 @@ import { renderWithProviders } from '../../../__testing-utils__' import { i18n } from '../../../i18n' import { QuickTransferCard } from '../QuickTransferCard' import { LongPressModal } from '../LongPressModal' -import type * as ReactRouterDom from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' import type { UseQueryResult } from 'react-query' import type { CompletedProtocolAnalysis, ProtocolResource, } from '@opentrons/shared-data' -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) vi.mock('@opentrons/react-api-client') @@ -81,7 +81,7 @@ describe('QuickTransferCard', () => { render() const name = screen.getByText('yay mock transfer') fireEvent.click(name) - expect(mockPush).toHaveBeenCalledWith('/quick-transfer/mockTransfer1') + expect(mockNavigate).toHaveBeenCalledWith('/quick-transfer/mockTransfer1') }) it('should display the analysis failed error modal when clicking on the transfer', () => { diff --git a/app/src/pages/QuickTransferDashboard/index.tsx b/app/src/pages/QuickTransferDashboard/index.tsx index ed35db7fedc..b47d14f5ed8 100644 --- a/app/src/pages/QuickTransferDashboard/index.tsx +++ b/app/src/pages/QuickTransferDashboard/index.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { useDispatch, useSelector } from 'react-redux' import { useTranslation } from 'react-i18next' @@ -46,7 +46,7 @@ import type { QuickTransfersOnDeviceSortKey } from '../../redux/config/types' export function QuickTransferDashboard(): JSX.Element { const protocols = useAllProtocolsQuery() const { data: attachedInstruments } = useInstrumentsQuery() - const history = useHistory() + const navigate = useNavigate() const { t } = useTranslation(['quick_transfer', 'protocol_info']) const dispatch = useDispatch() const [navMenuIsOpened, setNavMenuIsOpened] = React.useState(false) @@ -151,7 +151,7 @@ export function QuickTransferDashboard(): JSX.Element { } else if (quickTransfersData.length >= 20) { setShowStorageLimitReachedModal(true) } else { - history.push('/quick-transfer/new') + navigate('/quick-transfer/new') } } @@ -181,7 +181,7 @@ export function QuickTransferDashboard(): JSX.Element { setShowPipetteNotAttaachedModal(false) }} onAttach={() => { - history.push('/instruments') + navigate('/instruments') }} /> ) : null} diff --git a/app/src/pages/QuickTransferDetails/__tests__/QuickTransferDetails.test.tsx b/app/src/pages/QuickTransferDetails/__tests__/QuickTransferDetails.test.tsx index f9a2c84c40c..929f5d46f82 100644 --- a/app/src/pages/QuickTransferDetails/__tests__/QuickTransferDetails.test.tsx +++ b/app/src/pages/QuickTransferDetails/__tests__/QuickTransferDetails.test.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import { vi, it, describe, expect, beforeEach, afterEach } from 'vitest' import { fireEvent, screen } from '@testing-library/react' import { when } from 'vitest-when' -import { Route, MemoryRouter } from 'react-router-dom' +import { Route, MemoryRouter, Routes } from 'react-router-dom' import '@testing-library/jest-dom/vitest' import { renderWithProviders } from '../../../__testing-utils__' import { @@ -74,9 +74,12 @@ const MOCK_DATA = { const render = (path = '/quick-transfer/fakeTransferId') => { return renderWithProviders( - - - + + } + /> + , { i18nInstance: i18n, diff --git a/app/src/pages/QuickTransferDetails/index.tsx b/app/src/pages/QuickTransferDetails/index.tsx index 4bf429803b1..6742277aa95 100644 --- a/app/src/pages/QuickTransferDetails/index.tsx +++ b/app/src/pages/QuickTransferDetails/index.tsx @@ -3,7 +3,7 @@ import last from 'lodash/last' import { useTranslation } from 'react-i18next' import { useQueryClient } from 'react-query' import { useDispatch, useSelector } from 'react-redux' -import { useHistory, useParams } from 'react-router-dom' +import { useNavigate, useParams } from 'react-router-dom' import { ALIGN_CENTER, BORDERS, @@ -72,7 +72,7 @@ const QuickTransferHeader = ({ isScrolled, isTransferFetching, }: QuickTransferHeaderProps): JSX.Element => { - const history = useHistory() + const navigate = useNavigate() const { t } = useTranslation('protocol_details') const [truncate, setTruncate] = React.useState(true) const [startSetup, setStartSetup] = React.useState(false) @@ -107,7 +107,7 @@ const QuickTransferHeader = ({ paddingLeft="0rem" paddingRight={SPACING.spacing24} onClick={() => { - history.push('/quick-transfer') + navigate('/quick-transfer') }} width="3rem" > @@ -271,7 +271,9 @@ const TransferSectionContent = ({ export function QuickTransferDetails(): JSX.Element | null { const { t, i18n } = useTranslation(['quick_transfer', 'shared']) - const { quickTransferId: transferId } = useParams() + const { quickTransferId: transferId } = useParams< + keyof OnDeviceRouteParams + >() as OnDeviceRouteParams const { missingProtocolHardware, conflictedSlots, diff --git a/app/src/pages/RobotDashboard/__tests__/RobotDashboard.test.tsx b/app/src/pages/RobotDashboard/__tests__/RobotDashboard.test.tsx index f930ba4c6b7..df66762fdc9 100644 --- a/app/src/pages/RobotDashboard/__tests__/RobotDashboard.test.tsx +++ b/app/src/pages/RobotDashboard/__tests__/RobotDashboard.test.tsx @@ -19,15 +19,15 @@ import { RobotDashboard } from '..' import { useNotifyAllRunsQuery } from '../../../resources/runs' import type { ProtocolResource } from '@opentrons/shared-data' -import type * as ReactRouterDom from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) vi.mock('@opentrons/react-api-client') diff --git a/app/src/pages/RunSummary/index.tsx b/app/src/pages/RunSummary/index.tsx index 7a57150ccab..348d0c6031f 100644 --- a/app/src/pages/RunSummary/index.tsx +++ b/app/src/pages/RunSummary/index.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useSelector } from 'react-redux' -import { useParams, useHistory } from 'react-router-dom' +import { useParams, useNavigate } from 'react-router-dom' import { useTranslation } from 'react-i18next' import styled, { css } from 'styled-components' @@ -68,9 +68,11 @@ import type { OnDeviceRouteParams } from '../../App/types' import type { PipetteWithTip } from '../../organisms/DropTipWizardFlows' export function RunSummary(): JSX.Element { - const { runId } = useParams() + const { runId } = useParams< + keyof OnDeviceRouteParams + >() as OnDeviceRouteParams const { t } = useTranslation('run_details') - const history = useHistory() + const navigate = useNavigate() const host = useHost() const { data: runRecord } = useNotifyRunQuery(runId, { staleTime: Infinity }) const isRunCurrent = Boolean(runRecord?.data?.current) @@ -144,7 +146,7 @@ export function RunSummary(): JSX.Element { const returnToDash = (): void => { closeCurrentRun() - history.push('/') + navigate('/') } // TODO(jh, 05-30-24): EXEC-487. Refactor reset() so we can redirect to the setup page, showing the shimmer skeleton instead. diff --git a/app/src/pages/RunningProtocol/__tests__/RunningProtocol.test.tsx b/app/src/pages/RunningProtocol/__tests__/RunningProtocol.test.tsx index a9335b25c73..1114f4964eb 100644 --- a/app/src/pages/RunningProtocol/__tests__/RunningProtocol.test.tsx +++ b/app/src/pages/RunningProtocol/__tests__/RunningProtocol.test.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { Route, MemoryRouter } from 'react-router-dom' +import { Route, MemoryRouter, Routes } from 'react-router-dom' import { vi, it, describe, expect, beforeEach, afterEach } from 'vitest' import { when } from 'vitest-when' import { screen } from '@testing-library/react' @@ -82,9 +82,9 @@ const mockResumeRunFromRecovery = vi.fn() const render = (path = '/') => { return renderWithProviders( - - - + + } /> + ) } diff --git a/app/src/pages/RunningProtocol/index.tsx b/app/src/pages/RunningProtocol/index.tsx index e6c42bc85cb..5240196e9e1 100644 --- a/app/src/pages/RunningProtocol/index.tsx +++ b/app/src/pages/RunningProtocol/index.tsx @@ -79,7 +79,9 @@ export type ScreenOption = | 'RunningProtocolCommandList' export function RunningProtocol(): JSX.Element { - const { runId } = useParams() + const { runId } = useParams< + keyof OnDeviceRouteParams + >() as OnDeviceRouteParams const [currentOption, setCurrentOption] = React.useState( 'CurrentRunningProtocolCommand' ) diff --git a/app/src/pages/UpdateRobot/UpdateRobot.tsx b/app/src/pages/UpdateRobot/UpdateRobot.tsx index 810ff22bd40..413665365a0 100644 --- a/app/src/pages/UpdateRobot/UpdateRobot.tsx +++ b/app/src/pages/UpdateRobot/UpdateRobot.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useSelector, useDispatch } from 'react-redux' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { Flex, SPACING, DIRECTION_ROW } from '@opentrons/components' @@ -23,7 +23,7 @@ import { import type { State, Dispatch } from '../../redux/types' export function UpdateRobot(): JSX.Element { - const history = useHistory() + const navigate = useNavigate() const { i18n, t } = useTranslation(['device_settings', 'shared']) const localRobot = useSelector(getLocalRobot) const robotUpdateType = useSelector((state: State) => { @@ -48,7 +48,7 @@ export function UpdateRobot(): JSX.Element { buttonText={t('cancel_software_update')} onClick={() => { dispatch(clearRobotUpdateSession()) - history.goBack() + navigate(-1) }} /> + { + navigate(-1) + }} + /> ) : ( (true) - const history = useHistory() + const navigate = useNavigate() const { i18n, t } = useTranslation(['device_settings', 'shared']) const dispatchStartRobotUpdate = useDispatchStartRobotUpdate() const dispatch = useDispatch() @@ -86,7 +86,7 @@ export function UpdateRobotDuringOnboarding(): JSX.Element { buttonText={t('proceed_without_updating')} onClick={() => { dispatch(clearRobotUpdateSession()) - history.push('/emergency-stop') + navigate('/emergency-stop') }} /> { - history.push('/emergency-stop') + navigate('/emergency-stop') }} /> ) : ( diff --git a/app/src/pages/Welcome/__tests__/Welcome.test.tsx b/app/src/pages/Welcome/__tests__/Welcome.test.tsx index 4842206d807..756b7bcb4b5 100644 --- a/app/src/pages/Welcome/__tests__/Welcome.test.tsx +++ b/app/src/pages/Welcome/__tests__/Welcome.test.tsx @@ -8,16 +8,16 @@ import { renderWithProviders } from '../../../__testing-utils__' import { i18n } from '../../../i18n' import { Welcome } from '..' -import type * as ReactRouterDom from 'react-router-dom' +import type { NavigateFunction } from 'react-router-dom' const PNG_FILE_NAME = 'welcome_background.png' -const mockPush = vi.fn() +const mockNavigate = vi.fn() vi.mock('react-router-dom', async importOriginal => { - const actual = await importOriginal() + const actual = await importOriginal() return { ...actual, - useHistory: () => ({ push: mockPush } as any), + useNavigate: () => mockNavigate, } }) @@ -44,9 +44,9 @@ describe('Welcome', () => { expect(image.getAttribute('src')).toContain(PNG_FILE_NAME) }) - it('should call mockPush when tapping Get started', () => { + it('should call mockNavigate when tapping Get started', () => { render() fireEvent.click(screen.getByRole('button', { name: 'Get started' })) - expect(mockPush).toHaveBeenCalledWith('/network-setup') + expect(mockNavigate).toHaveBeenCalledWith('/network-setup') }) }) diff --git a/app/src/pages/Welcome/index.tsx b/app/src/pages/Welcome/index.tsx index 867af7c3fd1..d43c9e9e054 100644 --- a/app/src/pages/Welcome/index.tsx +++ b/app/src/pages/Welcome/index.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { useHistory } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { COLORS, DIRECTION_COLUMN, @@ -18,7 +18,7 @@ const IMAGE_ALT = 'Welcome screen background image' export function Welcome(): JSX.Element { const { t } = useTranslation(['device_settings', 'shared', 'branded']) - const history = useHistory() + const navigate = useNavigate() return ( { - history.push('/network-setup') + navigate('/network-setup') }} /> diff --git a/app/src/redux/reducer.ts b/app/src/redux/reducer.ts index 5bf33bb3b38..44831b0d70e 100644 --- a/app/src/redux/reducer.ts +++ b/app/src/redux/reducer.ts @@ -1,7 +1,4 @@ -import createHistory from 'history/createHashHistory' import { combineReducers } from 'redux' -import { connectRouter } from 'connected-react-router' -import type { RouterState } from 'connected-react-router' // api state import { robotApiReducer } from './robot-api/reducer' @@ -53,14 +50,8 @@ import { protocolStorageReducer } from './protocol-storage/reducer' import type { Reducer } from 'redux' import type { State, Action } from './types' -import type { History } from 'history' -export const history = createHistory() - -export const rootReducer: Reducer = combineReducers< - State, - Action ->({ +export const rootReducer: Reducer = combineReducers({ robotApi: robotApiReducer, robotAdmin: robotAdminReducer, robotControls: robotControlsReducer, @@ -77,7 +68,4 @@ export const rootReducer: Reducer = combineReducers< sessions: sessionReducer, calibration: calibrationReducer, protocolStorage: protocolStorageReducer, - router: connectRouter( - history as History> - ) as Reducer, }) diff --git a/app/src/redux/store.ts b/app/src/redux/store.ts index 0567386b313..0572d875655 100644 --- a/app/src/redux/store.ts +++ b/app/src/redux/store.ts @@ -1,22 +1,17 @@ import { createStore, applyMiddleware, compose } from 'redux' import thunk from 'redux-thunk' -import { routerMiddleware } from 'connected-react-router' import { createEpicMiddleware } from 'redux-observable' -import { rootReducer, history } from './reducer' +import { rootReducer } from './reducer' import { rootEpic } from './epic' import type { StoreEnhancer } from 'redux' -import type { Action, Middleware, State } from './types' +import type { Action, State } from './types' const epicMiddleware = createEpicMiddleware() -const middleware = applyMiddleware( - thunk, - epicMiddleware, - routerMiddleware(history) as Middleware -) +const middleware = applyMiddleware(thunk, epicMiddleware) const composeEnhancers = (window as any)?.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__?.({ maxAge: 200 }) ?? diff --git a/app/src/redux/types.ts b/app/src/redux/types.ts index a46c7f2dd96..9ed69c3e71f 100644 --- a/app/src/redux/types.ts +++ b/app/src/redux/types.ts @@ -1,7 +1,7 @@ /* eslint-disable no-use-before-define */ // application types import type { Store as ReduxStore, Dispatch as ReduxDispatch } from 'redux' -import type { RouterState, RouterAction } from 'connected-react-router' +import type { RouterAction } from 'connected-react-router' import type { Observable } from 'rxjs' import type { RobotApiState, RobotApiAction } from './robot-api/types' @@ -54,7 +54,6 @@ export interface State { readonly sessions: SessionState readonly calibration: CalibrationState readonly protocolStorage: ProtocolStorageState - readonly router: RouterState } export type Action = diff --git a/components/package.json b/components/package.json index b6d71152b6a..15306b92671 100644 --- a/components/package.json +++ b/components/package.json @@ -19,9 +19,7 @@ "homepage": "https://github.com/Opentrons/opentrons#readme", "peerDependencies": { "react": "18.2.0", - "react-dom": "18.2.0", - "react-router-dom": "5.3.4", - "@types/react-router-dom": "5.3.3" + "react-dom": "18.2.0" }, "dependencies": { "@opentrons/shared-data": "link:../shared-data", @@ -38,7 +36,6 @@ "react-i18next": "13.5.0", "react-popper": "1.0.0", "react-remove-scroll": "2.4.3", - "react-router-dom": "5.3.4", "react-select": "5.4.0", "redux": "4.0.5", "styled-components": "5.3.6" diff --git a/components/src/index.ts b/components/src/index.ts index 6e38096c4a5..afb56a0a9ed 100644 --- a/components/src/index.ts +++ b/components/src/index.ts @@ -18,7 +18,6 @@ export * from './lists' export * from './modals' export * from './nav' export * from './primitives' -export * from './tabbedNav' export * from './slotmap' export * from './structure' export * from './tooltips' diff --git a/components/src/lists/ListItem.tsx b/components/src/lists/ListItem.tsx deleted file mode 100644 index ecce326ea25..00000000000 --- a/components/src/lists/ListItem.tsx +++ /dev/null @@ -1,92 +0,0 @@ -// ListItem component to be used as a child of TitledList -import * as React from 'react' -import { NavLink } from 'react-router-dom' -import classnames from 'classnames' - -import styles from './lists.module.css' -import { Icon } from '../icons' -import type { IconName } from '../icons' - -// TODO(bc, 2021-03-31): this is only used in the app -// reconsider whether this belongs in components library -interface ListItemProps { - /** click handler */ - onClick?: (event: React.SyntheticEvent) => unknown - /** mouse enter handler */ - onMouseEnter?: (event: React.MouseEvent) => unknown - /** mouse leave handler */ - onMouseLeave?: (event: React.MouseEvent) => unknown - /** mouse enter handler */ - onPointerEnter?: (event: React.PointerEvent) => unknown - /** mouse leave handler */ - onPointerLeave?: (event: React.PointerEvent) => unknown - /** if URL is specified, ListItem is wrapped in a React Router NavLink */ - url?: string | null - /** if URL is specified NavLink can receive an active class name */ - activeClassName?: string - /** if URL is specified NavLink can receive an exact property for matching routes */ - exact?: boolean - /** Additional class name */ - className?: string - /** if disabled, the onClick handler will be disabled */ - isDisabled?: boolean - /** name constant of the icon to display */ - iconName?: IconName - 'aria-describedby'?: string - ref?: { current: Element | null } | ((current: Element | null) => unknown) - children?: React.ReactNode -} - -/** - * A styled `` with an optional icon, and an optional url for a React Router `NavLink` - * - */ -export const ListItem = React.forwardRef( - (props: ListItemProps, ref: React.ForwardedRef) => { - const { url, isDisabled, iconName, activeClassName, exact } = props - const onClick = props.onClick && !isDisabled ? props.onClick : undefined - // @ts-expect-error(sa, 2021-6-23): cast value to boolean - const className = classnames(props.className, styles.list_item, { - [styles.disabled]: isDisabled, - [styles.clickable]: onClick, - }) - - const itemIcon = iconName && ( - - ) - - if (url != null) { - return ( - - - {itemIcon} - {props.children} - - - ) - } - - return ( - - {itemIcon} - {props.children} - - ) - } -) diff --git a/components/src/lists/index.ts b/components/src/lists/index.ts index cd2586912f3..c11be61e41a 100644 --- a/components/src/lists/index.ts +++ b/components/src/lists/index.ts @@ -1,4 +1,3 @@ // list and list item components export * from './SidePanelGroup' export * from './TitledList' -export * from './ListItem' diff --git a/components/src/structure/PageTabs.tsx b/components/src/structure/PageTabs.tsx deleted file mode 100644 index 3475326e423..00000000000 --- a/components/src/structure/PageTabs.tsx +++ /dev/null @@ -1,46 +0,0 @@ -// page tabs bar - -import * as React from 'react' -import classnames from 'classnames' -import { Link } from 'react-router-dom' - -import styles from './structure.module.css' - -// TODO(bc, 2021-03-29): this component is only used in RA -// reconsider whether it belongs in components library -interface TabProps { - title: string - href: string - isActive: boolean - isDisabled: boolean -} - -export interface PageTabProps { - pages: TabProps[] -} - -export function PageTabs(props: PageTabProps): JSX.Element { - return ( - - {props.pages.map(page => ( - - ))} - - ) -} - -function Tab(props: TabProps): JSX.Element { - const { isDisabled } = props - const tabLinkClass = classnames(styles.tab_link, { - [styles.active_tab_link]: props.isActive, - }) - - // TODO(mc, 2017-12-14): make a component for proper disabling of links - const MaybeLink: any = !isDisabled ? Link : 'span' - - return ( - - {props.title} - - ) -} diff --git a/components/src/structure/index.ts b/components/src/structure/index.ts index 90dbf88700e..371cfc731d6 100644 --- a/components/src/structure/index.ts +++ b/components/src/structure/index.ts @@ -1,6 +1,5 @@ // structure components -export * from './PageTabs' export * from './TitleBar' export * from './Card' export * from './Splash' diff --git a/components/src/tabbedNav/index.ts b/components/src/tabbedNav/index.ts deleted file mode 100644 index 0b670948e40..00000000000 --- a/components/src/tabbedNav/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -// navigational components - -// TODO(bc, 2021-03-29): these components are only used in one place -// reconsider whether they belong in components library -export * from './TabbedNavBar' -export * from './NavTab' -export * from './OutsideLinkTab' diff --git a/labware-library/package.json b/labware-library/package.json index 9c0010a60c2..7c8e0cfa8e3 100644 --- a/labware-library/package.json +++ b/labware-library/package.json @@ -23,7 +23,6 @@ "@types/jszip": "3.1.7", "@types/mixpanel-browser": "^2.35.6", "@types/query-string": "6.2.0", - "@types/react-router-dom": "5.3.3", "@types/webpack-env": "^1.16.0", "@types/yup": "0.29.11" }, @@ -41,7 +40,7 @@ "query-string": "6.2.0", "react": "18.2.0", "react-dom": "18.2.0", - "react-router-dom": "5.3.4", + "react-router-dom": "6.24.1", "yup": "0.32.9" } } diff --git a/labware-library/src/components/App/index.tsx b/labware-library/src/components/App/index.tsx index 8b18a6d431d..bb9b907da77 100644 --- a/labware-library/src/components/App/index.tsx +++ b/labware-library/src/components/App/index.tsx @@ -1,7 +1,7 @@ // main application wrapper component import * as React from 'react' import cx from 'classnames' - +import { useLocation } from 'react-router-dom' import { DefinitionRoute } from '../../definitions' import { useFilters } from '../../filters' import { Nav, Breadcrumbs } from '../Nav' @@ -14,7 +14,8 @@ import styles from './styles.module.css' import type { DefinitionRouteRenderProps } from '../../definitions' export function AppComponent(props: DefinitionRouteRenderProps): JSX.Element { - const { definition, location } = props + const { definition } = props + const location = useLocation() const scrollRef = React.useRef(null) const filters = useFilters(location) const isDetailPage = Boolean(definition) diff --git a/labware-library/src/components/Sidebar/FilterManufacturer.tsx b/labware-library/src/components/Sidebar/FilterManufacturer.tsx index 315cc9c071e..6aed332f847 100644 --- a/labware-library/src/components/Sidebar/FilterManufacturer.tsx +++ b/labware-library/src/components/Sidebar/FilterManufacturer.tsx @@ -1,6 +1,6 @@ // filter labware by manufacturer import * as React from 'react' -import { withRouter } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { SelectField } from '@opentrons/components' import { getAllManufacturers, buildFiltersUrl } from '../../filters' import styles from './styles.module.css' @@ -8,17 +8,17 @@ import styles from './styles.module.css' import { MANUFACTURER, MANUFACTURER_VALUES } from '../../localization' import type { SelectOptionOrGroup } from '@opentrons/components' -import type { RouteComponentProps } from 'react-router-dom' import type { FilterParams } from '../../types' -export interface FilterManufacturerProps extends RouteComponentProps { +export interface FilterManufacturerProps { filters: FilterParams } -export function FilterManufacturerComponent( +export function FilterManufacturer( props: FilterManufacturerProps ): JSX.Element { - const { history, filters } = props + const { filters } = props + const navigate = useNavigate() const manufacturers = getAllManufacturers() const options: SelectOptionOrGroup[] = manufacturers.map(value => ({ value, @@ -37,14 +37,10 @@ export function FilterManufacturerComponent( options={options} onValueChange={(_, value) => { if (value) { - history.push(buildFiltersUrl({ ...filters, manufacturer: value })) + navigate(buildFiltersUrl({ ...filters, manufacturer: value })) } }} /> ) } -// @ts-expect-error react router type not portable -export const FilterManufacturer: (props: { - filters: FilterParams -}) => JSX.Element = withRouter(FilterManufacturerComponent) diff --git a/labware-library/src/components/ui/Link.tsx b/labware-library/src/components/ui/Link.tsx index 4672b01a3dd..f51572e6695 100644 --- a/labware-library/src/components/ui/Link.tsx +++ b/labware-library/src/components/ui/Link.tsx @@ -1,16 +1,15 @@ // internal link that preserves query parameters import * as React from 'react' -import { withRouter, Link as BaseLink } from 'react-router-dom' -import type { RouteComponentProps } from 'react-router-dom' +import { Link as BaseLink, useLocation } from 'react-router-dom' -export interface LinkProps extends RouteComponentProps { +export interface LinkProps { to: string children?: React.ReactNode className?: string } -export function WrappedLink(props: LinkProps): JSX.Element { - const { to, children, className, location } = props +export function Link({ to, children, className }: LinkProps): JSX.Element { + const location = useLocation() return ( ) } - -// @ts-expect-error react router type not portable -export const Link: (props: { - to: string - children?: React.ReactNode - className?: string -}) => JSX.Element = withRouter(WrappedLink) diff --git a/labware-library/src/definitions.tsx b/labware-library/src/definitions.tsx index b1f76208177..7a3c8bd0e8e 100644 --- a/labware-library/src/definitions.tsx +++ b/labware-library/src/definitions.tsx @@ -1,16 +1,14 @@ // labware definition helpers // TODO(mc, 2019-03-18): move to shared-data? import * as React from 'react' -import { Route } from 'react-router-dom' +import { useParams } from 'react-router-dom' import groupBy from 'lodash/groupBy' import uniq from 'lodash/uniq' import { LABWAREV2_DO_NOT_LIST, getAllDefinitions as _getAllDefinitions, } from '@opentrons/shared-data' -import { getPublicPath } from './public-path' -import type { RouteComponentProps } from 'react-router-dom' import type { LabwareDefinition2 } from '@opentrons/shared-data' import type { LabwareList, LabwareDefinition } from './types' @@ -76,7 +74,7 @@ export function getDefinition( return def || null } -export interface DefinitionRouteRenderProps extends RouteComponentProps { +export interface DefinitionRouteRenderProps { definition: LabwareDefinition | null } @@ -84,21 +82,13 @@ export interface DefinitionRouteProps { render: (props: DefinitionRouteRenderProps) => React.ReactNode } -export function DefinitionRoute(props: DefinitionRouteProps): JSX.Element { - return ( - { - const { loadName } = routeProps.match.params - const definition = getDefinition(loadName) +export const DefinitionRoute: React.FC = ({ render }) => { + const { loadName } = useParams<{ loadName: string }>() + const definition = getDefinition(loadName) - // TODO(mc, 2019-04-10): handle 404 if loadName exists but definition - // isn't found + // TODO: handle 404 if loadName exists but definition isn't found - return props.render({ ...routeProps, definition }) - }} - /> - ) + return <>{render({ definition })}> } export const NEW_LABWARE_DEFS = [ diff --git a/labware-library/src/filters.tsx b/labware-library/src/filters.tsx index 0ce9323879f..65e77f538b9 100644 --- a/labware-library/src/filters.tsx +++ b/labware-library/src/filters.tsx @@ -8,8 +8,8 @@ import uniq from 'lodash/uniq' import { getAllDefinitions } from './definitions' import { getPublicPath } from './public-path' -import type { Location } from 'history' import type { FilterParams, LabwareDefinition, LabwareList } from './types' +import type { Location } from 'react-router-dom' export const FILTER_OFF = 'all' @@ -30,7 +30,7 @@ export function getAllManufacturers(): string[] { return uniq([FILTER_OFF, ...brands, ...wellGroupBrands]) } -export function useFilters(location: Location): FilterParams { +export function useFilters(location: Location): FilterParams { const [params, setParams] = useState({ category: FILTER_OFF, manufacturer: FILTER_OFF, diff --git a/labware-library/src/index.tsx b/labware-library/src/index.tsx index 9bac13fe66c..7f244f10e75 100644 --- a/labware-library/src/index.tsx +++ b/labware-library/src/index.tsx @@ -1,7 +1,7 @@ // labware library entry import * as React from 'react' import { hydrate, render } from 'react-dom' -import { BrowserRouter, Route, Switch } from 'react-router-dom' +import { BrowserRouter, Route, Routes } from 'react-router-dom' import { App } from './components/App' import { LabwareCreator } from './labware-creator' @@ -19,10 +19,10 @@ if (!$root) { const Root = (): JSX.Element => ( - - - - + + } /> + } /> + ) diff --git a/package.json b/package.json index 0fe8099d97e..0727c37a148 100755 --- a/package.json +++ b/package.json @@ -63,7 +63,6 @@ "@types/react-color": "^3.0.6", "@types/react-dom": "18.2.0", "@types/react-redux": "7.1.32", - "@types/react-router-dom": "5.3.3", "@types/redux-mock-store": "^1.0.2", "@types/semver": "^7.3.6", "@typescript-eslint/eslint-plugin": "^6.20.0", diff --git a/protocol-designer/src/containers/ConnectedNav.tsx b/protocol-designer/src/containers/ConnectedNav.tsx index fcc7d2c3311..d22fd9420c7 100644 --- a/protocol-designer/src/containers/ConnectedNav.tsx +++ b/protocol-designer/src/containers/ConnectedNav.tsx @@ -2,9 +2,11 @@ import * as React from 'react' import { useDispatch, useSelector } from 'react-redux' import { useTranslation } from 'react-i18next' import { KNOWLEDGEBASE_ROOT_URL } from '../components/KnowledgeBaseLink' -import { NavTab, TabbedNavBar, OutsideLinkTab } from '@opentrons/components' import { selectors as fileSelectors } from '../file-data' import { actions, selectors } from '../navigation' +import { TabbedNavBar } from './TabbedNavBar' +import { NavTab } from './NavTab' +import { OutsideLinkTab } from './OutsideLinkTab' import type { Page } from '../navigation' export function ConnectedNav(): JSX.Element { diff --git a/components/src/tabbedNav/NavTab.tsx b/protocol-designer/src/containers/NavTab.tsx similarity index 90% rename from components/src/tabbedNav/NavTab.tsx rename to protocol-designer/src/containers/NavTab.tsx index a94f7c6e876..a409789b029 100644 --- a/components/src/tabbedNav/NavTab.tsx +++ b/protocol-designer/src/containers/NavTab.tsx @@ -2,12 +2,10 @@ import * as React from 'react' import { NavLink } from 'react-router-dom' import classnames from 'classnames' -import styles from './navbar.module.css' -import { Button } from '../buttons' -import { NotificationIcon } from '../icons' +import { Button, NotificationIcon } from '@opentrons/components' +import type { IconName, ButtonProps } from '@opentrons/components' -import type { IconName } from '../icons' -import type { ButtonProps } from '../buttons' +import styles from './navbar.module.css' export interface NavTabProps { /** optional click event for nav button */ diff --git a/components/src/tabbedNav/OutsideLinkTab.tsx b/protocol-designer/src/containers/OutsideLinkTab.tsx similarity index 92% rename from components/src/tabbedNav/OutsideLinkTab.tsx rename to protocol-designer/src/containers/OutsideLinkTab.tsx index e935df8ffd1..6ebbd5aca35 100644 --- a/components/src/tabbedNav/OutsideLinkTab.tsx +++ b/protocol-designer/src/containers/OutsideLinkTab.tsx @@ -1,11 +1,9 @@ import * as React from 'react' import cx from 'classnames' +import { Button, NotificationIcon } from '@opentrons/components' +import type { IconName } from '@opentrons/components' import styles from './navbar.module.css' -import { Button } from '../buttons' -import { NotificationIcon } from '../icons' - -import type { IconName } from '../icons' export interface OutsideLinkTabProps { /** optional click event for nav button */ diff --git a/components/src/tabbedNav/TabbedNavBar.tsx b/protocol-designer/src/containers/TabbedNavBar.tsx similarity index 100% rename from components/src/tabbedNav/TabbedNavBar.tsx rename to protocol-designer/src/containers/TabbedNavBar.tsx diff --git a/components/src/tabbedNav/navbar.module.css b/protocol-designer/src/containers/navbar.module.css similarity index 96% rename from components/src/tabbedNav/navbar.module.css rename to protocol-designer/src/containers/navbar.module.css index c1119a6a10c..078a300a395 100644 --- a/components/src/tabbedNav/navbar.module.css +++ b/protocol-designer/src/containers/navbar.module.css @@ -1,4 +1,4 @@ -@import '../index.module.css'; +@import '@opentrons/components/styles'; .navbar { flex: none; diff --git a/yarn.lock b/yarn.lock index f30ce404018..05383e56198 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1769,7 +1769,7 @@ core-js-pure "^3.30.2" regenerator-runtime "^0.14.0" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.23.8", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.10.5", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.23.8", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.24.4" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.4.tgz#de795accd698007a66ba44add6cc86542aff1edd" integrity sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA== @@ -3269,7 +3269,7 @@ react-intersection-observer "^8.33.1" react-markdown "9.0.1" react-redux "8.1.2" - react-router-dom "5.3.4" + react-router-dom "6.24.1" react-select "5.4.0" react-simple-keyboard "^3.7.0" react-viewport-list "6.3.0" @@ -3300,7 +3300,6 @@ react-i18next "13.5.0" react-popper "1.0.0" react-remove-scroll "2.4.3" - react-router-dom "5.3.4" react-select "5.4.0" redux "4.0.5" styled-components "5.3.6" @@ -3338,7 +3337,7 @@ query-string "6.2.0" react "18.2.0" react-dom "18.2.0" - react-router-dom "5.3.4" + react-router-dom "6.24.1" yup "0.32.9" "@opentrons/react-api-client@link:react-api-client": @@ -5350,11 +5349,6 @@ dependencies: "@types/unist" "*" -"@types/history@^4.7.11": - version "4.7.11" - resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64" - integrity sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA== - "@types/hoist-non-react-statics@*", "@types/hoist-non-react-statics@^3.3.0", "@types/hoist-non-react-statics@^3.3.1": version "3.3.5" resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz#dab7867ef789d87e2b4b0003c9d65c49cc44a494" @@ -5584,23 +5578,6 @@ hoist-non-react-statics "^3.3.0" redux "^4.0.0" -"@types/react-router-dom@5.3.3": - version "5.3.3" - resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.3.3.tgz#e9d6b4a66fcdbd651a5f106c2656a30088cc1e83" - integrity sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw== - dependencies: - "@types/history" "^4.7.11" - "@types/react" "*" - "@types/react-router" "*" - -"@types/react-router@*": - version "5.1.20" - resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.20.tgz#88eccaa122a82405ef3efbcaaa5dcdd9f021387c" - integrity sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q== - dependencies: - "@types/history" "^4.7.11" - "@types/react" "*" - "@types/react-transition-group@^4.4.0": version "4.4.10" resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.10.tgz#6ee71127bdab1f18f11ad8fb3322c6da27c327ac" @@ -12827,18 +12804,6 @@ history@4.7.2: value-equal "^0.4.0" warning "^3.0.0" -history@^4.9.0: - version "4.10.1" - resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" - integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== - dependencies: - "@babel/runtime" "^7.1.2" - loose-envify "^1.2.0" - resolve-pathname "^3.0.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - value-equal "^1.0.1" - hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -12848,7 +12813,7 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: +hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -14837,7 +14802,7 @@ longest@^1.0.1: resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" integrity sha512-k+yt5n3l48JU4k8ftnKG6V7u32wyH2NfKzeMto9F/QRE0amxy/LayxwlvjjkZEIzqR+19IrtFO8p5kB9QaYUFg== -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -16994,13 +16959,6 @@ path-to-regexp@3.0.0: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-3.0.0.tgz#c981a218f3df543fa28696be2f88e0c58d2e012a" integrity sha512-ZOtfhPttCrqp2M1PBBH4X13XlvnfhIwD7yCLx+GoGoXRPQyxGOTdQMpIzPSPKXAJT/JQrdfFrgdJOyAzvgpQ9A== -path-to-regexp@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" - integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== - dependencies: - isarray "0.0.1" - path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" @@ -18480,7 +18438,7 @@ react-is@18.1.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.1.0.tgz#61aaed3096d30eacf2a2127118b5b41387d32a67" integrity sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg== -react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0: +react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -18579,19 +18537,6 @@ react-remove-scroll@2.5.5: use-callback-ref "^1.3.0" use-sidecar "^1.1.2" -react-router-dom@5.3.4: - version "5.3.4" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.3.4.tgz#2ed62ffd88cae6db134445f4a0c0ae8b91d2e5e6" - integrity sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ== - dependencies: - "@babel/runtime" "^7.12.13" - history "^4.9.0" - loose-envify "^1.3.1" - prop-types "^15.6.2" - react-router "5.3.4" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - react-router-dom@6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.24.1.tgz#b1a22f7d6c5a1bfce30732bd370713f991ab4de4" @@ -18600,21 +18545,6 @@ react-router-dom@6.24.1: "@remix-run/router" "1.17.1" react-router "6.24.1" -react-router@5.3.4: - version "5.3.4" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.3.4.tgz#8ca252d70fcc37841e31473c7a151cf777887bb5" - integrity sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA== - dependencies: - "@babel/runtime" "^7.12.13" - history "^4.9.0" - hoist-non-react-statics "^3.1.0" - loose-envify "^1.3.1" - path-to-regexp "^1.7.0" - prop-types "^15.6.2" - react-is "^16.6.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - react-router@6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.24.1.tgz#5a3bbba0000afba68d42915456ca4c806f37a7de" @@ -19301,11 +19231,6 @@ resolve-pathname@^2.2.0: resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-2.2.0.tgz#7e9ae21ed815fd63ab189adeee64dc831eefa879" integrity sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg== -resolve-pathname@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" - integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== - resolve-pkg-maps@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" @@ -21178,12 +21103,12 @@ tiny-case@^1.0.3: resolved "https://registry.yarnpkg.com/tiny-case/-/tiny-case-1.0.3.tgz#d980d66bc72b5d5a9ca86fb7c9ffdb9c898ddd03" integrity sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q== -tiny-invariant@^1.0.2, tiny-invariant@^1.3.1, tiny-invariant@^1.3.3: +tiny-invariant@^1.3.1, tiny-invariant@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== -tiny-warning@^1.0.0, tiny-warning@^1.0.2: +tiny-warning@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== @@ -22193,11 +22118,6 @@ value-equal@^0.4.0: resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.4.0.tgz#c5bdd2f54ee093c04839d71ce2e4758a6890abc7" integrity sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw== -value-equal@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" - integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== - vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"