handle listing errors gracefully (#66986)

This commit is contained in:
Joe Reuter 2020-05-27 15:18:26 +02:00 committed by GitHub
parent b352f0b8c8
commit 16a51a18f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -37,7 +37,7 @@ import {
EuiCallOut,
EuiBasicTableColumn,
} from '@elastic/eui';
import { ToastsStart } from 'kibana/public';
import { HttpFetchError, ToastsStart } from 'kibana/public';
import { toMountPoint } from '../util';
interface Column {
@ -79,6 +79,7 @@ export interface TableListViewState {
isDeletingItems: boolean;
showDeleteModal: boolean;
showLimitError: boolean;
fetchError?: HttpFetchError;
filter: string;
selectedIds: string[];
totalItems: number;
@ -128,22 +129,33 @@ class TableListView extends React.Component<TableListViewProps, TableListViewSta
}
debouncedFetch = debounce(async (filter: string) => {
const response = await this.props.findItems(filter);
try {
const response = await this.props.findItems(filter);
if (!this._isMounted) {
return;
}
if (!this._isMounted) {
return;
}
// We need this check to handle the case where search results come back in a different
// order than they were sent out. Only load results for the most recent search.
// Also, in case filter is empty, items are being pre-sorted alphabetically.
if (filter === this.state.filter) {
// We need this check to handle the case where search results come back in a different
// order than they were sent out. Only load results for the most recent search.
// Also, in case filter is empty, items are being pre-sorted alphabetically.
if (filter === this.state.filter) {
this.setState({
hasInitialFetchReturned: true,
isFetchingItems: false,
items: !filter ? sortBy(response.hits, 'title') : response.hits,
totalItems: response.total,
showLimitError: response.total > this.props.listingLimit,
});
}
} catch (fetchError) {
this.setState({
hasInitialFetchReturned: true,
isFetchingItems: false,
items: !filter ? sortBy(response.hits, 'title') : response.hits,
totalItems: response.total,
showLimitError: response.total > this.props.listingLimit,
items: [],
totalItems: 0,
showLimitError: false,
fetchError,
});
}
}, 300);
@ -152,6 +164,7 @@ class TableListView extends React.Component<TableListViewProps, TableListViewSta
this.setState(
{
isFetchingItems: true,
fetchError: undefined,
},
this.debouncedFetch.bind(null, this.state.filter)
);
@ -312,6 +325,37 @@ class TableListView extends React.Component<TableListViewProps, TableListViewSta
}
}
renderFetchError() {
if (this.state.fetchError) {
return (
<React.Fragment>
<EuiCallOut
title={
<FormattedMessage
id="kibana-react.tableListView.listing.fetchErrorTitle"
defaultMessage="Fetching listing failed"
/>
}
color="danger"
iconType="alert"
>
<p>
<FormattedMessage
id="kibana-react.tableListView.listing.fetchErrorDescription"
defaultMessage="The {entityName} listing could not be fetched: {message}."
values={{
entityName: this.props.entityName,
message: this.state.fetchError.body?.message || this.state.fetchError.message,
}}
/>
</p>
</EuiCallOut>
<EuiSpacer size="m" />
</React.Fragment>
);
}
}
renderNoItemsMessage() {
if (this.props.noItemsFragment) {
return this.props.noItemsFragment;
@ -431,7 +475,7 @@ class TableListView extends React.Component<TableListViewProps, TableListViewSta
}
renderListingOrEmptyState() {
if (this.hasNoItems()) {
if (!this.state.fetchError && this.hasNoItems()) {
return this.renderNoItemsMessage();
}
@ -475,6 +519,7 @@ class TableListView extends React.Component<TableListViewProps, TableListViewSta
<EuiSpacer size="m" />
{this.renderListingLimitWarning()}
{this.renderFetchError()}
{this.renderTable()}
</div>