mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
Allow editing of APM rules (#106598)
By pulling out most of the things that depend on the URL into where we open the flyout and passing them in as metadata props, we can make it so editing rules while in Stack Management. You cannot edit a rule's service name, transaction type, or environment once it has been created (#106786 has been created to allow editing of these other values), but all other values can be edited. In order for useFetcher to work outside of the APM plugin, it has been changed to use useKibana instead of useApmContext for toast notifications. The notifications API from useKibana is slightly different and allows passing a react element instead of a mount point as the body. Fixes #76316.
This commit is contained in:
parent
76989b57eb
commit
a6211f86f2
13 changed files with 206 additions and 224 deletions
|
@ -14,6 +14,10 @@ import {
|
||||||
import { getInitialAlertValues } from '../get_initial_alert_values';
|
import { getInitialAlertValues } from '../get_initial_alert_values';
|
||||||
import { ApmPluginStartDeps } from '../../../plugin';
|
import { ApmPluginStartDeps } from '../../../plugin';
|
||||||
import { useServiceName } from '../../../hooks/use_service_name';
|
import { useServiceName } from '../../../hooks/use_service_name';
|
||||||
|
import { useApmParams } from '../../../hooks/use_apm_params';
|
||||||
|
import { AlertMetadata } from '../helper';
|
||||||
|
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
|
||||||
|
import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
addFlyoutVisible: boolean;
|
addFlyoutVisible: boolean;
|
||||||
|
@ -23,7 +27,17 @@ interface Props {
|
||||||
|
|
||||||
export function AlertingFlyout(props: Props) {
|
export function AlertingFlyout(props: Props) {
|
||||||
const { addFlyoutVisible, setAddFlyoutVisibility, alertType } = props;
|
const { addFlyoutVisible, setAddFlyoutVisibility, alertType } = props;
|
||||||
|
|
||||||
const serviceName = useServiceName();
|
const serviceName = useServiceName();
|
||||||
|
const { query } = useApmParams('/*');
|
||||||
|
const {
|
||||||
|
urlParams: { start, end },
|
||||||
|
} = useUrlParams();
|
||||||
|
const environment =
|
||||||
|
'environment' in query ? query.environment : ENVIRONMENT_ALL.value;
|
||||||
|
const transactionType =
|
||||||
|
'transactionType' in query ? query.transactionType : undefined;
|
||||||
|
|
||||||
const { services } = useKibana<ApmPluginStartDeps>();
|
const { services } = useKibana<ApmPluginStartDeps>();
|
||||||
const initialValues = getInitialAlertValues(alertType, serviceName);
|
const initialValues = getInitialAlertValues(alertType, serviceName);
|
||||||
|
|
||||||
|
@ -40,9 +54,26 @@ export function AlertingFlyout(props: Props) {
|
||||||
alertTypeId: alertType,
|
alertTypeId: alertType,
|
||||||
canChangeTrigger: false,
|
canChangeTrigger: false,
|
||||||
initialValues,
|
initialValues,
|
||||||
|
metadata: {
|
||||||
|
environment,
|
||||||
|
serviceName,
|
||||||
|
transactionType,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
} as AlertMetadata,
|
||||||
}),
|
}),
|
||||||
/* eslint-disable-next-line react-hooks/exhaustive-deps */
|
/* eslint-disable-next-line react-hooks/exhaustive-deps */
|
||||||
[alertType, onCloseAddFlyout, services.triggersActionsUi]
|
[
|
||||||
|
alertType,
|
||||||
|
environment,
|
||||||
|
onCloseAddFlyout,
|
||||||
|
services.triggersActionsUi,
|
||||||
|
serviceName,
|
||||||
|
transactionType,
|
||||||
|
environment,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
return <>{addFlyoutVisible && addAlertFlyout}</>;
|
return <>{addFlyoutVisible && addAlertFlyout}</>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,44 +5,47 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { AlertParams, ErrorCountAlertTrigger } from '.';
|
||||||
import { ErrorCountAlertTrigger } from '.';
|
import { CoreStart } from '../../../../../../../src/core/public';
|
||||||
import { ApmPluginContextValue } from '../../../context/apm_plugin/apm_plugin_context';
|
import { createKibanaReactContext } from '../../../../../../../src/plugins/kibana_react/public';
|
||||||
import {
|
|
||||||
mockApmPluginContextValue,
|
const KibanaReactContext = createKibanaReactContext(({
|
||||||
MockApmPluginContextWrapper,
|
notifications: { toasts: { add: () => {} } },
|
||||||
} from '../../../context/apm_plugin/mock_apm_plugin_context';
|
} as unknown) as Partial<CoreStart>);
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: 'app/ErrorCountAlertTrigger',
|
title: 'alerting/ErrorCountAlertTrigger',
|
||||||
component: ErrorCountAlertTrigger,
|
component: ErrorCountAlertTrigger,
|
||||||
decorators: [
|
decorators: [
|
||||||
(Story: React.ComponentClass) => (
|
(Story: React.ComponentClass) => (
|
||||||
<MockApmPluginContextWrapper
|
<KibanaReactContext.Provider>
|
||||||
value={(mockApmPluginContextValue as unknown) as ApmPluginContextValue}
|
<div style={{ width: 400 }}>
|
||||||
>
|
<Story />
|
||||||
<MemoryRouter>
|
</div>
|
||||||
<div style={{ width: 400 }}>
|
</KibanaReactContext.Provider>
|
||||||
<Story />
|
|
||||||
</div>
|
|
||||||
</MemoryRouter>
|
|
||||||
</MockApmPluginContextWrapper>
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export function Example() {
|
export function Example() {
|
||||||
const params = {
|
const [params, setParams] = useState<AlertParams>({
|
||||||
|
serviceName: 'testServiceName',
|
||||||
|
environment: 'testEnvironment',
|
||||||
threshold: 2,
|
threshold: 2,
|
||||||
window: '5m',
|
windowSize: 5,
|
||||||
};
|
windowUnit: 'm',
|
||||||
|
});
|
||||||
|
|
||||||
|
function setAlertParams(property: string, value: any) {
|
||||||
|
setParams({ ...params, [property]: value });
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ErrorCountAlertTrigger
|
<ErrorCountAlertTrigger
|
||||||
alertParams={params as any}
|
alertParams={params}
|
||||||
setAlertParams={() => undefined}
|
setAlertParams={setAlertParams}
|
||||||
setAlertProperty={() => undefined}
|
setAlertProperty={() => {}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,19 +6,16 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
|
import { defaults, omit } from 'lodash';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { defaults } from 'lodash';
|
|
||||||
import { ForLastExpression } from '../../../../../triggers_actions_ui/public';
|
import { ForLastExpression } from '../../../../../triggers_actions_ui/public';
|
||||||
import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values';
|
|
||||||
import { asInteger } from '../../../../common/utils/formatters';
|
import { asInteger } from '../../../../common/utils/formatters';
|
||||||
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
|
|
||||||
import { useEnvironmentsFetcher } from '../../../hooks/use_environments_fetcher';
|
import { useEnvironmentsFetcher } from '../../../hooks/use_environments_fetcher';
|
||||||
import { useFetcher } from '../../../hooks/use_fetcher';
|
import { useFetcher } from '../../../hooks/use_fetcher';
|
||||||
import { ChartPreview } from '../chart_preview';
|
import { ChartPreview } from '../chart_preview';
|
||||||
import { EnvironmentField, IsAboveField, ServiceField } from '../fields';
|
import { EnvironmentField, IsAboveField, ServiceField } from '../fields';
|
||||||
import { getAbsoluteTimeRange } from '../helper';
|
import { AlertMetadata, getAbsoluteTimeRange } from '../helper';
|
||||||
import { ServiceAlertTrigger } from '../service_alert_trigger';
|
import { ServiceAlertTrigger } from '../service_alert_trigger';
|
||||||
import { useServiceName } from '../../../hooks/use_service_name';
|
|
||||||
|
|
||||||
export interface AlertParams {
|
export interface AlertParams {
|
||||||
windowSize: number;
|
windowSize: number;
|
||||||
|
@ -30,33 +27,26 @@ export interface AlertParams {
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
alertParams: AlertParams;
|
alertParams: AlertParams;
|
||||||
|
metadata?: AlertMetadata;
|
||||||
setAlertParams: (key: string, value: any) => void;
|
setAlertParams: (key: string, value: any) => void;
|
||||||
setAlertProperty: (key: string, value: any) => void;
|
setAlertProperty: (key: string, value: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ErrorCountAlertTrigger(props: Props) {
|
export function ErrorCountAlertTrigger(props: Props) {
|
||||||
const { setAlertParams, setAlertProperty, alertParams } = props;
|
const { alertParams, metadata, setAlertParams, setAlertProperty } = props;
|
||||||
|
|
||||||
const serviceNameFromUrl = useServiceName();
|
|
||||||
|
|
||||||
const { urlParams } = useUrlParams();
|
|
||||||
const { start, end, environment: environmentFromUrl } = urlParams;
|
|
||||||
const { environmentOptions } = useEnvironmentsFetcher({
|
const { environmentOptions } = useEnvironmentsFetcher({
|
||||||
serviceName: serviceNameFromUrl,
|
serviceName: metadata?.serviceName,
|
||||||
start,
|
start: metadata?.start,
|
||||||
end,
|
end: metadata?.end,
|
||||||
});
|
});
|
||||||
|
|
||||||
const params = defaults(
|
const params = defaults(
|
||||||
{
|
{ ...omit(metadata, ['start', 'end']), ...alertParams },
|
||||||
...alertParams,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
threshold: 25,
|
threshold: 25,
|
||||||
windowSize: 1,
|
windowSize: 1,
|
||||||
windowUnit: 'm',
|
windowUnit: 'm',
|
||||||
environment: environmentFromUrl || ENVIRONMENT_ALL.value,
|
|
||||||
serviceName: serviceNameFromUrl,
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -36,13 +36,17 @@ export function EnvironmentField({
|
||||||
options: EuiSelectOption[];
|
options: EuiSelectOption[];
|
||||||
onChange: (event: React.ChangeEvent<HTMLSelectElement>) => void;
|
onChange: (event: React.ChangeEvent<HTMLSelectElement>) => void;
|
||||||
}) {
|
}) {
|
||||||
|
const title = i18n.translate('xpack.apm.alerting.fields.environment', {
|
||||||
|
defaultMessage: 'Environment',
|
||||||
|
});
|
||||||
|
|
||||||
|
// "1" means "All" is the only option and we should not show a select.
|
||||||
|
if (options.length === 1) {
|
||||||
|
return <EuiExpression description={title} value={currentValue} />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PopoverExpression
|
<PopoverExpression value={getEnvironmentLabel(currentValue)} title={title}>
|
||||||
value={getEnvironmentLabel(currentValue)}
|
|
||||||
title={i18n.translate('xpack.apm.alerting.fields.environment', {
|
|
||||||
defaultMessage: 'Environment',
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<EuiSelect
|
<EuiSelect
|
||||||
defaultValue={currentValue}
|
defaultValue={currentValue}
|
||||||
options={options}
|
options={options}
|
||||||
|
|
|
@ -7,6 +7,14 @@
|
||||||
|
|
||||||
import datemath from '@elastic/datemath';
|
import datemath from '@elastic/datemath';
|
||||||
|
|
||||||
|
export interface AlertMetadata {
|
||||||
|
environment: string;
|
||||||
|
serviceName?: string;
|
||||||
|
transactionType?: string;
|
||||||
|
start?: string;
|
||||||
|
end?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export function getAbsoluteTimeRange(windowSize: number, windowUnit: string) {
|
export function getAbsoluteTimeRange(windowSize: number, windowUnit: string) {
|
||||||
const now = new Date().toISOString();
|
const now = new Date().toISOString();
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ export function registerApmAlerts(
|
||||||
validate: () => ({
|
validate: () => ({
|
||||||
errors: [],
|
errors: [],
|
||||||
}),
|
}),
|
||||||
requiresAppContext: true,
|
requiresAppContext: false,
|
||||||
defaultActionMessage: i18n.translate(
|
defaultActionMessage: i18n.translate(
|
||||||
'xpack.apm.alertTypes.errorCount.defaultActionMessage',
|
'xpack.apm.alertTypes.errorCount.defaultActionMessage',
|
||||||
{
|
{
|
||||||
|
@ -126,7 +126,7 @@ export function registerApmAlerts(
|
||||||
validate: () => ({
|
validate: () => ({
|
||||||
errors: [],
|
errors: [],
|
||||||
}),
|
}),
|
||||||
requiresAppContext: true,
|
requiresAppContext: false,
|
||||||
defaultActionMessage: i18n.translate(
|
defaultActionMessage: i18n.translate(
|
||||||
'xpack.apm.alertTypes.transactionDuration.defaultActionMessage',
|
'xpack.apm.alertTypes.transactionDuration.defaultActionMessage',
|
||||||
{
|
{
|
||||||
|
@ -182,7 +182,7 @@ export function registerApmAlerts(
|
||||||
validate: () => ({
|
validate: () => ({
|
||||||
errors: [],
|
errors: [],
|
||||||
}),
|
}),
|
||||||
requiresAppContext: true,
|
requiresAppContext: false,
|
||||||
defaultActionMessage: i18n.translate(
|
defaultActionMessage: i18n.translate(
|
||||||
'xpack.apm.alertTypes.transactionErrorRate.defaultActionMessage',
|
'xpack.apm.alertTypes.transactionErrorRate.defaultActionMessage',
|
||||||
{
|
{
|
||||||
|
@ -237,7 +237,7 @@ export function registerApmAlerts(
|
||||||
validate: () => ({
|
validate: () => ({
|
||||||
errors: [],
|
errors: [],
|
||||||
}),
|
}),
|
||||||
requiresAppContext: true,
|
requiresAppContext: false,
|
||||||
defaultActionMessage: i18n.translate(
|
defaultActionMessage: i18n.translate(
|
||||||
'xpack.apm.alertTypes.transactionDurationAnomaly.defaultActionMessage',
|
'xpack.apm.alertTypes.transactionDurationAnomaly.defaultActionMessage',
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,69 +6,51 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Story } from '@storybook/react';
|
import { Story } from '@storybook/react';
|
||||||
import { cloneDeep, merge } from 'lodash';
|
import React, { ComponentType, useState } from 'react';
|
||||||
import React, { ComponentType } from 'react';
|
import { AlertParams, TransactionDurationAlertTrigger } from '.';
|
||||||
import { MemoryRouter, Route } from 'react-router-dom';
|
import { CoreStart } from '../../../../../../../src/core/public';
|
||||||
import { TransactionDurationAlertTrigger } from '.';
|
import { createKibanaReactContext } from '../../../../../../../src/plugins/kibana_react/public';
|
||||||
import { ApmPluginContextValue } from '../../../context/apm_plugin/apm_plugin_context';
|
|
||||||
import {
|
const KibanaReactContext = createKibanaReactContext(({
|
||||||
mockApmPluginContextValue,
|
notifications: { toasts: { add: () => {} } },
|
||||||
MockApmPluginContextWrapper,
|
} as unknown) as Partial<CoreStart>);
|
||||||
} from '../../../context/apm_plugin/mock_apm_plugin_context';
|
|
||||||
import { ApmServiceContextProvider } from '../../../context/apm_service/apm_service_context';
|
|
||||||
import { MockUrlParamsContextProvider } from '../../../context/url_params_context/mock_url_params_context_provider';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: 'alerting/TransactionDurationAlertTrigger',
|
title: 'alerting/TransactionDurationAlertTrigger',
|
||||||
component: TransactionDurationAlertTrigger,
|
component: TransactionDurationAlertTrigger,
|
||||||
decorators: [
|
decorators: [
|
||||||
(StoryComponent: ComponentType) => {
|
(StoryComponent: ComponentType) => {
|
||||||
const contextMock = (merge(cloneDeep(mockApmPluginContextValue), {
|
|
||||||
core: {
|
|
||||||
http: {
|
|
||||||
get: (endpoint: string) => {
|
|
||||||
if (endpoint === '/api/apm/environments') {
|
|
||||||
return Promise.resolve({ environments: ['production'] });
|
|
||||||
} else {
|
|
||||||
return Promise.resolve({
|
|
||||||
transactionTypes: ['request'],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}) as unknown) as ApmPluginContextValue;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ width: 400 }}>
|
<KibanaReactContext.Provider>
|
||||||
<MemoryRouter initialEntries={['/services/test-service-name']}>
|
<div style={{ width: 400 }}>
|
||||||
<Route path="/services/:serviceName">
|
<StoryComponent />
|
||||||
<MockApmPluginContextWrapper value={contextMock}>
|
</div>
|
||||||
<MockUrlParamsContextProvider>
|
</KibanaReactContext.Provider>
|
||||||
<ApmServiceContextProvider>
|
|
||||||
<StoryComponent />
|
|
||||||
</ApmServiceContextProvider>
|
|
||||||
</MockUrlParamsContextProvider>
|
|
||||||
</MockApmPluginContextWrapper>
|
|
||||||
</Route>
|
|
||||||
</MemoryRouter>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Example: Story = () => {
|
export const Example: Story = () => {
|
||||||
const params = {
|
const [params, setParams] = useState<AlertParams>({
|
||||||
threshold: 1500,
|
|
||||||
aggregationType: 'avg' as const,
|
aggregationType: 'avg' as const,
|
||||||
window: '5m',
|
environment: 'testEnvironment',
|
||||||
};
|
serviceName: 'testServiceName',
|
||||||
|
threshold: 1500,
|
||||||
|
transactionType: 'testTransactionType',
|
||||||
|
windowSize: 5,
|
||||||
|
windowUnit: 'm',
|
||||||
|
});
|
||||||
|
|
||||||
|
function setAlertParams(property: string, value: any) {
|
||||||
|
setParams({ ...params, [property]: value });
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TransactionDurationAlertTrigger
|
<TransactionDurationAlertTrigger
|
||||||
alertParams={params as any}
|
alertParams={params}
|
||||||
setAlertParams={() => undefined}
|
setAlertParams={setAlertParams}
|
||||||
setAlertProperty={() => undefined}
|
setAlertProperty={() => {}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,18 +7,16 @@
|
||||||
|
|
||||||
import { EuiSelect } from '@elastic/eui';
|
import { EuiSelect } from '@elastic/eui';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { map, defaults } from 'lodash';
|
import { defaults, map, omit } from 'lodash';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { CoreStart } from '../../../../../../../src/core/public';
|
||||||
|
import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
|
||||||
import { ForLastExpression } from '../../../../../triggers_actions_ui/public';
|
import { ForLastExpression } from '../../../../../triggers_actions_ui/public';
|
||||||
import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values';
|
|
||||||
import { getDurationFormatter } from '../../../../common/utils/formatters';
|
import { getDurationFormatter } from '../../../../common/utils/formatters';
|
||||||
import { getTransactionType } from '../../../context/apm_service/apm_service_context';
|
|
||||||
import { useServiceAgentNameFetcher } from '../../../context/apm_service/use_service_agent_name_fetcher';
|
|
||||||
import { useServiceTransactionTypesFetcher } from '../../../context/apm_service/use_service_transaction_types_fetcher';
|
import { useServiceTransactionTypesFetcher } from '../../../context/apm_service/use_service_transaction_types_fetcher';
|
||||||
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
|
|
||||||
import { useEnvironmentsFetcher } from '../../../hooks/use_environments_fetcher';
|
import { useEnvironmentsFetcher } from '../../../hooks/use_environments_fetcher';
|
||||||
import { useFetcher } from '../../../hooks/use_fetcher';
|
import { useFetcher } from '../../../hooks/use_fetcher';
|
||||||
import { useServiceName } from '../../../hooks/use_service_name';
|
import { createCallApmApi } from '../../../services/rest/createCallApmApi';
|
||||||
import {
|
import {
|
||||||
getMaxY,
|
getMaxY,
|
||||||
getResponseTimeTickFormatter,
|
getResponseTimeTickFormatter,
|
||||||
|
@ -30,18 +28,18 @@ import {
|
||||||
ServiceField,
|
ServiceField,
|
||||||
TransactionTypeField,
|
TransactionTypeField,
|
||||||
} from '../fields';
|
} from '../fields';
|
||||||
import { getAbsoluteTimeRange } from '../helper';
|
import { AlertMetadata, getAbsoluteTimeRange } from '../helper';
|
||||||
import { ServiceAlertTrigger } from '../service_alert_trigger';
|
import { ServiceAlertTrigger } from '../service_alert_trigger';
|
||||||
import { PopoverExpression } from '../service_alert_trigger/popover_expression';
|
import { PopoverExpression } from '../service_alert_trigger/popover_expression';
|
||||||
|
|
||||||
interface AlertParams {
|
export interface AlertParams {
|
||||||
|
aggregationType: 'avg' | '95th' | '99th';
|
||||||
|
environment: string;
|
||||||
|
serviceName: string;
|
||||||
|
threshold: number;
|
||||||
|
transactionType: string;
|
||||||
windowSize: number;
|
windowSize: number;
|
||||||
windowUnit: string;
|
windowUnit: string;
|
||||||
threshold: number;
|
|
||||||
aggregationType: 'avg' | '95th' | '99th';
|
|
||||||
serviceName: string;
|
|
||||||
transactionType: string;
|
|
||||||
environment: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const TRANSACTION_ALERT_AGGREGATION_TYPES = {
|
const TRANSACTION_ALERT_AGGREGATION_TYPES = {
|
||||||
|
@ -67,48 +65,38 @@ const TRANSACTION_ALERT_AGGREGATION_TYPES = {
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
alertParams: AlertParams;
|
alertParams: AlertParams;
|
||||||
|
metadata?: AlertMetadata;
|
||||||
setAlertParams: (key: string, value: any) => void;
|
setAlertParams: (key: string, value: any) => void;
|
||||||
setAlertProperty: (key: string, value: any) => void;
|
setAlertProperty: (key: string, value: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TransactionDurationAlertTrigger(props: Props) {
|
export function TransactionDurationAlertTrigger(props: Props) {
|
||||||
const { setAlertParams, alertParams, setAlertProperty } = props;
|
const { services } = useKibana();
|
||||||
const { urlParams } = useUrlParams();
|
const { alertParams, metadata, setAlertParams, setAlertProperty } = props;
|
||||||
|
|
||||||
const { start, end, environment: environmentFromUrl } = urlParams;
|
createCallApmApi(services as CoreStart);
|
||||||
|
|
||||||
const serviceNameFromUrl = useServiceName();
|
|
||||||
|
|
||||||
const transactionTypes = useServiceTransactionTypesFetcher(
|
const transactionTypes = useServiceTransactionTypesFetcher(
|
||||||
serviceNameFromUrl
|
metadata?.serviceName
|
||||||
);
|
);
|
||||||
const { agentName } = useServiceAgentNameFetcher(serviceNameFromUrl);
|
|
||||||
|
|
||||||
const transactionTypeFromUrl = getTransactionType({
|
|
||||||
transactionType: urlParams.transactionType,
|
|
||||||
transactionTypes,
|
|
||||||
agentName,
|
|
||||||
});
|
|
||||||
|
|
||||||
const params = defaults(
|
const params = defaults(
|
||||||
{
|
{
|
||||||
|
...omit(metadata, ['start', 'end']),
|
||||||
...alertParams,
|
...alertParams,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
aggregationType: 'avg',
|
aggregationType: 'avg',
|
||||||
environment: environmentFromUrl || ENVIRONMENT_ALL.value,
|
|
||||||
threshold: 1500,
|
threshold: 1500,
|
||||||
windowSize: 5,
|
windowSize: 5,
|
||||||
windowUnit: 'm',
|
windowUnit: 'm',
|
||||||
transactionType: transactionTypeFromUrl,
|
|
||||||
serviceName: serviceNameFromUrl,
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const { environmentOptions } = useEnvironmentsFetcher({
|
const { environmentOptions } = useEnvironmentsFetcher({
|
||||||
serviceName: params.serviceName,
|
serviceName: params.serviceName,
|
||||||
start,
|
start: metadata?.start,
|
||||||
end,
|
end: metadata?.end,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data } = useFetcher(
|
const { data } = useFetcher(
|
||||||
|
@ -155,7 +143,7 @@ export function TransactionDurationAlertTrigger(props: Props) {
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!transactionTypes.length || !params.serviceName) {
|
if (!params.serviceName) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,84 +6,67 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
|
import { defaults, omit } from 'lodash';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { defaults } from 'lodash';
|
|
||||||
import { ANOMALY_SEVERITY } from '../../../../common/ml_constants';
|
import { ANOMALY_SEVERITY } from '../../../../common/ml_constants';
|
||||||
|
import { useServiceTransactionTypesFetcher } from '../../../context/apm_service/use_service_transaction_types_fetcher';
|
||||||
import { useEnvironmentsFetcher } from '../../../hooks/use_environments_fetcher';
|
import { useEnvironmentsFetcher } from '../../../hooks/use_environments_fetcher';
|
||||||
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
|
import {
|
||||||
|
EnvironmentField,
|
||||||
|
ServiceField,
|
||||||
|
TransactionTypeField,
|
||||||
|
} from '../fields';
|
||||||
|
import { AlertMetadata } from '../helper';
|
||||||
import { ServiceAlertTrigger } from '../service_alert_trigger';
|
import { ServiceAlertTrigger } from '../service_alert_trigger';
|
||||||
import { PopoverExpression } from '../service_alert_trigger/popover_expression';
|
import { PopoverExpression } from '../service_alert_trigger/popover_expression';
|
||||||
import {
|
import {
|
||||||
AnomalySeverity,
|
AnomalySeverity,
|
||||||
SelectAnomalySeverity,
|
SelectAnomalySeverity,
|
||||||
} from './select_anomaly_severity';
|
} from './select_anomaly_severity';
|
||||||
import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values';
|
|
||||||
import {
|
|
||||||
EnvironmentField,
|
|
||||||
ServiceField,
|
|
||||||
TransactionTypeField,
|
|
||||||
} from '../fields';
|
|
||||||
import { useServiceName } from '../../../hooks/use_service_name';
|
|
||||||
import { useServiceTransactionTypesFetcher } from '../../../context/apm_service/use_service_transaction_types_fetcher';
|
|
||||||
import { useServiceAgentNameFetcher } from '../../../context/apm_service/use_service_agent_name_fetcher';
|
|
||||||
import { getTransactionType } from '../../../context/apm_service/apm_service_context';
|
|
||||||
|
|
||||||
interface AlertParams {
|
interface AlertParams {
|
||||||
windowSize: number;
|
|
||||||
windowUnit: string;
|
|
||||||
serviceName?: string;
|
|
||||||
transactionType?: string;
|
|
||||||
environment: string;
|
|
||||||
anomalySeverityType:
|
anomalySeverityType:
|
||||||
| ANOMALY_SEVERITY.CRITICAL
|
| ANOMALY_SEVERITY.CRITICAL
|
||||||
| ANOMALY_SEVERITY.MAJOR
|
| ANOMALY_SEVERITY.MAJOR
|
||||||
| ANOMALY_SEVERITY.MINOR
|
| ANOMALY_SEVERITY.MINOR
|
||||||
| ANOMALY_SEVERITY.WARNING;
|
| ANOMALY_SEVERITY.WARNING;
|
||||||
|
environment: string;
|
||||||
|
serviceName?: string;
|
||||||
|
transactionType?: string;
|
||||||
|
windowSize: number;
|
||||||
|
windowUnit: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
alertParams: AlertParams;
|
alertParams: AlertParams;
|
||||||
|
metadata?: AlertMetadata;
|
||||||
setAlertParams: (key: string, value: any) => void;
|
setAlertParams: (key: string, value: any) => void;
|
||||||
setAlertProperty: (key: string, value: any) => void;
|
setAlertProperty: (key: string, value: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TransactionDurationAnomalyAlertTrigger(props: Props) {
|
export function TransactionDurationAnomalyAlertTrigger(props: Props) {
|
||||||
const { setAlertParams, alertParams, setAlertProperty } = props;
|
const { alertParams, metadata, setAlertParams, setAlertProperty } = props;
|
||||||
const { urlParams } = useUrlParams();
|
|
||||||
|
|
||||||
const serviceNameFromUrl = useServiceName();
|
|
||||||
|
|
||||||
const transactionTypes = useServiceTransactionTypesFetcher(
|
const transactionTypes = useServiceTransactionTypesFetcher(
|
||||||
serviceNameFromUrl
|
metadata?.serviceName
|
||||||
);
|
);
|
||||||
const { agentName } = useServiceAgentNameFetcher(serviceNameFromUrl);
|
|
||||||
|
|
||||||
const transactionTypeFromUrl = getTransactionType({
|
|
||||||
transactionType: urlParams.transactionType,
|
|
||||||
transactionTypes,
|
|
||||||
agentName,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { start, end, environment: environmentFromUrl } = urlParams;
|
|
||||||
|
|
||||||
const params = defaults(
|
const params = defaults(
|
||||||
{
|
{
|
||||||
|
...omit(metadata, ['start', 'end']),
|
||||||
...alertParams,
|
...alertParams,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
windowSize: 15,
|
windowSize: 15,
|
||||||
windowUnit: 'm',
|
windowUnit: 'm',
|
||||||
transactionType: transactionTypeFromUrl,
|
|
||||||
environment: environmentFromUrl || ENVIRONMENT_ALL.value,
|
|
||||||
anomalySeverityType: ANOMALY_SEVERITY.CRITICAL,
|
anomalySeverityType: ANOMALY_SEVERITY.CRITICAL,
|
||||||
serviceName: serviceNameFromUrl,
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const { environmentOptions } = useEnvironmentsFetcher({
|
const { environmentOptions } = useEnvironmentsFetcher({
|
||||||
serviceName: params.serviceName,
|
serviceName: params.serviceName,
|
||||||
start,
|
start: metadata?.start,
|
||||||
end,
|
end: metadata?.end,
|
||||||
});
|
});
|
||||||
|
|
||||||
const fields = [
|
const fields = [
|
||||||
|
|
|
@ -5,14 +5,16 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { defaults, omit } from 'lodash';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { defaults } from 'lodash';
|
import { CoreStart } from '../../../../../../../src/core/public';
|
||||||
|
import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
|
||||||
import { ForLastExpression } from '../../../../../triggers_actions_ui/public';
|
import { ForLastExpression } from '../../../../../triggers_actions_ui/public';
|
||||||
import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values';
|
|
||||||
import { asPercent } from '../../../../common/utils/formatters';
|
import { asPercent } from '../../../../common/utils/formatters';
|
||||||
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
|
import { useServiceTransactionTypesFetcher } from '../../../context/apm_service/use_service_transaction_types_fetcher';
|
||||||
import { useEnvironmentsFetcher } from '../../../hooks/use_environments_fetcher';
|
import { useEnvironmentsFetcher } from '../../../hooks/use_environments_fetcher';
|
||||||
import { useFetcher } from '../../../hooks/use_fetcher';
|
import { useFetcher } from '../../../hooks/use_fetcher';
|
||||||
|
import { createCallApmApi } from '../../../services/rest/createCallApmApi';
|
||||||
import { ChartPreview } from '../chart_preview';
|
import { ChartPreview } from '../chart_preview';
|
||||||
import {
|
import {
|
||||||
EnvironmentField,
|
EnvironmentField,
|
||||||
|
@ -20,12 +22,8 @@ import {
|
||||||
ServiceField,
|
ServiceField,
|
||||||
TransactionTypeField,
|
TransactionTypeField,
|
||||||
} from '../fields';
|
} from '../fields';
|
||||||
import { getAbsoluteTimeRange } from '../helper';
|
import { AlertMetadata, getAbsoluteTimeRange } from '../helper';
|
||||||
import { ServiceAlertTrigger } from '../service_alert_trigger';
|
import { ServiceAlertTrigger } from '../service_alert_trigger';
|
||||||
import { useServiceName } from '../../../hooks/use_service_name';
|
|
||||||
import { useServiceTransactionTypesFetcher } from '../../../context/apm_service/use_service_transaction_types_fetcher';
|
|
||||||
import { useServiceAgentNameFetcher } from '../../../context/apm_service/use_service_agent_name_fetcher';
|
|
||||||
import { getTransactionType } from '../../../context/apm_service/apm_service_context';
|
|
||||||
|
|
||||||
interface AlertParams {
|
interface AlertParams {
|
||||||
windowSize: number;
|
windowSize: number;
|
||||||
|
@ -38,45 +36,34 @@ interface AlertParams {
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
alertParams: AlertParams;
|
alertParams: AlertParams;
|
||||||
|
metadata?: AlertMetadata;
|
||||||
setAlertParams: (key: string, value: any) => void;
|
setAlertParams: (key: string, value: any) => void;
|
||||||
setAlertProperty: (key: string, value: any) => void;
|
setAlertProperty: (key: string, value: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TransactionErrorRateAlertTrigger(props: Props) {
|
export function TransactionErrorRateAlertTrigger(props: Props) {
|
||||||
const { setAlertParams, alertParams, setAlertProperty } = props;
|
const { services } = useKibana();
|
||||||
const { urlParams } = useUrlParams();
|
const { alertParams, metadata, setAlertParams, setAlertProperty } = props;
|
||||||
|
|
||||||
const serviceNameFromUrl = useServiceName();
|
createCallApmApi(services as CoreStart);
|
||||||
|
|
||||||
const transactionTypes = useServiceTransactionTypesFetcher(
|
const transactionTypes = useServiceTransactionTypesFetcher(
|
||||||
serviceNameFromUrl
|
metadata?.serviceName
|
||||||
);
|
);
|
||||||
const { agentName } = useServiceAgentNameFetcher(serviceNameFromUrl);
|
|
||||||
|
|
||||||
const transactionTypeFromUrl = getTransactionType({
|
|
||||||
transactionType: urlParams.transactionType,
|
|
||||||
transactionTypes,
|
|
||||||
agentName,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { start, end, environment: environmentFromUrl } = urlParams;
|
|
||||||
|
|
||||||
const params = defaults(
|
const params = defaults(
|
||||||
{ ...alertParams },
|
{ ...omit(metadata, ['start', 'end']), ...alertParams },
|
||||||
{
|
{
|
||||||
threshold: 30,
|
threshold: 30,
|
||||||
windowSize: 5,
|
windowSize: 5,
|
||||||
windowUnit: 'm',
|
windowUnit: 'm',
|
||||||
transactionType: transactionTypeFromUrl,
|
|
||||||
environment: environmentFromUrl || ENVIRONMENT_ALL.value,
|
|
||||||
serviceName: serviceNameFromUrl,
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const { environmentOptions } = useEnvironmentsFetcher({
|
const { environmentOptions } = useEnvironmentsFetcher({
|
||||||
serviceName: params.serviceName,
|
serviceName: params.serviceName,
|
||||||
start,
|
start: metadata?.start,
|
||||||
end,
|
end: metadata?.end,
|
||||||
});
|
});
|
||||||
|
|
||||||
const thresholdAsPercent = (params.threshold ?? 0) / 100;
|
const thresholdAsPercent = (params.threshold ?? 0) / 100;
|
||||||
|
@ -106,10 +93,6 @@ export function TransactionErrorRateAlertTrigger(props: Props) {
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
if (params.serviceName && !transactionTypes.length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fields = [
|
const fields = [
|
||||||
<ServiceField value={params.serviceName} />,
|
<ServiceField value={params.serviceName} />,
|
||||||
<TransactionTypeField
|
<TransactionTypeField
|
||||||
|
|
|
@ -32,8 +32,11 @@ import { fromQuery } from '../../shared/Links/url_helpers';
|
||||||
import { MockUrlParamsContextProvider } from '../../../context/url_params_context/mock_url_params_context_provider';
|
import { MockUrlParamsContextProvider } from '../../../context/url_params_context/mock_url_params_context_provider';
|
||||||
import { uiSettingsServiceMock } from '../../../../../../../src/core/public/mocks';
|
import { uiSettingsServiceMock } from '../../../../../../../src/core/public/mocks';
|
||||||
|
|
||||||
|
const uiSettings = uiSettingsServiceMock.create().setup({} as any);
|
||||||
|
|
||||||
const KibanaReactContext = createKibanaReactContext(({
|
const KibanaReactContext = createKibanaReactContext(({
|
||||||
uiSettings: { get: () => true },
|
notifications: { toasts: { add: () => {} } },
|
||||||
|
uiSettings,
|
||||||
usageCollection: { reportUiCounter: () => {} },
|
usageCollection: { reportUiCounter: () => {} },
|
||||||
} as unknown) as Partial<CoreStart>);
|
} as unknown) as Partial<CoreStart>);
|
||||||
|
|
||||||
|
@ -48,8 +51,6 @@ const location = {
|
||||||
search: fromQuery(mockParams),
|
search: fromQuery(mockParams),
|
||||||
};
|
};
|
||||||
|
|
||||||
const uiSettings = uiSettingsServiceMock.create().setup({} as any);
|
|
||||||
|
|
||||||
function Wrapper({ children }: { children?: ReactNode }) {
|
function Wrapper({ children }: { children?: ReactNode }) {
|
||||||
const value = ({
|
const value = ({
|
||||||
...mockApmPluginContextValue,
|
...mockApmPluginContextValue,
|
||||||
|
@ -64,11 +65,7 @@ function Wrapper({ children }: { children?: ReactNode }) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MemoryRouter initialEntries={[location]}>
|
<MemoryRouter initialEntries={[location]}>
|
||||||
<KibanaReactContext.Provider
|
<KibanaReactContext.Provider>
|
||||||
services={{
|
|
||||||
uiSettings,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MockApmPluginContextWrapper value={value}>
|
<MockApmPluginContextWrapper value={value}>
|
||||||
<MockUrlParamsContextProvider params={mockParams}>
|
<MockUrlParamsContextProvider params={mockParams}>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
@ -6,22 +6,35 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { renderHook, RenderHookResult } from '@testing-library/react-hooks';
|
import { renderHook, RenderHookResult } from '@testing-library/react-hooks';
|
||||||
|
import React, { ReactNode } from 'react';
|
||||||
|
import { CoreStart } from '../../../../../src/core/public';
|
||||||
|
import { createKibanaReactContext } from '../../../../../src/plugins/kibana_react/public';
|
||||||
import { delay } from '../utils/testHelpers';
|
import { delay } from '../utils/testHelpers';
|
||||||
import { FetcherResult, useFetcher } from './use_fetcher';
|
import { FetcherResult, useFetcher } from './use_fetcher';
|
||||||
import { MockApmPluginContextWrapper } from '../context/apm_plugin/mock_apm_plugin_context';
|
|
||||||
import { ApmPluginContextValue } from '../context/apm_plugin/apm_plugin_context';
|
|
||||||
|
|
||||||
// Wrap the hook with a provider so it can useApmPluginContext
|
// Wrap the hook with a provider so it can useKibana
|
||||||
const wrapper = MockApmPluginContextWrapper;
|
const KibanaReactContext = createKibanaReactContext(({
|
||||||
|
notifications: { toasts: { add: () => {}, danger: () => {} } },
|
||||||
|
} as unknown) as Partial<CoreStart>);
|
||||||
|
|
||||||
|
interface WrapperProps {
|
||||||
|
children?: ReactNode;
|
||||||
|
callback: () => Promise<string>;
|
||||||
|
args: string[];
|
||||||
|
}
|
||||||
|
function wrapper({ children }: WrapperProps) {
|
||||||
|
return <KibanaReactContext.Provider>{children}</KibanaReactContext.Provider>;
|
||||||
|
}
|
||||||
|
|
||||||
describe('useFetcher', () => {
|
describe('useFetcher', () => {
|
||||||
describe('when resolving after 500ms', () => {
|
describe('when resolving after 500ms', () => {
|
||||||
let hook: RenderHookResult<
|
let hook: RenderHookResult<
|
||||||
{ children?: React.ReactNode; value?: ApmPluginContextValue },
|
WrapperProps,
|
||||||
FetcherResult<string> & {
|
FetcherResult<string> & {
|
||||||
refetch: () => void;
|
refetch: () => void;
|
||||||
}
|
}
|
||||||
>;
|
>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
async function fn() {
|
async function fn() {
|
||||||
|
@ -66,14 +79,15 @@ describe('useFetcher', () => {
|
||||||
|
|
||||||
describe('when throwing after 500ms', () => {
|
describe('when throwing after 500ms', () => {
|
||||||
let hook: RenderHookResult<
|
let hook: RenderHookResult<
|
||||||
{ children?: React.ReactNode; value?: ApmPluginContextValue },
|
WrapperProps,
|
||||||
FetcherResult<void> & {
|
FetcherResult<string> & {
|
||||||
refetch: () => void;
|
refetch: () => void;
|
||||||
}
|
}
|
||||||
>;
|
>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
async function fn() {
|
async function fn(): Promise<string> {
|
||||||
await delay(500);
|
await delay(500);
|
||||||
throw new Error('Something went wrong');
|
throw new Error('Something went wrong');
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,12 @@
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import React, { useEffect, useMemo, useState } from 'react';
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
import { IHttpFetchError } from 'src/core/public';
|
import { IHttpFetchError } from 'src/core/public';
|
||||||
import { toMountPoint } from '../../../../../src/plugins/kibana_react/public';
|
import { useKibana } from '../../../../../src/plugins/kibana_react/public';
|
||||||
import {
|
|
||||||
callApmApi,
|
|
||||||
AutoAbortedAPMClient,
|
|
||||||
} from '../services/rest/createCallApmApi';
|
|
||||||
import { useApmPluginContext } from '../context/apm_plugin/use_apm_plugin_context';
|
|
||||||
import { useUrlParams } from '../context/url_params_context/use_url_params';
|
import { useUrlParams } from '../context/url_params_context/use_url_params';
|
||||||
|
import {
|
||||||
|
AutoAbortedAPMClient,
|
||||||
|
callApmApi,
|
||||||
|
} from '../services/rest/createCallApmApi';
|
||||||
|
|
||||||
export enum FETCH_STATUS {
|
export enum FETCH_STATUS {
|
||||||
LOADING = 'loading',
|
LOADING = 'loading',
|
||||||
|
@ -68,7 +67,7 @@ export function useFetcher<TReturn>(
|
||||||
showToastOnError?: boolean;
|
showToastOnError?: boolean;
|
||||||
} = {}
|
} = {}
|
||||||
): FetcherResult<InferResponseType<TReturn>> & { refetch: () => void } {
|
): FetcherResult<InferResponseType<TReturn>> & { refetch: () => void } {
|
||||||
const { notifications } = useApmPluginContext().core;
|
const { notifications } = useKibana();
|
||||||
const { preservePreviousData = true, showToastOnError = true } = options;
|
const { preservePreviousData = true, showToastOnError = true } = options;
|
||||||
const [result, setResult] = useState<
|
const [result, setResult] = useState<
|
||||||
FetcherResult<InferResponseType<TReturn>>
|
FetcherResult<InferResponseType<TReturn>>
|
||||||
|
@ -124,12 +123,12 @@ export function useFetcher<TReturn>(
|
||||||
'response' in err ? getDetailsFromErrorResponse(err) : err.message;
|
'response' in err ? getDetailsFromErrorResponse(err) : err.message;
|
||||||
|
|
||||||
if (showToastOnError) {
|
if (showToastOnError) {
|
||||||
notifications.toasts.addDanger({
|
notifications.toasts.danger({
|
||||||
title: i18n.translate('xpack.apm.fetcher.error.title', {
|
title: i18n.translate('xpack.apm.fetcher.error.title', {
|
||||||
defaultMessage: `Error while fetching resource`,
|
defaultMessage: `Error while fetching resource`,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
text: toMountPoint(
|
body: (
|
||||||
<div>
|
<div>
|
||||||
<h5>
|
<h5>
|
||||||
{i18n.translate('xpack.apm.fetcher.error.status', {
|
{i18n.translate('xpack.apm.fetcher.error.status', {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue