Fix ENVIRONMENT_ALL links to exploratory view (#105704)
Leave the environment out of the URL for the exploratory view when "All" is selected in the environment dropdown. Move the analyze data button to its own component. Add tests and stories for the the APM service template and analyze data button. Fixes #105467.
This commit is contained in:
parent
219e1e5ab2
commit
ce5a798fdd
5 changed files with 241 additions and 78 deletions
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { Story, StoryContext } from '@storybook/react';
|
||||
import React, { ComponentType } from 'react';
|
||||
import { CoreStart } from '../../../../../../../../src/core/public';
|
||||
import { createKibanaReactContext } from '../../../../../../../../src/plugins/kibana_react/public';
|
||||
import { APMServiceContext } from '../../../../context/apm_service/apm_service_context';
|
||||
import { MockUrlParamsContextProvider } from '../../../../context/url_params_context/mock_url_params_context_provider';
|
||||
import { AnalyzeDataButton } from './analyze_data_button';
|
||||
|
||||
const KibanaContext = createKibanaReactContext(({
|
||||
http: { basePath: { get: () => '' } },
|
||||
} as unknown) as Partial<CoreStart>);
|
||||
|
||||
interface Args {
|
||||
agentName: string;
|
||||
environment?: string;
|
||||
serviceName: string;
|
||||
}
|
||||
|
||||
export default {
|
||||
title: 'routing/templates/ApmServiceTemplate/AnalyzeDataButton',
|
||||
component: AnalyzeDataButton,
|
||||
decorators: [
|
||||
(StoryComponent: ComponentType, { args }: StoryContext) => {
|
||||
const { agentName, environment, serviceName } = args;
|
||||
|
||||
return (
|
||||
<MockUrlParamsContextProvider
|
||||
params={{ environment, rangeFrom: 'now-15m', rangeTo: 'now' }}
|
||||
>
|
||||
<APMServiceContext.Provider
|
||||
value={{ agentName, alerts: [], transactionTypes: [], serviceName }}
|
||||
>
|
||||
<KibanaContext.Provider>
|
||||
<StoryComponent />
|
||||
</KibanaContext.Provider>
|
||||
</APMServiceContext.Provider>
|
||||
</MockUrlParamsContextProvider>
|
||||
);
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const Example: Story<Args> = () => {
|
||||
return <AnalyzeDataButton />;
|
||||
};
|
||||
Example.args = {
|
||||
agentName: 'iOS/swift',
|
||||
environment: 'testEnvironment',
|
||||
serviceName: 'testServiceName',
|
||||
};
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { composeStories } from '@storybook/testing-react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import {
|
||||
ENVIRONMENT_ALL,
|
||||
ENVIRONMENT_NOT_DEFINED,
|
||||
} from '../../../../../common/environment_filter_values';
|
||||
import * as stories from './analyze_data_button.stories';
|
||||
|
||||
const { Example } = composeStories(stories);
|
||||
|
||||
describe('AnalyzeDataButton', () => {
|
||||
describe('with a non-RUM and non-mobile agent', () => {
|
||||
it('renders nothing', () => {
|
||||
render(<Example agentName="java" />);
|
||||
|
||||
expect(screen.queryByRole('link')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('with a RUM agent', () => {
|
||||
it('uses a ux dataType', () => {
|
||||
render(<Example agentName="rum-js" />);
|
||||
|
||||
expect((screen.getByRole('link') as HTMLAnchorElement).href).toEqual(
|
||||
'http://localhost/app/observability/exploratory-view#?sr=(apm-series:(dt:ux,isNew:!t,op:average,rdf:(service.environment:!(testEnvironment),service.name:!(testServiceName)),rt:kpi-over-time,time:(from:now-15m,to:now)))'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with a mobile agent', () => {
|
||||
it('uses a mobile dataType', () => {
|
||||
render(<Example agentName="iOS/swift" />);
|
||||
|
||||
expect((screen.getByRole('link') as HTMLAnchorElement).href).toEqual(
|
||||
'http://localhost/app/observability/exploratory-view#?sr=(apm-series:(dt:mobile,isNew:!t,op:average,rdf:(service.environment:!(testEnvironment),service.name:!(testServiceName)),rt:kpi-over-time,time:(from:now-15m,to:now)))'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with no environment', () => {
|
||||
it('does not include the environment', () => {
|
||||
render(<Example environment={undefined} />);
|
||||
|
||||
expect((screen.getByRole('link') as HTMLAnchorElement).href).toEqual(
|
||||
'http://localhost/app/observability/exploratory-view#?sr=(apm-series:(dt:mobile,isNew:!t,op:average,rdf:(service.name:!(testServiceName)),rt:kpi-over-time,time:(from:now-15m,to:now)))'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with environment not defined', () => {
|
||||
it('does not include the environment', () => {
|
||||
render(<Example environment={ENVIRONMENT_NOT_DEFINED.value} />);
|
||||
|
||||
expect((screen.getByRole('link') as HTMLAnchorElement).href).toEqual(
|
||||
'http://localhost/app/observability/exploratory-view#?sr=(apm-series:(dt:mobile,isNew:!t,op:average,rdf:(service.name:!(testServiceName)),rt:kpi-over-time,time:(from:now-15m,to:now)))'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with environment all', () => {
|
||||
it('uses ALL_VALUES', () => {
|
||||
render(<Example environment={ENVIRONMENT_ALL.value} />);
|
||||
|
||||
expect((screen.getByRole('link') as HTMLAnchorElement).href).toEqual(
|
||||
'http://localhost/app/observability/exploratory-view#?sr=(apm-series:(dt:mobile,isNew:!t,op:average,rdf:(service.environment:!(ALL_VALUES),service.name:!(testServiceName)),rt:kpi-over-time,time:(from:now-15m,to:now)))'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { EuiButtonEmpty, EuiToolTip } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public';
|
||||
import {
|
||||
createExploratoryViewUrl,
|
||||
SeriesUrl,
|
||||
} from '../../../../../../observability/public';
|
||||
import { ALL_VALUES_SELECTED } from '../../../../../../observability/public';
|
||||
import {
|
||||
isIosAgentName,
|
||||
isRumAgentName,
|
||||
} from '../../../../../common/agent_name';
|
||||
import {
|
||||
SERVICE_ENVIRONMENT,
|
||||
SERVICE_NAME,
|
||||
} from '../../../../../common/elasticsearch_fieldnames';
|
||||
import {
|
||||
ENVIRONMENT_ALL,
|
||||
ENVIRONMENT_NOT_DEFINED,
|
||||
} from '../../../../../common/environment_filter_values';
|
||||
import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context';
|
||||
import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
|
||||
|
||||
function getEnvironmentDefinition(environment?: string) {
|
||||
switch (environment) {
|
||||
case ENVIRONMENT_ALL.value:
|
||||
return { [SERVICE_ENVIRONMENT]: [ALL_VALUES_SELECTED] };
|
||||
case ENVIRONMENT_NOT_DEFINED.value:
|
||||
case undefined:
|
||||
return {};
|
||||
default:
|
||||
return { [SERVICE_ENVIRONMENT]: [environment] };
|
||||
}
|
||||
}
|
||||
|
||||
export function AnalyzeDataButton() {
|
||||
const { agentName, serviceName } = useApmServiceContext();
|
||||
const { services } = useKibana();
|
||||
const { urlParams } = useUrlParams();
|
||||
const { rangeTo, rangeFrom, environment } = urlParams;
|
||||
const basepath = services.http?.basePath.get();
|
||||
|
||||
if (isRumAgentName(agentName) || isIosAgentName(agentName)) {
|
||||
const href = createExploratoryViewUrl(
|
||||
{
|
||||
'apm-series': {
|
||||
dataType: isRumAgentName(agentName) ? 'ux' : 'mobile',
|
||||
time: { from: rangeFrom, to: rangeTo },
|
||||
reportType: 'kpi-over-time',
|
||||
reportDefinitions: {
|
||||
[SERVICE_NAME]: [serviceName],
|
||||
...getEnvironmentDefinition(environment),
|
||||
},
|
||||
operationType: 'average',
|
||||
isNew: true,
|
||||
} as SeriesUrl,
|
||||
},
|
||||
basepath
|
||||
);
|
||||
|
||||
return (
|
||||
<EuiToolTip
|
||||
position="top"
|
||||
content={i18n.translate('xpack.apm.analyzeDataButton.tooltip', {
|
||||
defaultMessage:
|
||||
'EXPERIMENTAL - Analyze Data allows you to select and filter result data in any dimension, and look for the cause or impact of performance problems',
|
||||
})}
|
||||
>
|
||||
<EuiButtonEmpty href={href} iconType="visBarVerticalStacked">
|
||||
{i18n.translate('xpack.apm.analyzeDataButton.label', {
|
||||
defaultMessage: 'Analyze data',
|
||||
})}
|
||||
</EuiButtonEmpty>
|
||||
</EuiToolTip>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
|
@ -5,45 +5,33 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
EuiBetaBadge,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiPageHeaderProps,
|
||||
EuiTitle,
|
||||
EuiBetaBadge,
|
||||
EuiToolTip,
|
||||
EuiButtonEmpty,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { omit } from 'lodash';
|
||||
import { ApmMainTemplate } from './apm_main_template';
|
||||
import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
|
||||
import { ApmServiceContextProvider } from '../../../context/apm_service/apm_service_context';
|
||||
import { enableServiceOverview } from '../../../../common/ui_settings_keys';
|
||||
import React from 'react';
|
||||
import {
|
||||
isIosAgentName,
|
||||
isJavaAgentName,
|
||||
isRumAgentName,
|
||||
isIosAgentName,
|
||||
} from '../../../../common/agent_name';
|
||||
import { ServiceIcons } from '../../shared/service_icons';
|
||||
import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context';
|
||||
import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context';
|
||||
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
|
||||
import { ENVIRONMENT_NOT_DEFINED } from '../../../../common/environment_filter_values';
|
||||
import {
|
||||
SERVICE_NAME,
|
||||
SERVICE_ENVIRONMENT,
|
||||
} from '../../../../common/elasticsearch_fieldnames';
|
||||
import { Correlations } from '../../app/correlations';
|
||||
import { SearchBar } from '../../shared/search_bar';
|
||||
import {
|
||||
createExploratoryViewUrl,
|
||||
SeriesUrl,
|
||||
} from '../../../../../observability/public';
|
||||
import { useApmParams } from '../../../hooks/use_apm_params';
|
||||
import { useBreadcrumb } from '../../../context/breadcrumbs/use_breadcrumb';
|
||||
import { useApmRouter } from '../../../hooks/use_apm_router';
|
||||
} from '../../../../../common/agent_name';
|
||||
import { enableServiceOverview } from '../../../../../common/ui_settings_keys';
|
||||
import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context';
|
||||
import { ApmServiceContextProvider } from '../../../../context/apm_service/apm_service_context';
|
||||
import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context';
|
||||
import { useBreadcrumb } from '../../../../context/breadcrumbs/use_breadcrumb';
|
||||
import { useApmParams } from '../../../../hooks/use_apm_params';
|
||||
import { useApmRouter } from '../../../../hooks/use_apm_router';
|
||||
import { Correlations } from '../../../app/correlations';
|
||||
import { SearchBar } from '../../../shared/search_bar';
|
||||
import { ServiceIcons } from '../../../shared/service_icons';
|
||||
import { ApmMainTemplate } from '../apm_main_template';
|
||||
import { AnalyzeDataButton } from './analyze_data_button';
|
||||
|
||||
type Tab = NonNullable<EuiPageHeaderProps['tabs']>[0] & {
|
||||
key:
|
||||
|
@ -105,7 +93,7 @@ function TemplateWithContext({
|
|||
<EuiFlexGroup alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiTitle size="l">
|
||||
<h1>{serviceName}</h1>
|
||||
<>{serviceName}</>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
|
@ -115,7 +103,7 @@ function TemplateWithContext({
|
|||
</EuiFlexItem>
|
||||
|
||||
<EuiFlexItem grow={false}>
|
||||
<AnalyzeDataButton serviceName={serviceName} />
|
||||
<AnalyzeDataButton />
|
||||
</EuiFlexItem>
|
||||
|
||||
<EuiFlexItem grow={false}>
|
||||
|
@ -132,53 +120,6 @@ function TemplateWithContext({
|
|||
);
|
||||
}
|
||||
|
||||
function AnalyzeDataButton({ serviceName }: { serviceName: string }) {
|
||||
const { agentName } = useApmServiceContext();
|
||||
const { services } = useKibana();
|
||||
const { urlParams } = useUrlParams();
|
||||
const { rangeTo, rangeFrom, environment } = urlParams;
|
||||
const basepath = services.http?.basePath.get();
|
||||
|
||||
if (isRumAgentName(agentName) || isIosAgentName(agentName)) {
|
||||
const href = createExploratoryViewUrl(
|
||||
{
|
||||
'apm-series': {
|
||||
dataType: isRumAgentName(agentName) ? 'ux' : 'mobile',
|
||||
time: { from: rangeFrom, to: rangeTo },
|
||||
reportType: 'kpi-over-time',
|
||||
reportDefinitions: {
|
||||
[SERVICE_NAME]: [serviceName],
|
||||
...(!!environment && ENVIRONMENT_NOT_DEFINED.value !== environment
|
||||
? { [SERVICE_ENVIRONMENT]: [environment] }
|
||||
: {}),
|
||||
},
|
||||
operationType: 'average',
|
||||
isNew: true,
|
||||
} as SeriesUrl,
|
||||
},
|
||||
basepath
|
||||
);
|
||||
|
||||
return (
|
||||
<EuiToolTip
|
||||
position="top"
|
||||
content={i18n.translate('xpack.apm.analyzeDataButton.tooltip', {
|
||||
defaultMessage:
|
||||
'EXPERIMENTAL - Analyze Data allows you to select and filter result data in any dimension, and look for the cause or impact of performance problems',
|
||||
})}
|
||||
>
|
||||
<EuiButtonEmpty href={href} iconType="visBarVerticalStacked">
|
||||
{i18n.translate('xpack.apm.analyzeDataButton.label', {
|
||||
defaultMessage: 'Analyze data',
|
||||
})}
|
||||
</EuiButtonEmpty>
|
||||
</EuiToolTip>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function useTabs({ selectedTab }: { selectedTab: Tab['key'] }) {
|
||||
const { agentName } = useApmServiceContext();
|
||||
const { core, config } = useApmPluginContext();
|
|
@ -65,6 +65,7 @@ export { useBreadcrumbs } from './hooks/use_breadcrumbs';
|
|||
export { useTheme } from './hooks/use_theme';
|
||||
export { getApmTraceUrl } from './utils/get_apm_trace_url';
|
||||
export { createExploratoryViewUrl } from './components/shared/exploratory_view/configurations/utils';
|
||||
export { ALL_VALUES_SELECTED } from './components/shared/field_value_suggestions/field_value_combobox';
|
||||
export { FilterValueLabel } from './components/shared/filter_value_label/filter_value_label';
|
||||
export type { SeriesUrl } from './components/shared/exploratory_view/types';
|
||||
|
||||
|
|
Loading…
Reference in a new issue