Skip to content

Commit

Permalink
[UX] make route match optional in EnvironmentFilter (elastic#105780)
Browse files Browse the repository at this point in the history
  • Loading branch information
dgieselaar authored and kibanamachine committed Jul 16, 2021
1 parent 21a66ff commit 87c8c4a
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
13 changes: 10 additions & 3 deletions packages/kbn-typed-react-router-config/src/create_router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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}`);
}

Expand Down Expand Up @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions packages/kbn-typed-react-router-config/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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>>
Expand Down
4 changes: 2 additions & 2 deletions packages/kbn-typed-react-router-config/src/use_params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
11 changes: 7 additions & 4 deletions x-pack/plugins/apm/public/application/uxApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
});
Expand Down
14 changes: 12 additions & 2 deletions x-pack/plugins/apm/public/hooks/use_apm_params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

0 comments on commit 87c8c4a

Please sign in to comment.