Skip to content

Commit

Permalink
[APM] Service overview: Introduce time-series comparison (#88665)
Browse files Browse the repository at this point in the history
* adding comparision select option

* adding time comparison field on some pages

* removing unused files

* fixing unit test

* adding unit tests

* enabling comparison for more than 8 days

* removing tooltip

* refactoring search bar

* moving useBreakPoint to common hooks folder, removing useShouldUSeMobileLayout hook

* addressing PR comments

* addressing PR comments

* addressing PR comments

* addressing PR comments

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
cauemarcondes and kibanamachine authored Jan 21, 2021
1 parent bfcd990 commit d997f20
Show file tree
Hide file tree
Showing 16 changed files with 344 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { UXMetrics } from './UXMetrics';
import { ImpactfulMetrics } from './ImpactfulMetrics';
import { PageLoadAndViews } from './Panels/PageLoadAndViews';
import { VisitorBreakdownsPanel } from './Panels/VisitorBreakdowns';
import { useBreakPoints } from './hooks/useBreakPoints';
import { useBreakPoints } from '../../../hooks/use_break_points';
import { getPercentileLabel } from './UXMetrics/translations';
import { useUrlParams } from '../../../context/url_params_context/use_url_params';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export function TransactionDetails({
<h1>{transactionName}</h1>
</EuiTitle>
</ApmHeader>
<SearchBar />
<SearchBar showTimeComparison />
<EuiPage>
<EuiFlexGroup>
<EuiFlexItem grow={1}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export function ServiceInventory() {

return (
<>
<SearchBar />
<SearchBar showTimeComparison />
<EuiPage>
<EuiFlexGroup>
<EuiFlexItem grow={1}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ function wrapper({ children }: { children?: ReactNode }) {
rangeTo: 'now',
start: 'mystart',
end: 'myend',
comparisonEnabled: true,
comparisonType: 'yesterday',
}}
>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { isRumAgentName } from '../../../../common/agent_name';
import { AnnotationsContextProvider } from '../../../context/annotations/annotations_context';
import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context';
import { ChartPointerEventContextProvider } from '../../../context/chart_pointer_event/chart_pointer_event_context';
import { useBreakPoints } from '../../../hooks/use_break_points';
import { LatencyChart } from '../../shared/charts/latency_chart';
import { TransactionBreakdownChart } from '../../shared/charts/transaction_breakdown_chart';
import { TransactionErrorRateChart } from '../../shared/charts/transaction_error_rate_chart';
Expand All @@ -22,7 +23,6 @@ import { ServiceOverviewErrorsTable } from './service_overview_errors_table';
import { ServiceOverviewInstancesChartAndTable } from './service_overview_instances_chart_and_table';
import { ServiceOverviewThroughputChart } from './service_overview_throughput_chart';
import { ServiceOverviewTransactionsTable } from './service_overview_transactions_table';
import { useShouldUseMobileLayout } from './use_should_use_mobile_layout';

/**
* The height a chart should be if it's next to a table with 5 rows and a title.
Expand All @@ -44,8 +44,8 @@ export function ServiceOverview({

// The default EuiFlexGroup breaks at 768, but we want to break at 992, so we
// observe the window width and set the flex directions of rows accordingly
const shouldUseMobileLayout = useShouldUseMobileLayout();
const rowDirection = shouldUseMobileLayout ? 'column' : 'row';
const { isMedium } = useBreakPoints();
const rowDirection = isMedium ? 'column' : 'row';

const { transactionType } = useApmServiceContext();
const transactionTypeLabel = i18n.translate(
Expand All @@ -57,7 +57,7 @@ export function ServiceOverview({
return (
<AnnotationsContextProvider>
<ChartPointerEventContextProvider>
<SearchBar prepend={transactionTypeLabel} />
<SearchBar prepend={transactionTypeLabel} showTimeComparison />
<EuiPage>
<EuiFlexGroup direction="column" gutterSize="s">
{isRumAgent && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import React, { ReactNode } from 'react';
import styled from 'styled-components';
import { useShouldUseMobileLayout } from './use_should_use_mobile_layout';
import { useBreakPoints } from '../../../hooks/use_break_points';

/**
* The height for a table on the overview page. Is the height of a 5-row basic
Expand Down Expand Up @@ -58,12 +58,12 @@ export function ServiceOverviewTableContainer({
children?: ReactNode;
isEmptyAndLoading: boolean;
}) {
const shouldUseMobileLayout = useShouldUseMobileLayout();
const { isMedium } = useBreakPoints();

return (
<ServiceOverviewTableContainerDiv
isEmptyAndLoading={isEmptyAndLoading}
shouldUseMobileLayout={shouldUseMobileLayout}
shouldUseMobileLayout={isMedium}
>
{children}
</ServiceOverviewTableContainerDiv>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export function TransactionOverview({ serviceName }: TransactionOverviewProps) {

return (
<>
<SearchBar />
<SearchBar showTimeComparison />

<EuiPage>
<EuiFlexGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ describe('TransactionOverview', () => {
});

expect(history.location.search).toEqual(
'?transactionType=secondType&rangeFrom=now-15m&rangeTo=now'
'?transactionType=secondType&rangeFrom=now-15m&rangeTo=now&comparisonEnabled=true&comparisonType=yesterday'
);
expect(getByText(container, 'firstType')).toBeInTheDocument();
expect(getByText(container, 'secondType')).toBeInTheDocument();
Expand All @@ -139,7 +139,7 @@ describe('TransactionOverview', () => {

expect(history.push).toHaveBeenCalled();
expect(history.location.search).toEqual(
'?transactionType=firstType&rangeFrom=now-15m&rangeTo=now'
'?transactionType=firstType&rangeFrom=now-15m&rangeTo=now&comparisonEnabled=true&comparisonType=yesterday'
);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ export type APMQueryParams = {
searchTerm?: string;
percentile?: 50 | 75 | 90 | 95 | 99;
latencyAggregationType?: string;
comparisonEnabled?: boolean;
comparisonType?: string;
} & { [key in LocalUIFilterName]?: string };

// forces every value of T[K] to be type: string
Expand Down
39 changes: 33 additions & 6 deletions x-pack/plugins/apm/public/components/shared/search_bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,49 @@
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import React from 'react';
import styled from 'styled-components';
import { px, unit } from '../../style/variables';
import { DatePicker } from './DatePicker';
import { KueryBar } from './KueryBar';
import { TimeComparison } from './time_comparison';
import { useBreakPoints } from '../../hooks/use_break_points';

const SearchBarFlexGroup = styled(EuiFlexGroup)`
margin: ${({ theme }) =>
`${theme.eui.euiSizeM} ${theme.eui.euiSizeM} -${theme.eui.gutterTypes.gutterMedium} ${theme.eui.euiSizeM}`};
`;

export function SearchBar(props: { prepend?: React.ReactNode | string }) {
interface Props {
prepend?: React.ReactNode | string;
showTimeComparison?: boolean;
}

function getRowDirection(showColumn: boolean) {
return showColumn ? 'column' : 'row';
}

export function SearchBar({ prepend, showTimeComparison = false }: Props) {
const { isMedium, isLarge } = useBreakPoints();
const itemsStyle = { marginBottom: isLarge ? px(unit) : 0 };
return (
<SearchBarFlexGroup alignItems="flexStart" gutterSize="s">
<EuiFlexItem grow={3}>
<KueryBar prepend={props.prepend} />
<SearchBarFlexGroup gutterSize="s" direction={getRowDirection(isLarge)}>
<EuiFlexItem>
<KueryBar prepend={prepend} />
</EuiFlexItem>
<EuiFlexItem grow={1}>
<DatePicker />
<EuiFlexItem grow={false}>
<EuiFlexGroup
justifyContent="flexEnd"
gutterSize="s"
direction={getRowDirection(isMedium)}
>
{showTimeComparison && (
<EuiFlexItem style={{ ...itemsStyle, minWidth: px(300) }}>
<TimeComparison />
</EuiFlexItem>
)}
<EuiFlexItem style={itemsStyle}>
<DatePicker />
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</SearchBarFlexGroup>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* 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 { render } from '@testing-library/react';
import React, { ReactNode } from 'react';
import { MemoryRouter } from 'react-router-dom';
import { EuiThemeProvider } from '../../../../../observability/public';
import { MockUrlParamsContextProvider } from '../../../context/url_params_context/mock_url_params_context_provider';
import { IUrlParams } from '../../../context/url_params_context/types';
import {
expectTextsInDocument,
expectTextsNotInDocument,
} from '../../../utils/testHelpers';
import { TimeComparison } from './';
import * as urlHelpers from '../../shared/Links/url_helpers';

function getWrapper(params?: IUrlParams) {
return ({ children }: { children?: ReactNode }) => {
return (
<MemoryRouter>
<MockUrlParamsContextProvider params={params}>
<EuiThemeProvider>{children}</EuiThemeProvider>
</MockUrlParamsContextProvider>
</MemoryRouter>
);
};
}

describe('TimeComparison', () => {
const spy = jest.spyOn(urlHelpers, 'replace');
beforeEach(() => {
jest.resetAllMocks();
});
describe('Time range is between 0 - 24 hours', () => {
it('sets default values', () => {
const Wrapper = getWrapper({
start: '2021-01-28T14:45:00.000Z',
end: '2021-01-28T15:00:00.000Z',
});
render(<TimeComparison />, {
wrapper: Wrapper,
});
expect(spy).toHaveBeenCalledWith(expect.anything(), {
query: {
comparisonEnabled: 'true',
comparisonType: 'yesterday',
},
});
});
it('selects yesterday and enables comparison', () => {
const Wrapper = getWrapper({
start: '2021-01-28T14:45:00.000Z',
end: '2021-01-28T15:00:00.000Z',
comparisonEnabled: true,
comparisonType: 'yesterday',
});
const component = render(<TimeComparison />, {
wrapper: Wrapper,
});
expectTextsInDocument(component, ['Yesterday', 'A week ago']);
expect(
(component.getByTestId('comparisonSelect') as HTMLSelectElement)
.selectedIndex
).toEqual(0);
});
});

describe('Time range is between 24 hours - 1 week', () => {
it('sets default values', () => {
const Wrapper = getWrapper({
start: '2021-01-26T15:00:00.000Z',
end: '2021-01-28T15:00:00.000Z',
});
render(<TimeComparison />, {
wrapper: Wrapper,
});
expect(spy).toHaveBeenCalledWith(expect.anything(), {
query: {
comparisonEnabled: 'true',
comparisonType: 'week',
},
});
});
it('selects week and enables comparison', () => {
const Wrapper = getWrapper({
start: '2021-01-26T15:00:00.000Z',
end: '2021-01-28T15:00:00.000Z',
comparisonEnabled: true,
comparisonType: 'week',
});
const component = render(<TimeComparison />, {
wrapper: Wrapper,
});
expectTextsNotInDocument(component, ['Yesterday']);
expectTextsInDocument(component, ['A week ago']);
expect(
(component.getByTestId('comparisonSelect') as HTMLSelectElement)
.selectedIndex
).toEqual(0);
});
});

describe('Time range is greater than 7 days', () => {
it('Shows absolute times without year when within the same year', () => {
const Wrapper = getWrapper({
start: '2021-01-20T15:00:00.000Z',
end: '2021-01-28T15:00:00.000Z',
comparisonEnabled: true,
comparisonType: 'previousPeriod',
});
const component = render(<TimeComparison />, {
wrapper: Wrapper,
});
expect(spy).not.toHaveBeenCalled();
expectTextsInDocument(component, ['20/01 - 28/01']);
expect(
(component.getByTestId('comparisonSelect') as HTMLSelectElement)
.selectedIndex
).toEqual(0);
});

it('Shows absolute times with year when on different year', () => {
const Wrapper = getWrapper({
start: '2020-12-20T15:00:00.000Z',
end: '2021-01-28T15:00:00.000Z',
comparisonEnabled: true,
comparisonType: 'previousPeriod',
});
const component = render(<TimeComparison />, {
wrapper: Wrapper,
});
expect(spy).not.toHaveBeenCalled();
expectTextsInDocument(component, ['20/12/20 - 28/01/21']);
expect(
(component.getByTestId('comparisonSelect') as HTMLSelectElement)
.selectedIndex
).toEqual(0);
});
});
});
Loading

0 comments on commit d997f20

Please sign in to comment.