Skip to content

Commit

Permalink
[Infrastructure UI] Hosts view: Add links to apm and uptime for a sin…
Browse files Browse the repository at this point in the history
…gle host (#154269)

Closes #150985 

## Summary

This PR adds links to APM Traces and Uptime.
<img width="1909" alt="image"
src="https://user-images.githubusercontent.com/14139027/229580612-a3d0c03a-4f68-4b09-b333-ffa79c8454e6.png">

# Testing
1. Open Hosts view 
2. Click on the button to open the flyout for a single host
- Click on the APM traces link and verify the query parameters are
correct
- Click on the uptime link and verify the query parameters are correct
   


https://user-images.githubusercontent.com/14139027/229581672-3c50ea55-e834-4431-aac6-3ed3ff9f96cc.mov

---------

Co-authored-by: Carlos Crespo <[email protected]>
  • Loading branch information
jennypavlova and crespocarlos authored Apr 6, 2023
1 parent b8409c9 commit 8c2ff54
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,26 @@
*/

import React from 'react';
import { EuiFlyout, EuiFlyoutHeader, EuiTitle, EuiFlyoutBody } from '@elastic/eui';
import { EuiSpacer, EuiTabs, EuiTab } from '@elastic/eui';
import {
EuiFlyout,
EuiFlyoutHeader,
EuiTitle,
EuiFlyoutBody,
EuiFlexGroup,
EuiFlexItem,
EuiTab,
EuiSpacer,
EuiTabs,
useEuiTheme,
} from '@elastic/eui';
import { css } from '@emotion/react';
import { useUnifiedSearchContext } from '../../hooks/use_unified_search';
import { LinkToUptime } from './links/link_to_uptime';
import { LinkToApmServices } from './links/link_to_apm_services';
import { useLazyRef } from '../../../../../hooks/use_lazy_ref';
import { metadataTab } from './metadata';
import type { InventoryItemType } from '../../../../../../common/inventory_models/types';
import type { HostNodeRow } from '../../hooks/use_hosts_table';
import { useUnifiedSearchContext } from '../../hooks/use_unified_search';
import { processesTab } from './processes';
import { Metadata } from './metadata/metadata';
import { Processes } from './processes/processes';
Expand All @@ -28,6 +41,7 @@ const NODE_TYPE = 'host' as InventoryItemType;

export const Flyout = ({ node, closeFlyout }: Props) => {
const { getDateRangeAsTimestamp } = useUnifiedSearchContext();
const { euiTheme } = useEuiTheme();

const currentTimeRange = {
...getDateRangeAsTimestamp(),
Expand Down Expand Up @@ -57,9 +71,24 @@ export const Flyout = ({ node, closeFlyout }: Props) => {
return (
<EuiFlyout onClose={closeFlyout} ownFocus={false}>
<EuiFlyoutHeader hasBorder>
<EuiTitle size="xs">
<h2>{node.name}</h2>
</EuiTitle>
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem>
<EuiTitle size="xs">
<h2>{node.name}</h2>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<LinkToApmServices hostName={node.name} apmField={'host.hostname'} />
</EuiFlexItem>
<EuiFlexItem
grow={false}
css={css`
margin-right: ${euiTheme.size.l};
`}
>
<LinkToUptime nodeType={NODE_TYPE} node={node} />
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="s" />
<EuiTabs style={{ marginBottom: '-25px' }} size="s">
{tabEntries}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';
import { stringify } from 'querystring';
import { encode } from '@kbn/rison';
import { css } from '@emotion/react';
import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app';
import { EuiIcon, EuiLink, useEuiTheme } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { useKibanaContextForPlugin } from '../../../../../../hooks/use_kibana';

interface LinkToApmServicesProps {
hostName: string;
apmField: string;
}

export const LinkToApmServices = ({ hostName, apmField }: LinkToApmServicesProps) => {
const { services } = useKibanaContextForPlugin();
const { http } = services;
const { euiTheme } = useEuiTheme();

const queryString = new URLSearchParams(
encode(
stringify({
kuery: `${apmField}:"${hostName}"`,
})
)
);

const linkToApmServices = http.basePath.prepend(`/app/apm/services?${queryString}`);

return (
<RedirectAppLinks coreStart={services}>
<EuiLink href={linkToApmServices} data-test-subj="hostsView-flyout-apm-services-link">
<EuiIcon
type="popout"
css={css`
margin-right: ${euiTheme.size.xs};
`}
/>
<FormattedMessage
id="xpack.infra.hostsViewPage.flyout.apmServicesLinkLabel"
defaultMessage="APM Services"
/>
</EuiLink>
</RedirectAppLinks>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { EuiLink, EuiIcon, useEuiTheme } from '@elastic/eui';
import { css } from '@emotion/react';
import { FormattedMessage } from '@kbn/i18n-react';
import { uptimeOverviewLocatorID } from '@kbn/observability-plugin/public';
import { useKibanaContextForPlugin } from '../../../../../../hooks/use_kibana';
import type { InventoryItemType } from '../../../../../../../common/inventory_models/types';
import type { HostNodeRow } from '../../../hooks/use_hosts_table';

interface LinkTUptimeProps {
nodeType: InventoryItemType;
node: HostNodeRow;
}

export const LinkToUptime = ({ nodeType, node }: LinkTUptimeProps) => {
const { share } = useKibanaContextForPlugin().services;
const { euiTheme } = useEuiTheme();

return (
<EuiLink
data-test-subj="hostsView-flyout-uptime-link"
onClick={() =>
share.url.locators
.get(uptimeOverviewLocatorID)!
.navigate({ [nodeType]: node.name, ip: node.ip })
}
>
<EuiIcon
type="popout"
css={css`
margin-right: ${euiTheme.size.xs};
`}
/>
<FormattedMessage
id="xpack.infra.hostsViewPage.flyout.uptimeLinkLabel"
defaultMessage="Uptime"
/>
</EuiLink>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ describe('useHostTable hook', () => {
{
name: 'host-0',
os: '-',
ip: '',
id: 'host-0-0',
title: {
cloudProvider: 'aws',
Expand Down Expand Up @@ -103,6 +104,7 @@ describe('useHostTable hook', () => {
{
name: 'host-1',
os: 'macOS',
ip: '243.86.94.22',
id: 'host-1-1',
title: {
cloudProvider: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type HostMetrics = Record<HostMetric, SnapshotNodeMetric>;

export interface HostNodeRow extends HostMetrics {
os?: string | null;
ip?: string | null;
servicesOnHost?: number | null;
title: { name: string; cloudProvider?: CloudProvider | null };
name: string;
Expand All @@ -53,6 +54,7 @@ const buildItemsList = (nodes: SnapshotNode[]) => {
id: `${name}-${index}`,
name,
os: path.at(-1)?.os ?? '-',
ip: path.at(-1)?.ip ?? '',
title: {
name,
cloudProvider: path.at(-1)?.cloudProvider ?? null,
Expand Down
20 changes: 20 additions & 0 deletions x-pack/test/functional/apps/infra/hosts_view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,26 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
expect(metadataTab).to.contain('Metadata');
});

it('should navigate to Uptime after click', async () => {
await pageObjects.infraHostsView.clickFlyoutUptimeLink();
await pageObjects.infraHome.waitForLoading();
const url = await browser.getCurrentUrl();
expect(url).to.contain(
'app/uptime/?search=host.name%3A%20%22Jennys-MBP.fritz.box%22%20OR%20host.ip%3A%20%22192.168.1.79%22'
);
await browser.goBack();
await pageObjects.infraHome.waitForLoading();
});

it('should navigate to APM services after click', async () => {
await pageObjects.infraHostsView.clickFlyoutApmServicesLink();
await pageObjects.infraHome.waitForLoading();
const url = await browser.getCurrentUrl();
expect(url).to.contain('app/apm/services?kuery=host.hostname%3A%22Jennys-MBP.fritz.box%22');
await browser.goBack();
await pageObjects.infraHome.waitForLoading();
});

describe('should render processes tab', async () => {
const processTitles = [
'Total processes',
Expand Down
8 changes: 8 additions & 0 deletions x-pack/test/functional/page_objects/infra_hosts_view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ export function InfraHostsViewProvider({ getService }: FtrProviderContext) {
return testSubjects.click('infraProcessRowButton');
},

async clickFlyoutUptimeLink() {
return testSubjects.click('hostsView-flyout-uptime-link');
},

async clickFlyoutApmServicesLink() {
return testSubjects.click('hostsView-flyout-apm-services-link');
},

async getHostsLandingPageDisabled() {
const container = await testSubjects.find('hostView-no-enable-access');
const containerText = await container.getVisibleText();
Expand Down

0 comments on commit 8c2ff54

Please sign in to comment.