Add react-router-dom-v5-compat (#159173)

## Summary

Prep work for bumping react-router to v6
Following https://github.com/remix-run/react-router/discussions/8753

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Patryk Kopyciński 2023-06-14 14:13:15 +02:00 committed by GitHub
parent 2fba1b651e
commit 09577fa0af
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
42 changed files with 715 additions and 613 deletions

View file

@ -8,6 +8,7 @@
import React from 'react'; import React from 'react';
import { BrowserRouter as Router, Redirect, Switch } from 'react-router-dom'; import { BrowserRouter as Router, Redirect, Switch } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { Route } from '@kbn/shared-ux-router'; import { Route } from '@kbn/shared-ux-router';
import { EuiPage } from '@elastic/eui'; import { EuiPage } from '@elastic/eui';
import { useDeps } from '../../hooks/use_deps'; import { useDeps } from '../../hooks/use_deps';
@ -26,13 +27,15 @@ export const App: React.FC = () => {
return ( return (
<Router basename={appBasePath}> <Router basename={appBasePath}>
<EuiPage> <CompatRouter>
<Sidebar /> <EuiPage>
<Switch> <Sidebar />
{routeElements} <Switch>
<Redirect to="/count-until" /> {routeElements}
</Switch> <Redirect to="/count-until" />
</EuiPage> </Switch>
</EuiPage>
</CompatRouter>
</Router> </Router>
); );
}; };

View file

@ -10,6 +10,7 @@ import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
// eslint-disable-next-line no-restricted-imports // eslint-disable-next-line no-restricted-imports
import { Router, Switch, Route, Redirect } from 'react-router-dom'; import { Router, Switch, Route, Redirect } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app';
import { EuiPageTemplate, EuiSideNav } from '@elastic/eui'; import { EuiPageTemplate, EuiSideNav } from '@elastic/eui';
import { AppMountParameters, CoreStart } from '@kbn/core/public'; import { AppMountParameters, CoreStart } from '@kbn/core/public';
@ -24,50 +25,52 @@ export const renderApp = (
) => { ) => {
ReactDOM.render( ReactDOM.render(
<Router history={history}> <Router history={history}>
<RedirectAppLinks coreStart={core}> <CompatRouter>
<EuiPageTemplate offset={0}> <RedirectAppLinks coreStart={core}>
<EuiPageTemplate.Sidebar> <EuiPageTemplate offset={0}>
<EuiSideNav <EuiPageTemplate.Sidebar>
items={[ <EuiSideNav
{ items={[
id: 'Examples', {
name: 'Examples', id: 'Examples',
items: [ name: 'Examples',
{ items: [
id: 'todos', {
name: 'Todo app', id: 'todos',
'data-test-subj': 'todosExample', name: 'Todo app',
href: '/app/contentManagementExamples/todos', 'data-test-subj': 'todosExample',
}, href: '/app/contentManagementExamples/todos',
{ },
id: 'msearch', {
name: 'MSearch', id: 'msearch',
'data-test-subj': 'msearchExample', name: 'MSearch',
href: '/app/contentManagementExamples/msearch', 'data-test-subj': 'msearchExample',
}, href: '/app/contentManagementExamples/msearch',
], },
}, ],
]} },
/> ]}
</EuiPageTemplate.Sidebar> />
</EuiPageTemplate.Sidebar>
<EuiPageTemplate.Section> <EuiPageTemplate.Section>
<Switch> <Switch>
<Redirect from="/" to="/todos" exact /> <Redirect from="/" to="/todos" exact />
<Route path="/todos"> <Route path="/todos">
<TodoApp contentClient={contentManagement.client} /> <TodoApp contentClient={contentManagement.client} />
</Route> </Route>
<Route path="/msearch"> <Route path="/msearch">
<MSearchApp <MSearchApp
contentClient={contentManagement.client} contentClient={contentManagement.client}
core={core} core={core}
savedObjectsTagging={savedObjectsTaggingOss} savedObjectsTagging={savedObjectsTaggingOss}
/> />
</Route> </Route>
</Switch> </Switch>
</EuiPageTemplate.Section> </EuiPageTemplate.Section>
</EuiPageTemplate> </EuiPageTemplate>
</RedirectAppLinks> </RedirectAppLinks>
</CompatRouter>
</Router>, </Router>,
element element
); );

View file

@ -9,6 +9,7 @@
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import { BrowserRouter as Router, withRouter, RouteComponentProps } from 'react-router-dom'; import { BrowserRouter as Router, withRouter, RouteComponentProps } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { Route } from '@kbn/shared-ux-router'; import { Route } from '@kbn/shared-ux-router';
import { EuiPage, EuiPageSideBar_Deprecated as EuiPageSideBar, EuiSideNav } from '@elastic/eui'; import { EuiPage, EuiPageSideBar_Deprecated as EuiPageSideBar, EuiSideNav } from '@elastic/eui';
@ -126,12 +127,14 @@ const EmbeddableExplorerApp = ({
return ( return (
<Router basename={basename}> <Router basename={basename}>
<EuiPage> <CompatRouter>
<EuiPageSideBar> <EuiPage>
<Nav navigateToApp={navigateToApp} pages={pages} /> <EuiPageSideBar>
</EuiPageSideBar> <Nav navigateToApp={navigateToApp} pages={pages} />
{routes} </EuiPageSideBar>
</EuiPage> {routes}
</EuiPage>
</CompatRouter>
</Router> </Router>
); );
}; };

View file

@ -9,6 +9,7 @@
import React from 'react'; import React from 'react';
import { FormattedMessage, I18nProvider } from '@kbn/i18n-react'; import { FormattedMessage, I18nProvider } from '@kbn/i18n-react';
import { Router, Switch } from 'react-router-dom'; import { Router, Switch } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { Route } from '@kbn/shared-ux-router'; import { Route } from '@kbn/shared-ux-router';
import { EuiPageTemplate } from '@elastic/eui'; import { EuiPageTemplate } from '@elastic/eui';
@ -45,27 +46,25 @@ export const GuidedOnboardingExampleApp = (props: GuidedOnboardingExampleAppDeps
{guidedOnboarding.guidedOnboardingApi?.isEnabled ? ( {guidedOnboarding.guidedOnboardingApi?.isEnabled ? (
<EuiPageTemplate.Section> <EuiPageTemplate.Section>
<Router history={history}> <Router history={history}>
<Switch> <CompatRouter>
<Route exact path="/"> <Switch>
<Main notifications={notifications} guidedOnboarding={guidedOnboarding} /> <Route exact path="/">
</Route> <Main notifications={notifications} guidedOnboarding={guidedOnboarding} />
<Route exact path="/stepOne"> </Route>
<StepOne guidedOnboarding={guidedOnboarding} /> <Route exact path="/stepOne">
</Route> <StepOne guidedOnboarding={guidedOnboarding} />
<Route exact path="/stepTwo"> </Route>
<StepTwo /> <Route exact path="/stepTwo">
</Route> <StepTwo />
<Route exact path="/stepThree"> </Route>
<StepThree guidedOnboarding={guidedOnboarding} /> <Route exact path="/stepThree">
</Route> <StepThree guidedOnboarding={guidedOnboarding} />
p </Route>
<Route <Route path="/stepFour/:indexName?">
path="/stepFour/:indexName?" <StepFour guidedOnboarding={guidedOnboarding} />
render={(routeProps) => ( </Route>
<StepFour guidedOnboarding={guidedOnboarding} {...routeProps} /> </Switch>
)} </CompatRouter>
/>
</Switch>
</Router> </Router>
</EuiPageTemplate.Section> </EuiPageTemplate.Section>
) : ( ) : (

View file

@ -17,19 +17,16 @@ import {
EuiPageContentBody_Deprecated as EuiPageContentBody, EuiPageContentBody_Deprecated as EuiPageContentBody,
EuiCode, EuiCode,
} from '@elastic/eui'; } from '@elastic/eui';
import { RouteComponentProps } from 'react-router-dom'; import { useParams } from 'react-router-dom';
interface StepFourProps { interface StepFourProps {
guidedOnboarding: GuidedOnboardingPluginStart; guidedOnboarding: GuidedOnboardingPluginStart;
} }
export const StepFour = (props: StepFourProps & RouteComponentProps<{ indexName: string }>) => { export const StepFour: React.FC<StepFourProps> = ({
const { guidedOnboarding: { guidedOnboardingApi },
guidedOnboarding: { guidedOnboardingApi }, }) => {
match: { const { indexName } = useParams<{ indexName: string }>();
params: { indexName },
},
} = props;
const [, setIsTourStepOpen] = useState<boolean>(false); const [, setIsTourStepOpen] = useState<boolean>(false);

View file

@ -10,6 +10,7 @@ import ReactDOM from 'react-dom';
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { useAsync } from 'react-use/lib'; import { useAsync } from 'react-use/lib';
import { Router, Redirect, Switch } from 'react-router-dom'; import { Router, Redirect, Switch } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { Route } from '@kbn/shared-ux-router'; import { Route } from '@kbn/shared-ux-router';
import { AppMountParameters } from '@kbn/core/public'; import { AppMountParameters } from '@kbn/core/public';
@ -49,17 +50,19 @@ const PortableDashboardsDemos = ({
}) => { }) => {
return ( return (
<Router history={history}> <Router history={history}>
<Switch> <CompatRouter>
<Route exact path="/"> <Switch>
<Redirect to={DASHBOARD_DEMO_PATH} /> <Route exact path="/">
</Route> <Redirect to={DASHBOARD_DEMO_PATH} />
<Route path={DASHBOARD_LIST_PATH}> </Route>
<PortableDashboardListingDemo history={history} /> <Route path={DASHBOARD_LIST_PATH}>
</Route> <PortableDashboardListingDemo history={history} />
<Route path={DASHBOARD_DEMO_PATH}> </Route>
<DashboardsDemo data={data} dashboard={dashboard} history={history} /> <Route path={DASHBOARD_DEMO_PATH}>
</Route> <DashboardsDemo data={data} dashboard={dashboard} history={history} />
</Switch> </Route>
</Switch>
</CompatRouter>
</Router> </Router>
); );
}; };

View file

@ -8,6 +8,7 @@
import React from 'react'; import React from 'react';
import { BrowserRouter as Router, Redirect, Switch } from 'react-router-dom'; import { BrowserRouter as Router, Redirect, Switch } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { Route } from '@kbn/shared-ux-router'; import { Route } from '@kbn/shared-ux-router';
import { EuiPage } from '@elastic/eui'; import { EuiPage } from '@elastic/eui';
import { useDeps } from '../../hooks/use_deps'; import { useDeps } from '../../hooks/use_deps';
@ -26,13 +27,15 @@ export const App: React.FC = () => {
return ( return (
<Router basename={appBasePath}> <Router basename={appBasePath}>
<EuiPage> <CompatRouter>
<Sidebar /> <EuiPage>
<Switch> <Sidebar />
{routeElements} <Switch>
<Redirect to="/simple-string-stream" /> {routeElements}
</Switch> <Redirect to="/simple-string-stream" />
</EuiPage> </Switch>
</EuiPage>
</CompatRouter>
</Router> </Router>
); );
}; };

View file

@ -8,6 +8,7 @@
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { BrowserRouter as Router } from 'react-router-dom'; import { BrowserRouter as Router } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { FormattedMessage, I18nProvider } from '@kbn/i18n-react'; import { FormattedMessage, I18nProvider } from '@kbn/i18n-react';
import { import {
@ -62,61 +63,63 @@ export const ScreenshotModeExampleApp = ({
}, [isScreenshotMode, notifications, http]); }, [isScreenshotMode, notifications, http]);
return ( return (
<Router basename={basename}> <Router basename={basename}>
<I18nProvider> <CompatRouter>
<> <I18nProvider>
<navigation.ui.TopNavMenu <>
appName={PLUGIN_NAME} <navigation.ui.TopNavMenu
showSearchBar={true} appName={PLUGIN_NAME}
useDefaultBehaviors={true} showSearchBar={true}
/> useDefaultBehaviors={true}
<EuiPage restrictWidth="1000px"> />
<EuiPageBody> <EuiPage restrictWidth="1000px">
<EuiPageHeader> <EuiPageBody>
<EuiTitle size="l"> <EuiPageHeader>
<h1> <EuiTitle size="l">
<FormattedMessage <h1>
id="screenshotModeExample.helloWorldText" <FormattedMessage
defaultMessage="{name}" id="screenshotModeExample.helloWorldText"
values={{ name: PLUGIN_NAME }} defaultMessage="{name}"
/> values={{ name: PLUGIN_NAME }}
</h1> />
</EuiTitle> </h1>
</EuiPageHeader>
<EuiPageContent>
<EuiPageContentHeader>
<EuiTitle>
<h2>
{isScreenshotMode ? (
<FormattedMessage
id="screenshotModeExample.screenshotModeTitle"
defaultMessage="We are in screenshot mode!"
/>
) : (
<FormattedMessage
id="screenshotModeExample.normalModeTitle"
defaultMessage="We are not in screenshot mode!"
/>
)}
</h2>
</EuiTitle> </EuiTitle>
</EuiPageContentHeader> </EuiPageHeader>
<EuiPageContentBody> <EuiPageContent>
<EuiText> <EuiPageContentHeader>
{isScreenshotMode ? ( <EuiTitle>
<p>We detected screenshot mode. The chrome navbar should be hidden.</p> <h2>
) : ( {isScreenshotMode ? (
<p> <FormattedMessage
This is how the app looks in normal mode. The chrome navbar should be id="screenshotModeExample.screenshotModeTitle"
visible. defaultMessage="We are in screenshot mode!"
</p> />
)} ) : (
</EuiText> <FormattedMessage
</EuiPageContentBody> id="screenshotModeExample.normalModeTitle"
</EuiPageContent> defaultMessage="We are not in screenshot mode!"
</EuiPageBody> />
</EuiPage> )}
</> </h2>
</I18nProvider> </EuiTitle>
</EuiPageContentHeader>
<EuiPageContentBody>
<EuiText>
{isScreenshotMode ? (
<p>We detected screenshot mode. The chrome navbar should be hidden.</p>
) : (
<p>
This is how the app looks in normal mode. The chrome navbar should be
visible.
</p>
)}
</EuiText>
</EuiPageContentBody>
</EuiPageContent>
</EuiPageBody>
</EuiPage>
</>
</I18nProvider>
</CompatRouter>
</Router> </Router>
); );
}; };

View file

@ -9,6 +9,7 @@
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import { Router, Redirect } from 'react-router-dom'; import { Router, Redirect } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { Route } from '@kbn/shared-ux-router'; import { Route } from '@kbn/shared-ux-router';
import { I18nProvider } from '@kbn/i18n-react'; import { I18nProvider } from '@kbn/i18n-react';
import { AppMountParameters, CoreStart } from '@kbn/core/public'; import { AppMountParameters, CoreStart } from '@kbn/core/public';
@ -48,30 +49,32 @@ export const renderApp = (
<RedirectAppLinks application={application}> <RedirectAppLinks application={application}>
<SearchExamplePage exampleLinks={LINKS} basePath={http.basePath}> <SearchExamplePage exampleLinks={LINKS} basePath={http.basePath}>
<Router history={history}> <Router history={history}>
<Route path={LINKS[0].path}> <CompatRouter>
<SearchExamplesApp <Route path={LINKS[0].path}>
notifications={notifications} <SearchExamplesApp
navigation={navigation} notifications={notifications}
data={data} navigation={navigation}
http={http} data={data}
unifiedSearch={unifiedSearch} http={http}
/> unifiedSearch={unifiedSearch}
</Route> />
<Route path={LINKS[1].path}> </Route>
<SqlSearchExampleApp notifications={notifications} data={data} /> <Route path={LINKS[1].path}>
</Route> <SqlSearchExampleApp notifications={notifications} data={data} />
<Route path={LINKS[2].path}> </Route>
<SearchSessionsExampleApp <Route path={LINKS[2].path}>
navigation={navigation} <SearchSessionsExampleApp
notifications={notifications} navigation={navigation}
data={data} notifications={notifications}
unifiedSearch={unifiedSearch} data={data}
/> unifiedSearch={unifiedSearch}
</Route> />
</Route>
<Route path="/" exact={true}> <Route path="/" exact={true}>
<Redirect to={LINKS[0].path} /> <Redirect to={LINKS[0].path} />
</Route> </Route>
</CompatRouter>
</Router> </Router>
</SearchExamplePage> </SearchExamplePage>
</RedirectAppLinks> </RedirectAppLinks>

View file

@ -8,6 +8,7 @@
import React, { useEffect, useMemo } from 'react'; import React, { useEffect, useMemo } from 'react';
import { Link, Router, Switch, useLocation } from 'react-router-dom'; import { Link, Router, Switch, useLocation } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { Route } from '@kbn/shared-ux-router'; import { Route } from '@kbn/shared-ux-router';
import { History } from 'history'; import { History } from 'history';
import { import {
@ -185,57 +186,59 @@ export const TodoAppPage: React.FC<{
return ( return (
<Router history={props.history}> <Router history={props.history}>
<EuiPageBody> <CompatRouter>
<EuiPageHeader> <EuiPageBody>
<EuiPageHeaderSection> <EuiPageHeader>
<EuiTitle size="l"> <EuiPageHeaderSection>
<h1>{props.appTitle}</h1> <EuiTitle size="l">
</EuiTitle> <h1>{props.appTitle}</h1>
<EuiSpacer /> </EuiTitle>
<EuiText> <EuiSpacer />
<p> <EuiText>
This is a simple TODO app that uses state containers and state syncing utils. It <p>
stores state in the URL similar like Discover or Dashboard apps do. <br /> This is a simple TODO app that uses state containers and state syncing utils. It
Play with the app and see how the state is persisted in the URL. stores state in the URL similar like Discover or Dashboard apps do. <br />
<br /> Undo/Redo with browser history also works. Play with the app and see how the state is persisted in the URL.
</p> <br /> Undo/Redo with browser history also works.
</EuiText> </p>
</EuiPageHeaderSection> </EuiText>
</EuiPageHeader> </EuiPageHeaderSection>
<EuiPageContent> </EuiPageHeader>
<EuiPageContentBody> <EuiPageContent>
<Switch> <EuiPageContentBody>
<Route path={'/completed'}> <Switch>
<TodoApp filter={'completed'} stateContainer={stateContainer} /> <Route path={'/completed'}>
</Route> <TodoApp filter={'completed'} stateContainer={stateContainer} />
<Route path={'/not-completed'}> </Route>
<TodoApp filter={'not-completed'} stateContainer={stateContainer} /> <Route path={'/not-completed'}>
</Route> <TodoApp filter={'not-completed'} stateContainer={stateContainer} />
<Route path={'/'}> </Route>
<TodoApp filter={null} stateContainer={stateContainer} /> <Route path={'/'}>
</Route> <TodoApp filter={null} stateContainer={stateContainer} />
</Switch> </Route>
<EuiSpacer size={'xxl'} /> </Switch>
<EuiText size={'s'}> <EuiSpacer size={'xxl'} />
<p>Most of kibana apps persist state in the URL in two ways:</p> <EuiText size={'s'}>
<ol> <p>Most of kibana apps persist state in the URL in two ways:</p>
<li>Expanded state in rison format</li> <ol>
<li> <li>Expanded state in rison format</li>
Just a state hash. <br /> <li>
In the URL only the hash from the state is stored. The state itself is stored in Just a state hash. <br />
the sessionStorage. See `state:storeInSessionStorage` advanced option for more In the URL only the hash from the state is stored. The state itself is stored in
context. the sessionStorage. See `state:storeInSessionStorage` advanced option for more
</li> context.
</ol> </li>
<p>You can switch between these two mods:</p> </ol>
</EuiText> <p>You can switch between these two mods:</p>
<EuiSpacer /> </EuiText>
<EuiButton onClick={() => setUseHashedUrl(!useHashedUrl)}> <EuiSpacer />
{useHashedUrl ? 'Use Expanded State' : 'Use Hashed State'} <EuiButton onClick={() => setUseHashedUrl(!useHashedUrl)}>
</EuiButton> {useHashedUrl ? 'Use Expanded State' : 'Use Hashed State'}
</EuiPageContentBody> </EuiButton>
</EuiPageContent> </EuiPageContentBody>
</EuiPageBody> </EuiPageContent>
</EuiPageBody>
</CompatRouter>
</Router> </Router>
); );
}; };

View file

@ -9,6 +9,7 @@
import React, { useEffect, useMemo, useState } from 'react'; import React, { useEffect, useMemo, useState } from 'react';
import { History } from 'history'; import { History } from 'history';
import { Router } from 'react-router-dom'; import { Router } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { import {
EuiFieldText, EuiFieldText,
@ -79,7 +80,7 @@ export const App = ({
return ( return (
<StateContainersExamplesPage navigateToApp={navigateToApp} exampleLinks={exampleLinks}> <StateContainersExamplesPage navigateToApp={navigateToApp} exampleLinks={exampleLinks}>
<Router history={history}> <Router history={history}>
<> <CompatRouter>
<EuiPageBody> <EuiPageBody>
<EuiPageHeader> <EuiPageHeader>
<EuiTitle size="l"> <EuiTitle size="l">
@ -114,7 +115,7 @@ export const App = ({
/> />
</EuiPageContent> </EuiPageContent>
</EuiPageBody> </EuiPageBody>
</> </CompatRouter>
</Router> </Router>
</StateContainersExamplesPage> </StateContainersExamplesPage>
); );

View file

@ -933,9 +933,10 @@
"react-resizable": "^3.0.4", "react-resizable": "^3.0.4",
"react-resize-detector": "^7.1.1", "react-resize-detector": "^7.1.1",
"react-reverse-portal": "^2.1.0", "react-reverse-portal": "^2.1.0",
"react-router": "^5.2.0", "react-router": "^5.3.4",
"react-router-config": "^5.1.1", "react-router-config": "^5.1.1",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.3.4",
"react-router-dom-v5-compat": "^6.12.0",
"react-shortcuts": "^2.1.0", "react-shortcuts": "^2.1.0",
"react-syntax-highlighter": "^15.3.1", "react-syntax-highlighter": "^15.3.1",
"react-use": "^15.3.8", "react-use": "^15.3.8",
@ -1305,9 +1306,9 @@
"@types/react-grid-layout": "^1.3.2", "@types/react-grid-layout": "^1.3.2",
"@types/react-intl": "^2.3.15", "@types/react-intl": "^2.3.15",
"@types/react-is": "^17.0.3", "@types/react-is": "^17.0.3",
"@types/react-router": "^5.1.7", "@types/react-router": "^5.1.20",
"@types/react-router-config": "^5.0.2", "@types/react-router-config": "^5.0.7",
"@types/react-router-dom": "^5.1.5", "@types/react-router-dom": "^5.3.3",
"@types/react-syntax-highlighter": "^15.4.0", "@types/react-syntax-highlighter": "^15.4.0",
"@types/react-test-renderer": "^17.0.2", "@types/react-test-renderer": "^17.0.2",
"@types/react-virtualized": "^9.21.22", "@types/react-virtualized": "^9.21.22",

View file

@ -9,6 +9,7 @@
import React, { FunctionComponent, useMemo } from 'react'; import React, { FunctionComponent, useMemo } from 'react';
// eslint-disable-next-line no-restricted-imports // eslint-disable-next-line no-restricted-imports
import { RouteComponentProps, Router, Route, Switch } from 'react-router-dom'; import { RouteComponentProps, Router, Route, Switch } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { History } from 'history'; import { History } from 'history';
import { EMPTY, Observable } from 'rxjs'; import { EMPTY, Observable } from 'rxjs';
import useObservable from 'react-use/lib/useObservable'; import useObservable from 'react-use/lib/useObservable';
@ -55,60 +56,62 @@ export const AppRouter: FunctionComponent<Props> = ({
return ( return (
<Router history={history}> <Router history={history}>
<Switch> <CompatRouter>
{[...mounters].map(([appId, mounter]) => ( <Switch>
{[...mounters].map(([appId, mounter]) => (
<Route
key={mounter.appRoute}
path={mounter.appRoute}
exact={mounter.exactRoute}
render={({ match: { path } }) => (
<AppContainer
appPath={path}
appStatus={appStatuses.get(appId) ?? AppStatus.inaccessible}
createScopedHistory={createScopedHistory}
{...{
appId,
mounter,
setAppLeaveHandler,
setAppActionMenu,
setIsMounting,
theme$,
showPlainSpinner,
}}
/>
)}
/>
))}
{/* handler for legacy apps and used as a catch-all to display 404 page on not existing /app/appId apps*/}
<Route <Route
key={mounter.appRoute} path="/app/:appId"
path={mounter.appRoute} render={({
exact={mounter.exactRoute} match: {
render={({ match: { path } }) => ( params: { appId },
<AppContainer url,
appPath={path} },
appStatus={appStatuses.get(appId) ?? AppStatus.inaccessible} }: RouteComponentProps<Params>) => {
createScopedHistory={createScopedHistory} // the id/mounter retrieval can be removed once #76348 is addressed
{...{ const [id, mounter] = mounters.has(appId) ? [appId, mounters.get(appId)] : [];
appId, return (
mounter, <AppContainer
setAppLeaveHandler, appPath={url}
setAppActionMenu, appId={id ?? appId}
setIsMounting, appStatus={appStatuses.get(appId) ?? AppStatus.inaccessible}
theme$, createScopedHistory={createScopedHistory}
showPlainSpinner, {...{
}} mounter,
/> setAppLeaveHandler,
)} setAppActionMenu,
setIsMounting,
theme$,
showPlainSpinner,
}}
/>
);
}}
/> />
))} </Switch>
{/* handler for legacy apps and used as a catch-all to display 404 page on not existing /app/appId apps*/} </CompatRouter>
<Route
path="/app/:appId"
render={({
match: {
params: { appId },
url,
},
}: RouteComponentProps<Params>) => {
// the id/mounter retrieval can be removed once #76348 is addressed
const [id, mounter] = mounters.has(appId) ? [appId, mounters.get(appId)] : [];
return (
<AppContainer
appPath={url}
appId={id ?? appId}
appStatus={appStatuses.get(appId) ?? AppStatus.inaccessible}
createScopedHistory={createScopedHistory}
{...{
mounter,
setAppLeaveHandler,
setAppActionMenu,
setIsMounting,
theme$,
showPlainSpinner,
}}
/>
);
}}
/>
</Switch>
</Router> </Router>
); );
}; };

View file

@ -28,8 +28,9 @@ import {
import type { HttpStart } from '@kbn/core-http-browser'; import type { HttpStart } from '@kbn/core-http-browser';
import { MountPoint } from '@kbn/core-mount-utils-browser'; import { MountPoint } from '@kbn/core-mount-utils-browser';
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import React, { createRef, useState } from 'react'; import React, { createRef, useCallback, useState } from 'react';
import { Router } from 'react-router-dom'; import { Router } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import useLocalStorage from 'react-use/lib/useLocalStorage'; import useLocalStorage from 'react-use/lib/useLocalStorage';
import useObservable from 'react-use/lib/useObservable'; import useObservable from 'react-use/lib/useObservable';
import { Observable, debounceTime } from 'rxjs'; import { Observable, debounceTime } from 'rxjs';
@ -120,12 +121,15 @@ const Logo = (
fullHref = props.prependBasePath(homeHref); fullHref = props.prependBasePath(homeHref);
} }
const navigateHome = (event: React.MouseEvent) => { const navigateHome = useCallback(
if (fullHref) { (event: React.MouseEvent) => {
props.application.navigateToUrl(fullHref); if (fullHref) {
} props.application.navigateToUrl(fullHref);
event.preventDefault(); }
}; event.preventDefault();
},
[fullHref, props.application]
);
return ( return (
<span css={logo.container}> <span css={logo.container}>
@ -165,36 +169,45 @@ export const ProjectHeader = ({
const toggleCollapsibleNavRef = createRef<HTMLButtonElement & { euiAnimate: () => void }>(); const toggleCollapsibleNavRef = createRef<HTMLButtonElement & { euiAnimate: () => void }>();
const headerActionMenuMounter = useHeaderActionMenuMounter(observables.actionMenu$); const headerActionMenuMounter = useHeaderActionMenuMounter(observables.actionMenu$);
const handleCloseNav = useCallback(() => {
setIsOpen(false);
if (toggleCollapsibleNavRef.current) {
toggleCollapsibleNavRef.current.focus();
}
}, [setIsOpen, toggleCollapsibleNavRef]);
const handleToggleNavButtonClick = useCallback(
() => setIsOpen((prevIsOpen) => !prevIsOpen),
[setIsOpen]
);
return ( return (
<> <>
<EuiHeader position="fixed" data-test-subj="kibanaProjectHeader"> <EuiHeader position="fixed" data-test-subj="kibanaProjectHeader">
<EuiHeaderSection grow={false}> <EuiHeaderSection grow={false}>
<EuiHeaderSectionItem css={headerCss.nav.toggleNavButton}> <EuiHeaderSectionItem css={headerCss.nav.toggleNavButton}>
<Router history={application.history}> <Router history={application.history}>
<ProjectNavigation <CompatRouter>
isOpen={isOpen!} <ProjectNavigation
closeNav={() => { isOpen={isOpen!}
setIsOpen(false); closeNav={handleCloseNav}
if (toggleCollapsibleNavRef.current) { button={
toggleCollapsibleNavRef.current.focus(); <EuiHeaderSectionItemButton
data-test-subj="toggleNavButton"
aria-label={headerStrings.nav.closeNavAriaLabel}
onClick={handleToggleNavButtonClick}
aria-expanded={isOpen!}
aria-pressed={isOpen!}
aria-controls={navId}
ref={toggleCollapsibleNavRef}
>
<EuiIcon type={isOpen ? 'menuLeft' : 'menuRight'} size="m" />
</EuiHeaderSectionItemButton>
} }
}} >
button={ {children}
<EuiHeaderSectionItemButton </ProjectNavigation>
data-test-subj="toggleNavButton" </CompatRouter>
aria-label={headerStrings.nav.closeNavAriaLabel}
onClick={() => setIsOpen(!isOpen)}
aria-expanded={isOpen!}
aria-pressed={isOpen!}
aria-controls={navId}
ref={toggleCollapsibleNavRef}
>
<EuiIcon type={isOpen ? 'menuLeft' : 'menuRight'} size="m" />
</EuiHeaderSectionItemButton>
}
>
{children}
</ProjectNavigation>
</Router> </Router>
</EuiHeaderSectionItem> </EuiHeaderSectionItem>

View file

@ -2,6 +2,7 @@ import React, { useState } from 'react';
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import { FormattedMessage, I18nProvider } from '@kbn/i18n-react'; import { FormattedMessage, I18nProvider } from '@kbn/i18n-react';
import { BrowserRouter as Router } from 'react-router-dom'; import { BrowserRouter as Router } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { import {
EuiButton, EuiButton,
@ -52,62 +53,64 @@ export const <%= upperCamelCase(name) %>App = ({ basename, notifications, http,
// Note that `navigation.ui.TopNavMenu` is a stateful component exported on the `navigation` plugin's start contract. // Note that `navigation.ui.TopNavMenu` is a stateful component exported on the `navigation` plugin's start contract.
return ( return (
<Router basename={basename}> <Router basename={basename}>
<I18nProvider> <CompatRouter>
<> <I18nProvider>
<navigation.ui.TopNavMenu appName={ PLUGIN_ID } showSearchBar={true} useDefaultBehaviors={true}/> <>
<EuiPage restrictWidth="1000px"> <navigation.ui.TopNavMenu appName={ PLUGIN_ID } showSearchBar={true} useDefaultBehaviors={true}/>
<EuiPageBody> <EuiPage restrictWidth="1000px">
<EuiPageHeader> <EuiPageBody>
<EuiTitle size="l"> <EuiPageHeader>
<h1> <EuiTitle size="l">
<FormattedMessage <h1>
id="<%= camelCase(name) %>.helloWorldText"
defaultMessage="{name}"
values={{ name: PLUGIN_NAME }}
/>
</h1>
</EuiTitle>
</EuiPageHeader>
<EuiPageContent>
<EuiPageContentHeader>
<EuiTitle>
<h2>
<FormattedMessage <FormattedMessage
id="<%= camelCase(name) %>.congratulationsTitle" id="<%= camelCase(name) %>.helloWorldText"
defaultMessage="Congratulations, you have successfully created a new Kibana Plugin!" defaultMessage="{name}"
values={{ name: PLUGIN_NAME }}
/> />
</h2> </h1>
</EuiTitle> </EuiTitle>
</EuiPageContentHeader> </EuiPageHeader>
<EuiPageContentBody> <EuiPageContent>
<EuiText> <EuiPageContentHeader>
<p> <EuiTitle>
<FormattedMessage <h2>
id="<%= camelCase(name) %>.content" <FormattedMessage
defaultMessage="Look through the generated code and check out the plugin development documentation." id="<%= camelCase(name) %>.congratulationsTitle"
/> defaultMessage="Congratulations, you have successfully created a new Kibana Plugin!"
</p> />
<EuiHorizontalRule/> </h2>
<p> </EuiTitle>
<FormattedMessage </EuiPageContentHeader>
id="<%= camelCase(name) %>.timestampText" <EuiPageContentBody>
defaultMessage="Last timestamp: {time}" <EuiText>
values={{ time: timestamp ? timestamp : 'Unknown' }} <p>
/> <FormattedMessage
</p> id="<%= camelCase(name) %>.content"
<EuiButton type="primary" size="s" onClick={onClickHandler}> defaultMessage="Look through the generated code and check out the plugin development documentation."
<FormattedMessage />
id="<%= camelCase(name) %>.buttonText" </p>
defaultMessage="<%= hasServer ? 'Get data' : 'Click me' %>" <EuiHorizontalRule/>
/> <p>
</EuiButton> <FormattedMessage
</EuiText> id="<%= camelCase(name) %>.timestampText"
</EuiPageContentBody> defaultMessage="Last timestamp: {time}"
</EuiPageContent> values={{ time: timestamp ? timestamp : 'Unknown' }}
</EuiPageBody> />
</EuiPage> </p>
</> <EuiButton type="primary" size="s" onClick={onClickHandler}>
</I18nProvider> <FormattedMessage
id="<%= camelCase(name) %>.buttonText"
defaultMessage="<%= hasServer ? 'Get data' : 'Click me' %>"
/>
</EuiButton>
</EuiText>
</EuiPageContentBody>
</EuiPageContent>
</EuiPageBody>
</EuiPage>
</>
</I18nProvider>
</CompatRouter>
</Router> </Router>
); );
}; };

View file

@ -8,6 +8,7 @@
import { History } from 'history'; import { History } from 'history';
import React from 'react'; import React from 'react';
import { Router as ReactRouter } from 'react-router-dom'; import { Router as ReactRouter } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { RouteMap, Router } from './types'; import { RouteMap, Router } from './types';
import { RouterContextProvider } from './use_router'; import { RouterContextProvider } from './use_router';
@ -22,7 +23,9 @@ export function RouterProvider({
}) { }) {
return ( return (
<ReactRouter history={history}> <ReactRouter history={history}>
<RouterContextProvider router={router}>{children}</RouterContextProvider> <CompatRouter>
<RouterContextProvider router={router}>{children}</RouterContextProvider>
</CompatRouter>
</ReactRouter> </ReactRouter>
); );
} }

View file

@ -52,6 +52,7 @@ RUNTIME_DEPS = [
"@npm//react-beautiful-dnd", "@npm//react-beautiful-dnd",
"@npm//react-dom", "@npm//react-dom",
"@npm//react-router-dom", "@npm//react-router-dom",
"@npm//react-router-dom-v5-compat",
"@npm//react-router", "@npm//react-router",
"@npm//react", "@npm//react",
"@npm//rxjs", "@npm//rxjs",

View file

@ -99,6 +99,7 @@ module.exports = (_, argv) => {
'react-dom', 'react-dom',
'react-dom/server', 'react-dom/server',
'react-router-dom', 'react-router-dom',
'react-router-dom-v5-compat',
'react-router', 'react-router',
'react', 'react',
'rxjs', 'rxjs',

View file

@ -50,6 +50,7 @@ const externals = {
'react-dom/server': '__kbnSharedDeps__.ReactDomServer', 'react-dom/server': '__kbnSharedDeps__.ReactDomServer',
'react-router': '__kbnSharedDeps__.ReactRouter', 'react-router': '__kbnSharedDeps__.ReactRouter',
'react-router-dom': '__kbnSharedDeps__.ReactRouterDom', 'react-router-dom': '__kbnSharedDeps__.ReactRouterDom',
'react-router-dom-v5-compat': '__kbnSharedDeps__.ReactRouterDomV5Compat',
'styled-components': '__kbnSharedDeps__.StyledComponents', 'styled-components': '__kbnSharedDeps__.StyledComponents',
'@kbn/monaco': '__kbnSharedDeps__.KbnMonaco', '@kbn/monaco': '__kbnSharedDeps__.KbnMonaco',
// this is how plugins/consumers from npm load monaco // this is how plugins/consumers from npm load monaco

View file

@ -29,6 +29,7 @@ export const ReactDomServer = require('react-dom/server');
// eslint-disable-next-line @kbn/eslint/module_migration // eslint-disable-next-line @kbn/eslint/module_migration
export const ReactRouter = require('react-router'); export const ReactRouter = require('react-router');
export const ReactRouterDom = require('react-router-dom'); export const ReactRouterDom = require('react-router-dom');
export const ReactRouterDomV5Compat = require('react-router-dom-v5-compat');
export const StyledComponents = require('styled-components'); export const StyledComponents = require('styled-components');
Moment.tz.load(require('moment-timezone/data/packed/latest.json')); Moment.tz.load(require('moment-timezone/data/packed/latest.json'));

View file

@ -23,7 +23,12 @@ import { useSharedUXExecutionContext } from './use_execution_context';
* and send them to the execution context, later used to enrich APM * and send them to the execution context, later used to enrich APM
* 'route-change' transactions. * 'route-change' transactions.
*/ */
export const Route = ({ children, component: Component, render, ...rest }: RouteProps) => { export const Route = ({
children,
component: Component,
render,
...rest
}: RouteProps<string, { [K: string]: string }>) => {
const component = useMemo(() => { const component = useMemo(() => {
if (!Component) { if (!Component) {
return undefined; return undefined;

View file

@ -9,6 +9,7 @@
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import { Router, Switch, Redirect, RouteChildrenProps } from 'react-router-dom'; import { Router, Switch, Redirect, RouteChildrenProps } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { Route } from '@kbn/shared-ux-router'; import { Route } from '@kbn/shared-ux-router';
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
@ -42,10 +43,9 @@ const readOnlyBadge = {
iconType: 'glasses', iconType: 'glasses',
}; };
const redirectUrl = ({ type RedirectUrlProps = RouteChildrenProps<{ [QUERY]: string }>;
match,
location, const redirectUrl = ({ match, location }: RedirectUrlProps): LocationDescriptor => {
}: RouteChildrenProps<{ [QUERY]: string }>): LocationDescriptor => {
const search = url.addQueryParam(location.search, QUERY, match?.params[QUERY]); const search = url.addQueryParam(location.search, QUERY, match?.params[QUERY]);
return { return {
@ -78,26 +78,30 @@ export async function mountManagementSection(
<KibanaThemeProvider theme$={params.theme$}> <KibanaThemeProvider theme$={params.theme$}>
<I18nProvider> <I18nProvider>
<Router history={params.history}> <Router history={params.history}>
<Switch> <CompatRouter>
{/* TODO: remove route param (`query`) in 7.13 */} <Switch>
<Route path={`/:${QUERY}`}>{(props) => <Redirect to={redirectUrl(props)} />}</Route> {/* TODO: remove route param (`query`) in 7.13 */}
<Route path="/"> <Route path={`/:${QUERY}`}>
<Settings {(props: RedirectUrlProps) => <Redirect to={redirectUrl(props)} />}
history={params.history} </Route>
enableSaving={{ <Route path="/">
namespace: canSaveAdvancedSettings, <Settings
global: canSaveGlobalSettings, history={params.history}
}} enableSaving={{
enableShowing={{ namespace: true, global: canShowGlobalSettings }} namespace: canSaveAdvancedSettings,
toasts={notifications.toasts} global: canSaveGlobalSettings,
docLinks={docLinks.links} }}
settingsService={settings} enableShowing={{ namespace: true, global: canShowGlobalSettings }}
theme={params.theme$} toasts={notifications.toasts}
componentRegistry={componentRegistry} docLinks={docLinks.links}
trackUiMetric={trackUiMetric} settingsService={settings}
/> theme={params.theme$}
</Route> componentRegistry={componentRegistry}
</Switch> trackUiMetric={trackUiMetric}
/>
</Route>
</Switch>
</CompatRouter>
</Router> </Router>
</I18nProvider> </I18nProvider>
</KibanaThemeProvider>, </KibanaThemeProvider>,

View file

@ -12,6 +12,7 @@ import React from 'react';
import { parse, ParsedQuery } from 'query-string'; import { parse, ParsedQuery } from 'query-string';
import { render, unmountComponentAtNode } from 'react-dom'; import { render, unmountComponentAtNode } from 'react-dom';
import { Switch, RouteComponentProps, HashRouter, Redirect } from 'react-router-dom'; import { Switch, RouteComponentProps, HashRouter, Redirect } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { Route } from '@kbn/shared-ux-router'; import { Route } from '@kbn/shared-ux-router';
import { I18nProvider } from '@kbn/i18n-react'; import { I18nProvider } from '@kbn/i18n-react';
@ -149,17 +150,19 @@ export async function mountApp({ core, element, appUnMounted, mountContext }: Da
<DashboardMountContext.Provider value={mountContext}> <DashboardMountContext.Provider value={mountContext}>
<KibanaThemeProvider theme$={core.theme.theme$}> <KibanaThemeProvider theme$={core.theme.theme$}>
<HashRouter> <HashRouter>
<Switch> <CompatRouter>
<Route <Switch>
path={[CREATE_NEW_DASHBOARD_URL, `${VIEW_DASHBOARD_URL}/:id`]} <Route
render={renderDashboard} path={[CREATE_NEW_DASHBOARD_URL, `${VIEW_DASHBOARD_URL}/:id`]}
/> render={renderDashboard}
<Route exact path={LANDING_PAGE_PATH} render={renderListingPage} /> />
<Route exact path="/"> <Route exact path={LANDING_PAGE_PATH} render={renderListingPage} />
<Redirect to={LANDING_PAGE_PATH} /> <Route exact path="/">
</Route> <Redirect to={LANDING_PAGE_PATH} />
<Route render={renderNoMatch} /> </Route>
</Switch> <Route render={renderNoMatch} />
</Switch>
</CompatRouter>
</HashRouter> </HashRouter>
</KibanaThemeProvider> </KibanaThemeProvider>
</DashboardMountContext.Provider> </DashboardMountContext.Provider>

View file

@ -9,6 +9,7 @@
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import { Router, Switch, Redirect } from 'react-router-dom'; import { Router, Switch, Redirect } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { Route } from '@kbn/shared-ux-router'; import { Route } from '@kbn/shared-ux-router';
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
@ -87,21 +88,23 @@ export async function mountManagementSection(
<KibanaThemeProvider theme$={theme.theme$}> <KibanaThemeProvider theme$={theme.theme$}>
<I18nProvider> <I18nProvider>
<Router history={params.history}> <Router history={params.history}>
<Switch> <CompatRouter>
<Route path={['/create']}> <Switch>
<IndexPatternTableWithRouter canSave={canSave} showCreateDialog={true} /> <Route path={['/create']}>
</Route> <IndexPatternTableWithRouter canSave={canSave} showCreateDialog={true} />
<Route path={['/dataView/:id/field/:fieldName', '/dataView/:id/create-field/']}> </Route>
<CreateEditFieldContainer /> <Route path={['/dataView/:id/field/:fieldName', '/dataView/:id/create-field/']}>
</Route> <CreateEditFieldContainer />
<Route path={['/dataView/:id']}> </Route>
<EditIndexPatternContainer /> <Route path={['/dataView/:id']}>
</Route> <EditIndexPatternContainer />
<Redirect path={'/patterns*'} to={'dataView*'} /> </Route>
<Route path={['/']}> <Redirect path={'/patterns*'} to={'dataView*'} />
<IndexPatternTableWithRouter canSave={canSave} /> <Route path={['/']}>
</Route> <IndexPatternTableWithRouter canSave={canSave} />
</Switch> </Route>
</Switch>
</CompatRouter>
</Router> </Router>
</I18nProvider> </I18nProvider>
</KibanaThemeProvider> </KibanaThemeProvider>

View file

@ -10,6 +10,7 @@ import React, { useEffect, useRef } from 'react';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import { HashRouter as Router, Switch, Redirect, RouteComponentProps } from 'react-router-dom'; import { HashRouter as Router, Switch, Redirect, RouteComponentProps } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { Route } from '@kbn/shared-ux-router'; import { Route } from '@kbn/shared-ux-router';
import { EuiTab, EuiTabs, EuiToolTip, EuiBetaBadge } from '@elastic/eui'; import { EuiTab, EuiTabs, EuiToolTip, EuiBetaBadge } from '@elastic/eui';
import { I18nProvider } from '@kbn/i18n-react'; import { I18nProvider } from '@kbn/i18n-react';
@ -183,31 +184,33 @@ export function renderApp(
<I18nProvider> <I18nProvider>
<KibanaThemeProvider theme$={theme$}> <KibanaThemeProvider theme$={theme$}>
<Router> <Router>
<Switch> <CompatRouter>
{devTools <Switch>
// Only create routes for devtools that are not disabled {devTools
.filter((devTool) => !devTool.isDisabled()) // Only create routes for devtools that are not disabled
.map((devTool) => ( .filter((devTool) => !devTool.isDisabled())
<Route .map((devTool) => (
key={devTool.id} <Route
path={`/${devTool.id}`} key={devTool.id}
exact={!devTool.enableRouting} path={`/${devTool.id}`}
render={(props) => ( exact={!devTool.enableRouting}
<DevToolsWrapper render={(props) => (
updateRoute={props.history.push} <DevToolsWrapper
location={props.location} updateRoute={props.history.push}
activeDevTool={devTool} location={props.location}
devTools={devTools} activeDevTool={devTool}
theme$={theme$} devTools={devTools}
appServices={appServices} theme$={theme$}
/> appServices={appServices}
)} />
/> )}
))} />
<Route path="/"> ))}
<Redirect to={`/${devTools[0].id}`} /> <Route path="/">
</Route> <Redirect to={`/${devTools[0].id}`} />
</Switch> </Route>
</Switch>
</CompatRouter>
</Router> </Router>
</KibanaThemeProvider> </KibanaThemeProvider>
</I18nProvider>, </I18nProvider>,

View file

@ -7,6 +7,7 @@
*/ */
import { Redirect, Router, Switch } from 'react-router-dom'; import { Redirect, Router, Switch } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { Route } from '@kbn/shared-ux-router'; import { Route } from '@kbn/shared-ux-router';
import React from 'react'; import React from 'react';
import { History } from 'history'; import { History } from 'history';
@ -23,30 +24,32 @@ export const discoverRouter = (services: DiscoverServices, history: History, isD
<KibanaContextProvider services={services}> <KibanaContextProvider services={services}>
<EuiErrorBoundary> <EuiErrorBoundary>
<Router history={history} data-test-subj="discover-react-router"> <Router history={history} data-test-subj="discover-react-router">
<Switch> <CompatRouter>
<Route path="/context/:dataViewId/:id"> <Switch>
<ContextAppRoute /> <Route path="/context/:dataViewId/:id">
</Route> <ContextAppRoute />
<Route </Route>
path="/doc/:dataView/:index/:type" <Route
render={(props) => ( path="/doc/:dataView/:index/:type"
<Redirect to={`/doc/${props.match.params.dataView}/${props.match.params.index}`} /> render={(props) => (
)} <Redirect to={`/doc/${props.match.params.dataView}/${props.match.params.index}`} />
/> )}
<Route path="/doc/:dataViewId/:index"> />
<SingleDocRoute /> <Route path="/doc/:dataViewId/:index">
</Route> <SingleDocRoute />
<Route path="/viewAlert/:id"> </Route>
<ViewAlertRoute /> <Route path="/viewAlert/:id">
</Route> <ViewAlertRoute />
<Route path="/view/:id"> </Route>
<DiscoverMainRoute isDev={isDev} /> <Route path="/view/:id">
</Route> <DiscoverMainRoute isDev={isDev} />
<Route path="/" exact> </Route>
<DiscoverMainRoute isDev={isDev} /> <Route path="/" exact>
</Route> <DiscoverMainRoute isDev={isDev} />
<NotFoundRoute /> </Route>
</Switch> <NotFoundRoute />
</Switch>
</CompatRouter>
</Router> </Router>
</EuiErrorBoundary> </EuiErrorBoundary>
</KibanaContextProvider> </KibanaContextProvider>

View file

@ -7,7 +7,7 @@
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import { BrowserRouter as Router, RouteComponentProps } from 'react-router-dom'; import { BrowserRouter as Router } from 'react-router-dom';
import { Route } from '@kbn/shared-ux-router'; import { Route } from '@kbn/shared-ux-router';
import { EuiPage } from '@elastic/eui'; import { EuiPage } from '@elastic/eui';
import { AppMountParameters, CoreStart } from '@kbn/core/public'; import { AppMountParameters, CoreStart } from '@kbn/core/public';
@ -45,7 +45,7 @@ const AlertingExampleApp = ({
/> />
<Route <Route
path={`/rule/:id`} path={`/rule/:id`}
render={(props: RouteComponentProps<{ id: string }>) => { render={(props) => {
return ( return (
<Page title={`View Rule`} crumb={`View Rule ${props.match.params.id}`}> <Page title={`View Rule`} crumb={`View Rule ${props.match.params.id}`}>
<ViewAlertPage http={http} id={props.match.params.id} /> <ViewAlertPage http={http} id={props.match.params.id} />
@ -55,7 +55,7 @@ const AlertingExampleApp = ({
/> />
<Route <Route
path={`/astros/:id`} path={`/astros/:id`}
render={(props: RouteComponentProps<{ id: string }>) => { render={(props) => {
return ( return (
<Page title={`View People In Space Rule`} crumb={`Astros ${props.match.params.id}`}> <Page title={`View People In Space Rule`} crumb={`Astros ${props.match.params.id}`}>
<ViewPeopleInSpaceAlertPage http={http} id={props.match.params.id} /> <ViewPeopleInSpaceAlertPage http={http} id={props.match.params.id} />

View file

@ -9,7 +9,6 @@ import { act, fireEvent, render } from '@testing-library/react';
import React from 'react'; import React from 'react';
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';
import { createMemoryHistory } from 'history'; import { createMemoryHistory } from 'history';
import { RouterProvider } from '@kbn/typed-react-router-config';
import { License } from '@kbn/licensing-plugin/common/license'; import { License } from '@kbn/licensing-plugin/common/license';
import { Transaction } from '../../../../typings/es_schemas/ui/transaction'; import { Transaction } from '../../../../typings/es_schemas/ui/transaction';
import { ApmPluginContextValue } from '../../../context/apm_plugin/apm_plugin_context'; import { ApmPluginContextValue } from '../../../context/apm_plugin/apm_plugin_context';
@ -26,7 +25,6 @@ import {
} from '../../../utils/test_helpers'; } from '../../../utils/test_helpers';
import { TransactionActionMenu } from './transaction_action_menu'; import { TransactionActionMenu } from './transaction_action_menu';
import * as Transactions from './__fixtures__/mock_data'; import * as Transactions from './__fixtures__/mock_data';
import { apmRouter } from '../../routing/apm_route_config';
const apmContextMock = { const apmContextMock = {
...mockApmPluginContextValue, ...mockApmPluginContextValue,
@ -44,10 +42,8 @@ history.replace(
function Wrapper({ children }: { children?: React.ReactNode }) { function Wrapper({ children }: { children?: React.ReactNode }) {
return ( return (
<MemoryRouter> <MemoryRouter>
<MockApmPluginContextWrapper value={apmContextMock}> <MockApmPluginContextWrapper value={apmContextMock} history={history}>
<RouterProvider history={history} router={apmRouter as any}> {children}
{children}
</RouterProvider>
</MockApmPluginContextWrapper> </MockApmPluginContextWrapper>
</MemoryRouter> </MemoryRouter>
); );

View file

@ -15,7 +15,7 @@ import { decode } from '../route_state';
export const useRestoreHistory = () => { export const useRestoreHistory = () => {
const history = useHistory(); const history = useHistory();
const location = useLocation(); const location = useLocation<string>();
const dispatch = useDispatch(); const dispatch = useDispatch();
const { state: historyState } = location; const { state: historyState } = location;

View file

@ -14,7 +14,7 @@ import { encode, decode } from '../route_state';
import { State } from '../../../../types'; import { State } from '../../../../types';
export const useWorkpadHistory = () => { export const useWorkpadHistory = () => {
const history = useHistory(); const history = useHistory<string>();
const historyState = useSelector((state: State) => state.persistent); const historyState = useSelector((state: State) => state.persistent);
const hasRun = useRef<boolean>(false); const hasRun = useRef<boolean>(false);

View file

@ -5,6 +5,8 @@
* 2.0. * 2.0.
*/ */
// eslint-disable-next-line @kbn/eslint/module_migration
import type { ExtractRouteParams } from 'react-router';
import { generatePath } from 'react-router-dom'; import { generatePath } from 'react-router-dom';
import { import {
CASES_CREATE_PATH, CASES_CREATE_PATH,
@ -39,18 +41,24 @@ export const getCaseViewWithCommentPath = (casesBasePath: string) =>
export const generateCaseViewPath = (params: CaseViewPathParams): string => { export const generateCaseViewPath = (params: CaseViewPathParams): string => {
const { commentId, tabId } = params; const { commentId, tabId } = params;
// Cast for generatePath argument type constraint
const pathParams = params as unknown as { [paramName: string]: string };
// paths with commentId have their own specific path. // paths with commentId have their own specific path.
// Effectively overwrites the tabId // Effectively overwrites the tabId
if (commentId) { if (commentId) {
return normalizePath(generatePath(CASE_VIEW_COMMENT_PATH, pathParams)); return normalizePath(
generatePath(
CASE_VIEW_COMMENT_PATH,
params as ExtractRouteParams<typeof CASE_VIEW_COMMENT_PATH>
)
);
} }
if (tabId !== undefined) { if (tabId !== undefined) {
return normalizePath(generatePath(CASE_VIEW_TAB_PATH, pathParams)); return normalizePath(
generatePath(CASE_VIEW_TAB_PATH, params as ExtractRouteParams<typeof CASE_VIEW_TAB_PATH>)
);
} }
return normalizePath(generatePath(CASE_VIEW_PATH, pathParams)); return normalizePath(
generatePath(CASE_VIEW_PATH, params as ExtractRouteParams<typeof CASE_VIEW_PATH>)
);
}; };

View file

@ -9,7 +9,6 @@ import type { History } from 'history';
import type { FunctionComponent } from 'react'; import type { FunctionComponent } from 'react';
import React from 'react'; import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom'; import { render, unmountComponentAtNode } from 'react-dom';
import type { RouteComponentProps } from 'react-router-dom';
import { Redirect, Router, Switch } from 'react-router-dom'; import { Redirect, Router, Switch } from 'react-router-dom';
import type { Observable } from 'rxjs'; import type { Observable } from 'rxjs';
@ -37,10 +36,6 @@ interface CreateParams {
getStartServices: StartServicesAccessor<PluginStartDependencies>; getStartServices: StartServicesAccessor<PluginStartDependencies>;
} }
interface EditUserParams {
username: string;
}
export const usersManagementApp = Object.freeze({ export const usersManagementApp = Object.freeze({
id: 'users', id: 'users',
create({ authc, getStartServices }: CreateParams) { create({ authc, getStartServices }: CreateParams) {
@ -109,7 +104,7 @@ export const usersManagementApp = Object.freeze({
</Route> </Route>
<Route <Route
path="/edit/:username" path="/edit/:username"
render={(props: RouteComponentProps<EditUserParams>) => { render={(props) => {
// Additional decoding is a workaround for a bug in react-router's version of the `history` module. // Additional decoding is a workaround for a bug in react-router's version of the `history` module.
// See https://github.com/elastic/kibana/issues/82440 // See https://github.com/elastic/kibana/issues/82440
const username = tryDecodeURIComponent(props.match.params.username); const username = tryDecodeURIComponent(props.match.params.username);

View file

@ -27,7 +27,7 @@ import {
import { waitForPageFilters } from '../alerts'; import { waitForPageFilters } from '../alerts';
export const openFilterGroupContextMenu = () => { export const openFilterGroupContextMenu = () => {
cy.get(DETECTION_PAGE_FILTER_GROUP_CONTEXT_MENU).click({ force: true }); cy.get(DETECTION_PAGE_FILTER_GROUP_CONTEXT_MENU).click();
}; };
export const waitForFilterGroups = () => { export const waitForFilterGroups = () => {
@ -41,7 +41,7 @@ export const waitForFilterGroups = () => {
export const resetFilterGroup = () => { export const resetFilterGroup = () => {
openFilterGroupContextMenu(); openFilterGroupContextMenu();
cy.get(DETECTION_PAGE_FILTER_GROUP_RESET_BUTTON).click({ force: true }); cy.get(DETECTION_PAGE_FILTER_GROUP_RESET_BUTTON).click();
}; };
export const editFilterGroupControls = () => { export const editFilterGroupControls = () => {
@ -64,11 +64,11 @@ export const saveFilterGroupControls = () => {
export const discardFilterGroupControls = () => { export const discardFilterGroupControls = () => {
openFilterGroupContextMenu(); openFilterGroupContextMenu();
cy.get(FILTER_GROUP_CONTEXT_DISCARD_CHANGES).click({ force: true }); cy.get(FILTER_GROUP_CONTEXT_DISCARD_CHANGES).click();
}; };
export const openAddFilterGroupControlPanel = () => { export const openAddFilterGroupControlPanel = () => {
cy.get(FILTER_GROUP_ADD_CONTROL).click({ force: true }); cy.get(FILTER_GROUP_ADD_CONTROL).click();
cy.get(FILTER_GROUP_EDIT_CONTROLS_PANEL).should('be.visible'); cy.get(FILTER_GROUP_EDIT_CONTROLS_PANEL).should('be.visible');
}; };
@ -96,7 +96,7 @@ export const addNewFilterGroupControlValues = ({
export const deleteFilterGroupControl = (idx: number) => { export const deleteFilterGroupControl = (idx: number) => {
cy.get(CONTROL_FRAME_TITLE).eq(idx).realHover(); cy.get(CONTROL_FRAME_TITLE).eq(idx).realHover();
cy.get(FILTER_GROUP_CONTROL_ACTION_DELETE(idx)).click({ force: true }); cy.get(FILTER_GROUP_CONTROL_ACTION_DELETE(idx)).click();
cy.get(FILTER_GROUP_CONTROL_CONFIRM_DIALOG).should('be.visible'); cy.get(FILTER_GROUP_CONTROL_CONFIRM_DIALOG).should('be.visible');
cy.get(FILTER_GROUP_CONTROL_CONFIRM_BTN).click(); cy.get(FILTER_GROUP_CONTROL_CONFIRM_BTN).click();
}; };
@ -111,7 +111,7 @@ export const editFilterGroupControl = ({
label: string; label: string;
}) => { }) => {
cy.get(CONTROL_FRAME_TITLE).eq(idx).realHover(); cy.get(CONTROL_FRAME_TITLE).eq(idx).realHover();
cy.get(FILTER_GROUP_CONTROL_ACTION_EDIT(idx)).click({ force: true }); cy.get(FILTER_GROUP_CONTROL_ACTION_EDIT(idx)).click();
const { FIELD_SEARCH, FIELD_PICKER, FIELD_LABEL, SAVE } = FILTER_GROUP_EDIT_CONTROL_PANEL_ITEMS; const { FIELD_SEARCH, FIELD_PICKER, FIELD_LABEL, SAVE } = FILTER_GROUP_EDIT_CONTROL_PANEL_ITEMS;
cy.get(FIELD_SEARCH).type(fieldName); cy.get(FIELD_SEARCH).type(fieldName);
cy.get(FIELD_PICKER(fieldName)).should('exist').click(); cy.get(FIELD_PICKER(fieldName)).should('exist').click();

View file

@ -74,7 +74,7 @@ const NetworkContainerComponent = () => {
}) => ( }) => (
<Redirect <Redirect
to={{ to={{
pathname: getPathWithFlowType(detailName, flowTarget), pathname: getPathWithFlowType(detailName, flowTarget as FlowTargetSourceDest),
search, search,
}} }}
/> />

View file

@ -7,6 +7,7 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { Router, Switch, Redirect } from 'react-router-dom'; import { Router, Switch, Redirect } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { Route } from '@kbn/shared-ux-router'; import { Route } from '@kbn/shared-ux-router';
import { FormattedMessage } from '@kbn/i18n-react'; import { FormattedMessage } from '@kbn/i18n-react';
@ -183,7 +184,9 @@ export const App = ({ history }: { history: ScopedHistory }) => {
return ( return (
<Router history={history}> <Router history={history}>
<AppHandlingClusterUpgradeState /> <CompatRouter>
<AppHandlingClusterUpgradeState />
</CompatRouter>
</Router> </Router>
); );
}; };

View file

@ -11,6 +11,7 @@ import { CoreStart } from '@kbn/core/public';
import { of } from 'rxjs'; import { of } from 'rxjs';
import { createMemoryHistory } from 'history'; import { createMemoryHistory } from 'history';
import { Router } from 'react-router-dom'; import { Router } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { MemoryHistory } from 'history'; import { MemoryHistory } from 'history';
import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
@ -38,11 +39,13 @@ export const render = (
return testLibRender( return testLibRender(
<Router history={history}> <Router history={history}>
<KibanaContextProvider services={{ ...core }}> <CompatRouter>
<UrlParamsProvider> <KibanaContextProvider services={{ ...core }}>
<EuiThemeProvider>{component}</EuiThemeProvider> <UrlParamsProvider>
</UrlParamsProvider> <EuiThemeProvider>{component}</EuiThemeProvider>
</KibanaContextProvider> </UrlParamsProvider>
</KibanaContextProvider>
</CompatRouter>
</Router> </Router>
); );
}; };

View file

@ -11,6 +11,7 @@ import { History, Location } from 'history';
import moment from 'moment-timezone'; import moment from 'moment-timezone';
import * as React from 'react'; import * as React from 'react';
import { MemoryRouter, Router } from 'react-router-dom'; import { MemoryRouter, Router } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import type { UrlParams } from './types'; import type { UrlParams } from './types';
import { UrlParamsContext, UrlParamsProvider } from './url_params_context'; import { UrlParamsContext, UrlParamsProvider } from './url_params_context';
@ -164,25 +165,27 @@ describe('UrlParamsContext', () => {
const wrapper = mount( const wrapper = mount(
<Router history={history}> <Router history={history}>
<UrlParamsProvider> <CompatRouter>
<UrlParamsContext.Consumer> <UrlParamsProvider>
{({ urlParams, refreshTimeRange }) => { <UrlParamsContext.Consumer>
return ( {({ urlParams, refreshTimeRange }) => {
<React.Fragment> return (
<span id="data">{JSON.stringify(urlParams, null, 2)}</span> <React.Fragment>
<button <span id="data">{JSON.stringify(urlParams, null, 2)}</span>
onClick={() => <button
refreshTimeRange({ onClick={() =>
rangeFrom: 'now-1d/d', refreshTimeRange({
rangeTo: 'now-1d/d', rangeFrom: 'now-1d/d',
}) rangeTo: 'now-1d/d',
} })
/> }
</React.Fragment> />
); </React.Fragment>
}} );
</UrlParamsContext.Consumer> }}
</UrlParamsProvider> </UrlParamsContext.Consumer>
</UrlParamsProvider>
</CompatRouter>
</Router> </Router>
); );

View file

@ -18,6 +18,7 @@ import {
import type { SettingsStart } from '@kbn/core-ui-settings-browser'; import type { SettingsStart } from '@kbn/core-ui-settings-browser';
import { Router, Switch, Redirect, withRouter, RouteComponentProps } from 'react-router-dom'; import { Router, Switch, Redirect, withRouter, RouteComponentProps } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { Route } from '@kbn/shared-ux-router'; import { Route } from '@kbn/shared-ux-router';
@ -67,11 +68,13 @@ export const App = (deps: AppDeps) => {
} }
return ( return (
<Router history={deps.history}> <Router history={deps.history}>
<ShareRouter> <CompatRouter>
<AppContextProvider value={deps}> <ShareRouter>
<AppWithoutRouter /> <AppContextProvider value={deps}>
</AppContextProvider> <AppWithoutRouter />
</ShareRouter> </AppContextProvider>
</ShareRouter>
</CompatRouter>
</Router> </Router>
); );
}; };

View file

@ -7,7 +7,8 @@
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import { BrowserRouter as Router, RouteComponentProps } from 'react-router-dom'; import { BrowserRouter as Router } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { Route } from '@kbn/shared-ux-router'; import { Route } from '@kbn/shared-ux-router';
import { EuiPage, EuiText } from '@elastic/eui'; import { EuiPage, EuiText } from '@elastic/eui';
@ -21,18 +22,20 @@ const AlertingExampleApp = (deps: AlertingExampleComponentParams) => {
const { basename } = deps; const { basename } = deps;
return ( return (
<Router basename={basename}> <Router basename={basename}>
<EuiPage> <CompatRouter>
<Route <EuiPage>
path={`/rule/:id`} <Route
render={(props: RouteComponentProps<{ id: string }>) => { path={`/rule/:id`}
return ( render={(props) => {
<EuiText data-test-subj="noop-title"> return (
<h2>View Rule {props.match.params.id}</h2> <EuiText data-test-subj="noop-title">
</EuiText> <h2>View Rule {props.match.params.id}</h2>
); </EuiText>
}} );
/> }}
</EuiPage> />
</EuiPage>
</CompatRouter>
</Router> </Router>
); );
}; };

View file

@ -17,6 +17,7 @@ import {
EuiFlexGroup, EuiFlexGroup,
} from '@elastic/eui'; } from '@elastic/eui';
import { Router } from 'react-router-dom'; import { Router } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import { AppMountParameters, CoreStart } from '@kbn/core/public'; import { AppMountParameters, CoreStart } from '@kbn/core/public';
import { CasesUiStart } from '@kbn/cases-plugin/public'; import { CasesUiStart } from '@kbn/cases-plugin/public';
import { CommentType } from '@kbn/cases-plugin/common'; import { CommentType } from '@kbn/cases-plugin/common';
@ -110,9 +111,11 @@ const CasesFixtureApp: React.FC<{ deps: RenderAppProps }> = ({ deps }) => {
> >
<StyledComponentsThemeProvider> <StyledComponentsThemeProvider>
<Router history={history}> <Router history={history}>
<CasesContext owner={[]} permissions={permissions}> <CompatRouter>
<CasesFixtureAppWithContext cases={cases} /> <CasesContext owner={[]} permissions={permissions}>
</CasesContext> <CasesFixtureAppWithContext cases={cases} />
</CasesContext>
</CompatRouter>
</Router> </Router>
</StyledComponentsThemeProvider> </StyledComponentsThemeProvider>
</KibanaContextProvider> </KibanaContextProvider>

View file

@ -6,6 +6,7 @@
*/ */
import { Router } from 'react-router-dom'; import { Router } from 'react-router-dom';
import { CompatRouter } from 'react-router-dom-v5-compat';
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
@ -77,19 +78,21 @@ const AppRoot = React.memo(
return ( return (
<I18nProvider> <I18nProvider>
<Router history={parameters.history}> <Router history={parameters.history}>
<KibanaContextProvider services={coreStart}> <CompatRouter>
<Provider store={store}> <KibanaContextProvider services={coreStart}>
<Wrapper> <Provider store={store}>
<ResolverWithoutProviders <Wrapper>
databaseDocumentID="" <ResolverWithoutProviders
resolverComponentInstanceID="test" databaseDocumentID=""
indices={[]} resolverComponentInstanceID="test"
shouldUpdate={false} indices={[]}
filters={{}} shouldUpdate={false}
/> filters={{}}
</Wrapper> />
</Provider> </Wrapper>
</KibanaContextProvider> </Provider>
</KibanaContextProvider>
</CompatRouter>
</Router> </Router>
</I18nProvider> </I18nProvider>
); );

113
yarn.lock
View file

@ -1185,7 +1185,7 @@
core-js-pure "^3.25.1" core-js-pure "^3.25.1"
regenerator-runtime "^0.13.10" regenerator-runtime "^0.13.10"
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
version "7.21.0" version "7.21.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673"
integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw== integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==
@ -6779,6 +6779,11 @@
redux-thunk "^2.4.1" redux-thunk "^2.4.1"
reselect "^4.1.5" reselect "^4.1.5"
"@remix-run/router@1.6.3":
version "1.6.3"
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.6.3.tgz#8205baf6e17ef93be35bf62c37d2d594e9be0dad"
integrity sha512-EXJysQ7J3veRECd0kZFQwYYd5sJMcq2O/m60zu1W2l3oVQ9xtub8jTOtYRE0+M2iomyG/W3Ps7+vp2kna0C27Q==
"@samverschueren/stream-to-observable@^0.3.0": "@samverschueren/stream-to-observable@^0.3.0":
version "0.3.0" version "0.3.0"
resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f" resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f"
@ -8606,15 +8611,10 @@
resolved "https://registry.yarnpkg.com/@types/he/-/he-1.1.1.tgz#19e14033c4ee8f1a702c74dcc6182664839ac2b7" resolved "https://registry.yarnpkg.com/@types/he/-/he-1.1.1.tgz#19e14033c4ee8f1a702c74dcc6182664839ac2b7"
integrity sha512-jpzrsR1ns0n3kyWt92QfOUQhIuJGQ9+QGa7M62rO6toe98woQjnsnzjdMtsQXCdvjjmqjS2ZBCC7xKw0cdzU+Q== integrity sha512-jpzrsR1ns0n3kyWt92QfOUQhIuJGQ9+QGa7M62rO6toe98woQjnsnzjdMtsQXCdvjjmqjS2ZBCC7xKw0cdzU+Q==
"@types/history@*": "@types/history@^4.7.9", "@types/history@^4.7.11":
version "4.7.3" version "4.7.11"
resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.3.tgz#856c99cdc1551d22c22b18b5402719affec9839a" resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64"
integrity sha512-cS5owqtwzLN5kY+l+KgKdRJ/Cee8tlmQoGQuIE9tWnSmS3JMKzmxo2HIAk2wODMifGwO20d62xZQLYz+RLfXmw== integrity sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==
"@types/history@^4.7.9":
version "4.7.9"
resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.9.tgz#1cfb6d60ef3822c589f18e70f8b12f9a28ce8724"
integrity sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ==
"@types/hjson@^2.4.2": "@types/hjson@^2.4.2":
version "2.4.2" version "2.4.2"
@ -9216,30 +9216,30 @@
hoist-non-react-statics "^3.3.0" hoist-non-react-statics "^3.3.0"
redux "^4.0.0" redux "^4.0.0"
"@types/react-router-config@^5.0.2": "@types/react-router-config@^5.0.7":
version "5.0.2" version "5.0.7"
resolved "https://registry.yarnpkg.com/@types/react-router-config/-/react-router-config-5.0.2.tgz#4d3b52e71ed363a1976a12321e67b09a99ad6d10" resolved "https://registry.yarnpkg.com/@types/react-router-config/-/react-router-config-5.0.7.tgz#36207a3fe08b271abee62b26993ee932d13cbb02"
integrity sha512-WOSetDV3YPxbkVJAdv/bqExJjmcdCi/vpCJh3NfQOy1X15vHMSiMioXIcGekXDJJYhqGUMDo9e337mh508foAA== integrity sha512-pFFVXUIydHlcJP6wJm7sDii5mD/bCmmAY0wQzq+M+uX7bqS95AQqHZWP1iNMKrWVQSuHIzj5qi9BvrtLX2/T4w==
dependencies: dependencies:
"@types/history" "*" "@types/history" "^4.7.11"
"@types/react" "*"
"@types/react-router" "^5.1.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" "*"
"@types/react-router" "*" "@types/react-router" "*"
"@types/react-router-dom@^5.1.5": "@types/react-router@*", "@types/react-router@^5.1.0", "@types/react-router@^5.1.20":
version "5.1.5" version "5.1.20"
resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.1.5.tgz#7c334a2ea785dbad2b2dcdd83d2cf3d9973da090" resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.20.tgz#88eccaa122a82405ef3efbcaaa5dcdd9f021387c"
integrity sha512-ArBM4B1g3BWLGbaGvwBGO75GNFbLDUthrDojV2vHLih/Tq8M+tgvY1DSwkuNrPSwdp/GUL93WSEpTZs8nVyJLw== integrity sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==
dependencies: dependencies:
"@types/history" "*" "@types/history" "^4.7.11"
"@types/react" "*"
"@types/react-router" "*"
"@types/react-router@*", "@types/react-router@^5.1.7":
version "5.1.7"
resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.7.tgz#e9d12ed7dcfc79187e4d36667745b69a5aa11556"
integrity sha512-2ouP76VQafKjtuc0ShpwUebhHwJo0G6rhahW9Pb8au3tQTjYXd2jta4wv6U2tGLR/I42yuG00+UXjNYY0dTzbg==
dependencies:
"@types/history" "*"
"@types/react" "*" "@types/react" "*"
"@types/react-syntax-highlighter@^15.4.0": "@types/react-syntax-highlighter@^15.4.0":
@ -17528,6 +17528,13 @@ history@^4.9.0:
tiny-warning "^1.0.0" tiny-warning "^1.0.0"
value-equal "^0.4.0" value-equal "^0.4.0"
history@^5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/history/-/history-5.3.0.tgz#1548abaa245ba47992f063a0783db91ef201c73b"
integrity sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==
dependencies:
"@babel/runtime" "^7.7.6"
hjson@3.2.1: hjson@3.2.1:
version "3.2.1" version "3.2.1"
resolved "https://registry.yarnpkg.com/hjson/-/hjson-3.2.1.tgz#20de41dc87fc9a10d1557d0230b0e02afb1b09ac" resolved "https://registry.yarnpkg.com/hjson/-/hjson-3.2.1.tgz#20de41dc87fc9a10d1557d0230b0e02afb1b09ac"
@ -21401,14 +21408,6 @@ min-indent@^1.0.0:
resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.0.tgz#cfc45c37e9ec0d8f0a0ec3dd4ef7f7c3abe39256" resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.0.tgz#cfc45c37e9ec0d8f0a0ec3dd4ef7f7c3abe39256"
integrity sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY= integrity sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY=
mini-create-react-context@^0.4.0:
version "0.4.1"
resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz#072171561bfdc922da08a60c2197a497cc2d1d5e"
integrity sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==
dependencies:
"@babel/runtime" "^7.12.1"
tiny-warning "^1.0.3"
mini-css-extract-plugin@1.1.0: mini-css-extract-plugin@1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-1.1.0.tgz#dcc2f0bfbec660c0bd1200ff7c8f82deec2cc8a6" resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-1.1.0.tgz#dcc2f0bfbec660c0bd1200ff7c8f82deec2cc8a6"
@ -24689,35 +24688,49 @@ react-router-config@^5.1.1:
dependencies: dependencies:
"@babel/runtime" "^7.1.2" "@babel/runtime" "^7.1.2"
react-router-dom@^5.2.0: react-router-dom-v5-compat@^6.12.0:
version "5.2.0" version "6.12.0"
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662" resolved "https://registry.yarnpkg.com/react-router-dom-v5-compat/-/react-router-dom-v5-compat-6.12.0.tgz#d5b1df5dafce6120626e568fb3d827353941c026"
integrity sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA== integrity sha512-ewEx9QaGOPIEGhd7Y43xLBscqab1Et2LjAoCZo65jRB/naJypZpsqqJfzXRZax0PLNHebl/nACDvp3abxx565Q==
dependencies: dependencies:
"@babel/runtime" "^7.1.2" history "^5.3.0"
react-router "6.12.0"
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" history "^4.9.0"
loose-envify "^1.3.1" loose-envify "^1.3.1"
prop-types "^15.6.2" prop-types "^15.6.2"
react-router "5.2.0" react-router "5.3.4"
tiny-invariant "^1.0.2" tiny-invariant "^1.0.2"
tiny-warning "^1.0.0" tiny-warning "^1.0.0"
react-router@5.2.0, react-router@^5.2.0: react-router@5.3.4, react-router@^5.3.4:
version "5.2.0" version "5.3.4"
resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.0.tgz#424e75641ca8747fbf76e5ecca69781aa37ea293" resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.3.4.tgz#8ca252d70fcc37841e31473c7a151cf777887bb5"
integrity sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw== integrity sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==
dependencies: dependencies:
"@babel/runtime" "^7.1.2" "@babel/runtime" "^7.12.13"
history "^4.9.0" history "^4.9.0"
hoist-non-react-statics "^3.1.0" hoist-non-react-statics "^3.1.0"
loose-envify "^1.3.1" loose-envify "^1.3.1"
mini-create-react-context "^0.4.0"
path-to-regexp "^1.7.0" path-to-regexp "^1.7.0"
prop-types "^15.6.2" prop-types "^15.6.2"
react-is "^16.6.0" react-is "^16.6.0"
tiny-invariant "^1.0.2" tiny-invariant "^1.0.2"
tiny-warning "^1.0.0" tiny-warning "^1.0.0"
react-router@6.12.0:
version "6.12.0"
resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.12.0.tgz#1afae9219c24c8611809469d7a386c8023ade39a"
integrity sha512-/tCGtLq9umxRvbYeIx3j94CmpQfue0E3qnetVm9luKhu58cR4t+3O4ZrQXBdXfJrBATOAj+wF/1ihJJQI8AoTw==
dependencies:
"@remix-run/router" "1.6.3"
react-select@^3.2.0: react-select@^3.2.0:
version "3.2.0" version "3.2.0"
resolved "https://registry.yarnpkg.com/react-select/-/react-select-3.2.0.tgz#de9284700196f5f9b5277c5d850a9ce85f5c72fe" resolved "https://registry.yarnpkg.com/react-select/-/react-select-3.2.0.tgz#de9284700196f5f9b5277c5d850a9ce85f5c72fe"
@ -27752,7 +27765,7 @@ tiny-invariant@^1.0.2, tiny-invariant@^1.0.6:
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.0.6.tgz#b3f9b38835e36a41c843a3b0907a5a7b3755de73" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.0.6.tgz#b3f9b38835e36a41c843a3b0907a5a7b3755de73"
integrity sha512-FOyLWWVjG+aC0UqG76V53yAWdXfH8bO6FNmyZOuUrzDzK8DI3/JRY25UD7+g49JWM1LXwymsKERB+DzI0dTEQA== integrity sha512-FOyLWWVjG+aC0UqG76V53yAWdXfH8bO6FNmyZOuUrzDzK8DI3/JRY25UD7+g49JWM1LXwymsKERB+DzI0dTEQA==
tiny-warning@^1.0.0, tiny-warning@^1.0.2, tiny-warning@^1.0.3: tiny-warning@^1.0.0, tiny-warning@^1.0.2:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==