diff --git a/common/types/explorer.ts b/common/types/explorer.ts index 5b1e18304..10a84d01c 100644 --- a/common/types/explorer.ts +++ b/common/types/explorer.ts @@ -424,11 +424,11 @@ export interface GridSortingColumn { } export enum DirectQueryLoadingStatus { - SUCCESS = 'SUCCESS', - FAILED = 'FAILED', - RUNNING = 'RUNNING', - SCHEDULED = 'SCHEDULED', - CANCELED = 'CANCELED', + SUCCESS = 'success', + FAILED = 'failed', + RUNNING = 'running', + SCHEDULED = 'scheduled', + CANCELED = 'canceled', } export interface DirectQueryRequest { diff --git a/public/components/common/search/sql_search.tsx b/public/components/common/search/direct_search.tsx similarity index 86% rename from public/components/common/search/sql_search.tsx rename to public/components/common/search/direct_search.tsx index 1d53e6af6..b760ef1fa 100644 --- a/public/components/common/search/sql_search.tsx +++ b/public/components/common/search/direct_search.tsx @@ -28,9 +28,9 @@ import { DirectQueryLoadingStatus, DirectQueryRequest } from '../../../../common import { uiSettingsService } from '../../../../common/utils'; import { getAsyncSessionId, setAsyncSessionId } from '../../../../common/utils/query_session_utils'; import { get as getObjValue } from '../../../../common/utils/shared'; -import { useFetchEvents } from '../../../components/event_analytics/hooks'; -import { changeQuery } from '../../../components/event_analytics/redux/slices/query_slice'; -import { usePolling } from '../../../components/hooks/use_polling'; +import { useFetchEvents } from '../../event_analytics/hooks'; +import { changeQuery } from '../../event_analytics/redux/slices/query_slice'; +import { usePolling } from '../../hooks/use_polling'; import { coreRefs } from '../../../framework/core_refs'; import { SQLService } from '../../../services/requests/sql'; import { SavePanel } from '../../event_analytics/explorer/save_panel'; @@ -38,8 +38,10 @@ import { selectSearchMetaData, update as updateSearchMetaData, } from '../../event_analytics/redux/slices/search_meta_data_slice'; +import { reset as resetResults } from '../../event_analytics/redux/slices/query_result_slice'; import { PPLReferenceFlyout } from '../helpers'; import { Autocomplete } from './autocomplete'; +import { formatError } from '../../event_analytics/utils'; export interface IQueryBarProps { query: string; tempQuery: string; @@ -179,13 +181,33 @@ export const DirectSearch = (props: any) => { ); + const stopPollingWithStatus = (status: DirectQueryLoadingStatus | undefined) => { + stopPolling(); + setIsQueryRunning(false); + dispatch( + updateSearchMetaData({ + tabId, + data: { + isPolling: false, + status, + }, + }) + ); + }; + const onQuerySearch = (lang: string) => { setIsQueryRunning(true); batch(() => { + dispatch(resetResults({ tabId })); // reset results dispatch( changeQuery({ tabId, query: { [RAW_QUERY]: tempQuery.replaceAll(PPL_NEWLINE_REGEX, '') } }) ); - dispatch(updateSearchMetaData({ tabId, data: { isPolling: true, lang } })); + dispatch( + updateSearchMetaData({ + tabId, + data: { isPolling: true, lang, status: DirectQueryLoadingStatus.SCHEDULED }, + }) + ); }); const sessionId = getAsyncSessionId(); const requestPayload = { @@ -212,7 +234,15 @@ export const DirectSearch = (props: any) => { } }) .catch((e) => { - setIsQueryRunning(false); + stopPollingWithStatus(DirectQueryLoadingStatus.FAILED); + const formattedError = formatError( + '', + 'The query failed to execute and the operation could not be complete.', + e.body.message + ); + coreRefs.core?.notifications.toasts.addError(formattedError, { + title: 'Query Failed', + }); console.error(e); }); }; @@ -220,31 +250,32 @@ export const DirectSearch = (props: any) => { useEffect(() => { // cancel direct query if (!pollingResult) return; - const { status, datarows } = pollingResult; + const { status: anyCaseStatus, datarows, error } = pollingResult; + const status = anyCaseStatus?.toLowerCase(); if (status === DirectQueryLoadingStatus.SUCCESS || datarows) { - // stop polling - stopPolling(); - setIsQueryRunning(false); + stopPollingWithStatus(status); + // update page with data + dispatchOnGettingHis(pollingResult, ''); + } else if (status === DirectQueryLoadingStatus.FAILED) { + stopPollingWithStatus(status); + // send in a toast with error message + const formattedError = formatError( + '', + 'The query failed to execute and the operation could not be complete.', + error + ); + coreRefs.core?.notifications.toasts.addError(formattedError, { + title: 'Query Failed', + }); + } else { dispatch( updateSearchMetaData({ tabId, - data: { - isPolling: false, - status: undefined, - }, + data: { status }, }) ); - // update page with data - dispatchOnGettingHis(pollingResult, ''); - return; } - dispatch( - updateSearchMetaData({ - tabId, - data: { status }, - }) - ); }, [pollingResult, pollingError]); useEffect(() => { diff --git a/public/plugin.ts b/public/plugin.ts index aef5db217..8e8419759 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -53,7 +53,7 @@ import { uiSettingsService, } from '../common/utils'; import { Search } from './components/common/search/search'; -import { DirectSearch } from './components/common/search/sql_search'; +import { DirectSearch } from './components/common/search/direct_search'; import { convertLegacyNotebooksUrl } from './components/notebooks/components/helpers/legacy_route_helpers'; import { convertLegacyTraceAnalyticsUrl } from './components/trace_analytics/components/common/legacy_route_helpers'; import { registerAsssitantDependencies } from './dependencies/register_assistant'; diff --git a/server/routes/datasources/datasources_router.ts b/server/routes/datasources/datasources_router.ts index c740c4623..9a1ba396a 100644 --- a/server/routes/datasources/datasources_router.ts +++ b/server/routes/datasources/datasources_router.ts @@ -37,7 +37,7 @@ export function registerDatasourcesRoute(router: IRouter) { console.error('Error in running direct query:', error); return response.custom({ statusCode: error.statusCode || 500, - body: error.message, + body: error.body, }); } }