diff --git a/packages/kbn-typed-react-router-config/src/create_router.test.tsx b/packages/kbn-typed-react-router-config/src/create_router.test.tsx index 9837d45ddd869..d29079f37ec12 100644 --- a/packages/kbn-typed-react-router-config/src/create_router.test.tsx +++ b/packages/kbn-typed-react-router-config/src/create_router.test.tsx @@ -10,16 +10,13 @@ import * as t from 'io-ts'; import { toNumberRt } from '@kbn/io-ts-utils'; import { createRouter } from './create_router'; import { createMemoryHistory } from 'history'; -import { route } from './route'; describe('createRouter', () => { - const routes = route([ - { - path: '/', + const routes = { + '/': { element: <>, - children: [ - { - path: '/', + children: { + '/': { element: <>, params: t.type({ query: t.type({ @@ -32,31 +29,27 @@ describe('createRouter', () => { rangeFrom: 'now-30m', }, }, - children: [ - { - path: '/services/{serviceName}/errors', + children: { + '/services/{serviceName}/errors': { element: <>, params: t.type({ path: t.type({ serviceName: t.string, }), }), - children: [ - { - path: '/services/{serviceName}/errors/{groupId}', + children: { + '/services/{serviceName}/errors/{groupId}': { element: <>, params: t.type({ path: t.type({ groupId: t.string }), }), }, - { - path: '/services/{serviceName}/errors', + '/services/{serviceName}/errors': { element: <>, }, - ], + }, }, - { - path: '/services', + '/services': { element: <>, params: t.type({ query: t.type({ @@ -64,13 +57,11 @@ describe('createRouter', () => { }), }), }, - { - path: '/services/{serviceName}', + '/services/{serviceName}': { element: <>, - children: [ - { + children: { + '/services/{serviceName}': { element: <>, - path: '/services/{serviceName}', params: t.type({ path: t.type({ serviceName: t.string, @@ -81,10 +72,9 @@ describe('createRouter', () => { }), }), }, - ], + }, }, - { - path: '/traces', + '/traces': { element: <>, params: t.type({ query: t.type({ @@ -93,8 +83,7 @@ describe('createRouter', () => { }), }), }, - { - path: '/service-map', + '/service-map': { element: <>, params: t.type({ query: t.type({ @@ -102,11 +91,11 @@ describe('createRouter', () => { }), }), }, - ], + }, }, - ], + }, }, - ] as const); + }; let history = createMemoryHistory(); const router = createRouter(routes); diff --git a/packages/kbn-typed-react-router-config/src/create_router.ts b/packages/kbn-typed-react-router-config/src/create_router.ts index 27a4f1dd5de02..494540005224a 100644 --- a/packages/kbn-typed-react-router-config/src/create_router.ts +++ b/packages/kbn-typed-react-router-config/src/create_router.ts @@ -15,26 +15,29 @@ import { } from 'react-router-config'; import qs from 'query-string'; import { findLastIndex, merge, compact } from 'lodash'; -import { deepExactRt, mergeRt } from '@kbn/io-ts-utils'; -import { FlattenRoutesOf, Route, Router } from './types'; +import { mergeRt, deepExactRt } from '@kbn/io-ts-utils'; +import { FlattenRoutesOf, Route, RouteWithPath, Router, RouteMap } from './types'; function toReactRouterPath(path: string) { return path.replace(/(?:{([^\/]+)})/g, ':$1'); } -export function createRouter(routes: TRoutes): Router { +export function createRouter(routes: TRoutes): Router { const routesByReactRouterConfig = new Map(); const reactRouterConfigsByRoute = new Map(); - const reactRouterConfigs = routes.map((route) => toReactRouterConfigRoute(route)); + const reactRouterConfigs = Object.entries(routes).map(([path, route]) => + toReactRouterConfigRoute({ ...route, path }) + ); - function toReactRouterConfigRoute(route: Route): ReactRouterConfig { + function toReactRouterConfigRoute(route: RouteWithPath): ReactRouterConfig { const reactRouterConfig: ReactRouterConfig = { component: () => route.element, routes: - (route.children as Route[] | undefined)?.map((child) => toReactRouterConfigRoute(child)) ?? - [], - exact: !route.children?.length, + Object.entries((route.children as RouteMap | undefined) ?? {})?.map(([path, child]) => + toReactRouterConfigRoute({ ...child, path }) + ) ?? [], + exact: !route.children || Object.values(route.children).length === 0, path: toReactRouterPath(route.path), }; diff --git a/packages/kbn-typed-react-router-config/src/index.ts b/packages/kbn-typed-react-router-config/src/index.ts index b58c70998901c..9ba68aed7e3b2 100644 --- a/packages/kbn-typed-react-router-config/src/index.ts +++ b/packages/kbn-typed-react-router-config/src/index.ts @@ -8,10 +8,8 @@ export * from './create_router'; export * from './types'; export * from './outlet'; -export * from './route'; export * from './route_renderer'; export * from './router_provider'; -export * from './unconst'; export * from './use_current_route'; export * from './use_match_routes'; export * from './use_params'; diff --git a/packages/kbn-typed-react-router-config/src/route.ts b/packages/kbn-typed-react-router-config/src/route.ts deleted file mode 100644 index b9b228d1009e2..0000000000000 --- a/packages/kbn-typed-react-router-config/src/route.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ -import { Route } from './types'; -import { Unconst, unconst } from './unconst'; - -export function route( - r: TRoute -): Unconst { - return unconst(r); -} diff --git a/packages/kbn-typed-react-router-config/src/router_provider.tsx b/packages/kbn-typed-react-router-config/src/router_provider.tsx index 657df9e9fc592..ef06964f230be 100644 --- a/packages/kbn-typed-react-router-config/src/router_provider.tsx +++ b/packages/kbn-typed-react-router-config/src/router_provider.tsx @@ -8,7 +8,7 @@ import { History } from 'history'; import React from 'react'; import { Router as ReactRouter } from 'react-router-dom'; -import { Route, Router } from './types'; +import { RouteMap, Router } from './types'; import { RouterContextProvider } from './use_router'; export function RouterProvider({ @@ -16,7 +16,7 @@ export function RouterProvider({ router, history, }: { - router: Router; + router: Router; history: History; children: React.ReactNode; }) { diff --git a/packages/kbn-typed-react-router-config/src/types/index.ts b/packages/kbn-typed-react-router-config/src/types/index.ts index 97b58ce5a700f..a5121ba0d72c9 100644 --- a/packages/kbn-typed-react-router-config/src/types/index.ts +++ b/packages/kbn-typed-react-router-config/src/types/index.ts @@ -9,17 +9,31 @@ import { Location } from 'history'; import * as t from 'io-ts'; import { ReactElement } from 'react'; -import { RequiredKeys, ValuesType } from 'utility-types'; -// import { unconst } from '../unconst'; +import { RequiredKeys, ValuesType, UnionToIntersection } from 'utility-types'; import { NormalizePath } from './utils'; -// type PathsOfRoute = -// | TRoute['path'] -// | (TRoute extends { children: Route[] } -// ? AppendPath | PathsOf -// : never); +export type PathsOf = string & + ValuesType<{ + [key in keyof TRouteMap]: + | key + | (TRouteMap[key] extends { children: RouteMap } + ? AppendPath | PathsOf + : never); + }>; -export type PathsOf = keyof MapRoutes & string; +export type RouteMap = Record; + +export interface Route { + element: ReactElement; + children?: RouteMap; + params?: t.Type; + defaults?: Record>; + pre?: ReactElement; +} + +export interface RouteWithPath extends Route { + path: string; +} export interface RouteMatch { route: TRoute; @@ -35,91 +49,55 @@ export interface RouteMatch { }; } -type ToRouteMatch = TRoutes extends [] - ? [] - : TRoutes extends [Route] +type ToRouteMatch = TRoutes extends [Route] ? [RouteMatch] - : TRoutes extends [Route, ...infer TTail] - ? TTail extends Route[] - ? [RouteMatch, ...ToRouteMatch] - : [] - : []; - -type UnwrapRouteMap = TRoute extends { - parents: Route[]; -} - ? ToRouteMatch<[...TRoute['parents'], Omit]> - : ToRouteMatch<[Omit]>; - -export type Match = MapRoutes extends { - [key in TPath]: Route; -} - ? UnwrapRouteMap[TPath]> - : []; - -interface PlainRoute { - path: string; - element: ReactElement; - children?: PlainRoute[]; - params?: t.Type; - defaults?: Record>; - pre?: ReactElement; -} - -interface ReadonlyPlainRoute { - readonly path: string; - readonly element: ReactElement; - readonly children?: readonly ReadonlyPlainRoute[]; - readonly params?: t.Type; - readonly defaults?: Record>; - pre?: ReactElement; -} + : TRoutes extends [Route, ...infer TNextRoutes] + ? [RouteMatch, ...(TNextRoutes extends Route[] ? ToRouteMatch : [])] + : TRoutes extends [] + ? [] + : never; -export type Route = PlainRoute | ReadonlyPlainRoute; +export type Match = MapRoutes[TPath]; -interface DefaultOutput { +export interface DefaultOutput { path: {}; query: {}; } -type OutputOfRouteMatch = TRouteMatch extends { - route: { params: t.Type }; +type OutputOfRoute = TRoute extends { + params: t.Type; } - ? t.OutputOf - : DefaultOutput; + ? t.OutputOf + : {}; -type OutputOfMatches = TRouteMatches extends [RouteMatch] - ? OutputOfRouteMatch - : TRouteMatches extends [RouteMatch, ...infer TNextRouteMatches] - ? OutputOfRouteMatch & - (TNextRouteMatches extends RouteMatch[] ? OutputOfMatches : DefaultOutput) - : TRouteMatches extends RouteMatch[] - ? OutputOfRouteMatch> - : DefaultOutput; +type OutputOfRoutes = TRoutes extends [Route] + ? OutputOfRoute + : TRoutes extends [Route, ...infer TNextRoutes] + ? OutputOfRoute & (TNextRoutes extends Route[] ? OutputOfRoutes : {}) + : {}; -export type OutputOf> = OutputOfMatches< +export type OutputOf> = OutputOfRoutes< Match > & DefaultOutput; -type TypeOfRouteMatch = TRouteMatch extends { - route: { params: t.Type }; +type TypeOfRoute = TRoute extends { + params: t.Type; } - ? t.TypeOf + ? t.TypeOf : {}; -type TypeOfMatches = TRouteMatches extends [RouteMatch] - ? TypeOfRouteMatch - : TRouteMatches extends [RouteMatch, ...infer TNextRouteMatches] - ? TypeOfRouteMatch & - (TNextRouteMatches extends RouteMatch[] ? TypeOfMatches : {}) +type TypeOfRoutes = TRoutes extends [Route] + ? TypeOfRoute + : TRoutes extends [Route, ...infer TNextRoutes] + ? TypeOfRoute & (TNextRoutes extends Route[] ? TypeOfRoutes : {}) : {}; export type TypeOf< - TRoutes extends Route[], + TRoutes extends RouteMap, TPath extends PathsOf, TWithDefaultOutput extends boolean = true -> = TypeOfMatches> & (TWithDefaultOutput extends true ? DefaultOutput : {}); +> = TypeOfRoutes> & (TWithDefaultOutput extends true ? DefaultOutput : {}); export type TypeAsArgs = keyof TObject extends never ? [] @@ -127,16 +105,18 @@ export type TypeAsArgs = keyof TObject extends never ? [TObject] | [] : [TObject]; -export type FlattenRoutesOf = Array< - Omit>, 'parents'> +export type FlattenRoutesOf = Array< + ValuesType<{ + [key in keyof MapRoutes]: ValuesType[key]>; + }> >; -export interface Router { +export interface Router { matchRoutes>( path: TPath, location: Location - ): Match; - matchRoutes(location: Location): Match>; + ): ToRouteMatch>; + matchRoutes(location: Location): ToRouteMatch>>; getParams>( path: TPath, location: Location @@ -179,11 +159,11 @@ type MaybeUnion, U extends Record> = [key in keyof U]: key extends keyof T ? T[key] | U[key] : U[key]; }; -type MapRoute = MaybeUnion< +type MapRoute = MaybeUnion< { - [key in TRoute['path']]: TRoute & { parents: TParents }; + [key in TRoute['path']]: [...TParents, TRoute]; }, - TRoute extends { children: Route[] } + TRoute extends { children: RouteMap } ? MaybeUnion< MapRoutes, { @@ -195,107 +175,41 @@ type MapRoute = MaybeUnion< : {} >; -type MapRoutes = TRoutes extends [Route] - ? MapRoute - : TRoutes extends [Route, Route] - ? MapRoute & MapRoute - : TRoutes extends [Route, Route, Route] - ? MapRoute & MapRoute & MapRoute - : TRoutes extends [Route, Route, Route, Route] - ? MapRoute & - MapRoute & - MapRoute & - MapRoute - : TRoutes extends [Route, Route, Route, Route, Route] - ? MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute - : TRoutes extends [Route, Route, Route, Route, Route, Route] - ? MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute - : TRoutes extends [Route, Route, Route, Route, Route, Route, Route] - ? MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute - : TRoutes extends [Route, Route, Route, Route, Route, Route, Route, Route] - ? MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute - : TRoutes extends [Route, Route, Route, Route, Route, Route, Route, Route, Route] - ? MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute - : TRoutes extends [Route, Route, Route, Route, Route, Route, Route, Route, Route, Route] - ? MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute - : TRoutes extends [Route, Route, Route, Route, Route, Route, Route, Route, Route, Route, Route] - ? MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute & - MapRoute - : {}; +type FromRouteMap< + TRouteMap extends RouteMap, + TParents extends RouteWithPath[] = [] +> = UnionToIntersection< + ValuesType<{ + [key in keyof TRouteMap]: MapRoute; + }> +>; + +type MapRoutes = FromRouteMap< + TRouteMap, + TParents +> extends Record + ? FromRouteMap + : never; // const element = null as any; -// const routes = unconst([ -// { -// path: '/link-to/transaction/{transactionId}', +// const routes = { +// '/link-to/transaction/{transactionId}': { // element, // }, -// { -// path: '/link-to/trace/{traceId}', +// '/link-to/trace/{traceId}': { // element, // }, -// { -// path: '/', +// '/': { // element, -// children: [ -// { -// path: '/settings', +// children: { +// '/settings': { // element, -// children: [ -// { -// path: '/settings/agent-configuration', +// children: { +// '/settings/agent-configuration': { // element, // }, -// { -// path: '/settings/agent-configuration/create', +// '/settings/agent-configuration/create': { // element, // params: t.partial({ // query: t.partial({ @@ -303,8 +217,7 @@ type MapRoutes = TRoutes extends [Route] // }), // }), // }, -// { -// path: '/settings/agent-configuration/edit', +// '/settings/agent-configuration/edit': { // element, // params: t.partial({ // query: t.partial({ @@ -312,34 +225,27 @@ type MapRoutes = TRoutes extends [Route] // }), // }), // }, -// { -// path: '/settings/apm-indices', +// '/settings/apm-indices': { // element, // }, -// { -// path: '/settings/custom-links', +// '/settings/custom-links': { // element, // }, -// { -// path: '/settings/schema', +// '/settings/schema': { // element, // }, -// { -// path: '/settings/anomaly-detection', +// '/settings/anomaly-detection': { // element, // }, -// { -// path: '/settings/agent-keys', +// '/settings/agent-keys': { // element, // }, -// { -// path: '/settings', +// '/settings': { // element, // }, -// ], +// }, // }, -// { -// path: '/services/:serviceName', +// '/services/:serviceName': { // element, // params: t.intersection([ // t.type({ @@ -360,29 +266,23 @@ type MapRoutes = TRoutes extends [Route] // }), // }), // ]), -// children: [ -// { -// path: '/services/:serviceName/overview', +// children: { +// '/services/:serviceName/overview': { // element, // }, -// { -// path: '/services/:serviceName/transactions', +// '/services/:serviceName/transactions': { // element, // }, -// { -// path: '/services/:serviceName/transactions/view', +// '/services/:serviceName/transactions/view': { // element, // }, -// { -// path: '/services/:serviceName/dependencies', +// '/services/:serviceName/dependencies': { // element, // }, -// { -// path: '/services/:serviceName/errors', +// '/services/:serviceName/errors': { // element, -// children: [ -// { -// path: '/services/:serviceName/errors/:groupId', +// children: { +// '/services/:serviceName/errors/:groupId': { // element, // params: t.type({ // path: t.type({ @@ -390,8 +290,7 @@ type MapRoutes = TRoutes extends [Route] // }), // }), // }, -// { -// path: '/services/:serviceName/errors', +// '/services/:serviceName/errors': { // element, // params: t.partial({ // query: t.partial({ @@ -402,46 +301,37 @@ type MapRoutes = TRoutes extends [Route] // }), // }), // }, -// ], +// }, // }, -// { -// path: '/services/:serviceName/metrics', +// '/services/:serviceName/metrics': { // element, // }, -// { -// path: '/services/:serviceName/nodes', +// '/services/:serviceName/nodes': { // element, -// children: [ -// { -// path: '/services/{serviceName}/nodes/{serviceNodeName}/metrics', +// children: { +// '/services/{serviceName}/nodes/{serviceNodeName}/metrics': { // element, // }, -// { -// path: '/services/:serviceName/nodes', +// '/services/:serviceName/nodes': { // element, // }, -// ], +// }, // }, -// { -// path: '/services/:serviceName/service-map', +// '/services/:serviceName/service-map': { // element, // }, -// { -// path: '/services/:serviceName/logs', +// '/services/:serviceName/logs': { // element, // }, -// { -// path: '/services/:serviceName/profiling', +// '/services/:serviceName/profiling': { // element, // }, -// { -// path: '/services/:serviceName', +// '/services/:serviceName': { // element, // }, -// ], +// }, // }, -// { -// path: '/', +// '/': { // element, // params: t.partial({ // query: t.partial({ @@ -449,55 +339,47 @@ type MapRoutes = TRoutes extends [Route] // rangeTo: t.string, // }), // }), -// children: [ -// { -// path: '/services', +// children: { +// '/services': { // element, // }, -// { -// path: '/traces', +// '/traces': { // element, // }, -// { -// path: '/service-map', +// '/service-map': { // element, // }, -// { -// path: '/backends', +// '/backends': { // element, -// children: [ -// { -// path: '/backends/{backendName}/overview', +// children: { +// '/backends/{backendName}/overview': { // element, // }, -// { -// path: '/backends/overview', +// '/backends/overview': { // element, // }, -// { -// path: '/backends', +// '/backends': { // element, // }, -// ], +// }, // }, -// { -// path: '/', +// '/': { // element, // }, -// ], +// }, // }, -// ], +// }, // }, -// ] as const); +// }; // type Routes = typeof routes; -// type Mapped = keyof MapRoutes; +// type Mapped = MapRoutes; // type Paths = PathsOf; -// type Bar = ValuesType>['route']['path']; +// type Bar = Match; // type Foo = OutputOf; -// // type Baz = OutputOf; +// type Baz = OutputOf; // const { path }: Foo = {} as any; @@ -505,4 +387,7 @@ type MapRoutes = TRoutes extends [Route] // return {} as any; // } -// // const params = _useApmParams('/services/:serviceName/nodes/*'); +// const { +// path: { serviceName }, +// query: { comparisonType }, +// } = _useApmParams('/services/:serviceName/nodes/*'); diff --git a/packages/kbn-typed-react-router-config/src/unconst.ts b/packages/kbn-typed-react-router-config/src/unconst.ts deleted file mode 100644 index d10c8290e20e9..0000000000000 --- a/packages/kbn-typed-react-router-config/src/unconst.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ -import * as t from 'io-ts'; -import { DeepReadonly } from 'utility-types'; - -export type MaybeConst = TObject extends [object] - ? [DeepReadonly | TObject] - : TObject extends [object, ...infer TTail] - ? [DeepReadonly | TObject, ...(TTail extends object[] ? MaybeConst : [])] - : TObject extends object[] - ? DeepReadonly - : TObject extends object - ? [DeepReadonly | TObject] - : []; - -export type Unconst = T extends React.ReactElement - ? React.ReactElement - : T extends t.Type - ? T - : T extends readonly [any] - ? [Unconst] - : T extends readonly [any, any] - ? [Unconst, Unconst] - : T extends readonly [any, any, any] - ? [Unconst, Unconst, Unconst] - : T extends readonly [any, any, any, any] - ? [Unconst, Unconst, Unconst, Unconst] - : T extends readonly [any, any, any, any, any] - ? [Unconst, Unconst, Unconst, Unconst, Unconst] - : T extends readonly [any, any, any, any, any, any] - ? [Unconst, Unconst, Unconst, Unconst, Unconst, Unconst] - : T extends readonly [any, any, any, any, any, any, any] - ? [ - Unconst, - Unconst, - Unconst, - Unconst, - Unconst, - Unconst, - Unconst - ] - : T extends readonly [any, any, any, any, any, any, any, any] - ? [ - Unconst, - Unconst, - Unconst, - Unconst, - Unconst, - Unconst, - Unconst, - Unconst - ] - : T extends readonly [any, any, any, any, any, any, any, any, any] - ? [ - Unconst, - Unconst, - Unconst, - Unconst, - Unconst, - Unconst, - Unconst, - Unconst, - Unconst - ] - : T extends readonly [any, any, any, any, any, any, any, any, any, any] - ? [ - Unconst, - Unconst, - Unconst, - Unconst, - Unconst, - Unconst, - Unconst, - Unconst, - Unconst, - Unconst - ] - : T extends readonly [infer U, ...infer V] - ? [Unconst, ...Unconst] - : T extends Record - ? { -readonly [key in keyof T]: Unconst } - : T; - -export function unconst(value: T): Unconst { - return value as Unconst; -} diff --git a/packages/kbn-typed-react-router-config/src/use_router.tsx b/packages/kbn-typed-react-router-config/src/use_router.tsx index c78e85650f26d..f3a6c396d37d4 100644 --- a/packages/kbn-typed-react-router-config/src/use_router.tsx +++ b/packages/kbn-typed-react-router-config/src/use_router.tsx @@ -7,19 +7,19 @@ */ import React, { createContext, useContext } from 'react'; -import { Route, Router } from './types'; +import { RouteMap, Router } from './types'; -const RouterContext = createContext | undefined>(undefined); +const RouterContext = createContext | undefined>(undefined); export const RouterContextProvider = ({ router, children, }: { - router: Router; + router: Router; children: React.ReactNode; }) => {children}; -export function useRouter(): Router { +export function useRouter(): Router { const router = useContext(RouterContext); if (!router) { diff --git a/x-pack/plugins/apm/public/application/uxApp.tsx b/x-pack/plugins/apm/public/application/uxApp.tsx index fa29f04fccbad..f9883ca348c51 100644 --- a/x-pack/plugins/apm/public/application/uxApp.tsx +++ b/x-pack/plugins/apm/public/application/uxApp.tsx @@ -90,7 +90,7 @@ function UxApp() { ); } -const uxRouter = createRouter([]); +const uxRouter = createRouter({}); export function UXAppRoot({ appMountParameters, diff --git a/x-pack/plugins/apm/public/components/app/backend_inventory/index.tsx b/x-pack/plugins/apm/public/components/app/backend_inventory/index.tsx index 433d187bda0b3..f749927826231 100644 --- a/x-pack/plugins/apm/public/components/app/backend_inventory/index.tsx +++ b/x-pack/plugins/apm/public/components/app/backend_inventory/index.tsx @@ -19,7 +19,6 @@ export function BackendInventory() { const { query: { environment }, } = useApmParams('/backends'); - const kueryBarBoolFilter = getKueryBarBoolFilter({ environment, }); diff --git a/x-pack/plugins/apm/public/components/routing/apm_route_config.tsx b/x-pack/plugins/apm/public/components/routing/apm_route_config.tsx index 7e6ee849fdb0b..daab3003b18dc 100644 --- a/x-pack/plugins/apm/public/components/routing/apm_route_config.tsx +++ b/x-pack/plugins/apm/public/components/routing/apm_route_config.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { createRouter, Outlet, route } from '@kbn/typed-react-router-config'; +import { createRouter, Outlet } from '@kbn/typed-react-router-config'; import * as t from 'io-ts'; import React from 'react'; import { Breadcrumb } from '../app/breadcrumb'; @@ -19,9 +19,8 @@ import { settings } from './settings'; * The array of route definitions to be used when the application * creates the routes. */ -const apmRoutes = route([ - { - path: '/link-to/transaction/{transactionId}', +const apmRoutes = { + '/link-to/transaction/{transactionId}': { element: , params: t.intersection([ t.type({ @@ -37,8 +36,7 @@ const apmRoutes = route([ }), ]), }, - { - path: '/link-to/trace/{traceId}', + '/link-to/trace/{traceId}': { element: , params: t.intersection([ t.type({ @@ -54,16 +52,19 @@ const apmRoutes = route([ }), ]), }, - { - path: '/', + '/': { element: ( ), - children: [settings, serviceDetail, home], + children: { + ...settings, + ...serviceDetail, + ...home, + }, }, -] as const); +}; export type ApmRoutes = typeof apmRoutes; diff --git a/x-pack/plugins/apm/public/components/routing/home/index.tsx b/x-pack/plugins/apm/public/components/routing/home/index.tsx index 25a68592d2b11..efde391467dfd 100644 --- a/x-pack/plugins/apm/public/components/routing/home/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/home/index.tsx @@ -30,15 +30,26 @@ function page({ path: TPath; element: React.ReactElement; title: string; -}): { path: TPath; element: React.ReactElement } { +}): Record< + TPath, + { + element: React.ReactElement; + } +> { return { - path, - element: ( - - {element} - - ), - }; + [path]: { + element: ( + + {element} + + ), + }, + } as Record< + TPath, + { + element: React.ReactElement; + } + >; } export const ServiceInventoryTitle = i18n.translate( @@ -56,88 +67,85 @@ export const DependenciesInventoryTitle = i18n.translate( ); export const home = { - path: '/', - element: , - params: t.type({ - query: t.intersection([ - environmentRt, - t.type({ - rangeFrom: t.string, - rangeTo: t.string, - kuery: t.string, - }), - t.partial({ - refreshPaused: t.union([t.literal('true'), t.literal('false')]), - refreshInterval: t.string, - comparisonEnabled: toBooleanRt, - comparisonType: comparisonTypeRt, - }), - ]), - }), - defaults: { - query: { - environment: ENVIRONMENT_ALL.value, - kuery: '', - }, - }, - children: [ - page({ - path: '/services', - title: ServiceInventoryTitle, - element: , + '/': { + element: , + params: t.type({ + query: t.intersection([ + environmentRt, + t.type({ + rangeFrom: t.string, + rangeTo: t.string, + kuery: t.string, + }), + t.partial({ + refreshPaused: t.union([t.literal('true'), t.literal('false')]), + refreshInterval: t.string, + comparisonEnabled: toBooleanRt, + comparisonType: comparisonTypeRt, + }), + ]), }), - page({ - path: '/traces', - title: i18n.translate('xpack.apm.views.traceOverview.title', { - defaultMessage: 'Traces', + defaults: { + query: { + environment: ENVIRONMENT_ALL.value, + kuery: '', + }, + }, + children: { + ...page({ + path: '/services', + title: ServiceInventoryTitle, + element: , }), - element: , - }), - page({ - path: '/service-map', - title: i18n.translate('xpack.apm.views.serviceMap.title', { - defaultMessage: 'Service Map', + ...page({ + path: '/traces', + title: i18n.translate('xpack.apm.views.traceOverview.title', { + defaultMessage: 'Traces', + }), + element: , }), - element: , - }), - { - path: '/backends', - element: , - params: t.partial({ - query: t.partial({ - comparisonEnabled: toBooleanRt, - comparisonType: comparisonTypeRt, + ...page({ + path: '/service-map', + title: i18n.translate('xpack.apm.views.serviceMap.title', { + defaultMessage: 'Service Map', }), + element: , }), - children: [ - { - path: '/backends/{backendName}/overview', - element: , - params: t.type({ - path: t.type({ - backendName: t.string, - }), + '/backends': { + element: , + params: t.partial({ + query: t.partial({ + comparisonEnabled: toBooleanRt, + comparisonType: comparisonTypeRt, }), - }, - { - path: '/backends/overview', - element: , - params: t.type({ - query: t.type({ - backendName: t.string, + }), + children: { + '/backends/{backendName}/overview': { + element: , + params: t.type({ + path: t.type({ + backendName: t.string, + }), + }), + }, + '/backends/overview': { + element: , + params: t.type({ + query: t.type({ + backendName: t.string, + }), }), + }, + ...page({ + path: '/backends', + title: DependenciesInventoryTitle, + element: , }), }, - page({ - path: '/backends', - title: DependenciesInventoryTitle, - element: , - }), - ], + }, + '/': { + element: , + }, }, - { - path: '/', - element: , - }, - ], -} as const; + }, +}; diff --git a/x-pack/plugins/apm/public/components/routing/service_detail/index.tsx b/x-pack/plugins/apm/public/components/routing/service_detail/index.tsx index f8206f273abd4..6514c8288be0e 100644 --- a/x-pack/plugins/apm/public/components/routing/service_detail/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/service_detail/index.tsx @@ -29,14 +29,12 @@ import { ServiceDependencies } from '../../app/service_dependencies'; import { ServiceLogs } from '../../app/service_logs'; import { InfraOverview } from '../../app/infra_overview'; -function page({ - path, +function page({ title, tab, element, searchBarOptions, }: { - path: TPath; title: string; tab: React.ComponentProps['selectedTab']; element: React.ReactElement; @@ -48,10 +46,8 @@ function page({ }; }): { element: React.ReactElement; - path: TPath; } { return { - path, element: ( ({ {element} ), - } as any; + }; } export const serviceDetail = { - path: '/services/{serviceName}', - element: , - params: t.intersection([ - t.type({ - path: t.type({ - serviceName: t.string, - }), - }), - t.type({ - query: t.intersection([ - environmentRt, - t.type({ - rangeFrom: t.string, - rangeTo: t.string, - kuery: t.string, - }), - t.partial({ - comparisonEnabled: toBooleanRt, - comparisonType: comparisonTypeRt, - latencyAggregationType: t.string, - transactionType: t.string, - refreshPaused: t.union([t.literal('true'), t.literal('false')]), - refreshInterval: t.string, + '/services/{serviceName}': { + element: , + params: t.intersection([ + t.type({ + path: t.type({ + serviceName: t.string, }), - ]), - }), - ]), - defaults: { - query: { - kuery: '', - environment: ENVIRONMENT_ALL.value, - }, - }, - children: [ - page({ - path: '/services/{serviceName}/overview', - element: , - tab: 'overview', - title: i18n.translate('xpack.apm.views.overview.title', { - defaultMessage: 'Overview', }), - searchBarOptions: { - showTransactionTypeSelector: true, - showTimeComparison: true, + t.type({ + query: t.intersection([ + environmentRt, + t.type({ + rangeFrom: t.string, + rangeTo: t.string, + kuery: t.string, + }), + t.partial({ + comparisonEnabled: toBooleanRt, + comparisonType: comparisonTypeRt, + latencyAggregationType: t.string, + transactionType: t.string, + refreshPaused: t.union([t.literal('true'), t.literal('false')]), + refreshInterval: t.string, + }), + ]), + }), + ]), + defaults: { + query: { + kuery: '', + environment: ENVIRONMENT_ALL.value, }, - }), - { - ...page({ - path: '/services/{serviceName}/transactions', - tab: 'transactions', - title: i18n.translate('xpack.apm.views.transactions.title', { - defaultMessage: 'Transactions', + }, + children: { + '/services/{serviceName}/overview': page({ + element: , + tab: 'overview', + title: i18n.translate('xpack.apm.views.overview.title', { + defaultMessage: 'Overview', }), - element: , searchBarOptions: { showTransactionTypeSelector: true, showTimeComparison: true, }, }), - children: [ - { - path: '/services/{serviceName}/transactions/view', - element: , - params: t.type({ - query: t.intersection([ - t.type({ - transactionName: t.string, - }), - t.partial({ - traceId: t.string, - transactionId: t.string, - comparisonEnabled: toBooleanRt, - comparisonType: comparisonTypeRt, - }), - ]), + '/services/{serviceName}/transactions': { + ...page({ + tab: 'transactions', + title: i18n.translate('xpack.apm.views.transactions.title', { + defaultMessage: 'Transactions', }), + element: , + searchBarOptions: { + showTransactionTypeSelector: true, + showTimeComparison: true, + }, + }), + children: { + '/services/{serviceName}/transactions/view': { + element: , + params: t.type({ + query: t.intersection([ + t.type({ + transactionName: t.string, + }), + t.partial({ + traceId: t.string, + transactionId: t.string, + comparisonEnabled: toBooleanRt, + comparisonType: comparisonTypeRt, + }), + ]), + }), + }, + '/services/{serviceName}/transactions': { + element: , + }, }, - { - path: '/services/{serviceName}/transactions', - element: , - }, - ], - }, - page({ - path: '/services/{serviceName}/dependencies', - element: , - tab: 'dependencies', - title: i18n.translate('xpack.apm.views.dependencies.title', { - defaultMessage: 'Dependencies', - }), - searchBarOptions: { - showTimeComparison: true, }, - }), - { - ...page({ - path: '/services/{serviceName}/errors', - tab: 'errors', - title: i18n.translate('xpack.apm.views.errors.title', { - defaultMessage: 'Errors', + '/services/{serviceName}/dependencies': page({ + element: , + tab: 'dependencies', + title: i18n.translate('xpack.apm.views.dependencies.title', { + defaultMessage: 'Dependencies', }), - element: , searchBarOptions: { showTimeComparison: true, }, }), - params: t.partial({ - query: t.partial({ - sortDirection: t.string, - sortField: t.string, - pageSize: t.string, - page: t.string, + '/services/{serviceName}/errors': { + ...page({ + tab: 'errors', + title: i18n.translate('xpack.apm.views.errors.title', { + defaultMessage: 'Errors', + }), + element: , + searchBarOptions: { + showTimeComparison: true, + }, }), - }), - children: [ - { - path: '/services/{serviceName}/errors/{groupId}', - element: , - params: t.type({ - path: t.type({ - groupId: t.string, - }), + params: t.partial({ + query: t.partial({ + sortDirection: t.string, + sortField: t.string, + pageSize: t.string, + page: t.string, }), + }), + children: { + '/services/{serviceName}/errors/{groupId}': { + element: , + params: t.type({ + path: t.type({ + groupId: t.string, + }), + }), + }, + '/services/{serviceName}/errors': { + element: , + }, }, - { - path: '/services/{serviceName}/errors', - element: , - }, - ], - }, - page({ - path: '/services/{serviceName}/metrics', - tab: 'metrics', - title: i18n.translate('xpack.apm.views.metrics.title', { - defaultMessage: 'Metrics', - }), - element: , - }), - { - ...page({ - path: '/services/{serviceName}/nodes', - tab: 'nodes', - title: i18n.translate('xpack.apm.views.nodes.title', { - defaultMessage: 'JVMs', + }, + '/services/{serviceName}/metrics': page({ + tab: 'metrics', + title: i18n.translate('xpack.apm.views.metrics.title', { + defaultMessage: 'Metrics', }), - element: , + element: , }), - children: [ - { - path: '/services/{serviceName}/nodes/{serviceNodeName}/metrics', - element: , - params: t.type({ - path: t.type({ - serviceNodeName: t.string, - }), + '/services/{serviceName}/nodes': { + ...page({ + tab: 'nodes', + title: i18n.translate('xpack.apm.views.nodes.title', { + defaultMessage: 'JVMs', }), - }, - { - path: '/services/{serviceName}/nodes', - element: , - params: t.partial({ - query: t.partial({ - sortDirection: t.string, - sortField: t.string, - pageSize: t.string, - page: t.string, + element: , + }), + children: { + '/services/{serviceName}/nodes/{serviceNodeName}/metrics': { + element: , + params: t.type({ + path: t.type({ + serviceNodeName: t.string, + }), }), - }), + }, + '/services/{serviceName}/nodes': { + element: , + params: t.partial({ + query: t.partial({ + sortDirection: t.string, + sortField: t.string, + pageSize: t.string, + page: t.string, + }), + }), + }, }, - ], - }, - page({ - path: '/services/{serviceName}/service-map', - tab: 'service-map', - title: i18n.translate('xpack.apm.views.serviceMap.title', { - defaultMessage: 'Service Map', - }), - element: , - searchBarOptions: { - hidden: true, }, - }), - page({ - path: '/services/{serviceName}/logs', - tab: 'logs', - title: i18n.translate('xpack.apm.views.logs.title', { - defaultMessage: 'Logs', + '/services/{serviceName}/service-map': page({ + tab: 'service-map', + title: i18n.translate('xpack.apm.views.serviceMap.title', { + defaultMessage: 'Service Map', + }), + element: , + searchBarOptions: { + hidden: true, + }, }), - element: , - searchBarOptions: { - showKueryBar: false, - }, - }), - page({ - path: '/services/{serviceName}/profiling', - tab: 'profiling', - title: i18n.translate('xpack.apm.views.serviceProfiling.title', { - defaultMessage: 'Profiling', + '/services/{serviceName}/logs': page({ + tab: 'logs', + title: i18n.translate('xpack.apm.views.logs.title', { + defaultMessage: 'Logs', + }), + element: , + searchBarOptions: { + showKueryBar: false, + }, }), - element: , - }), - page({ - path: '/services/{serviceName}/infra', - tab: 'infra', - title: i18n.translate('xpack.apm.views.infra.title', { - defaultMessage: 'Infrastructure', + '/services/{serviceName}/profiling': page({ + tab: 'profiling', + title: i18n.translate('xpack.apm.views.serviceProfiling.title', { + defaultMessage: 'Profiling', + }), + element: , + }), + '/services/{serviceName}/infra': page({ + tab: 'infra', + title: i18n.translate('xpack.apm.views.infra.title', { + defaultMessage: 'Infrastructure', + }), + element: , + searchBarOptions: { + hidden: true, + }, }), - element: , - searchBarOptions: { - hidden: true, + '/services/{serviceName}/': { + element: , }, - }), - { - path: '/services/{serviceName}/', - element: , }, - ], -} as const; + }, +}; diff --git a/x-pack/plugins/apm/public/components/routing/settings/index.tsx b/x-pack/plugins/apm/public/components/routing/settings/index.tsx index afeef9c496d25..97748f2ce13ba 100644 --- a/x-pack/plugins/apm/public/components/routing/settings/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/settings/index.tsx @@ -21,129 +21,120 @@ import { Schema } from '../../app/Settings/schema'; import { AnomalyDetection } from '../../app/Settings/anomaly_detection'; import { AgentKeys } from '../../app/Settings/agent_keys'; -function page({ - path, +function page({ title, tab, element, }: { - path: TPath; title: string; tab: React.ComponentProps['selectedTab']; element: React.ReactElement; }): { element: React.ReactElement; - path: TPath; } { return { - path, element: ( - + {element} ), - } as any; + }; } export const settings = { - path: '/settings', - element: ( - - - - ), - children: [ - page({ - path: '/settings/agent-configuration', - tab: 'agent-configurations', - title: i18n.translate( - 'xpack.apm.views.settings.agentConfiguration.title', - { defaultMessage: 'Agent Configuration' } - ), - element: , - }), - { - ...page({ - path: '/settings/agent-configuration/create', + '/settings': { + element: ( + + + + ), + children: { + '/settings/agent-configuration': page({ + tab: 'agent-configuration', title: i18n.translate( - 'xpack.apm.views.settings.createAgentConfiguration.title', - { defaultMessage: 'Create Agent Configuration' } + 'xpack.apm.views.settings.agentConfiguration.title', + { defaultMessage: 'Agent Configuration' } ), - tab: 'agent-configurations', - element: , + element: , }), - params: t.partial({ - query: t.partial({ - pageStep: agentConfigurationPageStepRt, + '/settings/agent-configuration/create': { + ...page({ + title: i18n.translate( + 'xpack.apm.views.settings.createAgentConfiguration.title', + { defaultMessage: 'Create Agent Configuration' } + ), + tab: 'agent-configuration', + element: , }), - }), - }, - { - ...page({ - path: '/settings/agent-configuration/edit', - title: i18n.translate( - 'xpack.apm.views.settings.editAgentConfiguration.title', - { defaultMessage: 'Edit Agent Configuration' } - ), - tab: 'agent-configurations', - element: , - }), - params: t.partial({ - query: t.partial({ - environment: t.string, - name: t.string, - pageStep: agentConfigurationPageStepRt, + params: t.partial({ + query: t.partial({ + pageStep: agentConfigurationPageStepRt, + }), }), + }, + '/settings/agent-configuration/edit': { + ...page({ + title: i18n.translate( + 'xpack.apm.views.settings.editAgentConfiguration.title', + { defaultMessage: 'Edit Agent Configuration' } + ), + tab: 'agent-configuration', + element: , + }), + params: t.partial({ + query: t.partial({ + environment: t.string, + name: t.string, + pageStep: agentConfigurationPageStepRt, + }), + }), + }, + '/settings/apm-indices': page({ + title: i18n.translate('xpack.apm.views.settings.indices.title', { + defaultMessage: 'Indices', + }), + tab: 'apm-indices', + element: , }), - }, - page({ - path: '/settings/apm-indices', - title: i18n.translate('xpack.apm.views.settings.indices.title', { - defaultMessage: 'Indices', - }), - tab: 'apm-indices', - element: , - }), - page({ - path: '/settings/custom-links', - title: i18n.translate('xpack.apm.views.settings.customLink.title', { - defaultMessage: 'Custom Links', + '/settings/custom-links': page({ + title: i18n.translate('xpack.apm.views.settings.customLink.title', { + defaultMessage: 'Custom Links', + }), + tab: 'custom-links', + element: , }), - tab: 'custom-links', - element: , - }), - page({ - path: '/settings/schema', - title: i18n.translate('xpack.apm.views.settings.schema.title', { - defaultMessage: 'Schema', + '/settings/schema': page({ + title: i18n.translate('xpack.apm.views.settings.schema.title', { + defaultMessage: 'Schema', + }), + element: , + tab: 'schema', }), - element: , - tab: 'schema', - }), - page({ - path: '/settings/anomaly-detection', - title: i18n.translate('xpack.apm.views.settings.anomalyDetection.title', { - defaultMessage: 'Anomaly detection', + '/settings/anomaly-detection': page({ + title: i18n.translate( + 'xpack.apm.views.settings.anomalyDetection.title', + { + defaultMessage: 'Anomaly detection', + } + ), + element: , + tab: 'anomaly-detection', }), - element: , - tab: 'anomaly-detection', - }), - page({ - path: '/settings/agent-keys', - title: i18n.translate('xpack.apm.views.settings.agentKeys.title', { - defaultMessage: 'Agent keys', + '/settings/agent-keys': page({ + title: i18n.translate('xpack.apm.views.settings.agentKeys.title', { + defaultMessage: 'Agent keys', + }), + element: , + tab: 'agent-keys', }), - element: , - tab: 'agent-keys', - }), - { - path: '/settings', - element: , + '/settings': { + element: , + }, }, - ], -} as const; + }, +}; diff --git a/x-pack/plugins/apm/public/components/routing/templates/settings_template.stories.tsx b/x-pack/plugins/apm/public/components/routing/templates/settings_template.stories.tsx index 4fc35bf242a40..a1a5e38bdd2ea 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/settings_template.stories.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/settings_template.stories.tsx @@ -71,5 +71,5 @@ export const Example: Story = (args) => { }; Example.args = { children: <>test, - selectedTab: 'agent-configurations', + selectedTab: 'agent-configuration', }; diff --git a/x-pack/plugins/apm/public/components/routing/templates/settings_template.tsx b/x-pack/plugins/apm/public/components/routing/templates/settings_template.tsx index 43a865c0584c9..08cacc38e89f0 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/settings_template.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/settings_template.tsx @@ -17,7 +17,7 @@ import { getLegacyApmHref } from '../../shared/links/apm/apm_link'; type Tab = NonNullable[0] & { key: - | 'agent-configurations' + | 'agent-configuration' | 'agent-keys' | 'anomaly-detection' | 'apm-indices' @@ -66,7 +66,7 @@ function getTabs({ const tabs: Tab[] = [ { - key: 'agent-configurations', + key: 'agent-configuration', label: i18n.translate('xpack.apm.settings.agentConfig', { defaultMessage: 'Agent Configuration', }), diff --git a/x-pack/plugins/apm/public/hooks/use_apm_params.ts b/x-pack/plugins/apm/public/hooks/use_apm_params.ts index b4c17c1b329ae..89aca1e4bf1a6 100644 --- a/x-pack/plugins/apm/public/hooks/use_apm_params.ts +++ b/x-pack/plugins/apm/public/hooks/use_apm_params.ts @@ -16,17 +16,17 @@ export function useMaybeApmParams>( path: TPath, optional: true ): TypeOf | undefined { - return useParams(path, optional); + return useParams(path, optional) as TypeOf | undefined; } export function useApmParams>( path: TPath ): TypeOf { - return useParams(path)!; + return useParams(path)! as TypeOf; } export function useAnyOfApmParams>>( ...paths: TPaths ): TypeOf> { - return useParams(...paths)!; + return useParams(...paths)! as TypeOf>; } diff --git a/x-pack/plugins/apm/public/hooks/use_apm_router.ts b/x-pack/plugins/apm/public/hooks/use_apm_router.ts index dea66d7b2e1c8..d10b6da857802 100644 --- a/x-pack/plugins/apm/public/hooks/use_apm_router.ts +++ b/x-pack/plugins/apm/public/hooks/use_apm_router.ts @@ -14,8 +14,6 @@ export function useApmRouter() { const { core } = useApmPluginContext(); const link = (...args: [any]) => { - // @ts-expect-error router.link() expects never type, because - // no routes are specified. that's okay. return core.http.basePath.prepend('/app/apm' + router.link(...args)); };