diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ImpactfulMetrics/JSErrors.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ImpactfulMetrics/JSErrors.tsx
index a7b1d99072d26..c8956c091d267 100644
--- a/x-pack/plugins/apm/public/components/app/RumDashboard/ImpactfulMetrics/JSErrors.tsx
+++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ImpactfulMetrics/JSErrors.tsx
@@ -16,9 +16,10 @@ import {
EuiToolTip,
} from '@elastic/eui';
import numeral from '@elastic/numeral';
+import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
-import { useFetcher } from '../../../../hooks/use_fetcher';
+import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher';
import { I18LABELS } from '../translations';
import { CsmSharedContext } from '../CsmSharedContext';
import { ErrorDetailLink } from '../../../shared/Links/apm/ErrorDetailLink';
@@ -125,14 +126,21 @@ export function JSErrors() {
)
}
description={I18LABELS.totalErrors}
- isLoading={status !== 'success'}
+ isLoading={status === FETCH_STATUS.LOADING}
/>
({
status === FETCH_STATUS.LOADING ? loadingText : noDataText
}
loading={status === FETCH_STATUS.LOADING}
+ error={status === FETCH_STATUS.FAILURE ? errorMessage : ''}
columns={columns}
rowProps={(term) => {
return {
@@ -121,3 +122,8 @@ const noDataText = i18n.translate(
'xpack.apm.correlations.correlationsTable.noDataText',
{ defaultMessage: 'No data' }
);
+
+const errorMessage = i18n.translate(
+ 'xpack.apm.correlations.correlationsTable.errorMessage',
+ { defaultMessage: 'Failed to fetch' }
+);
diff --git a/x-pack/plugins/apm/public/components/app/service_inventory/index.tsx b/x-pack/plugins/apm/public/components/app/service_inventory/index.tsx
index 2cdb808622854..0b505c4f5ade8 100644
--- a/x-pack/plugins/apm/public/components/app/service_inventory/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/service_inventory/index.tsx
@@ -5,7 +5,12 @@
* 2.0.
*/
-import { EuiFlexGroup, EuiFlexItem, EuiLink } from '@elastic/eui';
+import {
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiLink,
+ EuiEmptyPrompt,
+} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React, { useEffect } from 'react';
import uuid from 'uuid';
@@ -20,7 +25,6 @@ import { useTimeRange } from '../../../hooks/use_time_range';
import { useUpgradeAssistantHref } from '../../shared/Links/kibana';
import { SearchBar } from '../../shared/search_bar';
import { getTimeRangeComparison } from '../../shared/time_comparison/get_time_range_comparison';
-import { NoServicesMessage } from './no_services_message';
import { ServiceList } from './service_list';
import { MLCallout } from './service_list/MLCallout';
@@ -179,6 +183,21 @@ export function ServiceInventory() {
canCreateJob &&
!userHasDismissedCallout;
+ const isLoading = mainStatisticsStatus === FETCH_STATUS.LOADING;
+ const isFailure = mainStatisticsStatus === FETCH_STATUS.FAILURE;
+ const noItemsMessage = (
+
+ {i18n.translate('xpack.apm.servicesTable.notFoundLabel', {
+ defaultMessage: 'No services found',
+ })}
+
+ }
+ titleSize="s"
+ />
+ );
+
return (
<>
@@ -190,10 +209,11 @@ export function ServiceInventory() {
)}
}
+ noItemsMessage={noItemsMessage}
/>
diff --git a/x-pack/plugins/apm/public/components/app/service_inventory/no_services_message.test.tsx b/x-pack/plugins/apm/public/components/app/service_inventory/no_services_message.test.tsx
deleted file mode 100644
index 3a3ddcc558679..0000000000000
--- a/x-pack/plugins/apm/public/components/app/service_inventory/no_services_message.test.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
- */
-
-import { render } from '@testing-library/react';
-import React, { ReactNode } from 'react';
-import { MockApmPluginContextWrapper } from '../../../context/apm_plugin/mock_apm_plugin_context';
-import { FETCH_STATUS } from '../../../hooks/use_fetcher';
-import { NoServicesMessage } from './no_services_message';
-
-function Wrapper({ children }: { children?: ReactNode }) {
- return {children};
-}
-
-describe('NoServicesMessage', () => {
- Object.values(FETCH_STATUS).forEach((status) => {
- [true, false].forEach((historicalDataFound) => {
- describe(`when status is ${status}`, () => {
- describe(`when historicalDataFound is ${historicalDataFound}`, () => {
- it('renders', () => {
- expect(() =>
- render(, {
- wrapper: Wrapper,
- })
- ).not.toThrowError();
- });
- });
- });
- });
- });
-});
diff --git a/x-pack/plugins/apm/public/components/app/service_inventory/no_services_message.tsx b/x-pack/plugins/apm/public/components/app/service_inventory/no_services_message.tsx
deleted file mode 100644
index 872359262cf02..0000000000000
--- a/x-pack/plugins/apm/public/components/app/service_inventory/no_services_message.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
- */
-
-import { EuiEmptyPrompt } from '@elastic/eui';
-import { i18n } from '@kbn/i18n';
-import React from 'react';
-import { FETCH_STATUS } from '../../../hooks/use_fetcher';
-import { ErrorStatePrompt } from '../../shared/ErrorStatePrompt';
-
-interface Props {
- status: FETCH_STATUS | undefined;
-}
-
-export function NoServicesMessage({ status }: Props) {
- if (status === FETCH_STATUS.LOADING) {
- return null;
- }
-
- if (status === FETCH_STATUS.FAILURE) {
- return ;
- }
-
- return (
-
- {i18n.translate('xpack.apm.servicesTable.notFoundLabel', {
- defaultMessage: 'No services found',
- })}
-
- }
- titleSize="s"
- />
- );
-}
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 e085c5794f80a..17dfee35e221b 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
@@ -214,6 +214,7 @@ interface Props {
comparisonData?: ServicesDetailedStatisticsAPIResponse;
noItemsMessage?: React.ReactNode;
isLoading: boolean;
+ isFailure?: boolean;
}
export function ServiceList({
@@ -221,6 +222,7 @@ export function ServiceList({
noItemsMessage,
comparisonData,
isLoading,
+ isFailure,
}: Props) {
const breakpoints = useBreakpoints();
const displayHealthStatus = items.some((item) => 'healthStatus' in item);
@@ -296,6 +298,7 @@ export function ServiceList({
-
-
+
- {
- setTableOptions({
- pageIndex: newTableOptions.page?.index ?? 0,
- sort: newTableOptions.sort
- ? {
- field: newTableOptions.sort.field as SortField,
- direction: newTableOptions.sort.direction,
- }
- : DEFAULT_SORT,
- });
- }}
- sorting={{
- enableAllColumns: true,
- sort,
- }}
- />
-
-
+ noItemsMessage={
+ status === FETCH_STATUS.LOADING
+ ? i18n.translate(
+ 'xpack.apm.serviceOverview.errorsTable.loading',
+ { defaultMessage: 'Loading...' }
+ )
+ : i18n.translate(
+ 'xpack.apm.serviceOverview.errorsTable.noResults',
+ { defaultMessage: 'No errors found' }
+ )
+ }
+ columns={columns}
+ items={items}
+ pagination={{
+ pageIndex,
+ pageSize: PAGE_SIZE,
+ totalItemCount: totalItems,
+ pageSizeOptions: [PAGE_SIZE],
+ hidePerPageOptions: true,
+ }}
+ loading={status === FETCH_STATUS.LOADING}
+ onChange={(newTableOptions: {
+ page?: {
+ index: number;
+ };
+ sort?: { field: string; direction: SortDirection };
+ }) => {
+ setTableOptions({
+ pageIndex: newTableOptions.page?.index ?? 0,
+ sort: newTableOptions.sort
+ ? {
+ field: newTableOptions.sort.field as SortField,
+ direction: newTableOptions.sort.direction,
+ }
+ : DEFAULT_SORT,
+ });
+ }}
+ sorting={{
+ enableAllColumns: true,
+ sort,
+ }}
+ />
+
);
diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/index.tsx
index 9312a3c68a1ec..1df6803fdbbb1 100644
--- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/index.tsx
@@ -17,7 +17,6 @@ import { useApmServiceContext } from '../../../../context/apm_service/use_apm_se
import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
import { FETCH_STATUS } from '../../../../hooks/use_fetcher';
import { APIReturnType } from '../../../../services/rest/createCallApmApi';
-import { TableFetchWrapper } from '../../../shared/table_fetch_wrapper';
import {
PAGE_SIZE,
SortDirection,
@@ -156,33 +155,39 @@ export function ServiceOverviewInstancesTable({
-
-
-
-
-
+
+
+
);
diff --git a/x-pack/plugins/apm/public/components/app/trace_overview/index.tsx b/x-pack/plugins/apm/public/components/app/trace_overview/index.tsx
index 5286b821dd23f..63cd27cba41e8 100644
--- a/x-pack/plugins/apm/public/components/app/trace_overview/index.tsx
+++ b/x-pack/plugins/apm/public/components/app/trace_overview/index.tsx
@@ -65,6 +65,7 @@ export function TraceOverview() {
>
);
diff --git a/x-pack/plugins/apm/public/components/app/trace_overview/trace_list.tsx b/x-pack/plugins/apm/public/components/app/trace_overview/trace_list.tsx
index 765a4b1aeae8c..7c4e0ffca1f58 100644
--- a/x-pack/plugins/apm/public/components/app/trace_overview/trace_list.tsx
+++ b/x-pack/plugins/apm/public/components/app/trace_overview/trace_list.tsx
@@ -30,6 +30,7 @@ const StyledTransactionLink = euiStyled(TransactionDetailLink)`
interface Props {
items: TraceGroup[];
isLoading: boolean;
+ isFailure: boolean;
}
const traceListColumns: Array> = [
@@ -124,10 +125,11 @@ const noItemsMessage = (
/>
);
-export function TraceList({ items = [], isLoading }: Props) {
+export function TraceList({ items = [], isLoading, isFailure }: Props) {
return (
-
-
-
-
-
+
+
+
);
diff --git a/x-pack/plugins/apm/public/components/shared/managed_table/__snapshots__/managed_table.test.tsx.snap b/x-pack/plugins/apm/public/components/shared/managed_table/__snapshots__/managed_table.test.tsx.snap
index 1e01c00543949..e4674b3add880 100644
--- a/x-pack/plugins/apm/public/components/shared/managed_table/__snapshots__/managed_table.test.tsx.snap
+++ b/x-pack/plugins/apm/public/components/shared/managed_table/__snapshots__/managed_table.test.tsx.snap
@@ -17,6 +17,7 @@ exports[`ManagedTable should render a page-full of items, with defaults 1`] = `
},
]
}
+ error=""
items={
Array [
Object {
@@ -74,6 +75,7 @@ exports[`ManagedTable should render when specifying initial values 1`] = `
},
]
}
+ error=""
items={
Array [
Object {
diff --git a/x-pack/plugins/apm/public/components/shared/managed_table/index.tsx b/x-pack/plugins/apm/public/components/shared/managed_table/index.tsx
index f7009956bcf84..54f0aebbe818c 100644
--- a/x-pack/plugins/apm/public/components/shared/managed_table/index.tsx
+++ b/x-pack/plugins/apm/public/components/shared/managed_table/index.tsx
@@ -43,6 +43,7 @@ interface Props {
) => T[];
pagination?: boolean;
isLoading?: boolean;
+ error?: boolean;
}
function defaultSortFn(
@@ -68,6 +69,7 @@ function UnoptimizedManagedTable(props: Props) {
sortFn = defaultSortFn,
pagination = true,
isLoading = false,
+ error = false,
} = props;
const {
@@ -138,6 +140,13 @@ function UnoptimizedManagedTable(props: Props) {
return (
>} // EuiBasicTableColumn is stricter than ITableColumn
diff --git a/x-pack/plugins/apm/public/components/shared/table_fetch_wrapper/index.tsx b/x-pack/plugins/apm/public/components/shared/table_fetch_wrapper/index.tsx
deleted file mode 100644
index 8a87ede9b3daa..0000000000000
--- a/x-pack/plugins/apm/public/components/shared/table_fetch_wrapper/index.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
- */
-
-import React, { ReactNode } from 'react';
-import { FETCH_STATUS } from '../../../hooks/use_fetcher';
-import { ErrorStatePrompt } from '../ErrorStatePrompt';
-
-export function TableFetchWrapper({
- status,
- children,
-}: {
- status: FETCH_STATUS;
- children: ReactNode;
-}) {
- if (status === FETCH_STATUS.FAILURE) {
- return ;
- }
-
- return <>{children}>;
-}
diff --git a/x-pack/plugins/apm/public/components/shared/transactions_table/index.tsx b/x-pack/plugins/apm/public/components/shared/transactions_table/index.tsx
index 08fc9e54c1444..60612b581e1d4 100644
--- a/x-pack/plugins/apm/public/components/shared/transactions_table/index.tsx
+++ b/x-pack/plugins/apm/public/components/shared/transactions_table/index.tsx
@@ -23,7 +23,6 @@ import { useApmServiceContext } from '../../../context/apm_service/use_apm_servi
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher';
import { TransactionOverviewLink } from '../Links/apm/transaction_overview_link';
-import { TableFetchWrapper } from '../table_fetch_wrapper';
import { getTimeRangeComparison } from '../time_comparison/get_time_range_comparison';
import { OverviewTableContainer } from '../overview_table_container';
import { getColumns } from './get_columns';
@@ -302,47 +301,52 @@ export function TransactionsTable({
)}
-
-
+
- {
- setTableOptions({
- pageIndex: newTableOptions.page?.index ?? 0,
- sort: newTableOptions.sort
- ? {
- field: newTableOptions.sort.field as SortField,
- direction: newTableOptions.sort.direction,
- }
- : DEFAULT_SORT,
- });
- }}
- />
-
-
+ loading={isLoading}
+ error={
+ status === FETCH_STATUS.FAILURE
+ ? i18n.translate('xpack.apm.transactionsTable.errorMessage', {
+ defaultMessage: 'Failed to fetch',
+ })
+ : ''
+ }
+ items={transactionGroups}
+ columns={columns}
+ pagination={pagination}
+ sorting={{ sort: { field, direction } }}
+ onChange={(newTableOptions: {
+ page?: {
+ index: number;
+ };
+ sort?: { field: string; direction: SortDirection };
+ }) => {
+ setTableOptions({
+ pageIndex: newTableOptions.page?.index ?? 0,
+ sort: newTableOptions.sort
+ ? {
+ field: newTableOptions.sort.field as SortField,
+ direction: newTableOptions.sort.direction,
+ }
+ : DEFAULT_SORT,
+ });
+ }}
+ />
+