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

[APM] Updated header icons #84760

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4b709ae
creating service name header
cauemarcondes Dec 2, 2020
47dd1dd
fixing icons
cauemarcondes Dec 2, 2020
de12761
removing unused api import
cauemarcondes Dec 10, 2020
7614d90
fixing some stuff
cauemarcondes Dec 10, 2020
3be873e
adding API tests
cauemarcondes Dec 10, 2020
5bac619
refactoring some stuff
cauemarcondes Dec 14, 2020
b59eee6
fixing tests
cauemarcondes Dec 14, 2020
a0d4017
refactoring some stuff
cauemarcondes Dec 14, 2020
4254999
fixing i18n
cauemarcondes Dec 14, 2020
689cf6e
reverting
cauemarcondes Dec 14, 2020
9072287
renaming
cauemarcondes Dec 14, 2020
6295806
applying min width
cauemarcondes Dec 14, 2020
cfc9fdc
Merge branch 'master' of github.com:elastic/kibana into apm-serv-over…
cauemarcondes Dec 14, 2020
2858596
addressing PR comments and adding test
cauemarcondes Dec 15, 2020
77eb860
sorting service version
cauemarcondes Dec 15, 2020
190810d
Merge branch 'master' of github.com:elastic/kibana into apm-serv-over…
cauemarcondes Dec 15, 2020
53335ea
changing sort type to desc
cauemarcondes Dec 15, 2020
c2eb190
addressing pr comments
cauemarcondes Dec 15, 2020
7903865
changing to show total and not avg
cauemarcondes Dec 15, 2020
a5edbe5
Merge branch 'master' into apm-serv-overview-header-icons
kibanamachine Dec 15, 2020
400c277
addressing pr comments
cauemarcondes Dec 16, 2020
588c76d
Merge branch 'apm-serv-overview-header-icons' of github.com:cauemarco…
cauemarcondes Dec 16, 2020
1e7c498
addressing pr comments
cauemarcondes Dec 16, 2020
00a78b8
addressing pr comments
cauemarcondes Dec 16, 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
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,31 @@ import {
EuiPopover,
EuiPopoverTitle,
} from '@elastic/eui';
import React, { useState } from 'react';
import React from 'react';
import { FETCH_STATUS } from '../../../../hooks/use_fetcher';
import { px } from '../../../../style/variables';

interface IconPopoverProps {
icon: string;
title: string;
children: React.ReactChild;
onClick: (isOpen: boolean) => void;
onClick: () => void;
cauemarcondes marked this conversation as resolved.
Show resolved Hide resolved
onClose: () => void;
detailsFetchStatus: FETCH_STATUS;
isOpen: boolean;
icon?: string;
}
export function IconPopover({
icon,
title,
children,
onClick,
onClose,
detailsFetchStatus,
isOpen,
}: IconPopoverProps) {
const [isOpen, setIsOpen] = useState(false);

const togglePopover = () => {
setIsOpen((prevState) => {
const nextState = !prevState;
onClick(nextState);
return nextState;
});
};

if (!icon) {
return null;
}
const isLoading =
detailsFetchStatus === FETCH_STATUS.LOADING ||
detailsFetchStatus === FETCH_STATUS.PENDING;
Expand All @@ -47,15 +44,12 @@ export function IconPopover({
anchorPosition="downCenter"
ownFocus={false}
button={
<EuiButtonEmpty
onClick={togglePopover}
data-test-subj={`popover_${title}`}
>
<EuiButtonEmpty onClick={onClick} data-test-subj={`popover_${title}`}>
<EuiIcon type={icon} size="l" color="black" />
</EuiButtonEmpty>
}
isOpen={isOpen}
closePopover={togglePopover}
closePopover={onClose}
>
<EuiPopoverTitle>{title}</EuiPopoverTitle>
<div style={{ minWidth: px(300) }}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ describe('ServiceIcons', () => {
</Wrapper>
);
expect(getByTestId('loading')).toBeInTheDocument();
expect(queryAllByTestId('java')).toHaveLength(0);
expect(queryAllByTestId('Kubernetes')).toHaveLength(0);
expect(queryAllByTestId('gcp')).toHaveLength(0);
expect(queryAllByTestId('service')).toHaveLength(0);
expect(queryAllByTestId('container')).toHaveLength(0);
expect(queryAllByTestId('cloud')).toHaveLength(0);
});
it("doesn't show any icons", () => {
jest.spyOn(fetcherHook, 'useFetcher').mockReturnValue({
Expand All @@ -80,9 +80,9 @@ describe('ServiceIcons', () => {
</Wrapper>
);
expect(queryAllByTestId('loading')).toHaveLength(0);
expect(queryAllByTestId('java')).toHaveLength(0);
expect(queryAllByTestId('Kubernetes')).toHaveLength(0);
expect(queryAllByTestId('gcp')).toHaveLength(0);
expect(queryAllByTestId('service')).toHaveLength(0);
expect(queryAllByTestId('container')).toHaveLength(0);
expect(queryAllByTestId('cloud')).toHaveLength(0);
});
it('shows service icon', () => {
jest.spyOn(fetcherHook, 'useFetcher').mockReturnValue({
Expand All @@ -99,9 +99,9 @@ describe('ServiceIcons', () => {
</Wrapper>
);
expect(queryAllByTestId('loading')).toHaveLength(0);
expect(getByTestId('java')).toBeInTheDocument();
expect(queryAllByTestId('Kubernetes')).toHaveLength(0);
expect(queryAllByTestId('gcp')).toHaveLength(0);
expect(getByTestId('service')).toBeInTheDocument();
expect(queryAllByTestId('container')).toHaveLength(0);
expect(queryAllByTestId('cloud')).toHaveLength(0);
});
it('shows service and container icons', () => {
jest.spyOn(fetcherHook, 'useFetcher').mockReturnValue({
Expand All @@ -119,9 +119,9 @@ describe('ServiceIcons', () => {
</Wrapper>
);
expect(queryAllByTestId('loading')).toHaveLength(0);
expect(queryAllByTestId('gcp')).toHaveLength(0);
expect(getByTestId('java')).toBeInTheDocument();
expect(getByTestId('Kubernetes')).toBeInTheDocument();
expect(queryAllByTestId('cloud')).toHaveLength(0);
expect(getByTestId('service')).toBeInTheDocument();
expect(getByTestId('container')).toBeInTheDocument();
});
it('shows service, container and cloud icons', () => {
jest.spyOn(fetcherHook, 'useFetcher').mockReturnValue({
Expand All @@ -140,9 +140,9 @@ describe('ServiceIcons', () => {
</Wrapper>
);
expect(queryAllByTestId('loading')).toHaveLength(0);
expect(getByTestId('java')).toBeInTheDocument();
expect(getByTestId('Kubernetes')).toBeInTheDocument();
expect(getByTestId('gcp')).toBeInTheDocument();
expect(getByTestId('service')).toBeInTheDocument();
expect(getByTestId('container')).toBeInTheDocument();
expect(getByTestId('cloud')).toBeInTheDocument();
});
});

Expand Down Expand Up @@ -183,9 +183,9 @@ describe('ServiceIcons', () => {
</Wrapper>
);
expect(queryAllByTestId('loading')).toHaveLength(0);
expect(getByTestId('java')).toBeInTheDocument();
expect(getByTestId('Kubernetes')).toBeInTheDocument();
expect(getByTestId('gcp')).toBeInTheDocument();
expect(getByTestId('service')).toBeInTheDocument();
expect(getByTestId('container')).toBeInTheDocument();
expect(getByTestId('cloud')).toBeInTheDocument();
fireEvent.click(getByTestId('popover_Service'));
expect(getByTestId('loading-content')).toBeInTheDocument();
});
Expand Down Expand Up @@ -219,9 +219,9 @@ describe('ServiceIcons', () => {
</Wrapper>
);
expect(queryAllByTestId('loading')).toHaveLength(0);
expect(getByTestId('java')).toBeInTheDocument();
expect(getByTestId('Kubernetes')).toBeInTheDocument();
expect(getByTestId('gcp')).toBeInTheDocument();
expect(getByTestId('service')).toBeInTheDocument();
expect(getByTestId('container')).toBeInTheDocument();
expect(getByTestId('cloud')).toBeInTheDocument();

fireEvent.click(getByTestId('popover_Service'));
expect(queryAllByTestId('loading-content')).toHaveLength(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React, { useState } from 'react';
import React, { ReactChild, useState } from 'react';
import { ContainerType } from '../../../../../common/service_metadata';
import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher';
Expand Down Expand Up @@ -44,12 +44,24 @@ function getContainerIcon(container?: ContainerType) {
}
}

type Icons = 'service' | 'container' | 'cloud';
interface PopoverItem {
key: Icons;
icon?: string;
isVisible: boolean;
title: string;
component: ReactChild;
}

export function ServiceIcons({ serviceName }: Props) {
const {
urlParams: { start, end },
uiFilters,
} = useUrlParams();
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const [
selectedIconPopover,
setSelectedIconPopover,
] = useState<Icons | null>();

const { data: icons, status: iconsFetchStatus } = useFetcher(
(callApmApi) => {
Expand All @@ -68,7 +80,7 @@ export function ServiceIcons({ serviceName }: Props) {

const { data: details, status: detailsFetchStatus } = useFetcher(
(callApmApi) => {
if (isPopoverOpen && serviceName && start && end) {
if (selectedIconPopover && serviceName && start && end) {
return callApmApi({
endpoint: 'GET /api/apm/services/{serviceName}/metadata/details',
params: {
Expand All @@ -78,12 +90,9 @@ export function ServiceIcons({ serviceName }: Props) {
});
}
},
[isPopoverOpen, serviceName, start, end, uiFilters]
[selectedIconPopover, serviceName, start, end, uiFilters]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the request made every time the popover is opened/closed or only the first time?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The request is going to be cached, so no, the details are going to be fetched once and used until the parameters are changed. Take a look:

ezgif com-gif-maker (3)

);

const cloudIcon = getCloudIcon(icons?.cloudProvider);
const containerIcon = getContainerIcon(icons?.containerType);

const isLoading =
!icons &&
(iconsFetchStatus === FETCH_STATUS.LOADING ||
Expand All @@ -93,50 +102,60 @@ export function ServiceIcons({ serviceName }: Props) {
return <EuiLoadingSpinner data-test-subj="loading" />;
}

const popoverItems: PopoverItem[] = [
{
key: 'service',
icon: getAgentIcon(icons?.agentName) || 'node',
isVisible: !!icons?.agentName,
title: i18n.translate('xpack.apm.serviceIcons.service', {
defaultMessage: 'Service',
}),
component: <ServiceDetails service={details?.service} />,
},
{
key: 'container',
icon: getContainerIcon(icons?.containerType),
isVisible: !!icons?.containerType,
title: i18n.translate('xpack.apm.serviceIcons.container', {
defaultMessage: 'Container',
}),
component: <ContainerDetails container={details?.container} />,
},
{
key: 'cloud',
icon: getCloudIcon(icons?.cloudProvider),
isVisible: !!icons?.cloudProvider,
title: i18n.translate('xpack.apm.serviceIcons.cloud', {
defaultMessage: 'Cloud',
}),
component: <CloudDetails cloud={details?.cloud} />,
},
];

return (
<EuiFlexGroup gutterSize="s" responsive={false}>
{icons?.agentName && (
<EuiFlexItem grow={false} data-test-subj={icons.agentName}>
<IconPopover
detailsFetchStatus={detailsFetchStatus}
onClick={setIsPopoverOpen}
icon={getAgentIcon(icons.agentName) || 'node'}
title={i18n.translate('xpack.apm.serviceIcons.service', {
defaultMessage: 'Service',
})}
>
<ServiceDetails service={details?.service} />
</IconPopover>
</EuiFlexItem>
)}
{containerIcon && (
<EuiFlexItem grow={false} data-test-subj={icons?.containerType}>
<IconPopover
detailsFetchStatus={detailsFetchStatus}
onClick={setIsPopoverOpen}
icon={containerIcon}
title={i18n.translate('xpack.apm.serviceIcons.container', {
defaultMessage: 'Container',
})}
>
<ContainerDetails container={details?.container} />
</IconPopover>
</EuiFlexItem>
)}
{cloudIcon && (
<EuiFlexItem grow={false} data-test-subj={icons?.cloudProvider}>
<IconPopover
detailsFetchStatus={detailsFetchStatus}
onClick={setIsPopoverOpen}
icon={cloudIcon}
title={i18n.translate('xpack.apm.serviceIcons.cloud', {
defaultMessage: 'Cloud',
})}
>
<CloudDetails cloud={details?.cloud} />
</IconPopover>
</EuiFlexItem>
)}
{popoverItems.map((item) => {
if (item.isVisible) {
return (
<EuiFlexItem grow={false} data-test-subj={item.key} key={item.key}>
<IconPopover
isOpen={selectedIconPopover === item.key}
icon={item.icon}
detailsFetchStatus={detailsFetchStatus}
title={item.title}
onClick={() => {
setSelectedIconPopover(item.key);
}}
onClose={() => {
setSelectedIconPopover(null);
}}
>
{item.component}
</IconPopover>
</EuiFlexItem>
);
}
})}
</EuiFlexGroup>
);
}