diff --git a/x-pack/plugins/infra/public/components/logging/log_analysis_results/analyze_in_ml_button.tsx b/x-pack/plugins/infra/public/components/logging/log_analysis_results/analyze_in_ml_button.tsx
index 6b946898f6330..7d523faafdb3c 100644
--- a/x-pack/plugins/infra/public/components/logging/log_analysis_results/analyze_in_ml_button.tsx
+++ b/x-pack/plugins/infra/public/components/logging/log_analysis_results/analyze_in_ml_button.tsx
@@ -8,22 +8,19 @@ import { EuiButton } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import React from 'react';
import { encode } from 'rison-node';
-import url from 'url';
-import { stringify } from 'query-string';
-import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
import { TimeRange } from '../../../../common/http_api/shared/time_range';
-import { url as urlUtils } from '../../../../../../../src/plugins/kibana_utils/public';
+import { useLinkProps, LinkDescriptor } from '../../../hooks/use_link_props';
export const AnalyzeInMlButton: React.FunctionComponent<{
jobId: string;
partition?: string;
timeRange: TimeRange;
}> = ({ jobId, partition, timeRange }) => {
- const prependBasePath = useKibana().services.http?.basePath?.prepend;
- if (!prependBasePath) {
- return null;
- }
- const pathname = prependBasePath('/app/ml');
+ const linkProps = useLinkProps(
+ typeof partition === 'string'
+ ? getPartitionSpecificSingleMetricViewerLinkDescriptor(jobId, partition, timeRange)
+ : getOverallAnomalyExplorerLinkDescriptor(jobId, timeRange)
+ );
const buttonLabel = (
);
return typeof partition === 'string' ? (
-
+
{buttonLabel}
) : (
-
+
{buttonLabel}
);
};
-const getOverallAnomalyExplorerLink = (pathname: string, jobId: string, timeRange: TimeRange) => {
+const getOverallAnomalyExplorerLinkDescriptor = (
+ jobId: string,
+ timeRange: TimeRange
+): LinkDescriptor => {
const { from, to } = convertTimeRangeToParams(timeRange);
const _g = encode({
@@ -62,20 +54,18 @@ const getOverallAnomalyExplorerLink = (pathname: string, jobId: string, timeRang
},
});
- const hash = `/explorer?${stringify(urlUtils.encodeQuery({ _g }), { encode: false })}`;
-
- return url.format({
- pathname,
- hash,
- });
+ return {
+ app: 'ml',
+ hash: '/explorer',
+ search: { _g },
+ };
};
-const getPartitionSpecificSingleMetricViewerLink = (
- pathname: string,
+const getPartitionSpecificSingleMetricViewerLinkDescriptor = (
jobId: string,
partition: string,
timeRange: TimeRange
-) => {
+): LinkDescriptor => {
const { from, to } = convertTimeRangeToParams(timeRange);
const _g = encode({
@@ -95,15 +85,11 @@ const getPartitionSpecificSingleMetricViewerLink = (
},
});
- const hash = `/timeseriesexplorer?${stringify(urlUtils.encodeQuery({ _g, _a }), {
- sort: false,
- encode: false,
- })}`;
-
- return url.format({
- pathname,
- hash,
- });
+ return {
+ app: 'ml',
+ hash: '/timeseriesexplorer',
+ search: { _g, _a },
+ };
};
const convertTimeRangeToParams = (timeRange: TimeRange): { from: string; to: string } => {
diff --git a/x-pack/plugins/infra/public/components/logging/log_analysis_setup/user_management_link.tsx b/x-pack/plugins/infra/public/components/logging/log_analysis_setup/user_management_link.tsx
index 9a2bbd3dabffc..e045e78471513 100644
--- a/x-pack/plugins/infra/public/components/logging/log_analysis_setup/user_management_link.tsx
+++ b/x-pack/plugins/infra/public/components/logging/log_analysis_setup/user_management_link.tsx
@@ -7,12 +7,19 @@
import { EuiButton, EuiButtonProps } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import React from 'react';
+import { useLinkProps } from '../../../hooks/use_link_props';
-export const UserManagementLink: React.FunctionComponent = props => (
-
-
-
-);
+export const UserManagementLink: React.FunctionComponent = props => {
+ const linkProps = useLinkProps({
+ app: 'kibana',
+ hash: '/management/security/users',
+ });
+ return (
+
+
+
+ );
+};
diff --git a/x-pack/plugins/infra/public/components/logging/log_entry_flyout/log_entry_actions_menu.test.tsx b/x-pack/plugins/infra/public/components/logging/log_entry_flyout/log_entry_actions_menu.test.tsx
index 16a91e3727c98..b4fa6b8800fba 100644
--- a/x-pack/plugins/infra/public/components/logging/log_entry_flyout/log_entry_actions_menu.test.tsx
+++ b/x-pack/plugins/infra/public/components/logging/log_entry_flyout/log_entry_actions_menu.test.tsx
@@ -10,22 +10,35 @@ import { act } from 'react-dom/test-utils';
import { mount } from 'enzyme';
import { LogEntryActionsMenu } from './log_entry_actions_menu';
+import { KibanaContextProvider } from '../../../../../../../src/plugins/kibana_react/public';
+import { coreMock } from 'src/core/public/mocks';
+
+const coreStartMock = coreMock.createStart();
+coreStartMock.application.getUrlForApp.mockImplementation((app, options) => {
+ return `/test-basepath/s/test-space/app/${app}${options?.path}`;
+});
+
+const ProviderWrapper: React.FC = ({ children }) => {
+ return {children};
+};
describe('LogEntryActionsMenu component', () => {
describe('uptime link', () => {
it('renders with a host ip filter when present in log entry', () => {
const elementWrapper = mount(
-
+
+
+
);
act(() => {
@@ -38,22 +51,24 @@ describe('LogEntryActionsMenu component', () => {
expect(
elementWrapper.find(`a${testSubject('~uptimeLogEntryActionsMenuItem')}`).prop('href')
- ).toMatchInlineSnapshot(`"/app/uptime#/?search=(host.ip:HOST_IP)"`);
+ ).toBe('/test-basepath/s/test-space/app/uptime#/?search=host.ip:HOST_IP');
});
it('renders with a container id filter when present in log entry', () => {
const elementWrapper = mount(
-
+
+
+
);
act(() => {
@@ -66,22 +81,24 @@ describe('LogEntryActionsMenu component', () => {
expect(
elementWrapper.find(`a${testSubject('~uptimeLogEntryActionsMenuItem')}`).prop('href')
- ).toMatchInlineSnapshot(`"/app/uptime#/?search=(container.id:CONTAINER_ID)"`);
+ ).toBe('/test-basepath/s/test-space/app/uptime#/?search=container.id:CONTAINER_ID');
});
it('renders with a pod uid filter when present in log entry', () => {
const elementWrapper = mount(
-
+
+
+
);
act(() => {
@@ -94,26 +111,28 @@ describe('LogEntryActionsMenu component', () => {
expect(
elementWrapper.find(`a${testSubject('~uptimeLogEntryActionsMenuItem')}`).prop('href')
- ).toMatchInlineSnapshot(`"/app/uptime#/?search=(kubernetes.pod.uid:POD_UID)"`);
+ ).toBe('/test-basepath/s/test-space/app/uptime#/?search=kubernetes.pod.uid:POD_UID');
});
it('renders with a disjunction of filters when multiple present in log entry', () => {
const elementWrapper = mount(
-
+
+
+
);
act(() => {
@@ -126,24 +145,26 @@ describe('LogEntryActionsMenu component', () => {
expect(
elementWrapper.find(`a${testSubject('~uptimeLogEntryActionsMenuItem')}`).prop('href')
- ).toMatchInlineSnapshot(
- `"/app/uptime#/?search=(container.id:CONTAINER_ID OR host.ip:HOST_IP OR kubernetes.pod.uid:POD_UID)"`
+ ).toBe(
+ '/test-basepath/s/test-space/app/uptime#/?search=container.id:CONTAINER_ID%20or%20host.ip:HOST_IP%20or%20kubernetes.pod.uid:POD_UID'
);
});
it('renders as disabled when no supported field is present in log entry', () => {
const elementWrapper = mount(
-
+
+
+
);
act(() => {
@@ -165,17 +186,19 @@ describe('LogEntryActionsMenu component', () => {
describe('apm link', () => {
it('renders with a trace id filter when present in log entry', () => {
const elementWrapper = mount(
-
+
+
+
);
act(() => {
@@ -194,20 +217,22 @@ describe('LogEntryActionsMenu component', () => {
it('renders with a trace id filter and timestamp when present in log entry', () => {
const timestamp = '2019-06-27T17:44:08.693Z';
const elementWrapper = mount(
-
+
+
+
);
act(() => {
@@ -225,17 +250,19 @@ describe('LogEntryActionsMenu component', () => {
it('renders as disabled when no supported field is present in log entry', () => {
const elementWrapper = mount(
-
+
+
+
);
act(() => {
diff --git a/x-pack/plugins/infra/public/components/logging/log_entry_flyout/log_entry_actions_menu.tsx b/x-pack/plugins/infra/public/components/logging/log_entry_flyout/log_entry_actions_menu.tsx
index 60e50f486d22a..206e9821190fb 100644
--- a/x-pack/plugins/infra/public/components/logging/log_entry_flyout/log_entry_actions_menu.tsx
+++ b/x-pack/plugins/infra/public/components/logging/log_entry_flyout/log_entry_actions_menu.tsx
@@ -4,41 +4,44 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import * as rt from 'io-ts';
import { EuiButtonEmpty, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import React, { useMemo } from 'react';
-import url from 'url';
-import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
import { useVisibilityState } from '../../../utils/use_visibility_state';
import { getTraceUrl } from '../../../../../../legacy/plugins/apm/public/components/shared/Links/apm/ExternalLinks';
import { LogEntriesItem } from '../../../../common/http_api';
+import { useLinkProps, LinkDescriptor } from '../../../hooks/use_link_props';
+import { decodeOrThrow } from '../../../../common/runtime_types';
const UPTIME_FIELDS = ['container.id', 'host.ip', 'kubernetes.pod.uid'];
export const LogEntryActionsMenu: React.FunctionComponent<{
logItem: LogEntriesItem;
}> = ({ logItem }) => {
- const prependBasePath = useKibana().services.http?.basePath?.prepend;
const { hide, isVisible, show } = useVisibilityState(false);
- const uptimeLink = useMemo(() => {
- const link = getUptimeLink(logItem);
- return prependBasePath && link ? prependBasePath(link) : link;
- }, [logItem, prependBasePath]);
+ const apmLinkDescriptor = useMemo(() => getAPMLink(logItem), [logItem]);
+ const uptimeLinkDescriptor = useMemo(() => getUptimeLink(logItem), [logItem]);
- const apmLink = useMemo(() => {
- const link = getAPMLink(logItem);
- return prependBasePath && link ? prependBasePath(link) : link;
- }, [logItem, prependBasePath]);
+ const uptimeLinkProps = useLinkProps({
+ app: 'uptime',
+ ...(uptimeLinkDescriptor ? uptimeLinkDescriptor : {}),
+ });
+
+ const apmLinkProps = useLinkProps({
+ app: 'apm',
+ ...(apmLinkDescriptor ? apmLinkDescriptor : {}),
+ });
const menuItems = useMemo(
() => [