From 9864ef24269866f9837c23ff48b7f4029e36ee99 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Wed, 12 Jun 2024 10:50:04 -0700 Subject: [PATCH] Fix loading state UI for event analytics (#1902) Signed-off-by: Joshua Li --- .../event_analytics/explorer/explorer.tsx | 34 ++--- .../event_analytics/explorer/no_results.tsx | 118 +++++++++--------- .../event_analytics/hooks/use_fetch_events.ts | 4 +- .../data_fetchers/ppl/ppl_data_fetcher.ts | 27 ++-- 4 files changed, 99 insertions(+), 84 deletions(-) diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index c2b57b8d8f..92441f6a6b 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -73,6 +73,7 @@ import { PPL_NEWLINE_REGEX, } from '../../../../common/constants/shared'; import { QueryManager } from '../../../../common/query_manager'; +import { DatasourceType } from '../../../../common/types/data_connections'; import { IExplorerProps, IField, @@ -88,6 +89,10 @@ import { } from '../../../../common/utils'; import { coreRefs } from '../../../framework/core_refs'; import { initialTabId } from '../../../framework/redux/store/shared_state'; +import { + getRenderCreateAccelerationFlyout, + getRenderLogExplorerTablesFlyout, +} from '../../../plugin'; import { PPLDataFetcher } from '../../../services/data_fetchers/ppl/ppl_data_fetcher'; import { getSavedObjectsClient } from '../../../services/saved_objects/saved_object_client/client_factory'; import { OSDSavedSearchClient } from '../../../services/saved_objects/saved_object_client/osd_saved_objects/saved_searches'; @@ -112,8 +117,8 @@ import { import { getVizContainerProps } from '../../visualizations/charts/helpers'; import { TabContext, useFetchEvents, useFetchPatterns, useFetchVisualizations } from '../hooks'; import { - selectCountDistribution, render as updateCountDistribution, + selectCountDistribution, } from '../redux/slices/count_distribution_slice'; import { selectFields, updateFields } from '../redux/slices/field_slice'; import { selectQueryResult } from '../redux/slices/query_result_slice'; @@ -123,11 +128,12 @@ import { selectExplorerVisualization } from '../redux/slices/visualization_slice import { change as changeVisualizationConfig, change as changeVizConfig, - selectVisualizationConfig, change as updateVizConfig, + selectVisualizationConfig, } from '../redux/slices/viualization_config_slice'; import { getDefaultVisConfig } from '../utils'; import { formatError, getContentTabTitle } from '../utils/utils'; +import { AccelerateCallout } from './accelerate_callout'; import { DataSourceSelection } from './datasources/datasources_selection'; import { DirectQueryRunning } from './direct_query_running'; import { DataGrid } from './events_views/data_grid'; @@ -137,12 +143,6 @@ import { ObservabilitySideBar } from './sidebar/observability_sidebar'; import { getTimeRangeFromCountDistribution, HitsCounter, Timechart } from './timechart'; import { ExplorerVisualizations } from './visualizations'; import { DirectQueryVisualization } from './visualizations/direct_query_vis'; -import { - getRenderCreateAccelerationFlyout, - getRenderLogExplorerTablesFlyout, -} from '../../../plugin'; -import { AccelerateCallout } from './accelerate_callout'; -import { DatasourceType } from '../../../../common/types/data_connections'; export const Explorer = ({ pplService, @@ -180,14 +180,11 @@ export const Explorer = ({ pplService, requestParams, }); - const { - isEventsLoading: _isPatternLoading, - getPatterns, - setDefaultPatternsField, - } = useFetchPatterns({ + const { getPatterns, setDefaultPatternsField } = useFetchPatterns({ pplService, requestParams, }); + const [eventsLoading, setEventsLoading] = useState(false); const appLogEvents = tabId.startsWith('application-analytics-tab'); const query = useSelector(selectQueries)[tabId]; @@ -394,7 +391,7 @@ export const Explorer = ({ setSummaryStatus?: boolean ) => { const curQuery: IQuery = queryRef.current!; - new PPLDataFetcher( + await new PPLDataFetcher( { ...curQuery }, { batch, dispatch, changeQuery, changeVizConfig }, { @@ -727,7 +724,11 @@ export const Explorer = ({ ) : ( - + )} ); @@ -742,6 +743,7 @@ export const Explorer = ({ isLiveTailOnRef.current, isQueryRunning, isS3Connection, + eventsLoading, ]); const visualizationSettings = !isEmpty(userVizConfigs[curVisId]) @@ -824,6 +826,7 @@ export const Explorer = ({ }; const handleQuerySearch = async (availability?: boolean, setSummaryStatus?: boolean) => { + setEventsLoading(true); // clear previous selected timestamp when index pattern changes const searchedQuery = tempQueryRef.current; if ( @@ -844,6 +847,7 @@ export const Explorer = ({ await updateQueryInStore(searchedQuery); } await fetchData(undefined, undefined, setSummaryStatus); + setEventsLoading(false); }; const handleQueryChange = async (newQuery: string) => setTempQuery(newQuery); diff --git a/public/components/event_analytics/explorer/no_results.tsx b/public/components/event_analytics/explorer/no_results.tsx index e6aa050b0a..ee5ee5fec4 100644 --- a/public/components/event_analytics/explorer/no_results.tsx +++ b/public/components/event_analytics/explorer/no_results.tsx @@ -20,21 +20,71 @@ import { import { FormattedMessage } from '@osd/i18n/react'; import React from 'react'; import { useSelector } from 'react-redux'; +import { DATA_SOURCE_TYPES, QUERY_LANGUAGE } from '../../../../common/constants/data_sources'; +import { CachedDataSourceStatus, DatasourceType } from '../../../../common/types/data_connections'; +import { CatalogCacheManager } from '../../../framework/catalog_cache/cache_manager'; import { coreRefs } from '../../../framework/core_refs'; +import { getRenderLogExplorerTablesFlyout } from '../../../plugin'; import { selectQueryAssistantSummarization } from '../redux/slices/query_assistant_summarization_slice'; import { selectQueries } from '../redux/slices/query_slice'; import { selectSearchMetaData } from '../redux/slices/search_meta_data_slice'; -import { DATA_SOURCE_TYPES, QUERY_LANGUAGE } from '../../../../common/constants/data_sources'; -import { CatalogCacheManager } from '../../../framework/catalog_cache/cache_manager'; -import { CachedDataSourceStatus, DatasourceType } from '../../../../common/types/data_connections'; -import { getRenderLogExplorerTablesFlyout } from '../../../plugin'; export interface NoResultsProps { tabId: string; dataSourceConnectionType: DatasourceType; + eventsLoading: boolean; } -export const NoResults = ({ tabId, dataSourceConnectionType }: NoResultsProps) => { +const CreatedCodeBlock = ({ code }: { code: string }) => { + return ( + + {code} + + ); +}; + +const LoadingResults: React.FC = () => ( + } body={

Loading results...

} /> +); + +const OpenSearchIndexNoResults = () => { + return ( + + + + } + color="warning" + iconType="help" + data-test-subj="observabilityNoResultsCallout" + /> + + + + +

+ +

+

+ +

+
+
+
+ ); +}; + +export const NoResults = ({ tabId, dataSourceConnectionType, eventsLoading }: NoResultsProps) => { // get the queries isLoaded, if it exists AND is true = show no res const queryInfo = useSelector(selectQueries)[tabId]; const summaryData = useSelector(selectQueryAssistantSummarization)[tabId]; @@ -46,14 +96,6 @@ export const NoResults = ({ tabId, dataSourceConnectionType }: NoResultsProps) = const queryInputted = queryInfo?.rawQuery !== ''; - const CreatedCodeBlock = ({ code }: any) => { - return ( - - {code} - - ); - }; - let arbitraryDatabaseName: string | undefined; let arbitraryTableName: string | undefined; let arbitraryRealQuery: string | undefined; @@ -74,7 +116,7 @@ export const NoResults = ({ tabId, dataSourceConnectionType }: NoResultsProps) = const renderTablesFlyout = getRenderLogExplorerTablesFlyout(); - const S3Callouts = () => { + const renderS3Callouts = () => { return ( {queryInputted && ( @@ -181,53 +223,13 @@ export const NoResults = ({ tabId, dataSourceConnectionType }: NoResultsProps) = ); }; - const OpenSearchIndexNoResults = () => { - return ( - - - - } - color="warning" - iconType="help" - data-test-subj="observabilityNoResultsCallout" - /> - - - - -

- -

-

- -

-
-
-
- ); - }; - return ( {coreRefs.queryAssistEnabled ? ( <> {/* check to see if the rawQuery is empty or not */} - {queryAssistLoading ? ( - } - body={

Loading results...

} - /> + {queryAssistLoading || eventsLoading ? ( + ) : queryInfo?.rawQuery ? ( @@ -273,7 +275,9 @@ export const NoResults = ({ tabId, dataSourceConnectionType }: NoResultsProps) = ) : ( <> {explorerSearchMeta?.datasources[0]?.type === DATA_SOURCE_TYPES.S3Glue ? ( - + renderS3Callouts() + ) : eventsLoading ? ( + ) : ( )} diff --git a/public/components/event_analytics/hooks/use_fetch_events.ts b/public/components/event_analytics/hooks/use_fetch_events.ts index fc25b46fd6..98894bfdc0 100644 --- a/public/components/event_analytics/hooks/use_fetch_events.ts +++ b/public/components/event_analytics/hooks/use_fetch_events.ts @@ -193,7 +193,7 @@ export const useFetchEvents = ({ pplService, requestParams }: IFetchEventsParams ); }; - const getEvents = ( + const getEvents = async ( query: string = '', errorHandler?: (error: any) => void, setSummaryStatus?: boolean @@ -201,7 +201,7 @@ export const useFetchEvents = ({ pplService, requestParams }: IFetchEventsParams if (isEmpty(query)) return; const cur = queriesRef.current; const searchQuery = isEmpty(query) ? cur![requestParams.tabId][FINAL_QUERY] : query; - fetchEvents( + await fetchEvents( { query: searchQuery }, 'jdbc', async (res: any) => { diff --git a/public/services/data_fetchers/ppl/ppl_data_fetcher.ts b/public/services/data_fetchers/ppl/ppl_data_fetcher.ts index 5c21bf780b..fe7b0a4178 100644 --- a/public/services/data_fetchers/ppl/ppl_data_fetcher.ts +++ b/public/services/data_fetchers/ppl/ppl_data_fetcher.ts @@ -4,14 +4,6 @@ */ import isEmpty from 'lodash/isEmpty'; -import { IDefaultTimestampState, IQuery } from '../../../../common/types/explorer'; -import { IDataFetcher } from '../fetch_interface'; -import { DataFetcherBase } from '../fetcher_base'; -import { - buildRawQuery, - composeFinalQuery, - getIndexPatternFromRawQuery, -} from '../../../../common/utils'; import { FILTERED_PATTERN, PATTERNS_REGEX, @@ -23,10 +15,18 @@ import { TAB_CHART_ID, } from '../../../../common/constants/explorer'; import { PPL_STATS_REGEX } from '../../../../common/constants/shared'; +import { IDefaultTimestampState, IQuery } from '../../../../common/types/explorer'; +import { + buildRawQuery, + composeFinalQuery, + getIndexPatternFromRawQuery, +} from '../../../../common/utils'; import { composeFinalQueryWithoutTimestamp, getDescribeQueryIndexFromRawQuery, } from '../../../components/common/query_utils'; +import { DataFetcherBase } from '../fetcher_base'; +import { IDataFetcher } from '../fetch_interface'; export class PPLDataFetcher extends DataFetcherBase implements IDataFetcher { protected queryIndex: string; @@ -132,10 +132,15 @@ export class PPLDataFetcher extends DataFetcherBase implements IDataFetcher { } // get query data + let getDataPromise: Promise; if (isLiveTailOn) { - getLiveTail(finalQuery, getErrorHandler('Error fetching events')); + getDataPromise = getLiveTail(finalQuery, getErrorHandler('Error fetching events')); } else { - getEvents(finalQuery, getErrorHandler('Error fetching events'), setSummaryStatus); + getDataPromise = getEvents( + finalQuery, + getErrorHandler('Error fetching events'), + setSummaryStatus + ); } // still need all fields when query contains stats if (finalQuery.match(PPL_STATS_REGEX)) getAvailableFields(`search source=${this.queryIndex}`); @@ -157,6 +162,8 @@ export class PPLDataFetcher extends DataFetcherBase implements IDataFetcher { }) ); } + // block search call until data retrieval and processing finishes + await getDataPromise; } async setLogPattern(query: IQuery, index: string, _finalQuery: string) {