diff --git a/x-pack/plugins/apm/public/components/app/ServiceMap/Popover/AnomalyDetection.tsx b/x-pack/plugins/apm/public/components/app/ServiceMap/Popover/AnomalyDetection.tsx
index 36c0c9f37f9c7..97c76b4139c8a 100644
--- a/x-pack/plugins/apm/public/components/app/ServiceMap/Popover/AnomalyDetection.tsx
+++ b/x-pack/plugins/apm/public/components/app/ServiceMap/Popover/AnomalyDetection.tsx
@@ -21,7 +21,7 @@ import {
import { useTheme } from '../../../../hooks/use_theme';
import { fontSize, px } from '../../../../style/variables';
import { asInteger, asDuration } from '../../../../../common/utils/formatters';
-import { MLJobLink } from '../../../shared/Links/MachineLearningLinks/MLJobLink';
+import { MLSingleMetricLink } from '../../../shared/Links/MachineLearningLinks/MLSingleMetricLink';
import { popoverWidth } from '../cytoscape_options';
import { TRANSACTION_REQUEST } from '../../../../../common/transaction_types';
import {
@@ -108,14 +108,14 @@ export function AnomalyDetection({ serviceName, serviceAnomalyStats }: Props) {
)}
{mlJobId && (
-
{ANOMALY_DETECTION_LINK}
-
+
)}
>
diff --git a/x-pack/plugins/apm/public/components/app/Settings/anomaly_detection/jobs_list.tsx b/x-pack/plugins/apm/public/components/app/Settings/anomaly_detection/jobs_list.tsx
index 8d6a0740a8a08..acc2550930b8e 100644
--- a/x-pack/plugins/apm/public/components/app/Settings/anomaly_detection/jobs_list.tsx
+++ b/x-pack/plugins/apm/public/components/app/Settings/anomaly_detection/jobs_list.tsx
@@ -19,8 +19,8 @@ import { FormattedMessage } from '@kbn/i18n/react';
import { FETCH_STATUS } from '../../../../hooks/use_fetcher';
import { ITableColumn, ManagedTable } from '../../../shared/ManagedTable';
import { LoadingStatePrompt } from '../../../shared/LoadingStatePrompt';
-import { MLJobLink } from '../../../shared/Links/MachineLearningLinks/MLJobLink';
-import { MLLink } from '../../../shared/Links/MachineLearningLinks/MLLink';
+import { MLSingleMetricLink } from '../../../shared/Links/MachineLearningLinks/MLSingleMetricLink';
+import { MLManageJobsLink } from '../../../shared/Links/MachineLearningLinks/MLManageJobsLink';
import { getEnvironmentLabel } from '../../../../../common/environment_filter_values';
import { LegacyJobsCallout } from './legacy_jobs_callout';
import { AnomalyDetectionApiResponse } from './index';
@@ -44,14 +44,14 @@ const columns: Array> = [
{ defaultMessage: 'Action' }
),
render: (jobId: string) => (
-
+
{i18n.translate(
'xpack.apm.settings.anomalyDetection.jobList.mlJobLinkText',
{
defaultMessage: 'View job in ML',
}
)}
-
+
),
},
];
@@ -97,14 +97,14 @@ export function JobsList({ data, status, onAddEnvironments }: Props) {
defaultMessage="To add anomaly detection to a new environment, create a machine learning job. Existing machine learning jobs can be managed in {mlJobsLink}."
values={{
mlJobsLink: (
-
+
{i18n.translate(
'xpack.apm.settings.anomalyDetection.jobList.mlDescriptionText.mlJobsLinkText',
{
defaultMessage: 'Machine Learning',
}
)}
-
+
),
}}
/>
diff --git a/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.tsx
deleted file mode 100644
index 887ac2ff6bbb9..0000000000000
--- a/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.tsx
+++ /dev/null
@@ -1,40 +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, { ReactNode } from 'react';
-import { EuiLink } from '@elastic/eui';
-import { useTimeSeriesExplorerHref } from './useTimeSeriesExplorerHref';
-
-interface Props {
- children?: ReactNode;
- jobId: string;
- external?: boolean;
- serviceName?: string;
- transactionType?: string;
-}
-
-export function MLJobLink({
- jobId,
- serviceName,
- transactionType,
- external,
- children,
-}: Props) {
- const href = useTimeSeriesExplorerHref({
- jobId,
- serviceName,
- transactionType,
- });
-
- return (
-
- );
-}
diff --git a/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.test.tsx b/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.test.tsx
deleted file mode 100644
index c453de709a5d2..0000000000000
--- a/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.test.tsx
+++ /dev/null
@@ -1,24 +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 { Location } from 'history';
-import React from 'react';
-import { getRenderedHref } from '../../../../utils/testHelpers';
-import { MLLink } from './MLLink';
-
-test('MLLink produces the correct URL', async () => {
- const href = await getRenderedHref(
- () => ,
- {
- search:
- '?rangeFrom=now-5h&rangeTo=now-2h&refreshPaused=true&refreshInterval=0',
- } as Location
- );
-
- expect(href).toMatchInlineSnapshot(
- `"/app/ml/jobs?_a=(jobs:(queryText:'id:(something)%20groups:(apm)'))&_g=(refreshInterval:(pause:!t,value:0),time:(from:now-5h,to:now-2h))"`
- );
-});
diff --git a/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLManageJobsLink.test.tsx b/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLManageJobsLink.test.tsx
new file mode 100644
index 0000000000000..21ca9a3ab53bc
--- /dev/null
+++ b/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLManageJobsLink.test.tsx
@@ -0,0 +1,21 @@
+/*
+ * 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 React from 'react';
+import { getRenderedHref } from '../../../../utils/testHelpers';
+import { MLManageJobsLink } from './MLManageJobsLink';
+
+test('MLManageJobsLink', async () => {
+ const href = await getRenderedHref(() => , {
+ search:
+ '?rangeFrom=now-5h&rangeTo=now-2h&refreshPaused=true&refreshInterval=0',
+ } as Location);
+
+ expect(href).toMatchInlineSnapshot(
+ `"/app/ml/jobs?_a=(jobs:(queryText:'groups:(apm)'))&_g=(refreshInterval:(pause:!t,value:0),time:(from:now-5h,to:now-2h))"`
+ );
+});
diff --git a/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLManageJobsLink.tsx
similarity index 57%
rename from x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.tsx
rename to x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLManageJobsLink.tsx
index 7bf017fb239e3..3406ce0b1e9d2 100644
--- a/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.tsx
+++ b/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLManageJobsLink.tsx
@@ -6,51 +6,44 @@
import { EuiLink } from '@elastic/eui';
import React from 'react';
+import { UI_SETTINGS } from '../../../../../../../../src/plugins/data/common';
import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context';
import { useMlHref, ML_PAGES } from '../../../../../../ml/public';
import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
-
-interface MlRisonData {
- ml?: {
- jobIds: string[];
- };
-}
+import { TimePickerRefreshInterval } from '../../DatePicker/typings';
interface Props {
- query?: MlRisonData;
- path?: string;
children?: React.ReactNode;
external?: boolean;
}
-export function MLLink({ children, path = '', query = {}, external }: Props) {
+export function MLManageJobsLink({ children, external }: Props) {
const {
core,
plugins: { ml },
} = useApmPluginContext();
- let jobIds: string[] = [];
- if (query.ml?.jobIds) {
- jobIds = query.ml.jobIds;
- }
const { urlParams } = useUrlParams();
- const { rangeFrom, rangeTo, refreshInterval, refreshPaused } = urlParams;
- // default to link to ML Anomaly Detection jobs management page
+ const timePickerRefreshIntervalDefaults = core.uiSettings.get(
+ UI_SETTINGS.TIMEPICKER_REFRESH_INTERVAL_DEFAULTS
+ );
+
+ const {
+ // hardcoding a custom default of 1 hour since the default kibana timerange of 15 minutes is shorter than the ML interval
+ rangeFrom = 'now-1h',
+ rangeTo = 'now',
+ refreshInterval = timePickerRefreshIntervalDefaults.value,
+ refreshPaused = timePickerRefreshIntervalDefaults.pause,
+ } = urlParams;
+
const mlADLink = useMlHref(ml, core.http.basePath.get(), {
page: ML_PAGES.ANOMALY_DETECTION_JOBS_MANAGE,
pageState: {
- jobId: jobIds,
groupIds: ['apm'],
globalState: {
- time:
- rangeFrom !== undefined && rangeTo !== undefined
- ? { from: rangeFrom, to: rangeTo }
- : undefined,
- refreshInterval:
- refreshPaused !== undefined && refreshInterval !== undefined
- ? { pause: refreshPaused, value: refreshInterval }
- : undefined,
+ time: { from: rangeFrom, to: rangeTo },
+ refreshInterval: { pause: refreshPaused, value: refreshInterval },
},
},
});
diff --git a/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.test.tsx b/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLSingleMetricLink.test.tsx
similarity index 91%
rename from x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.test.tsx
rename to x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLSingleMetricLink.test.tsx
index b13b1f89da352..146f216170ae0 100644
--- a/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.test.tsx
+++ b/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLSingleMetricLink.test.tsx
@@ -7,13 +7,13 @@
import { Location } from 'history';
import React from 'react';
import { getRenderedHref } from '../../../../utils/testHelpers';
-import { MLJobLink } from './MLJobLink';
+import { MLSingleMetricLink } from './MLSingleMetricLink';
-describe('MLJobLink', () => {
+describe('MLSingleMetricLink', () => {
it('should produce the correct URL with jobId', async () => {
const href = await getRenderedHref(
() => (
-
+
),
{
search:
@@ -28,7 +28,7 @@ describe('MLJobLink', () => {
it('should produce the correct URL with jobId, serviceName, and transactionType', async () => {
const href = await getRenderedHref(
() => (
- {
it('correctly encodes time range values', async () => {
const href = await getRenderedHref(
() => (
-
+ );
+}
+
+export function useSingleMetricHref({
+ jobId,
+ serviceName,
+ transactionType,
+}: {
+ jobId: string;
+ serviceName?: string;
+ transactionType?: string;
+}) {
+ const {
+ core,
+ plugins: { ml },
+ } = useApmPluginContext();
+ const { urlParams } = useUrlParams();
+
+ const timePickerRefreshIntervalDefaults = core.uiSettings.get(
+ UI_SETTINGS.TIMEPICKER_REFRESH_INTERVAL_DEFAULTS
+ );
+
+ const {
+ // hardcoding a custom default of 1 hour since the default kibana timerange of 15 minutes is shorter than the ML interval
+ rangeFrom = 'now-1h',
+ rangeTo = 'now',
+ refreshInterval = timePickerRefreshIntervalDefaults.value,
+ refreshPaused = timePickerRefreshIntervalDefaults.pause,
+ } = urlParams;
+
+ const entities =
+ serviceName && transactionType
+ ? {
+ entities: {
+ 'service.name': serviceName,
+ 'transaction.type': transactionType,
+ },
+ }
+ : {};
+
+ const href = useMlHref(ml, core.http.basePath.get(), {
+ page: ML_PAGES.SINGLE_METRIC_VIEWER,
+ pageState: {
+ jobIds: [jobId],
+ timeRange: { from: rangeFrom, to: rangeTo },
+ refreshInterval: { pause: refreshPaused, value: refreshInterval },
+ ...entities,
+ },
+ });
+
+ return href;
+}
diff --git a/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/useTimeSeriesExplorerHref.ts b/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/useTimeSeriesExplorerHref.ts
deleted file mode 100644
index eabef034bf3d9..0000000000000
--- a/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/useTimeSeriesExplorerHref.ts
+++ /dev/null
@@ -1,53 +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 { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context';
-import { useMlHref } from '../../../../../../ml/public';
-import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
-
-export function useTimeSeriesExplorerHref({
- jobId,
- serviceName,
- transactionType,
-}: {
- jobId: string;
- serviceName?: string;
- transactionType?: string;
-}) {
- // default to link to ML Anomaly Detection jobs management page
- const {
- core,
- plugins: { ml },
- } = useApmPluginContext();
- const { urlParams } = useUrlParams();
- const { rangeFrom, rangeTo, refreshInterval, refreshPaused } = urlParams;
-
- const timeRange =
- rangeFrom !== undefined && rangeTo !== undefined
- ? { from: rangeFrom, to: rangeTo }
- : undefined;
- const mlAnomalyDetectionHref = useMlHref(ml, core.http.basePath.get(), {
- page: 'timeseriesexplorer',
- pageState: {
- jobIds: [jobId],
- timeRange,
- refreshInterval:
- refreshPaused !== undefined && refreshInterval !== undefined
- ? { pause: refreshPaused, value: refreshInterval }
- : undefined,
- ...(serviceName && transactionType
- ? {
- entities: {
- 'service.name': serviceName,
- 'transaction.type': transactionType,
- },
- }
- : {}),
- },
- });
-
- return mlAnomalyDetectionHref;
-}
diff --git a/x-pack/plugins/apm/public/components/shared/charts/transaction_charts/ml_header.tsx b/x-pack/plugins/apm/public/components/shared/charts/transaction_charts/ml_header.tsx
index f0569ea1a0752..d125af70268cb 100644
--- a/x-pack/plugins/apm/public/components/shared/charts/transaction_charts/ml_header.tsx
+++ b/x-pack/plugins/apm/public/components/shared/charts/transaction_charts/ml_header.tsx
@@ -11,7 +11,7 @@ import React from 'react';
import { useParams } from 'react-router-dom';
import styled from 'styled-components';
import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
-import { MLJobLink } from '../../Links/MachineLearningLinks/MLJobLink';
+import { MLSingleMetricLink } from '../../Links/MachineLearningLinks/MLSingleMetricLink';
interface Props {
hasValidMlLicense?: boolean;
@@ -78,7 +78,7 @@ export function MLHeader({ hasValidMlLicense, mlJobId }: Props) {
}
)}{' '}
-
+
);