From 4dc2f7effa38bbe293b9cf1f66480467f9f0c27b Mon Sep 17 00:00:00 2001 From: abbyhu2000 Date: Thu, 29 Aug 2024 01:35:34 +0000 Subject: [PATCH 1/6] directly throw error in fetch Signed-off-by: abbyhu2000 --- .../query_enhancements/common/utils.ts | 12 ++----- .../query_enhancements/server/routes/index.ts | 2 +- .../server/search/ppl_search_strategy.ts | 6 +--- yarn.lock | 31 ++----------------- 4 files changed, 7 insertions(+), 44 deletions(-) diff --git a/src/plugins/query_enhancements/common/utils.ts b/src/plugins/query_enhancements/common/utils.ts index bdb8740e4e48..9c73ab351635 100644 --- a/src/plugins/query_enhancements/common/utils.ts +++ b/src/plugins/query_enhancements/common/utils.ts @@ -125,14 +125,6 @@ export class DataFramePolling { } } -export const handleDataFrameError = (response: any) => { - const df = response.body; - if (df.error) { - const jsError = new Error(df.error.response); - return throwError(jsError); - } -}; - export const fetch = (context: EnhancedFetchContext, query: Query, aggConfig?: QueryAggConfig) => { const { http, path, signal } = context; const body = JSON.stringify({ query: { ...query, format: 'jdbc' }, aggConfig }); @@ -143,7 +135,7 @@ export const fetch = (context: EnhancedFetchContext, query: Query, aggConfig?: Q body, signal, }) - ).pipe(tap(handleDataFrameError)); + ); }; export const fetchDataFrame = (context: EnhancedFetchContext, query: Query, df: IDataFrame) => { @@ -156,7 +148,7 @@ export const fetchDataFrame = (context: EnhancedFetchContext, query: Query, df: body, signal, }) - ).pipe(tap(handleDataFrameError)); + ); }; export const fetchDataFramePolling = (context: EnhancedFetchContext, df: IDataFrame) => { diff --git a/src/plugins/query_enhancements/server/routes/index.ts b/src/plugins/query_enhancements/server/routes/index.ts index a3673946114d..356230b317a9 100644 --- a/src/plugins/query_enhancements/server/routes/index.ts +++ b/src/plugins/query_enhancements/server/routes/index.ts @@ -87,7 +87,7 @@ function defineRoute( } catch (err) { logger.error(err); return res.custom({ - statusCode: 500, + statusCode: err.status ?? 500, body: err, }); } diff --git a/src/plugins/query_enhancements/server/search/ppl_search_strategy.ts b/src/plugins/query_enhancements/server/search/ppl_search_strategy.ts index ae2192d4155f..c6fcc262456d 100644 --- a/src/plugins/query_enhancements/server/search/ppl_search_strategy.ts +++ b/src/plugins/query_enhancements/server/search/ppl_search_strategy.ts @@ -41,11 +41,7 @@ export const pplSearchStrategyProvider = ( const rawResponse: any = await pplFacet.describeQuery(context, request); if (!rawResponse.success) { - return { - type: DATA_FRAME_TYPES.ERROR, - body: { error: rawResponse.data }, - took: rawResponse.took, - } as IDataFrameError; + throw new Error(rawResponse.data.body); } const dataFrame = createDataFrame({ diff --git a/yarn.lock b/yarn.lock index 9e9e097b9339..d19f58a17a00 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15986,7 +15986,7 @@ string-similarity@^4.0.1: resolved "https://registry.yarnpkg.com/string-similarity/-/string-similarity-4.0.4.tgz#42d01ab0b34660ea8a018da8f56a3309bb8b2a5b" integrity sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ== -"string-width-cjs@npm:string-width@^4.2.0": +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -16021,15 +16021,6 @@ string-width@^3.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -16108,7 +16099,7 @@ stringify-entities@^3.0.1: character-entities-legacy "^1.0.0" xtend "^4.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -16150,13 +16141,6 @@ strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -18300,7 +18284,7 @@ workerpool@6.2.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -18326,15 +18310,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" From c4f9dedb0928e0fb12705c1fa2f02802c26cf012 Mon Sep 17 00:00:00 2001 From: abbyhu2000 Date: Thu, 29 Aug 2024 22:07:02 +0000 Subject: [PATCH 2/6] catchign right code Signed-off-by: abbyhu2000 --- src/plugins/data/common/data_frames/types.ts | 5 +++++ .../application/view_components/utils/use_search.ts | 4 +++- .../public/search/ppl_search_interceptor.ts | 9 ++------- src/plugins/query_enhancements/server/routes/index.ts | 6 +++--- .../server/search/ppl_search_strategy.ts | 7 +++++-- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/plugins/data/common/data_frames/types.ts b/src/plugins/data/common/data_frames/types.ts index 978f2817bcf4..10c92e4aded3 100644 --- a/src/plugins/data/common/data_frames/types.ts +++ b/src/plugins/data/common/data_frames/types.ts @@ -105,6 +105,11 @@ export interface IDataFrameResponse extends SearchResponse { took: number; } +export interface IDataFrameResponseError { + status: number; + message: string; +} + export interface IDataFrameError extends IDataFrameResponse { error: Error; } diff --git a/src/plugins/discover/public/application/view_components/utils/use_search.ts b/src/plugins/discover/public/application/view_components/utils/use_search.ts index b6c13d4982f2..e7e72eff3ca5 100644 --- a/src/plugins/discover/public/application/view_components/utils/use_search.ts +++ b/src/plugins/discover/public/application/view_components/utils/use_search.ts @@ -226,7 +226,9 @@ export const useSearch = (services: DiscoverViewServices) => { rows: [], }); - data.search.showError(error as Error); + console.log('error', error.body); + + data.search.showError((error.body || error) as Error); } finally { initalSearchComplete.current = true; } diff --git a/src/plugins/query_enhancements/public/search/ppl_search_interceptor.ts b/src/plugins/query_enhancements/public/search/ppl_search_interceptor.ts index 4618945a35f7..c8a5165cb565 100644 --- a/src/plugins/query_enhancements/public/search/ppl_search_interceptor.ts +++ b/src/plugins/query_enhancements/public/search/ppl_search_interceptor.ts @@ -4,8 +4,7 @@ */ import { trimEnd } from 'lodash'; -import { Observable, throwError } from 'rxjs'; -import { catchError } from 'rxjs/operators'; +import { Observable } from 'rxjs'; import { formatTimePickerDate, Query } from '../../../data/common'; import { DataPublicPluginStart, @@ -52,11 +51,7 @@ export class PPLSearchInterceptor extends SearchInterceptor { const query = this.buildQuery(); - return fetch(context, query, this.getAggConfig(searchRequest, query)).pipe( - catchError((error) => { - return throwError(error); - }) - ); + return fetch(context, query, this.getAggConfig(searchRequest, query)); } public search(request: IOpenSearchDashboardsSearchRequest, options: ISearchOptions) { diff --git a/src/plugins/query_enhancements/server/routes/index.ts b/src/plugins/query_enhancements/server/routes/index.ts index 356230b317a9..60a5bed20496 100644 --- a/src/plugins/query_enhancements/server/routes/index.ts +++ b/src/plugins/query_enhancements/server/routes/index.ts @@ -15,6 +15,7 @@ import { ISearchStrategy } from '../../../data/server'; import { API, SEARCH_STRATEGY } from '../../common'; import { registerQueryAssistRoutes } from './query_assist'; import { registerDataSourceConnectionsRoutes } from './data_source_connection'; +import { instance } from '../../../console/public/application/contexts/editor_context/editor_registry'; /** * Defines a route for a specific search strategy. @@ -85,10 +86,9 @@ function defineRoute( ); return res.ok({ body: { ...queryRes } }); } catch (err) { - logger.error(err); return res.custom({ - statusCode: err.status ?? 500, - body: err, + statusCode: err.name, + body: err.message, }); } } diff --git a/src/plugins/query_enhancements/server/search/ppl_search_strategy.ts b/src/plugins/query_enhancements/server/search/ppl_search_strategy.ts index c6fcc262456d..e8fcbba04040 100644 --- a/src/plugins/query_enhancements/server/search/ppl_search_strategy.ts +++ b/src/plugins/query_enhancements/server/search/ppl_search_strategy.ts @@ -10,6 +10,7 @@ import { DATA_FRAME_TYPES, IDataFrameError, IDataFrameResponse, + IDataFrameResponseError, IDataFrameWithAggs, IOpenSearchDashboardsSearchRequest, Query, @@ -41,7 +42,9 @@ export const pplSearchStrategyProvider = ( const rawResponse: any = await pplFacet.describeQuery(context, request); if (!rawResponse.success) { - throw new Error(rawResponse.data.body); + const error = new Error(rawResponse.data.body); + error.name = rawResponse.data.status; + throw error; } const dataFrame = createDataFrame({ @@ -75,7 +78,7 @@ export const pplSearchStrategyProvider = ( took: rawResponse.took, } as IDataFrameResponse; } catch (e) { - logger.error(`pplSearchStrategy: ${e.message}`); + logger.error(`pplSearchStrategy: ${e}`); if (usage) usage.trackError(); throw e; } From f6006d13b27528aa1172646a24fa11bc0e1be258 Mon Sep 17 00:00:00 2001 From: abbyhu2000 Date: Fri, 30 Aug 2024 16:20:29 +0000 Subject: [PATCH 3/6] error able to show Signed-off-by: abbyhu2000 --- .../language_service/query_result.tsx | 54 +++++++++++++++++++ .../public/ui/query_editor/query_editor.tsx | 4 ++ .../ui/query_editor/query_editor_top_row.tsx | 4 ++ .../ui/search_bar/create_search_bar.tsx | 4 +- .../lib/use_query_string_manager.ts | 15 +++++- .../data/public/ui/search_bar/search_bar.tsx | 4 ++ .../view_components/canvas/top_nav.tsx | 5 +- .../application/view_components/index.ts | 1 + .../view_components/utils/index.tsx | 6 +++ .../view_components/utils/use_search.ts | 7 ++- src/plugins/discover/public/index.ts | 1 + .../public/top_nav_menu/top_nav_menu.tsx | 6 +++ 12 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 src/plugins/data/public/query/query_string/language_service/query_result.tsx create mode 100644 src/plugins/discover/public/application/view_components/utils/index.tsx diff --git a/src/plugins/data/public/query/query_string/language_service/query_result.tsx b/src/plugins/data/public/query/query_string/language_service/query_result.tsx new file mode 100644 index 000000000000..e7c5758c214c --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/query_result.tsx @@ -0,0 +1,54 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import './_recent_query.scss'; + +import { EuiButtonEmpty, EuiPopover, EuiText, EuiContextMenu, EuiPopoverTitle } from '@elastic/eui'; + +import React, { useState } from 'react'; +import { SearchData } from '../../../../../discover/public'; + +export function QueryResult(props: { queryResult: SearchData }) { + console.log('QueryResult', props.queryResult); + const [isPopoverOpen, setPopover] = useState(false); + const onButtonClick = () => { + setPopover(!isPopoverOpen); + }; + + const status = props.queryResult.status; + + if (status === 'ready') { + return ( + {}}> + + {'Complete'} + + + ); + } + + return ( + + + {'Error'} + + + } + isOpen={isPopoverOpen} + closePopover={() => setPopover(false)} + panelPaddingSize="none" + anchorPosition={'downRight'} + > + Error message +
+ + {props.queryResult.errorMsg && props.queryResult.errorMsg.message} + +
+
+ ); +} diff --git a/src/plugins/data/public/ui/query_editor/query_editor.tsx b/src/plugins/data/public/ui/query_editor/query_editor.tsx index 3c9e81b4824d..998e1623d98b 100644 --- a/src/plugins/data/public/ui/query_editor/query_editor.tsx +++ b/src/plugins/data/public/ui/query_editor/query_editor.tsx @@ -29,6 +29,8 @@ import { DatasetSelector } from '../dataset_selector'; import { QueryControls } from '../../query/query_string/language_service/get_query_control_links'; import { RecentQuery } from '../../query/query_string/language_service/recent_query'; import { DefaultInputProps } from './editors'; +import { SearchData } from '../../../../discover/public'; +import { QueryResult } from '../../query/query_string/language_service/query_result'; const LANGUAGE_ID_SQL = 'SQL'; monaco.languages.register({ id: LANGUAGE_ID_SQL }); @@ -59,6 +61,7 @@ export interface QueryEditorProps { filterBar?: any; prepend?: React.ComponentProps['prepend']; savedQueryManagement?: any; + queryResult?: SearchData; } interface Props extends QueryEditorProps { @@ -356,6 +359,7 @@ export default class QueryEditorUI extends Component { {this.props.query.dataset?.timeFieldName || ''} , + , ], end: [ ; savedQueryManagement?: any; + queryResult?: SearchData; } // Needed for React.lazy @@ -186,6 +189,7 @@ export default function QueryEditorTopRow(props: QueryEditorTopRowProps) { dataTestSubj={props.dataTestSubj} filterBar={props.filterBar} savedQueryManagement={props.savedQueryManagement} + queryResult={props.queryResult} /> ); diff --git a/src/plugins/data/public/ui/search_bar/create_search_bar.tsx b/src/plugins/data/public/ui/search_bar/create_search_bar.tsx index b3b240dfa2f1..c8c3bcc419ee 100644 --- a/src/plugins/data/public/ui/search_bar/create_search_bar.tsx +++ b/src/plugins/data/public/ui/search_bar/create_search_bar.tsx @@ -144,8 +144,9 @@ export function createSearchBar({ core, storage, data }: StatefulSearchBarDeps) filters: props.filters, filterManager: data.query.filterManager, }); - const { query } = useQueryStringManager({ + const { query, queryResult } = useQueryStringManager({ queryString: data.query.queryString, + data$: props.data$, }); const { timeRange, refreshInterval } = useTimefilter({ @@ -211,6 +212,7 @@ export function createSearchBar({ core, storage, data }: StatefulSearchBarDeps) datePickerRef={props.datePickerRef} isFilterBarPortable={props.isFilterBarPortable} {...overrideDefaultBehaviors(props)} + queryResult={queryResult} /> ); diff --git a/src/plugins/data/public/ui/search_bar/lib/use_query_string_manager.ts b/src/plugins/data/public/ui/search_bar/lib/use_query_string_manager.ts index 8f9d49f80fef..0ead9815e7cb 100644 --- a/src/plugins/data/public/ui/search_bar/lib/use_query_string_manager.ts +++ b/src/plugins/data/public/ui/search_bar/lib/use_query_string_manager.ts @@ -29,18 +29,21 @@ */ import { useState, useEffect, useCallback } from 'react'; -import { Subscription } from 'rxjs'; +import { BehaviorSubject, Subscription } from 'rxjs'; import { Query } from '../../..'; import { QueryStringContract } from '../../../query/query_string'; +import { SearchData } from '../../../../../discover/public'; interface UseQueryStringProps { query?: Query; queryString: QueryStringContract; + data$?: BehaviorSubject; } export const useQueryStringManager = (props: UseQueryStringProps) => { // Filters should be either what's passed in the initial state or the current state of the filter manager const [query, setQuery] = useState(() => props.query || props.queryString.getQuery()); + const [queryResult, setQueryResult] = useState(undefined); useEffect(() => { const subscriptions = new Subscription(); @@ -60,6 +63,15 @@ export const useQueryStringManager = (props: UseQueryStringProps) => { }; }, [props.queryString]); + useEffect(() => { + if (!props.data$) { + return; + } + const subscription = props.data$.subscribe((d) => { + setQueryResult(d); + }); + }, [props.data$]); + // Use callback to memoize the function const updateQuery = useCallback( (newQueryPartial: Partial) => { @@ -73,5 +85,6 @@ export const useQueryStringManager = (props: UseQueryStringProps) => { return { query, updateQuery, + queryResult, }; }; diff --git a/src/plugins/data/public/ui/search_bar/search_bar.tsx b/src/plugins/data/public/ui/search_bar/search_bar.tsx index bb9a2c7eb28c..bc91368f7d26 100644 --- a/src/plugins/data/public/ui/search_bar/search_bar.tsx +++ b/src/plugins/data/public/ui/search_bar/search_bar.tsx @@ -30,6 +30,7 @@ import { InjectedIntl, injectI18n } from '@osd/i18n/react'; import classNames from 'classnames'; +import { BehaviorSubject } from 'rxjs'; import { compact, get, isEqual } from 'lodash'; import React, { Component } from 'react'; import ResizeObserver from 'resize-observer-polyfill'; @@ -45,6 +46,7 @@ import { QueryEditorTopRow } from '../query_editor'; import QueryBarTopRow from '../query_string_input/query_bar_top_row'; import { SavedQueryMeta, SaveQueryForm } from '../saved_query_form'; import { FilterOptions } from '../filter_bar/filter_options'; +import { SearchData } from '../../../../discover/public'; interface SearchBarInjectedDeps { opensearchDashboards: OpenSearchDashboardsReactContextValue; @@ -92,6 +94,7 @@ export interface SearchBarOwnProps { onRefresh?: (payload: { dateRange: TimeRange }) => void; indicateNoData?: boolean; + queryResult?: SearchData; } export type SearchBarProps = SearchBarOwnProps & SearchBarInjectedDeps; @@ -550,6 +553,7 @@ class SearchBarUI extends Component { indicateNoData={this.props.indicateNoData} datePickerRef={this.props.datePickerRef} savedQueryManagement={searchBarMenu(false, true)} + queryResult={this.props.queryResult} /> ); } diff --git a/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx b/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx index 6cccc06cc0ee..50694c875e25 100644 --- a/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx +++ b/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx @@ -34,7 +34,7 @@ export interface TopNavProps { export const TopNav = ({ opts, showSaveQuery, isEnhancementsEnabled }: TopNavProps) => { const { services } = useOpenSearchDashboards(); - const { inspectorAdapters, savedSearch, indexPattern } = useDiscoverContext(); + const { data$, inspectorAdapters, savedSearch, indexPattern } = useDiscoverContext(); const [indexPatterns, setIndexPatterns] = useState(undefined); const [screenTitle, setScreenTitle] = useState(''); const state = useSelector((s) => s.discover); @@ -124,6 +124,8 @@ export const TopNav = ({ opts, showSaveQuery, isEnhancementsEnabled }: TopNavPro const displayToNavLinkInPortal = isEnhancementsEnabled && !!opts?.optionalRef?.topLinkRef?.current && !showActionsInGroup; + console.log('in discover top nav', data$); + return ( <> {displayToNavLinkInPortal && @@ -160,6 +162,7 @@ export const TopNav = ({ opts, showSaveQuery, isEnhancementsEnabled }: TopNavPro datePickerRef={opts?.optionalRef?.datePickerRef} groupActions={showActionsInGroup} screenTitle={screenTitle} + data$={data$} /> ); diff --git a/src/plugins/discover/public/application/view_components/index.ts b/src/plugins/discover/public/application/view_components/index.ts index 45fd68cf1285..7aff16330f66 100644 --- a/src/plugins/discover/public/application/view_components/index.ts +++ b/src/plugins/discover/public/application/view_components/index.ts @@ -5,3 +5,4 @@ export * from './canvas'; export * from './panel'; +export * from './utils'; diff --git a/src/plugins/discover/public/application/view_components/utils/index.tsx b/src/plugins/discover/public/application/view_components/utils/index.tsx new file mode 100644 index 000000000000..c9dbbb829a3f --- /dev/null +++ b/src/plugins/discover/public/application/view_components/utils/index.tsx @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { SearchData, ResultStatus } from './use_search'; diff --git a/src/plugins/discover/public/application/view_components/utils/use_search.ts b/src/plugins/discover/public/application/view_components/utils/use_search.ts index e7e72eff3ca5..80452ebcecdb 100644 --- a/src/plugins/discover/public/application/view_components/utils/use_search.ts +++ b/src/plugins/discover/public/application/view_components/utils/use_search.ts @@ -39,6 +39,7 @@ export enum ResultStatus { LOADING = 'loading', // initial data load READY = 'ready', // results came back NO_RESULTS = 'none', // no results came back + ERROR = 'error', // error occurred } export interface SearchData { @@ -50,6 +51,7 @@ export interface SearchData { bucketInterval?: TimechartHeaderBucketInterval | {}; chartData?: Chart; title?: string; + errorMsg?: any; } export type SearchRefetch = 'refetch' | undefined; @@ -222,13 +224,14 @@ export const useSearch = (services: DiscoverViewServices) => { if (error instanceof Error && error.name === 'AbortError') return; data$.next({ - status: ResultStatus.NO_RESULTS, + status: ResultStatus.ERROR, rows: [], + errorMsg: error.body || error, }); console.log('error', error.body); - data.search.showError((error.body || error) as Error); + //data.search.showError((error.body || error) as Error); } finally { initalSearchComplete.current = true; } diff --git a/src/plugins/discover/public/index.ts b/src/plugins/discover/public/index.ts index 164aea1fb5bc..54575735a518 100644 --- a/src/plugins/discover/public/index.ts +++ b/src/plugins/discover/public/index.ts @@ -40,3 +40,4 @@ export { SavedSearch, SavedSearchLoader, createSavedSearchesLoader } from './sav export { ISearchEmbeddable, SEARCH_EMBEDDABLE_TYPE, SearchInput } from './embeddable'; export { DISCOVER_APP_URL_GENERATOR, DiscoverUrlGeneratorState } from './url_generator'; +export { SearchData, ResultStatus } from './application/view_components'; diff --git a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx index ffc6656144f8..f327eb6d7c76 100644 --- a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx +++ b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx @@ -31,6 +31,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiHeaderLinks, EuiText } from '@elastic/eui'; import classNames from 'classnames'; import React, { ReactElement, useRef } from 'react'; +import { BehaviorSubject } from 'rxjs'; import { MountPoint } from '../../../../core/public'; import { @@ -42,6 +43,7 @@ import { DataSourceMenuProps, createDataSourceMenu } from '../../../data_source_ import { MountPointPortal } from '../../../opensearch_dashboards_react/public'; import { TopNavMenuData } from './top_nav_menu_data'; import { TopNavMenuItem } from './top_nav_menu_item'; +import { SearchData } from '../../../discover/public'; export enum TopNavMenuItemRenderType { IN_PORTAL = 'in_portal', @@ -82,6 +84,7 @@ export type TopNavMenuProps = Omit & * ``` */ setMenuMountPoint?: (menuMount: MountPoint | undefined) => void; + data$?: BehaviorSubject; }; /* @@ -102,6 +105,7 @@ export function TopNavMenu(props: TopNavMenuProps): ReactElement | null { dataSourceMenuConfig, groupActions, screenTitle, + data$, ...searchBarProps } = props; @@ -152,10 +156,12 @@ export function TopNavMenu(props: TopNavMenuProps): ReactElement | null { // Validate presence of all required fields if (!showSearchBar || !props.data) return null; const { SearchBar } = props.data.ui; + console.log('in top nav menu', props.data$); return ( ); From 4faa593f83cee713796f8e284beee7dab76b9b40 Mon Sep 17 00:00:00 2001 From: abbyhu2000 Date: Fri, 30 Aug 2024 18:51:10 +0000 Subject: [PATCH 4/6] progress Signed-off-by: abbyhu2000 --- src/plugins/data/public/ui/search_bar/search_bar.tsx | 1 + .../public/application/view_components/canvas/top_nav.tsx | 2 -- .../public/application/view_components/utils/use_search.ts | 5 ++++- src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx | 1 - 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/plugins/data/public/ui/search_bar/search_bar.tsx b/src/plugins/data/public/ui/search_bar/search_bar.tsx index bc91368f7d26..c13a18346eb2 100644 --- a/src/plugins/data/public/ui/search_bar/search_bar.tsx +++ b/src/plugins/data/public/ui/search_bar/search_bar.tsx @@ -95,6 +95,7 @@ export interface SearchBarOwnProps { onRefresh?: (payload: { dateRange: TimeRange }) => void; indicateNoData?: boolean; queryResult?: SearchData; + data$?: BehaviorSubject; } export type SearchBarProps = SearchBarOwnProps & SearchBarInjectedDeps; diff --git a/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx b/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx index 50694c875e25..b4ff1f5c57b0 100644 --- a/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx +++ b/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx @@ -124,8 +124,6 @@ export const TopNav = ({ opts, showSaveQuery, isEnhancementsEnabled }: TopNavPro const displayToNavLinkInPortal = isEnhancementsEnabled && !!opts?.optionalRef?.topLinkRef?.current && !showActionsInGroup; - console.log('in discover top nav', data$); - return ( <> {displayToNavLinkInPortal && diff --git a/src/plugins/discover/public/application/view_components/utils/use_search.ts b/src/plugins/discover/public/application/view_components/utils/use_search.ts index 80452ebcecdb..c5ac428c4fb3 100644 --- a/src/plugins/discover/public/application/view_components/utils/use_search.ts +++ b/src/plugins/discover/public/application/view_components/utils/use_search.ts @@ -225,8 +225,11 @@ export const useSearch = (services: DiscoverViewServices) => { data$.next({ status: ResultStatus.ERROR, - rows: [], errorMsg: error.body || error, + title: + indexPattern?.title !== searchSource.getDataFrame()?.name + ? searchSource.getDataFrame()?.name + : indexPattern?.title, }); console.log('error', error.body); diff --git a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx index f327eb6d7c76..9c4a9d33c44a 100644 --- a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx +++ b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx @@ -156,7 +156,6 @@ export function TopNavMenu(props: TopNavMenuProps): ReactElement | null { // Validate presence of all required fields if (!showSearchBar || !props.data) return null; const { SearchBar } = props.data.ui; - console.log('in top nav menu', props.data$); return ( Date: Fri, 30 Aug 2024 19:43:27 +0000 Subject: [PATCH 5/6] change to pass in query result directly Signed-off-by: abbyhu2000 --- .../public/ui/search_bar/create_search_bar.tsx | 5 ++--- .../ui/search_bar/lib/use_query_string_manager.ts | 15 +-------------- .../data/public/ui/search_bar/search_bar.tsx | 1 - .../view_components/canvas/top_nav.tsx | 14 +++++++++++++- .../public/top_nav_menu/top_nav_menu.tsx | 6 +++--- 5 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/plugins/data/public/ui/search_bar/create_search_bar.tsx b/src/plugins/data/public/ui/search_bar/create_search_bar.tsx index c8c3bcc419ee..e786050cbc05 100644 --- a/src/plugins/data/public/ui/search_bar/create_search_bar.tsx +++ b/src/plugins/data/public/ui/search_bar/create_search_bar.tsx @@ -144,9 +144,8 @@ export function createSearchBar({ core, storage, data }: StatefulSearchBarDeps) filters: props.filters, filterManager: data.query.filterManager, }); - const { query, queryResult } = useQueryStringManager({ + const { query } = useQueryStringManager({ queryString: data.query.queryString, - data$: props.data$, }); const { timeRange, refreshInterval } = useTimefilter({ @@ -212,7 +211,7 @@ export function createSearchBar({ core, storage, data }: StatefulSearchBarDeps) datePickerRef={props.datePickerRef} isFilterBarPortable={props.isFilterBarPortable} {...overrideDefaultBehaviors(props)} - queryResult={queryResult} + queryResult={props.queryResult} /> ); diff --git a/src/plugins/data/public/ui/search_bar/lib/use_query_string_manager.ts b/src/plugins/data/public/ui/search_bar/lib/use_query_string_manager.ts index 0ead9815e7cb..8f9d49f80fef 100644 --- a/src/plugins/data/public/ui/search_bar/lib/use_query_string_manager.ts +++ b/src/plugins/data/public/ui/search_bar/lib/use_query_string_manager.ts @@ -29,21 +29,18 @@ */ import { useState, useEffect, useCallback } from 'react'; -import { BehaviorSubject, Subscription } from 'rxjs'; +import { Subscription } from 'rxjs'; import { Query } from '../../..'; import { QueryStringContract } from '../../../query/query_string'; -import { SearchData } from '../../../../../discover/public'; interface UseQueryStringProps { query?: Query; queryString: QueryStringContract; - data$?: BehaviorSubject; } export const useQueryStringManager = (props: UseQueryStringProps) => { // Filters should be either what's passed in the initial state or the current state of the filter manager const [query, setQuery] = useState(() => props.query || props.queryString.getQuery()); - const [queryResult, setQueryResult] = useState(undefined); useEffect(() => { const subscriptions = new Subscription(); @@ -63,15 +60,6 @@ export const useQueryStringManager = (props: UseQueryStringProps) => { }; }, [props.queryString]); - useEffect(() => { - if (!props.data$) { - return; - } - const subscription = props.data$.subscribe((d) => { - setQueryResult(d); - }); - }, [props.data$]); - // Use callback to memoize the function const updateQuery = useCallback( (newQueryPartial: Partial) => { @@ -85,6 +73,5 @@ export const useQueryStringManager = (props: UseQueryStringProps) => { return { query, updateQuery, - queryResult, }; }; diff --git a/src/plugins/data/public/ui/search_bar/search_bar.tsx b/src/plugins/data/public/ui/search_bar/search_bar.tsx index c13a18346eb2..bc91368f7d26 100644 --- a/src/plugins/data/public/ui/search_bar/search_bar.tsx +++ b/src/plugins/data/public/ui/search_bar/search_bar.tsx @@ -95,7 +95,6 @@ export interface SearchBarOwnProps { onRefresh?: (payload: { dateRange: TimeRange }) => void; indicateNoData?: boolean; queryResult?: SearchData; - data$?: BehaviorSubject; } export type SearchBarProps = SearchBarOwnProps & SearchBarInjectedDeps; diff --git a/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx b/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx index b4ff1f5c57b0..939ca3448f08 100644 --- a/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx +++ b/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx @@ -21,6 +21,8 @@ import { useDispatch, setSavedQuery, useSelector } from '../../utils/state_manag import './discover_canvas.scss'; import { TopNavMenuItemRenderType } from '../../../../../navigation/public'; +import { SearchData } from '../utils'; +import { query } from '../../../../../console/server/lib/spec_definitions/js/query/dsl'; export interface TopNavProps { opts: { @@ -37,6 +39,7 @@ export const TopNav = ({ opts, showSaveQuery, isEnhancementsEnabled }: TopNavPro const { data$, inspectorAdapters, savedSearch, indexPattern } = useDiscoverContext(); const [indexPatterns, setIndexPatterns] = useState(undefined); const [screenTitle, setScreenTitle] = useState(''); + const [queryResult, setQueryResult] = useState(undefined); const state = useSelector((s) => s.discover); const dispatch = useDispatch(); @@ -113,6 +116,15 @@ export const TopNav = ({ opts, showSaveQuery, isEnhancementsEnabled }: TopNavPro ); }, [savedSearch?.title]); + useEffect(() => { + if (!data$) { + return; + } + const subscription = data$.subscribe((d) => { + setQueryResult(d); + }); + }, [data$]); + const showDatePicker = useMemo(() => (indexPattern ? indexPattern.isTimeBased() : false), [ indexPattern, ]); @@ -160,7 +172,7 @@ export const TopNav = ({ opts, showSaveQuery, isEnhancementsEnabled }: TopNavPro datePickerRef={opts?.optionalRef?.datePickerRef} groupActions={showActionsInGroup} screenTitle={screenTitle} - data$={data$} + queryResult={queryResult} /> ); diff --git a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx index 9c4a9d33c44a..70247d27e114 100644 --- a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx +++ b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx @@ -84,7 +84,7 @@ export type TopNavMenuProps = Omit & * ``` */ setMenuMountPoint?: (menuMount: MountPoint | undefined) => void; - data$?: BehaviorSubject; + queryResult?: SearchData; }; /* @@ -105,7 +105,7 @@ export function TopNavMenu(props: TopNavMenuProps): ReactElement | null { dataSourceMenuConfig, groupActions, screenTitle, - data$, + queryResult, ...searchBarProps } = props; @@ -160,7 +160,7 @@ export function TopNavMenu(props: TopNavMenuProps): ReactElement | null { ); From 726c11c3a17e3a29b9d3caa676a865b02b69c0d8 Mon Sep 17 00:00:00 2001 From: abbyhu2000 Date: Fri, 30 Aug 2024 20:22:46 +0000 Subject: [PATCH 6/6] pass in query time Signed-off-by: abbyhu2000 --- .../query/query_string/language_service/query_result.tsx | 2 +- .../public/application/view_components/canvas/index.tsx | 3 +++ .../application/view_components/utils/use_search.ts | 8 ++++++++ .../common/adapters/request/request_responder.ts | 4 ++++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/plugins/data/public/query/query_string/language_service/query_result.tsx b/src/plugins/data/public/query/query_string/language_service/query_result.tsx index e7c5758c214c..32a52590b5af 100644 --- a/src/plugins/data/public/query/query_string/language_service/query_result.tsx +++ b/src/plugins/data/public/query/query_string/language_service/query_result.tsx @@ -23,7 +23,7 @@ export function QueryResult(props: { queryResult: SearchData }) { return ( {}}> - {'Complete'} + {'Complete in ' + props.queryResult.queryTime + ' ms'} ); diff --git a/src/plugins/discover/public/application/view_components/canvas/index.tsx b/src/plugins/discover/public/application/view_components/canvas/index.tsx index a44ac89c5d62..2e956d6908e9 100644 --- a/src/plugins/discover/public/application/view_components/canvas/index.tsx +++ b/src/plugins/discover/public/application/view_components/canvas/index.tsx @@ -144,6 +144,9 @@ export default function DiscoverCanvas({ setHeaderActionMenu, history, optionalR {fetchState.status === ResultStatus.NO_RESULTS && ( )} + {fetchState.status === ResultStatus.ERROR && ( + + )} {fetchState.status === ResultStatus.UNINITIALIZED && ( refetch$.next()} /> )} diff --git a/src/plugins/discover/public/application/view_components/utils/use_search.ts b/src/plugins/discover/public/application/view_components/utils/use_search.ts index c5ac428c4fb3..2c8fafdf6639 100644 --- a/src/plugins/discover/public/application/view_components/utils/use_search.ts +++ b/src/plugins/discover/public/application/view_components/utils/use_search.ts @@ -52,6 +52,7 @@ export interface SearchData { chartData?: Chart; title?: string; errorMsg?: any; + queryTime?: number; } export type SearchRefetch = 'refetch' | undefined; @@ -151,6 +152,8 @@ export const useSearch = (services: DiscoverViewServices) => { dataset = searchSource.getField('index'); + let queryTime; + try { // Only show loading indicator if we are fetching when the rows are empty if (fetchStateRef.current.rows?.length === 0) { @@ -182,6 +185,9 @@ export const useSearch = (services: DiscoverViewServices) => { .ok({ json: fetchResp }); const hits = fetchResp.hits.total as number; const rows = fetchResp.hits.hits; + //setQueryTime(inspectorRequest.getTime()); + //console.log('queryTime', queryTime); + queryTime = inspectorRequest.getTime(); let bucketInterval = {}; let chartData; for (const row of rows) { @@ -218,6 +224,7 @@ export const useSearch = (services: DiscoverViewServices) => { indexPattern?.title !== searchSource.getDataFrame()?.name ? searchSource.getDataFrame()?.name : indexPattern?.title, + queryTime, }); } catch (error) { // If the request was aborted then no need to surface this error in the UI @@ -230,6 +237,7 @@ export const useSearch = (services: DiscoverViewServices) => { indexPattern?.title !== searchSource.getDataFrame()?.name ? searchSource.getDataFrame()?.name : indexPattern?.title, + queryTime, }); console.log('error', error.body); diff --git a/src/plugins/inspector/common/adapters/request/request_responder.ts b/src/plugins/inspector/common/adapters/request/request_responder.ts index a65d1b9bc9cd..539257ffaaeb 100644 --- a/src/plugins/inspector/common/adapters/request/request_responder.ts +++ b/src/plugins/inspector/common/adapters/request/request_responder.ts @@ -86,4 +86,8 @@ export class RequestResponder { public error(response: Response): void { this.finish(RequestStatus.ERROR, response); } + + public getTime() { + return this.request.time; + } }