[RUM Dashboard] Create new path for client side monitoring (#74740)

This commit is contained in:
Shahzad 2020-08-19 19:05:53 +02:00 committed by GitHub
parent 32bd45bfbb
commit 2c865f5649
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 213 additions and 46 deletions

View file

@ -0,0 +1,130 @@
/*
* 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 ReactDOM from 'react-dom';
import { Route, Router } from 'react-router-dom';
import styled, { ThemeProvider, DefaultTheme } from 'styled-components';
import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json';
import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
import { CoreStart, AppMountParameters } from 'kibana/public';
import { ApmPluginSetupDeps } from '../plugin';
import {
KibanaContextProvider,
useUiSetting$,
} from '../../../../../src/plugins/kibana_react/public';
import { px, units } from '../style/variables';
import { UpdateBreadcrumbs } from '../components/app/Main/UpdateBreadcrumbs';
import { ScrollToTopOnPathChange } from '../components/app/Main/ScrollToTopOnPathChange';
import { history, resetHistory } from '../utils/history';
import 'react-vis/dist/style.css';
import { RumHome } from '../components/app/RumDashboard/RumHome';
import { ConfigSchema } from '../index';
import { BreadcrumbRoute } from '../components/app/Main/ProvideBreadcrumbs';
import { RouteName } from '../components/app/Main/route_config/route_names';
import { renderAsRedirectTo } from '../components/app/Main/route_config';
import { ApmPluginContext } from '../context/ApmPluginContext';
import { UrlParamsProvider } from '../context/UrlParamsContext';
import { LoadingIndicatorProvider } from '../context/LoadingIndicatorContext';
import { createCallApmApi } from '../services/rest/createCallApmApi';
const CsmMainContainer = styled.div`
padding: ${px(units.plus)};
height: 100%;
`;
export const rumRoutes: BreadcrumbRoute[] = [
{
exact: true,
path: '/',
render: renderAsRedirectTo('/csm'),
breadcrumb: 'Client Side Monitoring',
name: RouteName.CSM,
},
];
function CsmApp() {
const [darkMode] = useUiSetting$<boolean>('theme:darkMode');
return (
<ThemeProvider
theme={(outerTheme?: DefaultTheme) => ({
...outerTheme,
eui: darkMode ? euiDarkVars : euiLightVars,
darkMode,
})}
>
<CsmMainContainer data-test-subj="csmMainContainer" role="main">
<UpdateBreadcrumbs routes={rumRoutes} />
<Route component={ScrollToTopOnPathChange} />
<RumHome />
</CsmMainContainer>
</ThemeProvider>
);
}
export function CsmAppRoot({
core,
deps,
routerHistory,
config,
}: {
core: CoreStart;
deps: ApmPluginSetupDeps;
routerHistory: typeof history;
config: ConfigSchema;
}) {
const i18nCore = core.i18n;
const plugins = deps;
const apmPluginContextValue = {
config,
core,
plugins,
};
return (
<ApmPluginContext.Provider value={apmPluginContextValue}>
<KibanaContextProvider services={{ ...core, ...plugins }}>
<i18nCore.Context>
<Router history={routerHistory}>
<UrlParamsProvider>
<LoadingIndicatorProvider>
<CsmApp />
</LoadingIndicatorProvider>
</UrlParamsProvider>
</Router>
</i18nCore.Context>
</KibanaContextProvider>
</ApmPluginContext.Provider>
);
}
/**
* This module is rendered asynchronously in the Kibana platform.
*/
export const renderApp = (
core: CoreStart,
deps: ApmPluginSetupDeps,
{ element }: AppMountParameters,
config: ConfigSchema
) => {
createCallApmApi(core.http);
resetHistory();
ReactDOM.render(
<CsmAppRoot
core={core}
deps={deps}
routerHistory={history}
config={config}
/>,
element
);
return () => {
ReactDOM.unmountComponentAtNode(element);
};
};

View file

@ -20,6 +20,7 @@ import { LocationProvider } from '../context/LocationContext';
import { MatchedRouteProvider } from '../context/MatchedRouteContext';
import { UrlParamsProvider } from '../context/UrlParamsContext';
import { AlertsContextProvider } from '../../../triggers_actions_ui/public';
import { createStaticIndexPattern } from '../services/rest/index_pattern';
import {
KibanaContextProvider,
useUiSetting$,
@ -29,6 +30,9 @@ import { UpdateBreadcrumbs } from '../components/app/Main/UpdateBreadcrumbs';
import { ScrollToTopOnPathChange } from '../components/app/Main/ScrollToTopOnPathChange';
import { routes } from '../components/app/Main/route_config';
import { history, resetHistory } from '../utils/history';
import { setHelpExtension } from '../setHelpExtension';
import { setReadonlyBadge } from '../updateBadge';
import { createCallApmApi } from '../services/rest/createCallApmApi';
import { ConfigSchema } from '..';
import 'react-vis/dist/style.css';
@ -61,7 +65,7 @@ function App() {
);
}
function ApmAppRoot({
export function ApmAppRoot({
core,
deps,
routerHistory,
@ -116,13 +120,27 @@ function ApmAppRoot({
/**
* This module is rendered asynchronously in the Kibana platform.
*/
export const renderApp = (
core: CoreStart,
deps: ApmPluginSetupDeps,
{ element }: AppMountParameters,
config: ConfigSchema
) => {
// render APM feedback link in global help menu
setHelpExtension(core);
setReadonlyBadge(core);
createCallApmApi(core.http);
resetHistory();
// Automatically creates static index pattern and stores as saved object
createStaticIndexPattern().catch((e) => {
// eslint-disable-next-line no-console
console.log('Error creating static index pattern', e);
});
ReactDOM.render(
<ApmAppRoot
core={core}

View file

@ -25,10 +25,9 @@ import { TraceLink } from '../../TraceLink';
import { CustomizeUI } from '../../Settings/CustomizeUI';
import { AnomalyDetection } from '../../Settings/anomaly_detection';
import {
EditAgentConfigurationRouteHandler,
CreateAgentConfigurationRouteHandler,
EditAgentConfigurationRouteHandler,
} from './route_handlers/agent_configuration';
import { RumHome } from '../../RumDashboard/RumHome';
const metricsBreadcrumb = i18n.translate('xpack.apm.breadcrumb.metricsTitle', {
defaultMessage: 'Metrics',
@ -38,7 +37,7 @@ interface RouteParams {
serviceName: string;
}
const renderAsRedirectTo = (to: string) => {
export const renderAsRedirectTo = (to: string) => {
return ({ location }: RouteComponentProps<RouteParams>) => (
<Redirect
to={{
@ -252,15 +251,6 @@ export const routes: BreadcrumbRoute[] = [
}),
name: RouteName.CUSTOMIZE_UI,
},
{
exact: true,
path: '/rum-preview',
component: () => <RumHome />,
breadcrumb: i18n.translate('xpack.apm.home.rumOverview.title', {
defaultMessage: 'Real User Monitoring',
}),
name: RouteName.RUM_OVERVIEW,
},
{
exact: true,
path: '/settings/anomaly-detection',

View file

@ -26,6 +26,6 @@ export enum RouteName {
SERVICE_NODES = 'nodes',
LINK_TO_TRACE = 'link_to_trace',
CUSTOMIZE_UI = 'customize_ui',
RUM_OVERVIEW = 'rum_overview',
ANOMALY_DETECTION = 'anomaly_detection',
CSM = 'csm',
}

View file

@ -6,6 +6,7 @@
import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui';
import React from 'react';
import { i18n } from '@kbn/i18n';
import { RumOverview } from '../RumDashboard';
import { RumHeader } from './RumHeader';
@ -16,7 +17,11 @@ export function RumHome() {
<EuiFlexGroup alignItems="center">
<EuiFlexItem grow={false}>
<EuiTitle size="l">
<h1>End User Experience</h1>
<h1>
{i18n.translate('xpack.apm.csm.title', {
defaultMessage: 'Client Side Monitoring',
})}
</h1>
</EuiTitle>
</EuiFlexItem>
</EuiFlexGroup>

View file

@ -7,7 +7,10 @@
import { i18n } from '@kbn/i18n';
import { lazy } from 'react';
import { ConfigSchema } from '.';
import { ObservabilityPluginSetup } from '../../observability/public';
import {
FetchDataParams,
ObservabilityPluginSetup,
} from '../../observability/public';
import {
AppMountParameters,
CoreSetup,
@ -33,15 +36,7 @@ import {
} from '../../triggers_actions_ui/public';
import { AlertType } from '../common/alert_types';
import { featureCatalogueEntry } from './featureCatalogueEntry';
import { createCallApmApi } from './services/rest/createCallApmApi';
import { setHelpExtension } from './setHelpExtension';
import { toggleAppLinkInNav } from './toggleAppLinkInNav';
import { setReadonlyBadge } from './updateBadge';
import { createStaticIndexPattern } from './services/rest/index_pattern';
import {
fetchOverviewPageData,
hasData,
} from './services/rest/apm_overview_fetchers';
export type ApmPluginSetup = void;
export type ApmPluginStart = void;
@ -71,7 +66,6 @@ export class ApmPlugin implements Plugin<ApmPluginSetup, ApmPluginStart> {
this.initializerContext = initializerContext;
}
public setup(core: CoreSetup, plugins: ApmPluginSetupDeps) {
createCallApmApi(core.http);
const config = this.initializerContext.config.get();
const pluginSetupDeps = plugins;
@ -79,10 +73,27 @@ export class ApmPlugin implements Plugin<ApmPluginSetup, ApmPluginStart> {
pluginSetupDeps.home.featureCatalogue.register(featureCatalogueEntry);
if (plugins.observability) {
const getApmDataHelper = async () => {
const {
fetchOverviewPageData,
hasData,
createCallApmApi,
} = await import('./services/rest/apm_overview_fetchers');
// have to do this here as well in case app isn't mounted yet
createCallApmApi(core.http);
return { fetchOverviewPageData, hasData };
};
plugins.observability.dashboard.register({
appName: 'apm',
fetchData: fetchOverviewPageData,
hasData,
hasData: async () => {
const dataHelper = await getApmDataHelper();
return await dataHelper.hasData();
},
fetchData: async (params: FetchDataParams) => {
const dataHelper = await getApmDataHelper();
return await dataHelper.fetchOverviewPageData(params);
},
});
}
@ -96,20 +107,28 @@ export class ApmPlugin implements Plugin<ApmPluginSetup, ApmPluginStart> {
category: DEFAULT_APP_CATEGORIES.observability,
async mount(params: AppMountParameters<unknown>) {
// Load application bundle
const { renderApp } = await import('./application');
// Get start services
const [coreStart] = await core.getStartServices();
// Load application bundle and Get start services
const [{ renderApp }, [coreStart]] = await Promise.all([
import('./application'),
core.getStartServices(),
]);
// render APM feedback link in global help menu
setHelpExtension(coreStart);
setReadonlyBadge(coreStart);
return renderApp(coreStart, pluginSetupDeps, params, config);
},
});
// Automatically creates static index pattern and stores as saved object
createStaticIndexPattern().catch((e) => {
// eslint-disable-next-line no-console
console.log('Error creating static index pattern', e);
});
core.application.register({
id: 'csm',
title: 'Client Side Monitoring',
order: 8500,
category: DEFAULT_APP_CATEGORIES.observability,
async mount(params: AppMountParameters<unknown>) {
// Load application bundle and Get start service
const [{ renderApp }, [coreStart]] = await Promise.all([
import('./application/csmApp'),
core.getStartServices(),
]);
return renderApp(coreStart, pluginSetupDeps, params, config);
},

View file

@ -11,6 +11,8 @@ import {
} from '../../../../observability/public';
import { callApmApi } from './createCallApmApi';
export { createCallApmApi } from './createCallApmApi';
export const fetchOverviewPageData = async ({
absoluteTime,
relativeTime,

View file

@ -15,7 +15,7 @@ export const APM_FEATURE = {
order: 900,
icon: 'apmApp',
navLinkId: 'apm',
app: ['apm', 'kibana'],
app: ['apm', 'csm', 'kibana'],
catalogue: ['apm'],
management: {
insightsAndAlerting: ['triggersActions'],
@ -24,7 +24,7 @@ export const APM_FEATURE = {
// see x-pack/plugins/features/common/feature_kibana_privileges.ts
privileges: {
all: {
app: ['apm', 'kibana'],
app: ['apm', 'csm', 'kibana'],
api: ['apm', 'apm_write'],
catalogue: ['apm'],
savedObject: {
@ -40,7 +40,7 @@ export const APM_FEATURE = {
ui: ['show', 'save', 'alerting:show', 'alerting:save'],
},
read: {
app: ['apm', 'kibana'],
app: ['apm', 'csm', 'kibana'],
api: ['apm'],
catalogue: ['apm'],
savedObject: {

View file

@ -4833,7 +4833,6 @@
"xpack.apm.header.badge.readOnly.tooltip": "を保存できませんでした",
"xpack.apm.helpMenu.upgradeAssistantLink": "アップグレードアシスタント",
"xpack.apm.histogram.plot.noDataLabel": "この時間範囲のデータがありません。",
"xpack.apm.home.rumOverview.title": "リアルユーザー監視",
"xpack.apm.home.serviceMapTabLabel": "サービスマップ",
"xpack.apm.home.servicesTabLabel": "サービス",
"xpack.apm.home.tracesTabLabel": "トレース",

View file

@ -4834,7 +4834,6 @@
"xpack.apm.header.badge.readOnly.tooltip": "无法保存",
"xpack.apm.helpMenu.upgradeAssistantLink": "升级助手",
"xpack.apm.histogram.plot.noDataLabel": "此时间范围内没有数据。",
"xpack.apm.home.rumOverview.title": "真实用户监测",
"xpack.apm.home.serviceMapTabLabel": "服务地图",
"xpack.apm.home.servicesTabLabel": "服务",
"xpack.apm.home.tracesTabLabel": "追溯",

View file

@ -60,7 +60,12 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
it('shows apm navlink', async () => {
const navLinks = await appsMenu.readLinks();
expect(navLinks.map((link) => link.text)).to.eql(['Overview', 'APM', 'Stack Management']);
expect(navLinks.map((link) => link.text)).to.eql([
'Overview',
'APM',
'Client Side Monitoring',
'Stack Management',
]);
});
it('can navigate to APM app', async () => {
@ -109,7 +114,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
it('shows apm navlink', async () => {
const navLinks = (await appsMenu.readLinks()).map((link) => link.text);
expect(navLinks).to.eql(['Overview', 'APM', 'Stack Management']);
expect(navLinks).to.eql(['Overview', 'APM', 'Client Side Monitoring', 'Stack Management']);
});
it('can navigate to APM app', async () => {