Merge pull request #1171 from spotify/blam/react-router

Migrate to React Router V6
This commit is contained in:
Ben Lambert
2020-06-12 02:58:35 +02:00
committed by GitHub
35 changed files with 159 additions and 203 deletions
+1 -2
View File
@@ -23,7 +23,7 @@
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-hot-loader": "^4.12.21",
"react-router-dom": "^5.2.0",
"react-router-dom": "6.0.0-alpha.5",
"react-use": "^14.2.0",
"zen-observable": "^0.8.15"
},
@@ -35,7 +35,6 @@
"@types/jest": "^25.2.2",
"@types/jquery": "^3.3.34",
"@types/node": "^12.0.0",
"@types/react-router-dom": "^5.1.3",
"@types/zen-observable": "^0.8.0",
"cross-env": "^7.0.0",
"cypress": "^4.2.0",
@@ -12,7 +12,7 @@
"plugin-welcome": "0.0.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-router-dom": "^5.2.0",
"react-router-dom": "6.0.0-alpha.5",
"react-use": "^14.2.0"
},
"devDependencies": {
@@ -21,7 +21,6 @@
"@testing-library/user-event": "^10.2.4",
"@types/jest": "^25.2.2",
"@types/node": "^12.0.0",
"@types/react-router-dom": "^5.1.3",
"@types/testing-library__jest-dom": "^5.0.4",
"cross-env": "^7.0.0",
"cypress": "^4.2.0",
@@ -27,7 +27,7 @@
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-use": "^14.2.0",
"react-router-dom": "^5.2.0"
"react-router-dom": "6.0.0-alpha.5"
},
"devDependencies": {
"@backstage/cli": "^{{version}}",
+1 -1
View File
@@ -37,7 +37,7 @@
"@types/react": "^16.9",
"prop-types": "^15.7.2",
"react": "^16.12.0",
"react-router-dom": "^5.2.0",
"react-router-dom": "6.0.0-alpha.5",
"react-use": "^14.2.0",
"zen-observable": "^0.8.15"
},
+13 -33
View File
@@ -13,9 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { ComponentType, FC, useMemo } from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
import { Route, Routes, Navigate } from 'react-router-dom';
import { AppContextProvider } from './AppContext';
import { BackstageApp, AppComponents, AppConfigLoader, Apis } from './types';
import { BackstagePlugin } from '../plugin';
@@ -90,50 +89,31 @@ export class PrivateAppImpl implements BackstageApp {
for (const output of plugin.output()) {
switch (output.type) {
case 'legacy-route': {
const { path, component, options = {} } = output;
const { exact = true } = options;
const { path, component: Component } = output;
routes.push(
<Route
key={path}
path={path}
component={component}
exact={exact}
/>,
<Route key={path} path={path} element={<Component />} />,
);
break;
}
case 'route': {
const { target, component, options = {} } = output;
const { exact = true } = options;
const { target, component: Component } = output;
routes.push(
<Route
key={`${plugin.getId()}-${target.path}`}
path={target.path}
component={component}
exact={exact}
element={<Component />}
/>,
);
break;
}
case 'legacy-redirect-route': {
const { path, target, options = {} } = output;
const { exact = true } = options;
routes.push(
<Redirect key={path} path={path} to={target} exact={exact} />,
);
const { path, target } = output;
routes.push(<Navigate key={path} to={target} />);
break;
}
case 'redirect-route': {
const { from, to, options = {} } = output;
const { exact = true } = options;
routes.push(
<Redirect
key={from.path}
path={from.path}
to={to.path}
exact={exact}
/>,
);
const { from, to } = output;
routes.push(<Navigate key={from.path} to={to.path} />);
break;
}
case 'feature-flag': {
@@ -155,10 +135,10 @@ export class PrivateAppImpl implements BackstageApp {
}
const rendered = (
<Switch>
<Routes>
{routes}
<Route component={NotFoundErrorPage} />
</Switch>
<Route element={<NotFoundErrorPage />} />
</Routes>
);
return () => rendered;
@@ -225,7 +205,7 @@ export class PrivateAppImpl implements BackstageApp {
<ApiProvider apis={apis}>
<AppContextProvider app={this}>
<AppThemeProvider>
<Router basename={pathname}>{children}</Router>
<Router>{children}</Router>
</AppThemeProvider>
</AppContextProvider>
</ApiProvider>
+1 -2
View File
@@ -25,12 +25,11 @@ export type BootErrorPageProps = {
step: 'load-config';
error: Error;
};
export type AppComponents = {
NotFoundErrorPage: ComponentType<{}>;
BootErrorPage: ComponentType<BootErrorPageProps>;
Progress: ComponentType<{}>;
Router: ComponentType<{ basename?: string }>;
Router: ComponentType<{}>;
};
/**
+2 -3
View File
@@ -37,7 +37,6 @@
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
"@types/react": "^16.9",
"@types/react-router-dom": "^5.1.5",
"@types/react-sparklines": "^1.7.0",
"classnames": "^2.2.6",
"clsx": "^1.1.0",
@@ -48,8 +47,8 @@
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-helmet": "6.0.0",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"react-router": "6.0.0-alpha.5",
"react-router-dom": "6.0.0-alpha.5",
"react-sparklines": "^1.7.0",
"react-syntax-highlighter": "^12.2.1",
"react-use": "^14.2.0"
@@ -15,12 +15,7 @@
*/
import React, { FunctionComponentFactory } from 'react';
import { Button } from './Button';
import {
MemoryRouter,
Route,
useLocation,
Link as RouterLink,
} from 'react-router-dom';
import { MemoryRouter, Route, useLocation } from 'react-router-dom';
import { createRouteRef } from '@backstage/core-api';
const Location = () => {
@@ -70,14 +65,7 @@ export const PassProps = () => {
return (
<>
<Button
to={routeRef.path}
/** react-router-dom related prop */
component={RouterLink}
/** material-ui related prop */
color="secondary"
variant="outlined"
>
<Button to={routeRef.path} color="secondary" variant="outlined">
This link
</Button>
&nbsp;has props for both material-ui's component as well as for
@@ -15,11 +15,10 @@
*/
import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import { render, fireEvent, act } from '@testing-library/react';
import { wrapInTestApp } from '@backstage/test-utils';
import { Button } from './Button';
import { MemoryRouter, Route } from 'react-router';
import { act } from 'react-dom/test-utils';
import { Route, Routes } from 'react-router';
describe('<Button />', () => {
it('navigates using react-router', async () => {
@@ -27,12 +26,13 @@ describe('<Button />', () => {
const buttonLabel = 'Navigate!';
const { getByText } = render(
wrapInTestApp(
<MemoryRouter>
<Routes>
<Route path="/test" element={<p>{testString}</p>} />
<Button to="/test">{buttonLabel}</Button>
<Route path="/test">{testString}</Route>{' '}
</MemoryRouter>,
</Routes>,
),
);
expect(() => getByText(testString)).toThrow();
await act(async () => fireEvent.click(getByText(buttonLabel)));
expect(getByText(testString)).toBeInTheDocument();
@@ -18,7 +18,7 @@ import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import { wrapInTestApp } from '@backstage/test-utils';
import { Link } from './Link';
import { MemoryRouter, Route } from 'react-router';
import { Route, Routes } from 'react-router';
import { act } from 'react-dom/test-utils';
describe('<Link />', () => {
@@ -27,10 +27,10 @@ describe('<Link />', () => {
const linkText = 'Navigate!';
const { getByText } = render(
wrapInTestApp(
<MemoryRouter>
<Routes>
<Link to="/test">{linkText}</Link>
<Route path="/test">{testString}</Route>
</MemoryRouter>,
<Route path="/test" element={<p>{testString}</p>} />
</Routes>,
),
);
expect(() => getByText(testString)).toThrow();
+1 -1
View File
@@ -19,7 +19,7 @@ import { Link as MaterialLink } from '@material-ui/core';
import { Link as RouterLink } from 'react-router-dom';
type Props = ComponentProps<typeof MaterialLink> &
ComponentProps<typeof RouterLink>;
ComponentProps<typeof RouterLink> & { component?: React.FC<any> };
/**
* Thin wrapper on top of material-ui's Link component
@@ -19,7 +19,7 @@ import { Typography, Link, Grid } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import { BackstageTheme } from '@backstage/theme';
import { MicDrop } from './MicDrop';
import { useHistory } from 'react-router';
import { useNavigate } from 'react-router';
interface IErrorPageProps {
status: string;
@@ -40,7 +40,7 @@ const useStyles = makeStyles<BackstageTheme>(theme => ({
export const ErrorPage = ({ status, statusMessage }: IErrorPageProps) => {
const classes = useStyles();
const history = useHistory();
const navigate = useNavigate();
return (
<Grid container className={classes.container}>
@@ -53,7 +53,7 @@ export const ErrorPage = ({ status, statusMessage }: IErrorPageProps) => {
Looks like someone dropped the mic!
</Typography>
<Typography variant="h6">
<Link data-testid="go-back-link" onClick={history.goBack}>
<Link data-testid="go-back-link" onClick={() => navigate(-1)}>
Go back
</Link>
... or if you think this is a bug, please file an{' '}
+4 -5
View File
@@ -121,7 +121,8 @@ export const SidebarItem: FC<SidebarItemProps> = ({
icon: Icon,
text,
to = '#',
disableSelected = false,
// TODO: isActive is not in v6
// disableSelected = false,
hasNotifications = false,
onClick,
children,
@@ -148,8 +149,7 @@ export const SidebarItem: FC<SidebarItemProps> = ({
<NavLink
className={clsx(classes.root, classes.closed)}
activeClassName={classes.selected}
isActive={match => Boolean(match && !disableSelected)}
exact
end
to={to}
onClick={onClick}
>
@@ -161,8 +161,7 @@ export const SidebarItem: FC<SidebarItemProps> = ({
<NavLink
className={clsx(classes.root, classes.open)}
activeClassName={classes.selected}
isActive={match => Boolean(match && !disableSelected)}
exact
end
to={to}
onClick={onClick}
>
+2 -2
View File
@@ -43,8 +43,8 @@
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-hot-loader": "^4.12.21",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0"
"react-router": "^6.0.0-alpha.5",
"react-router-dom": "^6.0.0-alpha.5"
},
"devDependencies": {
"@types/jest": "^25.2.2",
+2 -2
View File
@@ -41,8 +41,8 @@
"@types/react": "^16.9",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0"
"react-router": "^6.0.0-alpha.5",
"react-router-dom": "^6.0.0-alpha.5"
},
"devDependencies": {
"@types/jest": "^25.2.2",
@@ -17,7 +17,7 @@
import React, { FC, useEffect } from 'react';
import { render } from '@testing-library/react';
import { wrapInTestApp, renderInTestApp } from './appWrappers';
import { Route } from 'react-router';
import { Route, Routes } from 'react-router';
import { withLogCollector } from '@backstage/test-utils-core';
import {
useApi,
@@ -32,15 +32,15 @@ describe('wrapInTestApp', () => {
const { error } = await withLogCollector(['error'], async () => {
const rendered = render(
wrapInTestApp(
<>
<Route path="/route1">Route 1</Route>
<Route path="/route2">Route 2</Route>
</>,
<Routes>
<Route path="/route1" element={<p>Route 1</p>} />
<Route path="/route2" element={<p>Route 2</p>} />
</Routes>,
{ routeEntries: ['/route2'] },
),
);
expect(rendered.getByText('Route 2')).toBeInTheDocument();
expect(rendered.getByText('Route 2')).toBeInTheDocument();
// Wait for async actions to trigger the act() warnings that we assert below
await Promise.resolve();
});
@@ -92,7 +92,9 @@ export function wrapInTestApp(
return (
<AppProvider>
<Route component={Wrapper} />
{/* The path of * here is needed to be set as a catch all, so it will render the wrapper element
* and work with nested routes if they exist too */}
<Route path="*" element={<Wrapper />} />
</AppProvider>
);
}
+2 -2
View File
@@ -32,8 +32,8 @@
"@material-ui/lab": "4.0.0-alpha.45",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"react-router": "^6.0.0-alpha.5",
"react-router-dom": "^6.0.0-alpha.5",
"react-use": "^14.2.0",
"swr": "^0.2.2"
},
@@ -14,32 +14,38 @@
* limitations under the License.
*/
jest.mock('react-router-dom', () => {
const actual = jest.requireActual('react-router-dom');
const mockNavigate = jest.fn();
return {
...actual,
useNavigate: jest.fn(() => mockNavigate),
useParams: jest.fn(),
};
});
import { ApiProvider, ApiRegistry, errorApiRef } from '@backstage/core';
import { wrapInTestApp } from '@backstage/test-utils';
import { render, wait } from '@testing-library/react';
import * as React from 'react';
import { CatalogApi, catalogApiRef } from '../../api/types';
import { EntityPage } from './EntityPage';
const getTestProps = (name: string) => {
return {
match: {
params: {
optionalNamespaceAndName: name,
kind: 'Component',
},
},
history: {
push: jest.fn(),
},
};
};
const {
useParams,
useNavigate,
}: { useParams: jest.Mock; useNavigate: () => jest.Mock } = jest.requireMock(
'react-router-dom',
);
const errorApi = { post: () => {} };
describe('EntityPage', () => {
it('should redirect to catalog page when name is not provided', async () => {
const props = getTestProps('');
useParams.mockReturnValue({
kind: 'Component',
optionalNamespaceAndName: '',
});
render(
wrapInTestApp(
<ApiProvider
@@ -53,13 +59,11 @@ describe('EntityPage', () => {
],
])}
>
<EntityPage {...props} />
<EntityPage />
</ApiProvider>,
),
);
await wait(() =>
expect(props.history.push).toHaveBeenCalledWith('/catalog'),
);
await wait(() => expect(useNavigate()).toHaveBeenCalledWith('/catalog'));
});
});
@@ -34,21 +34,9 @@ import { catalogApiRef } from '../..';
import { EntityContextMenu } from '../EntityContextMenu/EntityContextMenu';
import { EntityMetadataCard } from '../EntityMetadataCard/EntityMetadataCard';
import { UnregisterEntityDialog } from '../UnregisterEntityDialog/UnregisterEntityDialog';
import { useParams, useNavigate } from 'react-router-dom';
const REDIRECT_DELAY = 1000;
type Props = {
match: {
params: {
optionalNamespaceAndName: string;
kind: string;
};
};
history: {
push: (url: string) => void;
};
};
function headerProps(
kind: string,
namespace: string | undefined,
@@ -68,8 +56,12 @@ function headerProps(
};
}
export const EntityPage: FC<Props> = ({ match, history }) => {
const { optionalNamespaceAndName, kind } = match.params;
export const EntityPage: FC<{}> = () => {
const { optionalNamespaceAndName, kind } = useParams() as {
optionalNamespaceAndName: string;
kind: string;
};
const navigate = useNavigate();
const [name, namespace] = optionalNamespaceAndName.split(':').reverse();
const errorApi = useApi(errorApiRef);
@@ -85,19 +77,19 @@ export const EntityPage: FC<Props> = ({ match, history }) => {
if (!error && !loading && !entity) {
errorApi.post(new Error('Entity not found!'));
setTimeout(() => {
history.push('/');
navigate('/');
}, REDIRECT_DELAY);
}
}, [errorApi, history, error, loading, entity]);
}, [errorApi, navigate, error, loading, entity]);
if (!name) {
history.push('/catalog');
navigate('/catalog');
return null;
}
const cleanUpAfterRemoval = async () => {
setConfirmationDialogOpen(false);
history.push('/');
navigate('/');
};
const showRemovalDialog = () => setConfirmationDialogOpen(true);
+2 -2
View File
@@ -42,8 +42,8 @@
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-lazylog": "^4.5.2",
"react-router": "^5.1.2",
"react-router-dom": "^5.1.2",
"react-router": "^6.0.0-alpha.5",
"react-router-dom": "^6.0.0-alpha.5",
"react-use": "^14.2.0"
},
"devDependencies": {
+9 -14
View File
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import React from 'react';
import { Switch, Route, MemoryRouter } from 'react-router';
import { Route, MemoryRouter, Routes } from 'react-router';
import { BuildsPage, Builds } from '../pages/BuildsPage';
import { DetailedViewPage, BuildWithSteps } from '../pages/BuildWithStepsPage';
import { AppStateProvider } from '../state';
@@ -24,14 +24,13 @@ export const App = () => {
return (
<AppStateProvider>
<>
<Switch>
<Route path="/circleci" exact component={BuildsPage} />
<Routes>
<Route path="/circleci" element={<BuildsPage />} />
<Route
path="/circleci/build/:buildId"
exact
component={DetailedViewPage}
element={<DetailedViewPage />}
/>
</Switch>
</Routes>
<Settings />
</>
</AppStateProvider>
@@ -45,14 +44,10 @@ export const CircleCIWidget = () => (
<MemoryRouter initialEntries={['/circleci']}>
<AppStateProvider>
<>
<Switch>
<Route path="/circleci" exact component={Builds} />
<Route
path="/circleci/build/:buildId"
exact
component={BuildWithSteps}
/>
</Switch>
<Routes>
<Route path="/circleci" element={<Builds />} />
<Route path="/circleci/build/:buildId" element={<BuildWithSteps />} />
</Routes>
<Settings />
</>
</AppStateProvider>
@@ -33,8 +33,7 @@ import { gitOpsApiRef, Status } from '../../api';
import { transformRunStatus } from '../ProfileCatalog';
const ClusterPage: FC<{}> = () => {
const params = useParams<{ owner: string; repo: string }>();
const params = useParams() as { owner: string; repo: string };
const [loginInfo] = useLocalStorage<{
token: string;
username: string;
+1 -1
View File
@@ -55,7 +55,7 @@
"@types/node": "^12.0.0",
"@types/testing-library__jest-dom": "^5.0.4",
"jest-fetch-mock": "^3.0.3",
"react-router-dom": "^5.2.0"
"react-router-dom": "6.0.0-alpha.5"
},
"files": [
"dist/**/*.{js,d.ts}"
+1 -1
View File
@@ -41,7 +41,7 @@
"@types/node": "^12.0.0",
"@types/testing-library__jest-dom": "^5.0.4",
"jest-fetch-mock": "^3.0.3",
"react-router-dom": "^5.2.0"
"react-router-dom": "6.0.0-alpha.5"
},
"files": [
"dist/**/*.{js,d.ts}"
+1 -1
View File
@@ -30,7 +30,7 @@
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-markdown": "^4.3.1",
"react-router-dom": "^5.2.0",
"react-router-dom": "6.0.0-alpha.5",
"react-use": "^14.2.0"
},
"devDependencies": {
@@ -16,13 +16,10 @@
jest.mock('react-router-dom', () => {
const actual = jest.requireActual('react-router-dom');
const mocks = {
replace: jest.fn(),
push: jest.fn(),
};
const mockNavigation = jest.fn();
return {
...actual,
useHistory: jest.fn(() => mocks),
useNavigate: jest.fn(() => mockNavigation),
};
});
@@ -41,7 +38,7 @@ import AuditList from '.';
import * as data from '../../__fixtures__/website-list-response.json';
const { useHistory } = jest.requireMock('react-router-dom');
const { useNavigate } = jest.requireMock('react-router-dom');
const websiteListResponse = data as WebsiteListResponse;
describe('AuditList', () => {
@@ -145,7 +142,8 @@ describe('AuditList', () => {
);
const element = await rendered.findByLabelText(/Go to page 1/);
fireEvent.click(element);
expect(useHistory().replace).toHaveBeenCalledWith(`/lighthouse?page=1`);
expect(useNavigate()).toHaveBeenCalledWith(`/lighthouse?page=1`);
});
});
});
@@ -16,7 +16,7 @@
import React, { useState, useMemo, FC, ReactNode } from 'react';
import { useLocalStorage, useAsync } from 'react-use';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import { Grid, Button } from '@material-ui/core';
import Alert from '@material-ui/lab/Alert';
import Pagination from '@material-ui/lab/Pagination';
@@ -65,7 +65,7 @@ const AuditList: FC<{}> = () => {
return 0;
}, [value?.total, value?.limit]);
const history = useHistory();
const navigate = useNavigate();
let content: ReactNode = null;
if (value) {
@@ -77,7 +77,7 @@ const AuditList: FC<{}> = () => {
page={page}
count={pageCount}
onChange={(_event: Event, newPage: number) => {
history.replace(`/lighthouse?page=${newPage}`);
navigate(`/lighthouse?page=${newPage}`);
}}
/>
)}
@@ -18,10 +18,10 @@ import { Link, useParams } from 'react-router-dom';
import { useAsync } from 'react-use';
import {
makeStyles,
Button,
Grid,
List,
ListItem,
Button,
ListItemIcon,
ListItemText,
} from '@material-ui/core';
@@ -68,7 +68,7 @@ const AuditLinkList: FC<AuditLinkListProps> = ({
component="nav"
aria-label="lighthouse audit history"
>
{audits.map((audit) => (
{audits.map(audit => (
<ListItem
key={audit.id}
selected={audit.id === selectedId}
@@ -88,7 +88,7 @@ const AuditLinkList: FC<AuditLinkListProps> = ({
const AuditView: FC<{ audit?: Audit }> = ({ audit }: { audit?: Audit }) => {
const classes = useStyles();
const params = useParams<{ id: string }>();
const params = useParams() as { id: string };
const { url: lighthouseUrl } = useApi(lighthouseApiRef);
if (audit?.status === 'RUNNING') return <Progress />;
@@ -114,7 +114,7 @@ const AuditView: FC<{ audit?: Audit }> = ({ audit }: { audit?: Audit }) => {
const ConnectedAuditView: FC<{}> = () => {
const lighthouseApi = useApi(lighthouseApiRef);
const params = useParams<{ id: string }>();
const params = useParams() as { id: string };
const classes = useStyles();
const { loading, error, value: nextValue } = useAsync<Website>(
@@ -136,7 +136,7 @@ const ConnectedAuditView: FC<{}> = () => {
<AuditLinkList audits={value?.audits} selectedId={params.id} />
</Grid>
<Grid item xs={9}>
<AuditView audit={value?.audits.find((a) => a.id === params.id)} />
<AuditView audit={value?.audits.find(a => a.id === params.id)} />
</Grid>
</Grid>
);
@@ -16,13 +16,10 @@
jest.mock('react-router-dom', () => {
const actual = jest.requireActual('react-router-dom');
const mocks = {
replace: jest.fn(),
push: jest.fn(),
};
const mockNavigate = jest.fn();
return {
...actual,
useHistory: jest.fn(() => mocks),
useNavigate: jest.fn(() => mockNavigate),
};
});
@@ -41,7 +38,7 @@ import { lighthouseApiRef, LighthouseRestApi, Audit } from '../../api';
import CreateAudit from '.';
import * as data from '../../__fixtures__/create-audit-response.json';
const { useHistory }: { useHistory: jest.Mock } = jest.requireMock(
const { useNavigate }: { useNavigate: jest.Mock } = jest.requireMock(
'react-router-dom',
);
const createAuditResponse = data as Audit;
@@ -115,7 +112,7 @@ describe('CreateAudit', () => {
describe('when the audit is successfully created', () => {
it('triggers a location change to the table', async () => {
useHistory().push.mockClear();
useNavigate.mockClear();
mockFetch.mockResponseOnce(JSON.stringify(createAuditResponse));
const rendered = render(
@@ -140,7 +137,7 @@ describe('CreateAudit', () => {
await wait(() => expect(rendered.getByLabelText(/URL/)).toBeEnabled());
expect(useHistory().push).toHaveBeenCalledWith('/lighthouse');
expect(useNavigate()).toHaveBeenCalledWith('/lighthouse');
});
});
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import React, { useState, useCallback, FC } from 'react';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import {
makeStyles,
Grid,
@@ -40,7 +40,7 @@ import { lighthouseApiRef } from '../../api';
import { useQuery } from '../../utils';
import LighthouseSupportButton from '../SupportButton';
const useStyles = makeStyles((theme) => ({
const useStyles = makeStyles(theme => ({
input: {
minWidth: 300,
},
@@ -58,7 +58,7 @@ const CreateAudit: FC<{}> = () => {
const lighthouseApi = useApi(lighthouseApiRef);
const classes = useStyles();
const query = useQuery();
const history = useHistory();
const navigate = useNavigate();
const [submitting, setSubmitting] = useState(false);
const [url, setUrl] = useState<string>(query.get('url') || '');
const [emulatedFormFactor, setEmulatedFormFactor] = useState('mobile');
@@ -78,7 +78,7 @@ const CreateAudit: FC<{}> = () => {
},
},
});
history.push('/lighthouse');
navigate('/lighthouse');
} catch (err) {
errorApi.post(err);
} finally {
@@ -90,7 +90,7 @@ const CreateAudit: FC<{}> = () => {
lighthouseApi,
setSubmitting,
errorApi,
history,
navigate,
]);
return (
@@ -113,7 +113,7 @@ const CreateAudit: FC<{}> = () => {
<Grid item xs={12} sm={6}>
<InfoCard>
<form
onSubmit={(ev) => {
onSubmit={ev => {
ev.preventDefault();
triggerAudit();
}}
@@ -128,7 +128,7 @@ const CreateAudit: FC<{}> = () => {
helperText="The target URL for Lighthouse to use."
required
disabled={submitting}
onChange={(ev) => setUrl(ev.target.value)}
onChange={ev => setUrl(ev.target.value)}
value={url}
inputProps={{ 'aria-label': 'URL' }}
/>
@@ -142,7 +142,7 @@ const CreateAudit: FC<{}> = () => {
select
required
disabled={submitting}
onChange={(ev) => setEmulatedFormFactor(ev.target.value)}
onChange={ev => setEmulatedFormFactor(ev.target.value)}
value={emulatedFormFactor}
inputProps={{ 'aria-label': 'Emulated form factor' }}
>
+2 -2
View File
@@ -32,8 +32,8 @@
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-hook-form": "^5.7.2",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"react-router": "^6.0.0-alpha.5",
"react-router-dom": "^6.0.0-alpha.5",
"react-use": "^14.2.0"
},
"devDependencies": {
+1 -1
View File
@@ -29,7 +29,7 @@
"@material-ui/lab": "4.0.0-alpha.45",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-router-dom": "^5.2.0",
"react-router-dom": "6.0.0-alpha.5",
"react-use": "^14.2.0"
},
"devDependencies": {
+1 -1
View File
@@ -29,7 +29,7 @@
"@material-ui/lab": "4.0.0-alpha.45",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-router-dom": "^5.2.0",
"react-router-dom": "6.0.0-alpha.5",
"react-use": "^14.2.0"
},
"devDependencies": {
+25 -19
View File
@@ -3894,23 +3894,6 @@
"@types/react" "*"
immutable ">=3.8.2"
"@types/react-router-dom@^5.1.3", "@types/react-router-dom@^5.1.5":
version "5.1.5"
resolved "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.1.5.tgz#7c334a2ea785dbad2b2dcdd83d2cf3d9973da090"
integrity sha512-ArBM4B1g3BWLGbaGvwBGO75GNFbLDUthrDojV2vHLih/Tq8M+tgvY1DSwkuNrPSwdp/GUL93WSEpTZs8nVyJLw==
dependencies:
"@types/history" "*"
"@types/react" "*"
"@types/react-router" "*"
"@types/react-router@*":
version "5.1.4"
resolved "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.4.tgz#7d70bd905543cb6bcbdcc6bd98902332054f31a6"
integrity sha512-PZtnBuyfL07sqCJvGg3z+0+kt6fobc/xmle08jBiezLS8FrmGeiGkJnuxL/8Zgy9L83ypUhniV5atZn/L8n9MQ==
dependencies:
"@types/history" "*"
"@types/react" "*"
"@types/react-sparklines@^1.7.0":
version "1.7.0"
resolved "https://registry.npmjs.org/@types/react-sparklines/-/react-sparklines-1.7.0.tgz#f956d0f7b0e746ad445ce1cd250fe81f8a384684"
@@ -9971,6 +9954,13 @@ highlight.js@~9.15.0, highlight.js@~9.15.1:
resolved "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.10.tgz#7b18ed75c90348c045eef9ed08ca1319a2219ad2"
integrity sha512-RoV7OkQm0T3os3Dd2VHLNMoaoDVx77Wygln3n9l5YV172XonWG6rgQD3XnF/BuFFZw9A0TJgmMSO8FEWQgvcXw==
history@5.0.0-beta.9:
version "5.0.0-beta.9"
resolved "https://registry.npmjs.org/history/-/history-5.0.0-beta.9.tgz#fe230706c18c5f7f132001e55215e71b4aaab6d6"
integrity sha512-iLpu0fzu3iM041KDMNsawyB6YZjPLB+Bn+Pvq2lMnY7xxpxDIYvEz7r4et3Na8FthWzbYeukjl74ZKGWXcLhIA==
dependencies:
"@babel/runtime" "^7.7.6"
history@^4.9.0:
version "4.10.1"
resolved "https://registry.npmjs.org/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3"
@@ -15567,7 +15557,15 @@ react-redux@^7.0.3:
prop-types "^15.7.2"
react-is "^16.9.0"
react-router-dom@^5.1.2, react-router-dom@^5.2.0:
react-router-dom@6.0.0-alpha.5, react-router-dom@^6.0.0-alpha.5:
version "6.0.0-alpha.5"
resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.0.0-alpha.5.tgz#3c3e22226ee610eb91042a351741ce3f53596323"
integrity sha512-xo3VM55aE563uyZBPoUplfCPOYKJmTP2oA8wamm0k4K07e/6T4x4DDunS5Gu2VIy+m2+5mZp8n0rT6S+tYCb6Q==
dependencies:
history "5.0.0-beta.9"
prop-types "^15.7.2"
react-router-dom@^5.2.0:
version "5.2.0"
resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662"
integrity sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==
@@ -15580,7 +15578,7 @@ react-router-dom@^5.1.2, react-router-dom@^5.2.0:
tiny-invariant "^1.0.2"
tiny-warning "^1.0.0"
react-router@5.2.0, react-router@^5.1.2, react-router@^5.2.0:
react-router@5.2.0:
version "5.2.0"
resolved "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz#424e75641ca8747fbf76e5ecca69781aa37ea293"
integrity sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==
@@ -15596,6 +15594,14 @@ react-router@5.2.0, react-router@^5.1.2, react-router@^5.2.0:
tiny-invariant "^1.0.2"
tiny-warning "^1.0.0"
react-router@6.0.0-alpha.5, react-router@^6.0.0-alpha.5:
version "6.0.0-alpha.5"
resolved "https://registry.npmjs.org/react-router/-/react-router-6.0.0-alpha.5.tgz#c98805e50dc0e64787aa8aa4fa6753b435f2496b"
integrity sha512-cDj70bTUAgcfx6b5Fx1+wVlBSDVZGo8N+GUDk/yNFDCyGLfAsFlRpS3BhQqx8c49w2cCW+OrXxFhB4cbLZxWJw==
dependencies:
history "5.0.0-beta.9"
prop-types "^15.7.2"
react-side-effect@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.0.tgz#1ce4a8b4445168c487ed24dab886421f74d380d3"