diff --git a/x-pack/legacy/plugins/apm/public/components/app/Main/ProvideBreadcrumbs.tsx b/x-pack/legacy/plugins/apm/public/components/app/Main/ProvideBreadcrumbs.tsx index b6a0814c74fa7..0c1d20d65b7b9 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Main/ProvideBreadcrumbs.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/Main/ProvideBreadcrumbs.tsx @@ -13,6 +13,7 @@ import { withRouter } from 'react-router-dom'; import { StringMap } from '../../../../typings/common'; +import { RouteName } from './route_config/route_names'; type LocationMatch = Pick< RouteComponentProps>, @@ -23,6 +24,7 @@ type BreadcrumbFunction = (props: LocationMatch) => string; export interface BreadcrumbRoute extends RouteProps { breadcrumb: string | BreadcrumbFunction | null; + name: RouteName; } export interface Breadcrumb extends LocationMatch { diff --git a/x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx b/x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx index f3b6e63f62476..30aeb5fe31733 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx @@ -10,7 +10,7 @@ import React from 'react'; import chrome from 'ui/chrome'; import { getAPMHref } from '../../shared/Links/APMLink'; import { Breadcrumb, ProvideBreadcrumbs } from './ProvideBreadcrumbs'; -import { routes } from './routeConfig'; +import { routes } from './route_config'; interface Props { location: Location; diff --git a/x-pack/legacy/plugins/apm/public/components/app/Main/__test__/ProvideBreadcrumbs.test.tsx b/x-pack/legacy/plugins/apm/public/components/app/Main/__test__/ProvideBreadcrumbs.test.tsx index 7826bf16350d0..cb983cdffa028 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Main/__test__/ProvideBreadcrumbs.test.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/Main/__test__/ProvideBreadcrumbs.test.tsx @@ -6,19 +6,27 @@ import { Location } from 'history'; import { BreadcrumbRoute, getBreadcrumbs } from '../ProvideBreadcrumbs'; +import { RouteName } from '../route_config/route_names'; describe('getBreadcrumbs', () => { const getTestRoutes = (): BreadcrumbRoute[] => [ - { path: '/a', exact: true, breadcrumb: 'A' }, - { path: '/a/ignored', exact: true, breadcrumb: 'Ignored Route' }, + { path: '/a', exact: true, breadcrumb: 'A', name: RouteName.HOME }, + { + path: '/a/ignored', + exact: true, + breadcrumb: 'Ignored Route', + name: RouteName.METRICS + }, { path: '/a/:letter', exact: true, + name: RouteName.SERVICE, breadcrumb: ({ match }) => `Second level: ${match.params.letter}` }, { path: '/a/:letter/c', exact: true, + name: RouteName.ERRORS, breadcrumb: ({ match }) => `Third level: ${match.params.letter}` } ]; diff --git a/x-pack/legacy/plugins/apm/public/components/app/Main/routeConfig.tsx b/x-pack/legacy/plugins/apm/public/components/app/Main/route_config/index.tsx similarity index 75% rename from x-pack/legacy/plugins/apm/public/components/app/Main/routeConfig.tsx rename to x-pack/legacy/plugins/apm/public/components/app/Main/route_config/index.tsx index d4b25fd763ec0..cfa9c13dd538d 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Main/routeConfig.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/Main/route_config/index.tsx @@ -7,12 +7,13 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; import { Redirect, RouteComponentProps } from 'react-router-dom'; -import { legacyDecodeURIComponent } from '../../shared/Links/url_helpers'; -import { ErrorGroupDetails } from '../ErrorGroupDetails'; -import { ServiceDetails } from '../ServiceDetails'; -import { TransactionDetails } from '../TransactionDetails'; -import { Home } from './Home'; -import { BreadcrumbRoute } from './ProvideBreadcrumbs'; +import { legacyDecodeURIComponent } from '../../../shared/Links/url_helpers'; +import { ErrorGroupDetails } from '../../ErrorGroupDetails'; +import { ServiceDetails } from '../../ServiceDetails'; +import { TransactionDetails } from '../../TransactionDetails'; +import { Home } from '../Home'; +import { BreadcrumbRoute } from '../ProvideBreadcrumbs'; +import { RouteName } from './route_names'; interface RouteParams { serviceName: string; @@ -34,7 +35,8 @@ export const routes: BreadcrumbRoute[] = [ exact: true, path: '/', render: renderAsRedirectTo('/services'), - breadcrumb: 'APM' + breadcrumb: 'APM', + name: RouteName.HOME }, { exact: true, @@ -42,7 +44,8 @@ export const routes: BreadcrumbRoute[] = [ component: Home, breadcrumb: i18n.translate('xpack.apm.breadcrumb.servicesTitle', { defaultMessage: 'Services' - }) + }), + name: RouteName.SERVICES }, { exact: true, @@ -50,7 +53,8 @@ export const routes: BreadcrumbRoute[] = [ component: Home, breadcrumb: i18n.translate('xpack.apm.breadcrumb.tracesTitle', { defaultMessage: 'Traces' - }) + }), + name: RouteName.TRACES }, { exact: true, @@ -59,13 +63,15 @@ export const routes: BreadcrumbRoute[] = [ render: (props: RouteComponentProps) => renderAsRedirectTo(`/${props.match.params.serviceName}/transactions`)( props - ) + ), + name: RouteName.SERVICE }, { exact: true, path: '/:serviceName/errors/:groupId', component: ErrorGroupDetails, - breadcrumb: ({ match }) => match.params.groupId + breadcrumb: ({ match }) => match.params.groupId, + name: RouteName.ERROR }, { exact: true, @@ -73,7 +79,8 @@ export const routes: BreadcrumbRoute[] = [ component: ServiceDetails, breadcrumb: i18n.translate('xpack.apm.breadcrumb.errorsTitle', { defaultMessage: 'Errors' - }) + }), + name: RouteName.ERRORS }, { exact: true, @@ -81,7 +88,8 @@ export const routes: BreadcrumbRoute[] = [ component: ServiceDetails, breadcrumb: i18n.translate('xpack.apm.breadcrumb.transactionsTitle', { defaultMessage: 'Transactions' - }) + }), + name: RouteName.TRANSACTIONS }, // Have to split this out as its own route to prevent duplicate breadcrumbs from both matching // if we use :transactionType? as a single route here @@ -89,7 +97,8 @@ export const routes: BreadcrumbRoute[] = [ exact: true, path: '/:serviceName/transactions/:transactionType', component: ServiceDetails, - breadcrumb: null + breadcrumb: null, + name: RouteName.TRANSACTION_TYPE }, { exact: true, @@ -97,13 +106,15 @@ export const routes: BreadcrumbRoute[] = [ component: ServiceDetails, breadcrumb: i18n.translate('xpack.apm.breadcrumb.metricsTitle', { defaultMessage: 'Metrics' - }) + }), + name: RouteName.METRICS }, { exact: true, path: '/:serviceName/transactions/:transactionType/:transactionName', component: TransactionDetails, breadcrumb: ({ match }) => - legacyDecodeURIComponent(match.params.transactionName) || '' + legacyDecodeURIComponent(match.params.transactionName) || '', + name: RouteName.TRANSACTION_NAME } ]; diff --git a/x-pack/legacy/plugins/apm/public/components/app/Main/route_config/route_names.tsx b/x-pack/legacy/plugins/apm/public/components/app/Main/route_config/route_names.tsx new file mode 100644 index 0000000000000..bd2591075edae --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/components/app/Main/route_config/route_names.tsx @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export enum RouteName { + HOME = 'home', + SERVICES = 'services', + TRACES = 'traces', + SERVICE = 'service', + TRANSACTIONS = 'transactions', + ERRORS = 'errors', + ERROR = 'error', + METRICS = 'metrics', + TRANSACTION_TYPE = 'transaction_type', + TRANSACTION_NAME = 'transaction_name' +} diff --git a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/Typeahead/index.js b/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/Typeahead/index.js index 260b53abca76b..71f40fd4815dc 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/Typeahead/index.js +++ b/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/Typeahead/index.js @@ -156,6 +156,8 @@ export class Typeahead extends Component { }; render() { + const { queryExample } = this.props; + return ( 300000 AND http.response.status_code >= 400' + queryExample } } )} @@ -224,7 +225,8 @@ Typeahead.propTypes = { disabled: PropTypes.bool, onChange: PropTypes.func.isRequired, onSubmit: PropTypes.func.isRequired, - suggestions: PropTypes.array.isRequired + suggestions: PropTypes.array.isRequired, + queryExample: PropTypes.string.isRequired }; Typeahead.defaultProps = { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx b/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx index f044e214218df..0bef2e49a77e8 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx @@ -27,6 +27,8 @@ import { getBoolFilter } from './get_bool_filter'; import { useLocation } from '../../../hooks/useLocation'; import { useUrlParams } from '../../../hooks/useUrlParams'; import { history } from '../../../utils/history'; +import { useMatchedRoutes } from '../../../hooks/useMatchedRoutes'; +import { RouteName } from '../../app/Main/route_config/route_names'; const Container = styled.div` margin-bottom: 10px; @@ -48,11 +50,24 @@ export function KueryBar() { }); const { urlParams } = useUrlParams(); const location = useLocation(); + const matchedRoutes = useMatchedRoutes(); + const apmIndexPatternTitle = chrome.getInjected('apmIndexPatternTitle'); const indexPatternMissing = !state.isLoadingIndexPattern && !state.indexPattern; let currentRequestCheck; + const exampleMap: { [key: string]: string } = { + [RouteName.TRANSACTIONS]: 'transaction.duration.us > 300000', + [RouteName.ERRORS]: 'http.response.status_code >= 400', + [RouteName.METRICS]: 'process.pid = "1234"' + }; + + // sets queryExample to the first matched example query, else default example + const queryExample = + matchedRoutes.map(({ name }) => exampleMap[name]).find(Boolean) || + 'transaction.duration.us > 300000 AND http.response.status_code >= 400'; + useEffect(() => { let didCancel = false; @@ -143,6 +158,7 @@ export function KueryBar() { onChange={onChange} onSubmit={onSubmit} suggestions={state.suggestions} + queryExample={queryExample} /> {indexPatternMissing && ( diff --git a/x-pack/legacy/plugins/apm/public/context/MatchedRouteContext.tsx b/x-pack/legacy/plugins/apm/public/context/MatchedRouteContext.tsx new file mode 100644 index 0000000000000..2dc0cd56f794f --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/context/MatchedRouteContext.tsx @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React, { useMemo } from 'react'; +import { matchPath } from 'react-router-dom'; +import { routes } from '../components/app/Main/route_config'; +import { useLocation } from '../hooks/useLocation'; + +export const MatchedRouteContext = React.createContext>( + [] +); + +export const MatchedRouteProvider: React.FC = ({ children }) => { + const { pathname } = useLocation(); + + const contextValue = useMemo( + () => { + return routes.filter(route => { + return matchPath(pathname, { + path: route.path + }); + }); + }, + [pathname] + ); + + return ( + + ); +}; diff --git a/x-pack/legacy/plugins/apm/public/hooks/useMatchedRoutes.tsx b/x-pack/legacy/plugins/apm/public/hooks/useMatchedRoutes.tsx new file mode 100644 index 0000000000000..74250096022d0 --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/hooks/useMatchedRoutes.tsx @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { useContext } from 'react'; +import { MatchedRouteContext } from '../context/MatchedRouteContext'; + +export function useMatchedRoutes() { + return useContext(MatchedRouteContext); +} diff --git a/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx b/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx index 40984460ea691..4c80f8226cbaf 100644 --- a/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx +++ b/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx @@ -16,9 +16,10 @@ import { px, topNavHeight, unit, units } from '../style/variables'; import { LoadingIndicatorProvider } from '../context/LoadingIndicatorContext'; import { LicenseProvider } from '../context/LicenseContext'; import { UpdateBreadcrumbs } from '../components/app/Main/UpdateBreadcrumbs'; -import { routes } from '../components/app/Main/routeConfig'; +import { routes } from '../components/app/Main/route_config'; import { ScrollToTopOnPathChange } from '../components/app/Main/ScrollToTopOnPathChange'; import { useUpdateBadgeEffect } from '../components/app/Main/useUpdateBadgeEffect'; +import { MatchedRouteProvider } from '../context/MatchedRouteContext'; export const REACT_APP_ROOT_ID = 'react-apm-root'; @@ -32,21 +33,23 @@ function App() { useUpdateBadgeEffect(); return ( - - - - - - - - {routes.map((route, i) => ( - - ))} - - - - - + + + + + + + + + {routes.map((route, i) => ( + + ))} + + + + + + ); }