[UX] make route match optional in EnvironmentFilter (#105780) (#105969)

Closes #105757.

Co-authored-by: Dario Gieselaar <dario.gieselaar@elastic.co>
This commit is contained in:
Kibana Machine 2021-07-16 13:07:59 -04:00 committed by GitHub
parent 4463abf202
commit 38f6c18e63
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 47 additions and 13 deletions

View file

@ -158,6 +158,12 @@ describe('createRouter', () => {
router.getParams('/service-map', history.location);
}).toThrowError('No matching route found for /service-map');
});
it('does not throw an error if the given path does not match any routes but is marked as optional', () => {
expect(() => {
router.getParams('/service-map', history.location, true);
}).not.toThrowError();
});
});
describe('matchRoutes', () => {

View file

@ -45,10 +45,12 @@ export function createRouter<TRoutes extends Route[]>(routes: TRoutes): Router<T
const matchRoutes = (...args: any[]) => {
let path: string = args[0];
let location: Location = args[1];
let optional: boolean = args[2];
if (args.length === 1) {
location = args[0] as Location;
path = location.pathname;
optional = args[1];
}
const greedy = path.endsWith('/*') || args.length === 1;
@ -64,6 +66,9 @@ export function createRouter<TRoutes extends Route[]>(routes: TRoutes): Router<T
: findLastIndex(matches, (match) => match.route.path === path);
if (matchIndex === -1) {
if (optional) {
return [];
}
throw new Error(`No matching route found for ${path}`);
}
@ -144,9 +149,11 @@ export function createRouter<TRoutes extends Route[]>(routes: TRoutes): Router<T
link: (path, ...args) => {
return link(path, ...args);
},
getParams: (path, location) => {
const matches = matchRoutes(path, location);
return merge({ path: {}, query: {} }, ...matches.map((match) => match.match.params));
getParams: (...args: any[]) => {
const matches = matchRoutes(...args);
return matches.length
? merge({ path: {}, query: {} }, ...matches.map((match) => match.match.params))
: undefined;
},
matchRoutes: (...args: any[]) => {
return matchRoutes(...args) as any;

View file

@ -125,6 +125,11 @@ export interface Router<TRoutes extends Route[]> {
path: TPath,
location: Location
): OutputOf<TRoutes, TPath>;
getParams<TPath extends PathsOf<TRoutes>, TOptional extends boolean>(
path: TPath,
location: Location,
optional: TOptional
): TOptional extends true ? OutputOf<TRoutes, TPath> | undefined : OutputOf<TRoutes, TPath>;
link<TPath extends PathsOf<TRoutes>>(
path: TPath,
...args: TypeAsArgs<TypeOf<TRoutes, TPath>>

View file

@ -9,9 +9,9 @@
import { useLocation } from 'react-router-dom';
import { useRouter } from './use_router';
export function useParams(path: string) {
export function useParams(path: string, optional: boolean = false) {
const router = useRouter();
const location = useLocation();
return router.getParams(path as never, location);
return router.getParams(path as never, location, optional);
}

View file

@ -10,7 +10,8 @@ import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
import { AppMountParameters, CoreStart } from 'kibana/public';
import React from 'react';
import ReactDOM from 'react-dom';
import { Route, Router } from 'react-router-dom';
import { Route as ReactRouterRoute } from 'react-router-dom';
import { RouterProvider, createRouter } from '@kbn/typed-react-router-config';
import { DefaultTheme, ThemeProvider } from 'styled-components';
import { i18n } from '@kbn/i18n';
import type { ObservabilityRuleTypeRegistry } from '../../../observability/public';
@ -66,13 +67,15 @@ function UxApp() {
})}
>
<div data-test-subj="csmMainContainer" role="main">
<Route component={ScrollToTopOnPathChange} />
<ReactRouterRoute component={ScrollToTopOnPathChange} />
<RumHome />
</div>
</ThemeProvider>
);
}
const uxRouter = createRouter([]);
export function UXAppRoot({
appMountParameters,
core,
@ -107,12 +110,12 @@ export function UXAppRoot({
services={{ ...core, ...plugins, embeddable, data }}
>
<i18nCore.Context>
<Router history={history}>
<RouterProvider history={history} router={uxRouter}>
<UrlParamsProvider>
<UxApp />
<UXActionMenu appMountParameters={appMountParameters} />
</UrlParamsProvider>
</Router>
</RouterProvider>
</i18nCore.Context>
</KibanaContextProvider>
</ApmPluginContext.Provider>

View file

@ -64,12 +64,15 @@ function getOptions(environments: string[]) {
export function EnvironmentFilter() {
const history = useHistory();
const location = useLocation();
const { path } = useApmParams('/*');
const apmParams = useApmParams('/*', true);
const { urlParams } = useUrlParams();
const { environment, start, end } = urlParams;
const { environments, status = 'loading' } = useEnvironmentsFetcher({
serviceName: 'serviceName' in path ? path.serviceName : undefined,
serviceName:
apmParams && 'serviceName' in apmParams.path
? apmParams.path.serviceName
: undefined,
start,
end,
});

View file

@ -8,8 +8,18 @@
import { OutputOf, PathsOf, useParams } from '@kbn/typed-react-router-config';
import { ApmRoutes } from '../components/routing/apm_route_config';
export function useApmParams<TPath extends PathsOf<ApmRoutes>>(
path: TPath,
optional: true
): OutputOf<ApmRoutes, TPath> | undefined;
export function useApmParams<TPath extends PathsOf<ApmRoutes>>(
path: TPath
): OutputOf<ApmRoutes, TPath> {
return useParams(path as never);
): OutputOf<ApmRoutes, TPath>;
export function useApmParams(
path: string,
optional?: true
): OutputOf<ApmRoutes, PathsOf<ApmRoutes>> | undefined {
return useParams(path, optional);
}