diff --git a/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/Distribution/index.tsx b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/Distribution/index.tsx
index 99316e3520a76..159f111bee04c 100644
--- a/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/Distribution/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/Distribution/index.tsx
@@ -90,7 +90,12 @@ export function ErrorDistribution({ distribution, title }: Props) {
showOverlappingTicks
tickFormat={xFormatter}
/>
-
+
formatYShort(value)}
/>
({
- dataValue: annotation['@timestamp'],
- header: asAbsoluteDateTime(annotation['@timestamp']),
- details: `${i18n.translate('xpack.apm.chart.annotation.version', {
- defaultMessage: 'Version',
- })} ${annotation.text}`,
- }))}
- style={{ line: { strokeWidth: 1, stroke: color, opacity: 1 } }}
- marker={}
- markerPosition={Position.Top}
- />
- );
-}
diff --git a/x-pack/plugins/apm/public/components/shared/charts/timeseries_chart.tsx b/x-pack/plugins/apm/public/components/shared/charts/timeseries_chart.tsx
index c4f5abe104aa9..ea6f2a4a233e5 100644
--- a/x-pack/plugins/apm/public/components/shared/charts/timeseries_chart.tsx
+++ b/x-pack/plugins/apm/public/components/shared/charts/timeseries_chart.tsx
@@ -5,28 +5,35 @@
*/
import {
+ AnnotationDomainTypes,
AreaSeries,
Axis,
Chart,
CurveType,
LegendItemListener,
+ LineAnnotation,
LineSeries,
niceTimeFormatter,
Placement,
Position,
ScaleType,
Settings,
+ YDomainRange,
} from '@elastic/charts';
+import { EuiIcon } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
import moment from 'moment';
import React, { useEffect } from 'react';
import { useHistory } from 'react-router-dom';
import { useChartTheme } from '../../../../../observability/public';
+import { asAbsoluteDateTime } from '../../../../common/utils/formatters';
import { TimeSeries } from '../../../../typings/timeseries';
import { FETCH_STATUS } from '../../../hooks/useFetcher';
+import { useTheme } from '../../../hooks/useTheme';
import { useUrlParams } from '../../../hooks/useUrlParams';
+import { useAnnotations } from '../../../hooks/use_annotations';
import { useChartPointerEvent } from '../../../hooks/use_chart_pointer_event';
import { unit } from '../../../style/variables';
-import { Annotations } from './annotations';
import { ChartContainer } from './chart_container';
import { onBrushEnd } from './helper/helper';
@@ -45,6 +52,7 @@ interface Props {
*/
yTickFormat?: (y: number) => string;
showAnnotations?: boolean;
+ yDomain?: YDomainRange;
}
export function TimeseriesChart({
@@ -56,12 +64,16 @@ export function TimeseriesChart({
yLabelFormat,
yTickFormat,
showAnnotations = true,
+ yDomain,
}: Props) {
const history = useHistory();
const chartRef = React.createRef();
+ const { annotations } = useAnnotations();
const chartTheme = useChartTheme();
const { pointerEvent, setPointerEvent } = useChartPointerEvent();
const { urlParams } = useUrlParams();
+ const theme = useTheme();
+
const { start, end } = urlParams;
useEffect(() => {
@@ -83,6 +95,8 @@ export function TimeseriesChart({
y === null || y === undefined
);
+ const annotationColor = theme.eui.euiColorSecondary;
+
return (
@@ -108,17 +122,35 @@ export function TimeseriesChart({
position={Position.Bottom}
showOverlappingTicks
tickFormat={xFormatter}
+ gridLine={{ visible: false }}
/>
- {showAnnotations && }
+ {showAnnotations && (
+ ({
+ dataValue: annotation['@timestamp'],
+ header: asAbsoluteDateTime(annotation['@timestamp']),
+ details: `${i18n.translate('xpack.apm.chart.annotation.version', {
+ defaultMessage: 'Version',
+ })} ${annotation.text}`,
+ }))}
+ style={{
+ line: { strokeWidth: 1, stroke: annotationColor, opacity: 1 },
+ }}
+ marker={}
+ markerPosition={Position.Top}
+ />
+ )}
{timeseries.map((serie) => {
const Series = serie.type === 'area' ? AreaSeries : LineSeries;
diff --git a/x-pack/plugins/apm/public/components/shared/charts/transaction_breakdown_chart/transaction_breakdown_chart_contents.tsx b/x-pack/plugins/apm/public/components/shared/charts/transaction_breakdown_chart/transaction_breakdown_chart_contents.tsx
index 04c07c01442a4..20056a6831adf 100644
--- a/x-pack/plugins/apm/public/components/shared/charts/transaction_breakdown_chart/transaction_breakdown_chart_contents.tsx
+++ b/x-pack/plugins/apm/public/components/shared/charts/transaction_breakdown_chart/transaction_breakdown_chart_contents.tsx
@@ -5,27 +5,35 @@
*/
import {
+ AnnotationDomainTypes,
AreaSeries,
Axis,
Chart,
CurveType,
+ LineAnnotation,
niceTimeFormatter,
Placement,
Position,
ScaleType,
Settings,
} from '@elastic/charts';
+import { EuiIcon } from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
import moment from 'moment';
import React, { useEffect } from 'react';
import { useHistory } from 'react-router-dom';
import { useChartTheme } from '../../../../../../observability/public';
-import { asPercent } from '../../../../../common/utils/formatters';
+import {
+ asAbsoluteDateTime,
+ asPercent,
+} from '../../../../../common/utils/formatters';
import { TimeSeries } from '../../../../../typings/timeseries';
import { FETCH_STATUS } from '../../../../hooks/useFetcher';
+import { useTheme } from '../../../../hooks/useTheme';
import { useUrlParams } from '../../../../hooks/useUrlParams';
+import { useAnnotations } from '../../../../hooks/use_annotations';
import { useChartPointerEvent } from '../../../../hooks/use_chart_pointer_event';
import { unit } from '../../../../style/variables';
-import { Annotations } from '../../charts/annotations';
import { ChartContainer } from '../../charts/chart_container';
import { onBrushEnd } from '../../charts/helper/helper';
@@ -44,9 +52,11 @@ export function TransactionBreakdownChartContents({
}: Props) {
const history = useHistory();
const chartRef = React.createRef();
+ const { annotations } = useAnnotations();
const chartTheme = useChartTheme();
const { pointerEvent, setPointerEvent } = useChartPointerEvent();
const { urlParams } = useUrlParams();
+ const theme = useTheme();
const { start, end } = urlParams;
useEffect(() => {
@@ -64,6 +74,8 @@ export function TransactionBreakdownChartContents({
const xFormatter = niceTimeFormatter([min, max]);
+ const annotationColor = theme.eui.euiColorSecondary;
+
return (
@@ -85,6 +97,7 @@ export function TransactionBreakdownChartContents({
position={Position.Bottom}
showOverlappingTicks
tickFormat={xFormatter}
+ gridLine={{ visible: false }}
/>
asPercent(y ?? 0, 1)}
/>
- {showAnnotations && }
+ {showAnnotations && (
+ ({
+ dataValue: annotation['@timestamp'],
+ header: asAbsoluteDateTime(annotation['@timestamp']),
+ details: `${i18n.translate('xpack.apm.chart.annotation.version', {
+ defaultMessage: 'Version',
+ })} ${annotation.text}`,
+ }))}
+ style={{
+ line: { strokeWidth: 1, stroke: annotationColor, opacity: 1 },
+ }}
+ marker={}
+ markerPosition={Position.Top}
+ />
+ )}
{timeseries?.length ? (
timeseries.map((serie) => {
diff --git a/x-pack/plugins/apm/public/components/shared/charts/transaction_charts/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/transaction_charts/index.tsx
index 221f17bb9e1d5..3f8071ec39f0f 100644
--- a/x-pack/plugins/apm/public/components/shared/charts/transaction_charts/index.tsx
+++ b/x-pack/plugins/apm/public/components/shared/charts/transaction_charts/index.tsx
@@ -20,13 +20,14 @@ import {
TRANSACTION_ROUTE_CHANGE,
} from '../../../../../common/transaction_types';
import { asTransactionRate } from '../../../../../common/utils/formatters';
+import { AnnotationsContextProvider } from '../../../../context/annotations_context';
import { ChartPointerEventContextProvider } from '../../../../context/chart_pointer_event_context';
import { LicenseContext } from '../../../../context/LicenseContext';
import { IUrlParams } from '../../../../context/UrlParamsContext/types';
import { FETCH_STATUS } from '../../../../hooks/useFetcher';
import { ITransactionChartData } from '../../../../selectors/chart_selectors';
-import { TransactionBreakdownChart } from '../transaction_breakdown_chart';
import { TimeseriesChart } from '../timeseries_chart';
+import { TransactionBreakdownChart } from '../transaction_breakdown_chart';
import { TransactionErrorRateChart } from '../transaction_error_rate_chart/';
import { getResponseTimeTickFormatter } from './helper';
import { MLHeader } from './ml_header';
@@ -51,65 +52,69 @@ export function TransactionCharts({
return (
<>
-
-
-
-
-
-
-
- {responseTimeLabel(transactionType)}
-
-
-
- {(license) => (
-
- )}
-
-
- {
- if (serie) {
- toggleSerie(serie);
- }
- }}
- />
-
-
+
+
+
+
+
+
+
+
+ {responseTimeLabel(transactionType)}
+
+
+
+ {(license) => (
+
+ )}
+
+
+ {
+ if (serie) {
+ toggleSerie(serie);
+ }
+ }}
+ />
+
+
-
-
-
- {tpmLabel(transactionType)}
-
-
-
-
-
+
+
+
+ {tpmLabel(transactionType)}
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
>
);
}
diff --git a/x-pack/plugins/apm/public/components/shared/charts/transaction_error_rate_chart/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/transaction_error_rate_chart/index.tsx
index b9028ff2e9e8c..00472df95c4b1 100644
--- a/x-pack/plugins/apm/public/components/shared/charts/transaction_error_rate_chart/index.tsx
+++ b/x-pack/plugins/apm/public/components/shared/charts/transaction_error_rate_chart/index.tsx
@@ -91,6 +91,7 @@ export function TransactionErrorRateChart({
]}
yLabelFormat={yLabelFormat}
yTickFormat={yTickFormat}
+ yDomain={{ min: 0, max: 1 }}
/>
);
diff --git a/x-pack/plugins/apm/public/context/annotations_context.tsx b/x-pack/plugins/apm/public/context/annotations_context.tsx
new file mode 100644
index 0000000000000..4e09a3d227b11
--- /dev/null
+++ b/x-pack/plugins/apm/public/context/annotations_context.tsx
@@ -0,0 +1,49 @@
+/*
+ * 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, { createContext } from 'react';
+import { useParams } from 'react-router-dom';
+import { Annotation } from '../../common/annotations';
+import { useFetcher } from '../hooks/useFetcher';
+import { useUrlParams } from '../hooks/useUrlParams';
+import { callApmApi } from '../services/rest/createCallApmApi';
+
+export const AnnotationsContext = createContext({ annotations: [] } as {
+ annotations: Annotation[];
+});
+
+const INITIAL_STATE = { annotations: [] };
+
+export function AnnotationsContextProvider({
+ children,
+}: {
+ children: React.ReactNode;
+}) {
+ const { serviceName } = useParams<{ serviceName?: string }>();
+ const { urlParams, uiFilters } = useUrlParams();
+ const { start, end } = urlParams;
+ const { environment } = uiFilters;
+
+ const { data = INITIAL_STATE } = useFetcher(() => {
+ if (start && end && serviceName) {
+ return callApmApi({
+ endpoint: 'GET /api/apm/services/{serviceName}/annotation/search',
+ params: {
+ path: {
+ serviceName,
+ },
+ query: {
+ start,
+ end,
+ environment,
+ },
+ },
+ });
+ }
+ }, [start, end, environment, serviceName]);
+
+ return ;
+}
diff --git a/x-pack/plugins/apm/public/hooks/use_annotations.ts b/x-pack/plugins/apm/public/hooks/use_annotations.ts
index e8f6785706a91..1cd9a7e65dda2 100644
--- a/x-pack/plugins/apm/public/hooks/use_annotations.ts
+++ b/x-pack/plugins/apm/public/hooks/use_annotations.ts
@@ -3,36 +3,16 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
-import { useParams } from 'react-router-dom';
-import { callApmApi } from '../services/rest/createCallApmApi';
-import { useFetcher } from './useFetcher';
-import { useUrlParams } from './useUrlParams';
-const INITIAL_STATE = { annotations: [] };
+import { useContext } from 'react';
+import { AnnotationsContext } from '../context/annotations_context';
export function useAnnotations() {
- const { serviceName } = useParams<{ serviceName?: string }>();
- const { urlParams, uiFilters } = useUrlParams();
- const { start, end } = urlParams;
- const { environment } = uiFilters;
+ const context = useContext(AnnotationsContext);
- const { data = INITIAL_STATE } = useFetcher(() => {
- if (start && end && serviceName) {
- return callApmApi({
- endpoint: 'GET /api/apm/services/{serviceName}/annotation/search',
- params: {
- path: {
- serviceName,
- },
- query: {
- start,
- end,
- environment,
- },
- },
- });
- }
- }, [start, end, environment, serviceName]);
+ if (!context) {
+ throw new Error('Missing Annotations context provider');
+ }
- return data;
+ return context;
}