diff --git a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx index 57c5a9041dac2..db500566d3143 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx @@ -7,7 +7,14 @@ */ import './discover_layout.scss'; import React, { ReactElement, useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { EuiPage, EuiPageBody, EuiPanel, useEuiBackgroundColor } from '@elastic/eui'; +import { + EuiPage, + EuiPageBody, + EuiPanel, + EuiProgress, + useEuiBackgroundColor, + EuiDelayRender, +} from '@elastic/eui'; import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import { METRIC_TYPE } from '@kbn/analytics'; @@ -81,7 +88,10 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) { if (uiSettings.get(SHOW_FIELD_STATISTICS) !== true) return VIEW_MODE.DOCUMENT_LEVEL; return state.viewMode ?? VIEW_MODE.DOCUMENT_LEVEL; }); - const dataView = useInternalStateSelector((state) => state.dataView!); + const [dataView, dataViewLoading] = useInternalStateSelector((state) => [ + state.dataView!, + state.isDataViewLoading, + ]); const dataState: DataMainMsg = useDataState(main$); const savedSearch = useSavedSearchInitial(); @@ -293,6 +303,11 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) { height: 100%; `} > + {dataViewLoading && ( + + + + )} { const savedSearch = savedSearchMock; @@ -26,7 +28,14 @@ const setupTestParams = (dataView: DataView | undefined) => { discoverState.internalState.transitions.setDataView(savedSearch.searchSource.getField('index')!); services.dataViews.get = jest.fn(() => Promise.resolve(dataView as DataView)); discoverState.appState.update = jest.fn(); - return { services, appState: discoverState.appState, internalState: discoverState.internalState }; + discoverState.internalState.transitions = { + setIsDataViewLoading: jest.fn(), + } as unknown as Readonly>; + return { + services, + appState: discoverState.appState, + internalState: discoverState.internalState, + }; }; describe('changeDataView', () => { @@ -38,6 +47,8 @@ describe('changeDataView', () => { index: 'data-view-with-user-default-column-id', sort: [['@timestamp', 'desc']], }); + expect(params.internalState.transitions.setIsDataViewLoading).toHaveBeenNthCalledWith(1, true); + expect(params.internalState.transitions.setIsDataViewLoading).toHaveBeenNthCalledWith(2, false); }); it('should set the right app state when a valid data view to switch to is given', async () => { @@ -48,11 +59,15 @@ describe('changeDataView', () => { index: 'data-view-with-various-field-types-id', sort: [['data', 'desc']], }); + expect(params.internalState.transitions.setIsDataViewLoading).toHaveBeenNthCalledWith(1, true); + expect(params.internalState.transitions.setIsDataViewLoading).toHaveBeenNthCalledWith(2, false); }); it('should not set the app state when an invalid data view to switch to is given', async () => { const params = setupTestParams(undefined); await changeDataView('data-view-with-various-field-types', params); expect(params.appState.update).not.toHaveBeenCalled(); + expect(params.internalState.transitions.setIsDataViewLoading).toHaveBeenNthCalledWith(1, true); + expect(params.internalState.transitions.setIsDataViewLoading).toHaveBeenNthCalledWith(2, false); }); }); diff --git a/src/plugins/discover/public/application/main/hooks/utils/change_data_view.ts b/src/plugins/discover/public/application/main/hooks/utils/change_data_view.ts index 7218ea76b2ac6..41a911295cacd 100644 --- a/src/plugins/discover/public/application/main/hooks/utils/change_data_view.ts +++ b/src/plugins/discover/public/application/main/hooks/utils/change_data_view.ts @@ -39,6 +39,7 @@ export async function changeDataView( const dataView = internalState.getState().dataView; const state = appState.getState(); let nextDataView: DataView | null = null; + internalState.transitions.setIsDataViewLoading(true); try { nextDataView = typeof id === 'string' ? await dataViews.get(id, false) : id; @@ -63,4 +64,5 @@ export async function changeDataView( internalState.transitions.setExpandedDoc(undefined); } } + internalState.transitions.setIsDataViewLoading(false); } diff --git a/src/plugins/discover/public/application/main/services/discover_internal_state_container.ts b/src/plugins/discover/public/application/main/services/discover_internal_state_container.ts index ec8d7ec6c57f2..5825e4d2cef6c 100644 --- a/src/plugins/discover/public/application/main/services/discover_internal_state_container.ts +++ b/src/plugins/discover/public/application/main/services/discover_internal_state_container.ts @@ -17,14 +17,16 @@ import type { DataTableRecord } from '@kbn/discover-utils/types'; export interface InternalState { dataView: DataView | undefined; + isDataViewLoading: boolean; savedDataViews: DataViewListItem[]; adHocDataViews: DataView[]; expandedDoc: DataTableRecord | undefined; customFilters: Filter[]; } -interface InternalStateTransitions { +export interface InternalStateTransitions { setDataView: (state: InternalState) => (dataView: DataView) => InternalState; + setIsDataViewLoading: (state: InternalState) => (isLoading: boolean) => InternalState; setSavedDataViews: (state: InternalState) => (dataView: DataViewListItem[]) => InternalState; setAdHocDataViews: (state: InternalState) => (dataViews: DataView[]) => InternalState; appendAdHocDataViews: ( @@ -52,6 +54,7 @@ export function getInternalStateContainer() { return createStateContainer( { dataView: undefined, + isDataViewLoading: false, adHocDataViews: [], savedDataViews: [], expandedDoc: undefined, @@ -62,6 +65,10 @@ export function getInternalStateContainer() { ...prevState, dataView: nextDataView, }), + setIsDataViewLoading: (prevState: InternalState) => (loading: boolean) => ({ + ...prevState, + isDataViewLoading: loading, + }), setSavedDataViews: (prevState: InternalState) => (nextDataViewList: DataViewListItem[]) => ({ ...prevState, savedDataViews: nextDataViewList, diff --git a/src/plugins/discover/public/application/main/utils/fetch_all.test.ts b/src/plugins/discover/public/application/main/utils/fetch_all.test.ts index 744ca9039d8c0..08fae23110972 100644 --- a/src/plugins/discover/public/application/main/utils/fetch_all.test.ts +++ b/src/plugins/discover/public/application/main/utils/fetch_all.test.ts @@ -72,6 +72,7 @@ describe('test fetchAll', () => { getAppState: () => ({}), getInternalState: () => ({ dataView: undefined, + isDataViewLoading: false, savedDataViews: [], adHocDataViews: [], expandedDoc: undefined, @@ -269,6 +270,7 @@ describe('test fetchAll', () => { getAppState: () => ({ query }), getInternalState: () => ({ dataView: undefined, + isDataViewLoading: false, savedDataViews: [], adHocDataViews: [], expandedDoc: undefined, @@ -394,6 +396,7 @@ describe('test fetchAll', () => { getAppState: () => ({ query }), getInternalState: () => ({ dataView: undefined, + isDataViewLoading: false, savedDataViews: [], adHocDataViews: [], expandedDoc: undefined,