From 1b1b6cf504b8d758b45b1b52efad678342a02cc6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cau=C3=AA=20Marcondes?=
<55978943+cauemarcondes@users.noreply.github.com>
Date: Tue, 10 Aug 2021 15:36:50 -0400
Subject: [PATCH] [APM] Fixing service inventory responsive design (#107690)
* fixing service inventory responsive design
* truncate service name
* adding unit test
* addressing PR comments
* fixing test
* fixing merge problem
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
---
.../service_list/ServiceListMetric.tsx | 27 +++-
.../service_inventory/service_list/index.tsx | 83 ++++++----
.../service_list/service_list.test.tsx | 146 ++++++++++++++++--
.../shared/truncate_with_tooltip/index.tsx | 5 +-
.../apm/public/hooks/use_break_points.ts | 2 +
5 files changed, 207 insertions(+), 56 deletions(-)
diff --git a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/ServiceListMetric.tsx b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/ServiceListMetric.tsx
index af2cde7f861cc..7a4721407e69b 100644
--- a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/ServiceListMetric.tsx
+++ b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/ServiceListMetric.tsx
@@ -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';
@@ -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 (
+
+ );
+ }
+
return (
-
+
+
+
+ {valueLabel}
+
+
+
);
}
diff --git a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/index.tsx b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/index.tsx
index 39e65f7eb15d1..f50816809df07 100644
--- a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/index.tsx
@@ -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 {
@@ -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'];
@@ -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,
@@ -67,11 +64,16 @@ export function getServiceColumns({
query,
showTransactionTypeColumn,
comparisonData,
+ breakPoints,
}: {
query: TypeOf['query'];
showTransactionTypeColumn: boolean;
+ breakPoints: BreakPoints;
comparisonData?: ServicesDetailedStatisticsAPIResponse;
}): Array> {
+ const { isSmall, isLarge, isXl } = breakPoints;
+ const showWhenSmallOrGreaterThanLarge = isSmall || !isLarge;
+ const showWhenSmallOrGreaterThanXL = isSmall || !isXl;
return [
{
field: 'healthStatus',
@@ -96,34 +98,38 @@ export function getServiceColumns({
width: '40%',
sortable: true,
render: (_, { serviceName, agentName }) => (
-
-
+
-
-
- ),
- },
- {
- field: 'environments',
- name: i18n.translate('xpack.apm.servicesTable.environmentColumnLabel', {
- defaultMessage: 'Environment',
- }),
- width: `${unit * 10}px`,
- sortable: true,
- render: (_, { environments }) => (
-
+ }
+ />
),
},
- ...(showTransactionTypeColumn
+ ...(showWhenSmallOrGreaterThanLarge
+ ? [
+ {
+ field: 'environments',
+ name: i18n.translate(
+ 'xpack.apm.servicesTable.environmentColumnLabel',
+ {
+ defaultMessage: 'Environment',
+ }
+ ),
+ width: `${unit * 10}px`,
+ sortable: true,
+ render: (_, { environments }) => (
+
+ ),
+ } as ITableColumn,
+ ]
+ : []),
+ ...(showTransactionTypeColumn && showWhenSmallOrGreaterThanXL
? [
{
field: 'transactionType',
@@ -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',
@@ -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',
@@ -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',
},
];
}
@@ -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(
@@ -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
diff --git a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/service_list.test.tsx b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/service_list.test.tsx
index d6cf7bf018d0f..51636e938f8cb 100644
--- a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/service_list.test.tsx
+++ b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/service_list.test.tsx
@@ -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';
@@ -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',
@@ -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(`
-
- `);
+ 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(`
+
+ `);
+ expect(renderedColumns[3]).toMatchInlineSnapshot(`"request"`);
+ expect(renderedColumns[4]).toMatchInlineSnapshot(`
+
+ `);
+ });
+ });
+
+ 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(`
+
+ `);
+ });
+
+ 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(`
+
+ `);
+ expect(renderedColumns[3]).toMatchInlineSnapshot(`
+
+ `);
+ });
+ });
+
+ 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(`
+
+ `);
+ expect(renderedColumns[3]).toMatchInlineSnapshot(`"request"`);
+ expect(renderedColumns[4]).toMatchInlineSnapshot(`
+
+ `);
+ });
+ });
+ });
});
describe('without ML data', () => {
diff --git a/x-pack/plugins/apm/public/components/shared/truncate_with_tooltip/index.tsx b/x-pack/plugins/apm/public/components/shared/truncate_with_tooltip/index.tsx
index d9268c14aa2ea..3b649d77172ee 100644
--- a/x-pack/plugins/apm/public/components/shared/truncate_with_tooltip/index.tsx
+++ b/x-pack/plugins/apm/public/components/shared/truncate_with_tooltip/index.tsx
@@ -27,13 +27,14 @@ const ContentWrapper = euiStyled.div`
interface Props {
text: string;
content?: React.ReactNode;
+ 'data-test-subj'?: string;
}
export function TruncateWithTooltip(props: Props) {
- const { text, content } = props;
+ const { text, content, ...rest } = props;
return (
-
+
;
+
export function getScreenSizes(windowWidth: number) {
return {
isXSmall: isWithinMaxBreakpoint(windowWidth, 'xs'),