Skip to content

Commit

Permalink
Overview heights and loading states (#83360) (#83508)
Browse files Browse the repository at this point in the history
* Set the chart height to fill the whole container
* Remove the initial loading spinner for the tables and always show the progress bar
* Make the last seen column on the errors table a bit wider so it doesn't wrap
* Make a `ServiceOverviewTable` component that pins the pagination to the bottom of the panel
* Show the loading spinner on charts when doing updates
  • Loading branch information
smith authored Nov 17, 2020
1 parent 7860685 commit c1b42f6
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 50 deletions.
41 changes: 19 additions & 22 deletions x-pack/plugins/apm/public/components/app/service_overview/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import styled from 'styled-components';
import { useTrackPageview } from '../../../../../observability/public';
import { isRumAgentName } from '../../../../common/agent_name';
import { ChartsSyncContextProvider } from '../../../context/charts_sync_context';
Expand All @@ -24,16 +23,11 @@ import { SearchBar } from '../../shared/search_bar';
import { ServiceOverviewErrorsTable } from './service_overview_errors_table';
import { TableLinkFlexItem } from './table_link_flex_item';

const rowHeight = 310;
const latencyChartRowHeight = 230;

const Row = styled(EuiFlexItem)`
height: ${rowHeight}px;
`;

const LatencyChartRow = styled(EuiFlexItem)`
height: ${latencyChartRowHeight}px;
`;
/**
* The height a chart should be if it's next to a table with 5 rows and a title.
* Add the height of the pagination row.
*/
export const chartHeight = 322;

interface ServiceOverviewProps {
agentName?: string;
Expand All @@ -52,7 +46,7 @@ export function ServiceOverview({
<SearchBar />
<EuiPage>
<EuiFlexGroup direction="column" gutterSize="s">
<LatencyChartRow>
<EuiFlexItem>
<EuiPanel>
<EuiTitle size="xs">
<h2>
Expand All @@ -65,8 +59,8 @@ export function ServiceOverview({
</h2>
</EuiTitle>
</EuiPanel>
</LatencyChartRow>
<Row>
</EuiFlexItem>
<EuiFlexItem>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem grow={4}>
<EuiPanel>
Expand Down Expand Up @@ -111,12 +105,15 @@ export function ServiceOverview({
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
</Row>
<Row>
</EuiFlexItem>
<EuiFlexItem>
<EuiFlexGroup gutterSize="s">
{!isRumAgentName(agentName) && (
<EuiFlexItem grow={4}>
<TransactionErrorRateChart showAnnotations={false} />
<TransactionErrorRateChart
height={chartHeight}
showAnnotations={false}
/>
</EuiFlexItem>
)}
<EuiFlexItem grow={6}>
Expand All @@ -125,8 +122,8 @@ export function ServiceOverview({
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
</Row>
<Row>
</EuiFlexItem>
<EuiFlexItem>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem grow={4}>
<EuiPanel>
Expand Down Expand Up @@ -175,8 +172,8 @@ export function ServiceOverview({
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
</Row>
<Row>
</EuiFlexItem>
<EuiFlexItem>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem grow={4}>
<EuiPanel>
Expand Down Expand Up @@ -207,7 +204,7 @@ export function ServiceOverview({
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
</Row>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPage>
</ChartsSyncContextProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,20 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import React, { ReactNode } from 'react';
import { FETCH_STATUS } from '../../../../hooks/useFetcher';
import { ErrorStatePrompt } from '../../../shared/ErrorStatePrompt';
import { LoadingStatePrompt } from '../../../shared/LoadingStatePrompt';

export function FetchWrapper({
hasData,
status,
children,
}: {
hasData: boolean;
status: FETCH_STATUS;
children: React.ReactNode;
children: ReactNode;
}) {
if (status === FETCH_STATUS.FAILURE) {
return <ErrorStatePrompt />;
}

if (!hasData && status !== FETCH_STATUS.SUCCESS) {
return <LoadingStatePrompt />;
}

return <>{children}</>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,27 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import React, { useState } from 'react';
import { EuiTitle } from '@elastic/eui';
import { EuiFlexItem } from '@elastic/eui';
import { EuiFlexGroup } from '@elastic/eui';
import {
EuiBasicTableColumn,
EuiFlexGroup,
EuiFlexItem,
EuiTitle,
EuiToolTip,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { EuiBasicTable } from '@elastic/eui';
import { EuiBasicTableColumn } from '@elastic/eui';
import React, { useState } from 'react';
import styled from 'styled-components';
import { EuiToolTip } from '@elastic/eui';
import { asInteger } from '../../../../../common/utils/formatters';
import { FETCH_STATUS, useFetcher } from '../../../../hooks/useFetcher';
import { useUrlParams } from '../../../../hooks/useUrlParams';
import { ErrorOverviewLink } from '../../../shared/Links/apm/ErrorOverviewLink';
import { TableLinkFlexItem } from '../table_link_flex_item';
import { SparkPlotWithValueLabel } from '../../../shared/charts/spark_plot/spark_plot_with_value_label';
import { callApmApi } from '../../../../services/rest/createCallApmApi';
import { TimestampTooltip } from '../../../shared/TimestampTooltip';
import { ErrorDetailLink } from '../../../shared/Links/apm/ErrorDetailLink';
import { px, truncate, unit } from '../../../../style/variables';
import { SparkPlotWithValueLabel } from '../../../shared/charts/spark_plot/spark_plot_with_value_label';
import { ErrorDetailLink } from '../../../shared/Links/apm/ErrorDetailLink';
import { ErrorOverviewLink } from '../../../shared/Links/apm/ErrorOverviewLink';
import { TimestampTooltip } from '../../../shared/TimestampTooltip';
import { ServiceOverviewTable } from '../service_overview_table';
import { TableLinkFlexItem } from '../table_link_flex_item';
import { FetchWrapper } from './fetch_wrapper';

interface Props {
Expand Down Expand Up @@ -108,7 +110,7 @@ export function ServiceOverviewErrorsTable({ serviceName }: Props) {
render: (_, { last_seen: lastSeen }) => {
return <TimestampTooltip time={lastSeen} timeUnit="minutes" />;
},
width: px(unit * 8),
width: px(unit * 9),
},
{
field: 'occurrences',
Expand Down Expand Up @@ -223,8 +225,8 @@ export function ServiceOverviewErrorsTable({ serviceName }: Props) {
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem>
<FetchWrapper hasData={!!items.length} status={status}>
<EuiBasicTable
<FetchWrapper status={status}>
<ServiceOverviewTable
columns={columns}
items={items}
pagination={{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* 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 { EuiBasicTable, EuiBasicTableProps } from '@elastic/eui';
import React from 'react';
import styled from 'styled-components';

/**
* The height for a table on the overview page. Is the height of a 5-row basic
* table.
*/
const tableHeight = 298;

/**
* A container for the table. Sets height and flex properties on the EUI Basic
* Table contained within and the first child div of that. This makes it so the
* pagination controls always stay fixed at the bottom in the same position.
*
* Hide the empty message when we don't yet have any items and are still loading.
*/
const ServiceOverviewTableContainer = styled.div<{
isEmptyAndLoading: boolean;
}>`
height: ${tableHeight}px;
display: flex;
flex-direction: column;
.euiBasicTable {
display: flex;
flex-direction: column;
flex-grow: 1;
> :first-child {
flex-grow: 1;
}
}
.euiTableRowCell {
visibility: ${({ isEmptyAndLoading }) =>
isEmptyAndLoading ? 'hidden' : 'visible'};
}
`;

export function ServiceOverviewTable<T>(props: EuiBasicTableProps<T>) {
const { items, loading } = props;
const isEmptyAndLoading = !!(items.length === 0 && loading);

return (
<ServiceOverviewTableContainer isEmptyAndLoading={isEmptyAndLoading}>
<EuiBasicTable {...props} />
</ServiceOverviewTableContainer>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { onBrushEnd } from '../helper/helper';
interface Props {
id: string;
fetchStatus: FETCH_STATUS;
height?: number;
onToggleLegend?: LegendItemListener;
timeseries: TimeSeries[];
/**
Expand All @@ -44,10 +45,9 @@ interface Props {
showAnnotations?: boolean;
}

const XY_HEIGHT = unit * 16;

export function LineChart({
id,
height = unit * 16,
fetchStatus,
onToggleLegend,
timeseries,
Expand Down Expand Up @@ -88,7 +88,7 @@ export function LineChart({
);

return (
<ChartContainer status={fetchStatus} hasData={!isEmpty} height={XY_HEIGHT}>
<ChartContainer hasData={!isEmpty} height={height} status={fetchStatus}>
<Chart ref={chartRef} id={id}>
<Settings
onBrushEnd={({ x }) => onBrushEnd({ x, history })}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,14 @@ function yTickFormat(y?: number | null) {
}

interface Props {
height?: number;
showAnnotations?: boolean;
}

export function TransactionErrorRateChart({ showAnnotations = true }: Props) {
export function TransactionErrorRateChart({
height,
showAnnotations = true,
}: Props) {
const theme = useTheme();
const { serviceName } = useParams<{ serviceName?: string }>();
const { urlParams, uiFilters } = useUrlParams();
Expand Down Expand Up @@ -71,6 +75,7 @@ export function TransactionErrorRateChart({ showAnnotations = true }: Props) {
</EuiTitle>
<LineChart
id="errorRate"
height={height}
showAnnotations={showAnnotations}
fetchStatus={status}
timeseries={[
Expand Down

0 comments on commit c1b42f6

Please sign in to comment.