From f6d7da151e2bdb509cbb5816c05cab3b05c67f9f Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Tue, 18 Jan 2022 21:15:33 +0100 Subject: [PATCH] Simplify router types --- .../src/create_router.ts | 17 +- .../src/index.ts | 2 - .../src/route.ts | 15 - .../src/router_provider.tsx | 4 +- .../src/types/index.ts | 301 +++++--------- .../src/unconst.ts | 91 ----- .../src/use_router.tsx | 8 +- .../backend_detail_dependencies_table.tsx | 2 + .../components/routing/apm_route_config.tsx | 21 +- .../public/components/routing/home/index.tsx | 176 +++++---- .../routing/service_detail/index.tsx | 366 +++++++++--------- .../components/routing/settings/index.tsx | 185 +++++---- .../routing/templates/settings_template.tsx | 4 +- 13 files changed, 479 insertions(+), 713 deletions(-) delete mode 100644 packages/kbn-typed-react-router-config/src/route.ts delete mode 100644 packages/kbn-typed-react-router-config/src/unconst.ts 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 27a4f1dd5de023b..f3f83dfecdc47c2 100644 --- a/packages/kbn-typed-react-router-config/src/create_router.ts +++ b/packages/kbn-typed-react-router-config/src/create_router.ts @@ -15,25 +15,28 @@ 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)) ?? - [], + Object.entries((route.children as RouteMap | undefined) ?? {})?.map(([path, child]) => + toReactRouterConfigRoute({ ...child, path }) + ) ?? [], exact: !route.children?.length, 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 b58c70998901c3f..9ba68aed7e3b257 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 b9b228d1009e2f6..000000000000000 --- 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 657df9e9fc59226..ef06964f230be8a 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 97b58ce5a700fff..f768990ac014a10 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,24 @@ 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 = keyof MapRoutes & string; -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; @@ -51,33 +58,13 @@ type UnwrapRouteMap = TRoute exten ? ToRouteMatch<[...TRoute['parents'], Omit]> : ToRouteMatch<[Omit]>; -export type Match = MapRoutes extends { +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; -} - -export type Route = PlainRoute | ReadonlyPlainRoute; - -interface DefaultOutput { +export interface DefaultOutput { path: {}; query: {}; } @@ -97,7 +84,7 @@ type OutputOfMatches = TRouteMatches extends ? OutputOfRouteMatch> : DefaultOutput; -export type OutputOf> = OutputOfMatches< +export type OutputOf> = OutputOfMatches< Match > & DefaultOutput; @@ -116,7 +103,7 @@ type TypeOfMatches = TRouteMatches extends [ : {}; export type TypeOf< - TRoutes extends Route[], + TRoutes extends RouteMap, TPath extends PathsOf, TWithDefaultOutput extends boolean = true > = TypeOfMatches> & (TWithDefaultOutput extends true ? DefaultOutput : {}); @@ -127,11 +114,11 @@ export type TypeAsArgs = keyof TObject extends never ? [TObject] | [] : [TObject]; -export type FlattenRoutesOf = Array< +export type FlattenRoutesOf = Array< Omit>, 'parents'> >; -export interface Router { +export interface Router { matchRoutes>( path: TPath, location: Location @@ -179,11 +166,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 }; }, - TRoute extends { children: Route[] } + TRoute extends { children: RouteMap } ? MaybeUnion< MapRoutes, { @@ -195,107 +182,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 +224,7 @@ type MapRoutes = TRoutes extends [Route] // }), // }), // }, -// { -// path: '/settings/agent-configuration/edit', +// '/settings/agent-configuration/edit': { // element, // params: t.partial({ // query: t.partial({ @@ -312,34 +232,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 +273,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 +297,7 @@ type MapRoutes = TRoutes extends [Route] // }), // }), // }, -// { -// path: '/services/:serviceName/errors', +// '/services/:serviceName/errors': { // element, // params: t.partial({ // query: t.partial({ @@ -402,46 +308,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 +346,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 Foo = OutputOf; -// // type Baz = OutputOf; +// type Baz = OutputOf; // const { path }: Foo = {} as any; @@ -505,4 +394,4 @@ type MapRoutes = TRoutes extends [Route] // return {} as any; // } -// // const params = _useApmParams('/services/:serviceName/nodes/*'); +// const params = _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 d10c8290e20e9aa..000000000000000 --- 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 c78e85650f26d30..f3a6c396d37d4a9 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/components/app/backend_detail_overview/backend_detail_dependencies_table.tsx b/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_detail_dependencies_table.tsx index 4e3f7f4bee81132..17180b9cb9d8b18 100644 --- a/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_detail_dependencies_table.tsx +++ b/x-pack/plugins/apm/public/components/app/backend_detail_overview/backend_detail_dependencies_table.tsx @@ -58,6 +58,8 @@ export function BackendDetailDependenciesTable() { [start, end, environment, offset, backendName, kuery] ); + data?.services; + const dependencies = data?.services.map((dependency) => { const { location } = dependency; 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 7e6ee849fdb0b3f..daab3003b18dcbe 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 25a68592d2b1190..d81d69aa4e587fc 100644 --- a/x-pack/plugins/apm/public/components/routing/home/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/home/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ import { i18n } from '@kbn/i18n'; -import { Outlet } from '@kbn/typed-react-router-config'; +import { Outlet, Route } from '@kbn/typed-react-router-config'; import * as t from 'io-ts'; import React from 'react'; import { toBooleanRt } from '@kbn/io-ts-utils'; @@ -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 f8206f273abd4c7..6514c8288be0ec4 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 afeef9c496d25db..97748f2ce13ba82 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.tsx b/x-pack/plugins/apm/public/components/routing/templates/settings_template.tsx index 43a865c0584c900..08cacc38e89f0ff 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', }),