Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ML] Migrate machine learning URLs to BrowserRouter format for APM, Security, and Infra #78209

Merged
merged 26 commits into from
Sep 30, 2020
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
0064270
[ML] Adds ability to pass multiple jobIds to job management url
qn895 Sep 21, 2020
357c42b
[ML][APM] Update links to jobs management page for MLLink and LegacyJ…
qn895 Sep 21, 2020
ec58132
[ML][APM] Update useTimeSeriesExplorerHref
qn895 Sep 21, 2020
d9ed2a5
[ML][APM] Update tests
qn895 Sep 21, 2020
6696c06
[ML][APM] Move test from useTimeSeriesExplorerHref to MLJobLink.test.tsx
qn895 Sep 21, 2020
a897190
[ML][Infra] Update ML links in infra to non-hash paths
qn895 Sep 21, 2020
dcf92e0
[ML] Move MlUrlGenerator registration outside of licensing block for …
qn895 Sep 22, 2020
76ffb79
[ML][Security] Update ml links in security
qn895 Sep 22, 2020
639c331
Merge remote-tracking branch 'upstream/master' into ml-exernal-url-re…
qn895 Sep 22, 2020
cdd5045
[ML][APM] Update test snapshots
qn895 Sep 22, 2020
b9258f2
[ML][APM] Update snapshots
qn895 Sep 22, 2020
02cb4c6
[ML][Security solution] Update tests
qn895 Sep 22, 2020
d37abef
[ML] Update MLLink to include globalState
qn895 Sep 22, 2020
937ef9d
Merge remote-tracking branch 'upstream/master' into ml-exernal-url-re…
qn895 Sep 22, 2020
9be734d
[ML] Update useTimeSeriesExplorerHref
qn895 Sep 22, 2020
55c25a4
[ML] Update apm and security_solution to use useMlHref hook
qn895 Sep 24, 2020
6da3cb3
Merge remote-tracking branch 'upstream/master' into ml-exernal-url-re…
qn895 Sep 24, 2020
b24dcdb
Merge branch 'master' into ml-exernal-url-replace-hash
elasticmachine Sep 28, 2020
c890c97
[ML] Update APM to use useUrlParams hook, update security solution hook
qn895 Sep 28, 2020
7ccc111
Merge remote-tracking branch 'upstream/master' into ml-exernal-url-re…
qn895 Sep 28, 2020
7e66d56
[ML] Update tests, fix duplicate imports
qn895 Sep 29, 2020
3ad1996
Merge remote-tracking branch 'upstream/master' into ml-exernal-url-re…
qn895 Sep 29, 2020
4903e35
[ML] Update imports, remove ml exports to shared cause it's not needed
qn895 Sep 29, 2020
f57f4e2
Merge remote-tracking branch 'upstream/master' into ml-exernal-url-re…
qn895 Sep 30, 2020
5e09d95
[ML] Update snapshot
qn895 Sep 30, 2020
1c390c1
[ML] Fix warnings for jobs_table.test.tsx
qn895 Sep 30, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,20 @@ import { EuiCallOut, EuiButton } from '@elastic/eui';
import React from 'react';
import { i18n } from '@kbn/i18n';
import { useApmPluginContext } from '../../../../hooks/useApmPluginContext';
import { useMlHref } from '../../../../../../ml/public';

export function LegacyJobsCallout() {
const { core } = useApmPluginContext();
const {
core,
plugins: { ml },
} = useApmPluginContext();
const mlADLink = useMlHref(ml, core.http.basePath.get(), {
page: 'jobs',
pageState: {
jobId: 'high_mean_response_time',
},
});

return (
<EuiCallOut
title={i18n.translate(
Expand All @@ -28,11 +39,7 @@ export function LegacyJobsCallout() {
}
)}
</p>
<EuiButton
href={core.http.basePath.prepend(
'/app/ml#/jobs?mlManagement=(jobId:high_mean_response_time)'
)}
>
<EuiButton href={mlADLink}>
{i18n.translate(
'xpack.apm.settings.anomaly_detection.legacy_jobs.button',
{ defaultMessage: 'Review jobs' }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('MLJobLink', () => {
);

expect(href).toMatchInlineSnapshot(
`"/basepath/app/ml#/timeseriesexplorer?_g=(ml:(jobIds:!(myservicename-mytransactiontype-high_mean_response_time)),refreshInterval:(pause:!t,value:0),time:(from:now/w,to:now-4h))"`
`"/app/ml/timeseriesexplorer?_g=(ml:(jobIds:!(myservicename-mytransactiontype-high_mean_response_time)),refreshInterval:(pause:!t,value:0),time:(from:now%2Fw,to:now-4h))&_a=(mlTimeSeriesExplorer:(),zoom:(from:now%2Fw,to:now-4h))"`
);
});
it('should produce the correct URL with jobId, serviceName, and transactionType', async () => {
Expand All @@ -41,7 +41,27 @@ describe('MLJobLink', () => {
);

expect(href).toMatchInlineSnapshot(
`"/basepath/app/ml#/timeseriesexplorer?_g=(ml:(jobIds:!(myservicename-mytransactiontype-high_mean_response_time)),refreshInterval:(pause:!t,value:0),time:(from:now/w,to:now-4h))&_a=(mlTimeSeriesExplorer:(entities:(service.name:opbeans-test,transaction.type:request)))"`
`"/app/ml/timeseriesexplorer?_g=(ml:(jobIds:!(myservicename-mytransactiontype-high_mean_response_time)),refreshInterval:(pause:!t,value:0),time:(from:now%2Fw,to:now-4h))&_a=(mlTimeSeriesExplorer:(entities:(service.name:opbeans-test,transaction.type:request)),zoom:(from:now%2Fw,to:now-4h))"`
);
});

it('correctly encodes time range values', async () => {
const href = await getRenderedHref(
() => (
<MLJobLink
jobId="apm-production-485b-high_mean_transaction_duration"
serviceName="opbeans-java"
transactionType="request"
/>
),
{
search:
'?rangeFrom=2020-07-29T17:27:29.000Z&rangeTo=2020-07-29T18:45:00.000Z&refreshInterval=10000&refreshPaused=true',
} as Location
);

expect(href).toMatchInlineSnapshot(
`"/app/ml/timeseriesexplorer?_g=(ml:(jobIds:!(apm-production-485b-high_mean_transaction_duration)),refreshInterval:(pause:!t,value:10000),time:(from:'2020-07-29T17:27:29.000Z',to:'2020-07-29T18:45:00.000Z'))&_a=(mlTimeSeriesExplorer:(entities:(service.name:opbeans-java,transaction.type:request)),zoom:(from:'2020-07-29T17:27:29.000Z',to:'2020-07-29T18:45:00.000Z'))"`
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ test('MLLink produces the correct URL', async () => {
);

expect(href).toMatchInlineSnapshot(
`"/basepath/app/ml#/some/path?_g=(ml:(jobIds:!(something)),refreshInterval:(pause:!t,value:0),time:(from:now-5h,to:now-2h))&mlManagement=(groupIds:!(apm))"`
`"/app/ml/jobs?mlManagement=(groupIds:!(apm),jobId:!(something))&_g=(refreshInterval:(pause:!t,value:0),time:(from:now-5h,to:now-2h))"`
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@

import { EuiLink } from '@elastic/eui';
import React from 'react';
import { useLocation } from 'react-router-dom';
import rison, { RisonValue } from 'rison-node';
import url from 'url';
import { useApmPluginContext } from '../../../../hooks/useApmPluginContext';
import { getTimepickerRisonData, TimepickerRisonData } from '../rison_helpers';
import { useMlHref, ML_PAGES } from '../../../../../../ml/public';
import { useUrlParams } from '../../../../hooks/useUrlParams';

interface MlRisonData {
ml?: {
Expand All @@ -26,28 +24,41 @@ interface Props {
}

export function MLLink({ children, path = '', query = {}, external }: Props) {
const { core } = useApmPluginContext();
const location = useLocation();
const {
core,
plugins: { ml },
} = useApmPluginContext();

const risonQuery: MlRisonData & TimepickerRisonData = getTimepickerRisonData(
location.search
);

if (query.ml) {
risonQuery.ml = query.ml;
let jobIds: string[] = [];
if (query.ml?.jobIds) {
jobIds = query.ml.jobIds;
}
const { urlParams } = useUrlParams();
const { rangeFrom, rangeTo, refreshInterval, refreshPaused } = urlParams;

const href = url.format({
pathname: core.http.basePath.prepend('/app/ml'),
hash: `${path}?_g=${rison.encode(
risonQuery as RisonValue
)}&mlManagement=${rison.encode({ groupIds: ['apm'] })}`,
// default to link to ML Anomaly Detection jobs management page
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,
sorenlouv marked this conversation as resolved.
Show resolved Hide resolved
},
},
});

return (
<EuiLink
children={children}
href={href}
href={mlADLink}
external={external}
target={external ? '_blank' : undefined}
/>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/

import querystring from 'querystring';
import { useLocation } from 'react-router-dom';
import rison from 'rison-node';
import url from 'url';
import { useApmPluginContext } from '../../../../hooks/useApmPluginContext';
import { getTimepickerRisonData } from '../rison_helpers';
import { useMlHref } from '../../../../../../ml/public';
import { useUrlParams } from '../../../../hooks/useUrlParams';

export function useTimeSeriesExplorerHref({
jobId,
Expand All @@ -20,41 +17,38 @@ export function useTimeSeriesExplorerHref({
serviceName?: string;
transactionType?: string;
}) {
const { core } = useApmPluginContext();
const location = useLocation();
const { time, refreshInterval } = getTimepickerRisonData(location.search);
// 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 search = querystring.stringify(
{
_g: rison.encode({
ml: { jobIds: [jobId] },
time,
refreshInterval,
}),
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,
zoom: timeRange,
...(serviceName && transactionType
? {
_a: rison.encode({
mlTimeSeriesExplorer: {
entities: {
'service.name': serviceName,
'transaction.type': transactionType,
},
},
}),
entities: {
'service.name': serviceName,
'transaction.type': transactionType,
},
}
: null),
: {}),
},
undefined,
undefined,
{
encodeURIComponent(str: string) {
return str;
},
}
);

return url.format({
pathname: core.http.basePath.prepend('/app/ml'),
hash: url.format({ pathname: '/timeseriesexplorer', search }),
});

return mlAnomalyDetectionHref;
}
Loading