mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Removes APM custom breadcrumbs, leaves only chrome.breadcrumbs.set (#29286)
* Removes APM custom breadcrumbs, leaves only chrome.breadcrumbs.set * Updates breadcrumb tests * Changes route structure to simplify TS
This commit is contained in:
parent
015e831ab0
commit
06a5ce7165
10 changed files with 293 additions and 245 deletions
|
@ -1,80 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { withBreadcrumbs } from 'react-router-breadcrumbs-hoc';
|
||||
import { flatten, capitalize } from 'lodash';
|
||||
import chrome from 'ui/chrome';
|
||||
import { toQuery } from '../../shared/Links/url_helpers';
|
||||
import { routes } from './routeConfig';
|
||||
|
||||
class Breadcrumbs extends React.Component {
|
||||
updateHeaderBreadcrumbs() {
|
||||
const { _g = '', kuery = '' } = toQuery(this.props.location.search);
|
||||
const breadcrumbs = this.props.breadcrumbs.map(({ breadcrumb, match }) => ({
|
||||
text: breadcrumb,
|
||||
href: `#${match.url}?_g=${_g}&kuery=${kuery}`
|
||||
}));
|
||||
|
||||
chrome.breadcrumbs.set(breadcrumbs);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.updateHeaderBreadcrumbs();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.updateHeaderBreadcrumbs();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { breadcrumbs, location, showPluginBreadcrumbs } = this.props;
|
||||
const { _g = '', kuery = '' } = toQuery(location.search);
|
||||
|
||||
// If we don't display plugin breadcrumbs, render null, but continue
|
||||
// to push updates to header.
|
||||
if (!showPluginBreadcrumbs) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="kuiLocalBreadcrumbs">
|
||||
{breadcrumbs.map(({ breadcrumb, path, match }, i) => {
|
||||
const isLast = i === breadcrumbs.length - 1;
|
||||
return (
|
||||
<div
|
||||
key={path}
|
||||
className="kuiLocalBreadcrumb"
|
||||
style={{ lineHeight: '29px' }}
|
||||
>
|
||||
{isLast ? (
|
||||
<span
|
||||
ref={node => {
|
||||
if (node && document.title !== node.textContent) {
|
||||
document.title = capitalize(node.textContent);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{breadcrumb}
|
||||
</span>
|
||||
) : (
|
||||
<a href={`#${match.url}?_g=${_g}&kuery=${kuery}`}>
|
||||
{breadcrumb}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const flatRoutes = flatten(
|
||||
routes.map(route => (route.switch ? route.routes : route))
|
||||
);
|
||||
|
||||
export default withBreadcrumbs(flatRoutes)(Breadcrumbs);
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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 { Location } from 'history';
|
||||
import { flatten } from 'lodash';
|
||||
import React from 'react';
|
||||
// @ts-ignore
|
||||
import { withBreadcrumbs } from 'react-router-breadcrumbs-hoc';
|
||||
import chrome from 'ui/chrome';
|
||||
import { toQuery } from '../../shared/Links/url_helpers';
|
||||
import { routes } from './routeConfig';
|
||||
|
||||
interface Props {
|
||||
location: Location;
|
||||
breadcrumbs: Array<{
|
||||
breadcrumb: any;
|
||||
match: {
|
||||
url: string;
|
||||
};
|
||||
}>;
|
||||
}
|
||||
|
||||
class UpdateBreadcrumbsComponent extends React.Component<Props> {
|
||||
public updateHeaderBreadcrumbs() {
|
||||
const { _g = '', kuery = '' } = toQuery(this.props.location.search);
|
||||
const breadcrumbs = this.props.breadcrumbs.map(({ breadcrumb, match }) => ({
|
||||
text: breadcrumb,
|
||||
href: `#${match.url}?_g=${_g}&kuery=${kuery}`
|
||||
}));
|
||||
|
||||
chrome.breadcrumbs.set(breadcrumbs);
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
this.updateHeaderBreadcrumbs();
|
||||
}
|
||||
|
||||
public componentDidUpdate() {
|
||||
this.updateHeaderBreadcrumbs();
|
||||
}
|
||||
|
||||
public render() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const flatRoutes = flatten(
|
||||
routes.map(route => (route.switchRoutes ? route.switchRoutes : route))
|
||||
);
|
||||
|
||||
const UpdateBreadcrumbs = withBreadcrumbs(flatRoutes)(
|
||||
UpdateBreadcrumbsComponent
|
||||
);
|
||||
|
||||
export { UpdateBreadcrumbs };
|
|
@ -7,15 +7,14 @@
|
|||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
import Breadcrumbs from '../Breadcrumbs';
|
||||
import { toJson } from '../../../../utils/testHelpers';
|
||||
import { UpdateBreadcrumbs } from '../UpdateBreadcrumbs';
|
||||
import chrome from 'ui/chrome';
|
||||
|
||||
jest.mock(
|
||||
'ui/chrome',
|
||||
() => ({
|
||||
breadcrumbs: {
|
||||
set: () => {}
|
||||
set: jest.fn()
|
||||
},
|
||||
getBasePath: () => `/some/base/path`,
|
||||
getUiSettingsClient: () => {
|
||||
|
@ -37,17 +36,20 @@ jest.mock(
|
|||
);
|
||||
|
||||
function expectBreadcrumbToMatchSnapshot(route) {
|
||||
const wrapper = mount(
|
||||
mount(
|
||||
<MemoryRouter initialEntries={[`${route}?_g=myG&kuery=myKuery`]}>
|
||||
<Breadcrumbs showPluginBreadcrumbs={true} />
|
||||
<UpdateBreadcrumbs />
|
||||
</MemoryRouter>
|
||||
);
|
||||
expect(
|
||||
toJson(wrapper.find('.kuiLocalBreadcrumb').children())
|
||||
).toMatchSnapshot();
|
||||
expect(chrome.breadcrumbs.set).toHaveBeenCalledTimes(1);
|
||||
expect(chrome.breadcrumbs.set.mock.calls[0][0]).toMatchSnapshot();
|
||||
}
|
||||
|
||||
describe('Breadcrumbs', () => {
|
||||
beforeEach(() => {
|
||||
chrome.breadcrumbs.set.mockReset();
|
||||
});
|
||||
|
||||
it('Homepage', () => {
|
||||
expectBreadcrumbToMatchSnapshot('/');
|
||||
});
|
||||
|
@ -77,13 +79,4 @@ describe('Breadcrumbs', () => {
|
|||
'/:serviceName/transactions/request/my-transaction-name'
|
||||
);
|
||||
});
|
||||
|
||||
it('does not render breadcrumbs when showPluginBreadcrumbs = false', () => {
|
||||
const wrapper = mount(
|
||||
<MemoryRouter initialEntries={[`/?_g=myG&kuery=myKuery`]}>
|
||||
<Breadcrumbs showPluginBreadcrumbs={false} />
|
||||
</MemoryRouter>
|
||||
);
|
||||
expect(wrapper.find('.kuiLocalBreadcrumbs').exists()).toEqual(false);
|
||||
});
|
||||
});
|
|
@ -1,120 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Breadcrumbs /:serviceName 1`] = `
|
||||
Array [
|
||||
<a
|
||||
href="#/?_g=myG&kuery=myKuery"
|
||||
>
|
||||
APM
|
||||
</a>,
|
||||
<span>
|
||||
opbeans-node
|
||||
</span>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Breadcrumbs /:serviceName/errors 1`] = `
|
||||
Array [
|
||||
<a
|
||||
href="#/?_g=myG&kuery=myKuery"
|
||||
>
|
||||
APM
|
||||
</a>,
|
||||
<a
|
||||
href="#/opbeans-node?_g=myG&kuery=myKuery"
|
||||
>
|
||||
opbeans-node
|
||||
</a>,
|
||||
<span>
|
||||
Errors
|
||||
</span>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Breadcrumbs /:serviceName/errors/:groupId 1`] = `
|
||||
Array [
|
||||
<a
|
||||
href="#/?_g=myG&kuery=myKuery"
|
||||
>
|
||||
APM
|
||||
</a>,
|
||||
<a
|
||||
href="#/opbeans-node?_g=myG&kuery=myKuery"
|
||||
>
|
||||
opbeans-node
|
||||
</a>,
|
||||
<a
|
||||
href="#/opbeans-node/errors?_g=myG&kuery=myKuery"
|
||||
>
|
||||
Errors
|
||||
</a>,
|
||||
<span>
|
||||
myGroupId
|
||||
</span>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Breadcrumbs /:serviceName/transactions 1`] = `
|
||||
Array [
|
||||
<a
|
||||
href="#/?_g=myG&kuery=myKuery"
|
||||
>
|
||||
APM
|
||||
</a>,
|
||||
<a
|
||||
href="#/opbeans-node?_g=myG&kuery=myKuery"
|
||||
>
|
||||
opbeans-node
|
||||
</a>,
|
||||
<span>
|
||||
Transactions
|
||||
</span>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Breadcrumbs /:serviceName/transactions/:transactionType 1`] = `
|
||||
Array [
|
||||
<a
|
||||
href="#/?_g=myG&kuery=myKuery"
|
||||
>
|
||||
APM
|
||||
</a>,
|
||||
<a
|
||||
href="#/opbeans-node?_g=myG&kuery=myKuery"
|
||||
>
|
||||
opbeans-node
|
||||
</a>,
|
||||
<span>
|
||||
Transactions
|
||||
</span>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Breadcrumbs /:serviceName/transactions/:transactionType/:transactionName 1`] = `
|
||||
Array [
|
||||
<a
|
||||
href="#/?_g=myG&kuery=myKuery"
|
||||
>
|
||||
APM
|
||||
</a>,
|
||||
<a
|
||||
href="#/:serviceName?_g=myG&kuery=myKuery"
|
||||
>
|
||||
:serviceName
|
||||
</a>,
|
||||
<a
|
||||
href="#/:serviceName/transactions?_g=myG&kuery=myKuery"
|
||||
>
|
||||
Transactions
|
||||
</a>,
|
||||
<span>
|
||||
my-transaction-name
|
||||
</span>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Breadcrumbs Homepage 1`] = `
|
||||
<span>
|
||||
APM
|
||||
</span>
|
||||
`;
|
|
@ -0,0 +1,207 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Breadcrumbs /:serviceName 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"href": "#/?_g=myG&kuery=myKuery",
|
||||
"text": "APM",
|
||||
},
|
||||
Object {
|
||||
"href": "#/opbeans-node?_g=myG&kuery=myKuery",
|
||||
"text": <breadcrumb
|
||||
match={
|
||||
Object {
|
||||
"isExact": true,
|
||||
"params": Object {
|
||||
"serviceName": "opbeans-node",
|
||||
},
|
||||
"path": "/:serviceName",
|
||||
"url": "/opbeans-node",
|
||||
}
|
||||
}
|
||||
/>,
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Breadcrumbs /:serviceName/errors 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"href": "#/?_g=myG&kuery=myKuery",
|
||||
"text": "APM",
|
||||
},
|
||||
Object {
|
||||
"href": "#/opbeans-node?_g=myG&kuery=myKuery",
|
||||
"text": <breadcrumb
|
||||
match={
|
||||
Object {
|
||||
"isExact": true,
|
||||
"params": Object {
|
||||
"serviceName": "opbeans-node",
|
||||
},
|
||||
"path": "/:serviceName",
|
||||
"url": "/opbeans-node",
|
||||
}
|
||||
}
|
||||
/>,
|
||||
},
|
||||
Object {
|
||||
"href": "#/opbeans-node/errors?_g=myG&kuery=myKuery",
|
||||
"text": "Errors",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Breadcrumbs /:serviceName/errors/:groupId 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"href": "#/?_g=myG&kuery=myKuery",
|
||||
"text": "APM",
|
||||
},
|
||||
Object {
|
||||
"href": "#/opbeans-node?_g=myG&kuery=myKuery",
|
||||
"text": <breadcrumb
|
||||
match={
|
||||
Object {
|
||||
"isExact": true,
|
||||
"params": Object {
|
||||
"serviceName": "opbeans-node",
|
||||
},
|
||||
"path": "/:serviceName",
|
||||
"url": "/opbeans-node",
|
||||
}
|
||||
}
|
||||
/>,
|
||||
},
|
||||
Object {
|
||||
"href": "#/opbeans-node/errors?_g=myG&kuery=myKuery",
|
||||
"text": "Errors",
|
||||
},
|
||||
Object {
|
||||
"href": "#/opbeans-node/errors/myGroupId?_g=myG&kuery=myKuery",
|
||||
"text": <breadcrumb
|
||||
match={
|
||||
Object {
|
||||
"isExact": true,
|
||||
"params": Object {
|
||||
"groupId": "myGroupId",
|
||||
"serviceName": "opbeans-node",
|
||||
},
|
||||
"path": "/:serviceName/errors/:groupId",
|
||||
"url": "/opbeans-node/errors/myGroupId",
|
||||
}
|
||||
}
|
||||
/>,
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Breadcrumbs /:serviceName/transactions 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"href": "#/?_g=myG&kuery=myKuery",
|
||||
"text": "APM",
|
||||
},
|
||||
Object {
|
||||
"href": "#/opbeans-node?_g=myG&kuery=myKuery",
|
||||
"text": <breadcrumb
|
||||
match={
|
||||
Object {
|
||||
"isExact": true,
|
||||
"params": Object {
|
||||
"serviceName": "opbeans-node",
|
||||
},
|
||||
"path": "/:serviceName",
|
||||
"url": "/opbeans-node",
|
||||
}
|
||||
}
|
||||
/>,
|
||||
},
|
||||
Object {
|
||||
"href": "#/opbeans-node/transactions?_g=myG&kuery=myKuery",
|
||||
"text": "Transactions",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Breadcrumbs /:serviceName/transactions/:transactionType 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"href": "#/?_g=myG&kuery=myKuery",
|
||||
"text": "APM",
|
||||
},
|
||||
Object {
|
||||
"href": "#/opbeans-node?_g=myG&kuery=myKuery",
|
||||
"text": <breadcrumb
|
||||
match={
|
||||
Object {
|
||||
"isExact": true,
|
||||
"params": Object {
|
||||
"serviceName": "opbeans-node",
|
||||
},
|
||||
"path": "/:serviceName",
|
||||
"url": "/opbeans-node",
|
||||
}
|
||||
}
|
||||
/>,
|
||||
},
|
||||
Object {
|
||||
"href": "#/opbeans-node/transactions?_g=myG&kuery=myKuery",
|
||||
"text": "Transactions",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Breadcrumbs /:serviceName/transactions/:transactionType/:transactionName 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"href": "#/?_g=myG&kuery=myKuery",
|
||||
"text": "APM",
|
||||
},
|
||||
Object {
|
||||
"href": "#/:serviceName?_g=myG&kuery=myKuery",
|
||||
"text": <breadcrumb
|
||||
match={
|
||||
Object {
|
||||
"isExact": true,
|
||||
"params": Object {
|
||||
"serviceName": ":serviceName",
|
||||
},
|
||||
"path": "/:serviceName",
|
||||
"url": "/:serviceName",
|
||||
}
|
||||
}
|
||||
/>,
|
||||
},
|
||||
Object {
|
||||
"href": "#/:serviceName/transactions?_g=myG&kuery=myKuery",
|
||||
"text": "Transactions",
|
||||
},
|
||||
Object {
|
||||
"href": "#/:serviceName/transactions/request/my-transaction-name?_g=myG&kuery=myKuery",
|
||||
"text": <breadcrumb
|
||||
match={
|
||||
Object {
|
||||
"isExact": true,
|
||||
"params": Object {
|
||||
"serviceName": ":serviceName",
|
||||
"transactionName": "my-transaction-name",
|
||||
"transactionType": "request",
|
||||
},
|
||||
"path": "/:serviceName/transactions/:transactionType/:transactionName",
|
||||
"url": "/:serviceName/transactions/request/my-transaction-name",
|
||||
}
|
||||
}
|
||||
/>,
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Breadcrumbs Homepage 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"href": "#/?_g=myG&kuery=myKuery",
|
||||
"text": "APM",
|
||||
},
|
||||
]
|
||||
`;
|
|
@ -11,6 +11,7 @@ import { routes } from './routeConfig';
|
|||
import ScrollToTopOnPathChange from './ScrollToTopOnPathChange';
|
||||
import { px, units, unit, topNavHeight } from '../../../style/variables';
|
||||
import ConnectRouterToRedux from '../../shared/ConnectRouterToRedux';
|
||||
import { UpdateBreadcrumbs } from './UpdateBreadcrumbs';
|
||||
|
||||
const MainContainer = styled.div`
|
||||
min-width: ${px(unit * 50)};
|
||||
|
@ -21,12 +22,13 @@ const MainContainer = styled.div`
|
|||
export default function Main() {
|
||||
return (
|
||||
<MainContainer>
|
||||
<UpdateBreadcrumbs />
|
||||
<Route component={ConnectRouterToRedux} />
|
||||
<Route component={ScrollToTopOnPathChange} />
|
||||
{routes.map((route, i) => {
|
||||
return route.switch ? (
|
||||
return route.switchRoutes ? (
|
||||
<Switch key={i}>
|
||||
{route.routes.map((route, i) => (
|
||||
{route.switchRoutes.map((route, i) => (
|
||||
<Route key={i} {...route} />
|
||||
))}
|
||||
</Switch>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { Redirect, RouteComponentProps } from 'react-router-dom';
|
||||
import { Redirect, RouteComponentProps, RouteProps } from 'react-router-dom';
|
||||
import { legacyDecodeURIComponent } from 'x-pack/plugins/apm/public/components/shared/Links/url_helpers';
|
||||
import { StringMap } from '../../../../typings/common';
|
||||
// @ts-ignore
|
||||
|
@ -25,6 +25,13 @@ interface RouteParams {
|
|||
serviceName: string;
|
||||
}
|
||||
|
||||
type BreadcrumbFunction = (args: BreadcrumbArgs) => string | null;
|
||||
|
||||
interface Route extends RouteProps {
|
||||
switchRoutes?: Route[];
|
||||
breadcrumb?: string | BreadcrumbFunction | null;
|
||||
}
|
||||
|
||||
const renderAsRedirectTo = (to: string) => {
|
||||
return ({ location }: RouteComponentProps<RouteParams>) => (
|
||||
<Redirect
|
||||
|
@ -36,7 +43,7 @@ const renderAsRedirectTo = (to: string) => {
|
|||
);
|
||||
};
|
||||
|
||||
export const routes = [
|
||||
export const routes: Route[] = [
|
||||
{
|
||||
exact: true,
|
||||
path: '/',
|
||||
|
@ -58,8 +65,7 @@ export const routes = [
|
|||
})
|
||||
},
|
||||
{
|
||||
switch: true,
|
||||
routes: [
|
||||
switchRoutes: [
|
||||
{
|
||||
exact: true,
|
||||
path: '/invalid-license',
|
||||
|
|
|
@ -18,7 +18,6 @@ import './style/global_overrides.css';
|
|||
|
||||
import template from './templates/index.html';
|
||||
import Main from './components/app/Main';
|
||||
import Breadcrumbs from './components/app/Main/Breadcrumbs';
|
||||
|
||||
import { initTimepicker } from './utils/timepicker';
|
||||
import configureStore from './store/config/configureStore';
|
||||
|
@ -33,17 +32,6 @@ chrome.setRootTemplate(template);
|
|||
const store = configureStore();
|
||||
|
||||
initTimepicker(history, store.dispatch).then(() => {
|
||||
const showPluginBreadcrumbs = !chrome
|
||||
.getUiSettingsClient()
|
||||
.get('k7design', false);
|
||||
|
||||
ReactDOM.render(
|
||||
<Router history={history}>
|
||||
<Breadcrumbs showPluginBreadcrumbs={showPluginBreadcrumbs} />
|
||||
</Router>,
|
||||
document.getElementById('react-apm-breadcrumbs')
|
||||
);
|
||||
|
||||
ReactDOM.render(
|
||||
<I18nProvider>
|
||||
<Provider store={store}>
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
<div ng-controller="TimePickerController">
|
||||
<kbn-top-nav name="apm" config="topNavMenu">
|
||||
<div data-transclude-slots>
|
||||
<div data-transclude-slot="topLeftCorner">
|
||||
<div id="react-apm-breadcrumbs"></div>
|
||||
</div>
|
||||
</div>
|
||||
</kbn-top-nav>
|
||||
<div ng-controller="TimePickerController" id="kibana-angular-template">
|
||||
<kbn-top-nav name="apm" config="topNavMenu"></kbn-top-nav>
|
||||
</div>
|
||||
|
||||
<div id="react-apm-root" style="overflow-x: auto;"></div>
|
||||
|
|
|
@ -15,7 +15,7 @@ let currentInterval;
|
|||
// hack to wait for angular template to be ready
|
||||
const waitForAngularReady = new Promise(resolve => {
|
||||
const checkInterval = setInterval(() => {
|
||||
const hasElm = !!document.querySelector('#react-apm-breadcrumbs');
|
||||
const hasElm = !!document.querySelector('#kibana-angular-template');
|
||||
if (hasElm) {
|
||||
clearInterval(checkInterval);
|
||||
resolve();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue