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] Fixing service inventory responsive design #107690

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 2.0.
*/

import { EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui';
import React from 'react';
import { Coordinate } from '../../../../../typings/timeseries';
import { SparkPlot } from '../../../shared/charts/spark_plot';
Expand All @@ -14,18 +15,32 @@ export function ServiceListMetric({
series,
valueLabel,
comparisonSeries,
hideSeries = false,
}: {
color: 'euiColorVis1' | 'euiColorVis0' | 'euiColorVis7';
series?: Coordinate[];
comparisonSeries?: Coordinate[];
valueLabel: React.ReactNode;
hideSeries?: boolean;
}) {
if (!hideSeries) {
return (
<SparkPlot
valueLabel={valueLabel}
series={series}
color={color}
comparisonSeries={comparisonSeries}
/>
);
}

return (
<SparkPlot
valueLabel={valueLabel}
series={series}
color={color}
comparisonSeries={comparisonSeries}
/>
<EuiFlexGroup gutterSize="none" alignItems="flexEnd">
<EuiFlexItem>
<EuiText size="s" textAlign="right">
{valueLabel}
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ import { TypeOf } from '@kbn/typed-react-router-config';
import { orderBy } from 'lodash';
import React, { useMemo } from 'react';
import { ValuesType } from 'utility-types';
import { euiStyled } from '../../../../../../../../src/plugins/kibana_react/common';
import {
BreakPoints,
useBreakPoints,
} from '../../../../hooks/use_break_points';
import { NOT_AVAILABLE_LABEL } from '../../../../../common/i18n';
import { ServiceHealthStatus } from '../../../../../common/service_health_status';
import {
Expand All @@ -38,6 +41,7 @@ import { ITableColumn, ManagedTable } from '../../../shared/managed_table';
import { ServiceLink } from '../../../shared/service_link';
import { HealthBadge } from './HealthBadge';
import { ServiceListMetric } from './ServiceListMetric';
import { TruncateWithTooltip } from '../../../shared/truncate_with_tooltip';

type ServiceListAPIResponse = APIReturnType<'GET /api/apm/services'>;
type Items = ServiceListAPIResponse['items'];
Expand All @@ -49,13 +53,6 @@ function formatString(value?: string | null) {
return value || NOT_AVAILABLE_LABEL;
}

const ToolTipWrapper = euiStyled.span`
width: 100%;
.apmServiceList__serviceNameTooltip {
width: 100%;
}
`;

const SERVICE_HEALTH_STATUS_ORDER = [
ServiceHealthStatus.unknown,
ServiceHealthStatus.healthy,
Expand All @@ -67,11 +64,16 @@ export function getServiceColumns({
query,
showTransactionTypeColumn,
comparisonData,
breakPoints,
}: {
query: TypeOf<ApmRoutes, '/services'>['query'];
showTransactionTypeColumn: boolean;
breakPoints: BreakPoints;
comparisonData?: ServicesDetailedStatisticsAPIResponse;
}): Array<ITableColumn<ServiceListItem>> {
const { isSmall, isLarge, isXl } = breakPoints;
const showWhenSmallOrGreaterThanLarge = isSmall || !isLarge;
const showWhenSmallOrGreaterThanXL = isSmall || !isXl;
return [
{
field: 'healthStatus',
Expand All @@ -96,34 +98,38 @@ export function getServiceColumns({
width: '40%',
sortable: true,
render: (_, { serviceName, agentName }) => (
<ToolTipWrapper data-test-subj="apmServiceListAppLink">
<EuiToolTip
delay="long"
content={formatString(serviceName)}
id="service-name-tooltip"
anchorClassName="apmServiceList__serviceNameTooltip"
>
<TruncateWithTooltip
data-test-subj="apmServiceListAppLink"
text={formatString(serviceName)}
content={
<ServiceLink
agentName={agentName}
query={query}
serviceName={serviceName}
/>
</EuiToolTip>
</ToolTipWrapper>
),
},
{
field: 'environments',
name: i18n.translate('xpack.apm.servicesTable.environmentColumnLabel', {
defaultMessage: 'Environment',
}),
width: `${unit * 10}px`,
sortable: true,
render: (_, { environments }) => (
<EnvironmentBadge environments={environments ?? []} />
}
/>
),
},
...(showTransactionTypeColumn
...(showWhenSmallOrGreaterThanLarge
? [
{
field: 'environments',
name: i18n.translate(
'xpack.apm.servicesTable.environmentColumnLabel',
{
defaultMessage: 'Environment',
}
),
width: `${unit * 10}px`,
sortable: true,
render: (_, { environments }) => (
<EnvironmentBadge environments={environments ?? []} />
),
} as ITableColumn<ServiceListItem>,
]
: []),
...(showTransactionTypeColumn && showWhenSmallOrGreaterThanXL
? [
{
field: 'transactionType',
Expand All @@ -149,12 +155,13 @@ export function getServiceColumns({
comparisonSeries={
comparisonData?.previousPeriod[serviceName]?.latency
}
hideSeries={!showWhenSmallOrGreaterThanLarge}
color="euiColorVis1"
valueLabel={asMillisecondDuration(latency || 0)}
/>
),
align: 'left',
width: `${unit * 10}px`,
width: showWhenSmallOrGreaterThanLarge ? `${unit * 10}px` : 'auto',
},
{
field: 'throughput',
Expand All @@ -169,12 +176,13 @@ export function getServiceColumns({
comparisonSeries={
comparisonData?.previousPeriod[serviceName]?.throughput
}
hideSeries={!showWhenSmallOrGreaterThanLarge}
color="euiColorVis0"
valueLabel={asTransactionRate(throughput)}
/>
),
align: 'left',
width: `${unit * 10}px`,
width: showWhenSmallOrGreaterThanLarge ? `${unit * 10}px` : 'auto',
},
{
field: 'transactionErrorRate',
Expand All @@ -193,13 +201,14 @@ export function getServiceColumns({
comparisonSeries={
comparisonData?.previousPeriod[serviceName]?.transactionErrorRate
}
hideSeries={!showWhenSmallOrGreaterThanLarge}
color="euiColorVis7"
valueLabel={valueLabel}
/>
);
},
align: 'left',
width: `${unit * 10}px`,
width: showWhenSmallOrGreaterThanLarge ? `${unit * 10}px` : 'auto',
},
];
}
Expand All @@ -217,6 +226,7 @@ export function ServiceList({
comparisonData,
isLoading,
}: Props) {
const breakPoints = useBreakPoints();
const displayHealthStatus = items.some((item) => 'healthStatus' in item);

const showTransactionTypeColumn = items.some(
Expand All @@ -229,8 +239,13 @@ export function ServiceList({

const serviceColumns = useMemo(
() =>
getServiceColumns({ query, showTransactionTypeColumn, comparisonData }),
[query, showTransactionTypeColumn, comparisonData]
getServiceColumns({
query,
showTransactionTypeColumn,
comparisonData,
breakPoints,
}),
[query, showTransactionTypeColumn, comparisonData, breakPoints]
);

const columns = displayHealthStatus
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import React, { ReactNode } from 'react';
import { MemoryRouter } from 'react-router-dom';
import { BreakPoints } from '../../../../hooks/use_break_points';
import { ServiceHealthStatus } from '../../../../../common/service_health_status';
import { MockApmPluginContextWrapper } from '../../../../context/apm_plugin/mock_apm_plugin_context';
import { mockMoment, renderWithTheme } from '../../../../utils/testHelpers';
Expand Down Expand Up @@ -42,7 +43,12 @@ describe('ServiceList', () => {
).not.toThrowError();
});

it('renders columns correctly', () => {
describe('responsive columns', () => {
const query = {
rangeFrom: 'now-15m',
rangeTo: 'now',
};

const service: any = {
serviceName: 'opbeans-python',
agentName: 'python',
Expand All @@ -59,20 +65,132 @@ describe('ServiceList', () => {
timeseries: [],
},
environments: ['test'],
transactionType: 'request',
};
const renderedColumns = getServiceColumns({
query: {
rangeFrom: 'now-15m',
rangeTo: 'now',
},
showTransactionTypeColumn: false,
}).map((c) => c.render!(service[c.field!], service));

expect(renderedColumns[0]).toMatchInlineSnapshot(`
<HealthBadge
healthStatus="unknown"
/>
`);
describe('when small', () => {
it('shows environment, transaction type and sparklines', () => {
const renderedColumns = getServiceColumns({
query,
showTransactionTypeColumn: true,
breakPoints: {
isSmall: true,
isLarge: true,
isXl: true,
} as BreakPoints,
}).map((c) =>
c.render ? c.render!(service[c.field!], service) : service[c.field!]
);
expect(renderedColumns.length).toEqual(7);
expect(renderedColumns[2]).toMatchInlineSnapshot(`
<EnvironmentBadge
environments={
Array [
"test",
]
}
/>
`);
expect(renderedColumns[3]).toMatchInlineSnapshot(`"request"`);
expect(renderedColumns[4]).toMatchInlineSnapshot(`
<ServiceListMetric
color="euiColorVis1"
hideSeries={false}
valueLabel="0 ms"
/>
`);
});
});

describe('when Large', () => {
it('hides environment, transaction type and sparklines', () => {
const renderedColumns = getServiceColumns({
query,
showTransactionTypeColumn: true,
breakPoints: {
isSmall: false,
isLarge: true,
isXl: true,
} as BreakPoints,
}).map((c) =>
c.render ? c.render!(service[c.field!], service) : service[c.field!]
);
expect(renderedColumns.length).toEqual(5);
expect(renderedColumns[2]).toMatchInlineSnapshot(`
<ServiceListMetric
color="euiColorVis1"
hideSeries={true}
valueLabel="0 ms"
/>
`);
});

describe('when XL', () => {
it('hides transaction type', () => {
const renderedColumns = getServiceColumns({
query,
showTransactionTypeColumn: true,
breakPoints: {
isSmall: false,
isLarge: false,
isXl: true,
} as BreakPoints,
}).map((c) =>
c.render ? c.render!(service[c.field!], service) : service[c.field!]
);
expect(renderedColumns.length).toEqual(6);
expect(renderedColumns[2]).toMatchInlineSnapshot(`
<EnvironmentBadge
environments={
Array [
"test",
]
}
/>
`);
expect(renderedColumns[3]).toMatchInlineSnapshot(`
<ServiceListMetric
color="euiColorVis1"
hideSeries={false}
valueLabel="0 ms"
/>
`);
});
});

describe('when XXL', () => {
it('hides transaction type', () => {
const renderedColumns = getServiceColumns({
query,
showTransactionTypeColumn: true,
breakPoints: {
isSmall: false,
isLarge: false,
isXl: false,
} as BreakPoints,
}).map((c) =>
c.render ? c.render!(service[c.field!], service) : service[c.field!]
);
expect(renderedColumns.length).toEqual(7);
expect(renderedColumns[2]).toMatchInlineSnapshot(`
<EnvironmentBadge
environments={
Array [
"test",
]
}
/>
`);
expect(renderedColumns[3]).toMatchInlineSnapshot(`"request"`);
expect(renderedColumns[4]).toMatchInlineSnapshot(`
<ServiceListMetric
color="euiColorVis1"
hideSeries={false}
valueLabel="0 ms"
/>
`);
});
});
});
});

describe('without ML data', () => {
Expand Down
Loading