[Content management] fix table list flashes table interface when empty (#160650)

Closes https://github.com/elastic/kibana/issues/159507
Closes https://github.com/elastic/kibana/issues/148557

Flaky test runner
https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/2508

### Test instructions
* Install sample web logs data set
* Delete dashboard that ships with sample data set
* switch to another app, like visualize
* Use debugger tools to throttle network connection to "slow 3g"
* Open dashboard application again
* Verify empty table view is never displayed and there is no flickering
between views.

---------

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Nathan Reese 2023-06-29 07:55:16 -06:00 committed by GitHub
parent 2f03a25362
commit 9f73f9479c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 43 additions and 18 deletions

View file

@ -7,7 +7,7 @@
*/
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
import React, { ReactNode, useState } from 'react';
import React, { ReactNode, useCallback, useState } from 'react';
import {
TableListViewTable,
type TableListViewTableProps,
@ -81,6 +81,12 @@ export const TableListView = <T extends UserContentCommonSchema>({
const [hasInitialFetchReturned, setHasInitialFetchReturned] = useState(false);
const [pageDataTestSubject, setPageDataTestSubject] = useState<string>();
const onFetchSuccess = useCallback(() => {
if (!hasInitialFetchReturned) {
setHasInitialFetchReturned(true);
}
}, [hasInitialFetchReturned]);
return (
<PageTemplate panelled data-test-subj={pageDataTestSubject}>
<KibanaPageTemplate.Header
@ -115,11 +121,7 @@ export const TableListView = <T extends UserContentCommonSchema>({
contentEditor={contentEditor}
titleColumnName={titleColumnName}
withoutPageTemplateWrapper={withoutPageTemplateWrapper}
onFetchSuccess={() => {
if (!hasInitialFetchReturned) {
setHasInitialFetchReturned(true);
}
}}
onFetchSuccess={onFetchSuccess}
setPageDataTestSubject={setPageDataTestSubject}
/>
</KibanaPageTemplate.Section>

View file

@ -1197,10 +1197,23 @@ describe('TableList', () => {
}
);
it('refreshes the list when the bouncer changes', async () => {
it('refreshes the list when "refreshListBouncer" changes', async () => {
let testBed: TestBed;
const findItems = jest.fn().mockResolvedValue({ total: 0, hits: [] });
const originalHits: UserContentCommonSchema[] = [
{
id: `item`,
type: 'dashboard',
updatedAt: 'original timestamp',
attributes: {
title: `Original title`,
},
references: [],
},
];
const findItems = jest
.fn()
.mockResolvedValue({ total: originalHits.length, hits: originalHits });
await act(async () => {
testBed = setup({ findItems });
@ -1215,7 +1228,7 @@ describe('TableList', () => {
{
id: `item`,
type: 'dashboard',
updatedAt: 'some date',
updatedAt: 'updated timestamp',
attributes: {
title: `Updated title`,
},

View file

@ -369,7 +369,7 @@ function TableListViewTableComp<T extends UserContentCommonSchema>({
} = state;
const hasQuery = searchQuery.text !== '';
const hasNoItems = !isFetchingItems && items.length === 0 && !hasQuery;
const hasNoItems = hasInitialFetchReturned && items.length === 0 && !hasQuery;
const showFetchError = Boolean(fetchError);
const showLimitError = !showFetchError && totalItems > listingLimit;
@ -411,10 +411,6 @@ function TableListViewTableComp<T extends UserContentCommonSchema>({
}
}, [searchQueryParser, searchQuery.text, findItems, onFetchSuccess]);
useEffect(() => {
fetchItems();
}, [fetchItems, refreshListBouncer]);
const updateQuery = useCallback(
(query: Query) => {
if (urlStateEnabled) {
@ -800,7 +796,17 @@ function TableListViewTableComp<T extends UserContentCommonSchema>({
// ------------
// Effects
// ------------
useDebounce(fetchItems, 300, [fetchItems]);
useDebounce(
() => {
// Do not call fetchItems on dependency changes when initial fetch does not load any items
// to avoid flashing between empty table and no items view
if (!hasNoItems) {
fetchItems();
}
},
300,
[fetchItems, refreshListBouncer]
);
useEffect(() => {
if (!urlStateEnabled) {

View file

@ -148,7 +148,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await listingTable.clickDeleteSelected();
await a11y.testAppSnapshot();
await PageObjects.common.clickConfirmOnModal();
await listingTable.searchForItemWithName('');
await listingTable.isShowingEmptyPromptCreateNewButton();
});
});
}

View file

@ -256,6 +256,10 @@ export class ListingTableService extends FtrService {
await this.testSubjects.click('newItemButton');
}
public async isShowingEmptyPromptCreateNewButton(): Promise<void> {
await this.testSubjects.existOrFail('newItemButton');
}
public async onListingPage(appName: AppName) {
return await this.testSubjects.exists(`${appName}LandingPage`, {
timeout: 5000,

View file

@ -34,8 +34,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
return colorMapping;
}
// Failing: See https://github.com/elastic/kibana/issues/148557
describe.skip('sync colors', function () {
describe('sync colors', function () {
before(async function () {
await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional');
await kibanaServer.importExport.load(