From 473edacaa0dc3e90222dfbec9c2879aaea017a73 Mon Sep 17 00:00:00 2001 From: Joshua Li Date: Tue, 23 Jan 2024 13:16:52 -0800 Subject: [PATCH] (query assist) support option to disable summary (#1376) Signed-off-by: Joshua Li --- common/constants/shared.ts | 2 +- .../common/search/__tests__/search.test.tsx | 4 +- .../search/query_assist_summarization.tsx | 2 +- public/components/common/search/search.tsx | 35 ++------------- .../components/common/search/sql_search.tsx | 4 +- .../explorer/events_views/data_grid.tsx | 13 +++--- .../event_analytics/explorer/explorer.tsx | 20 +++++---- .../event_analytics/explorer/no_results.tsx | 2 +- .../query_assist/__tests__/input.test.tsx | 16 +++++++ .../explorer/query_assist/input.tsx | 43 +++++++++++-------- .../sidebar/__tests__/sidebar.test.tsx | 26 ++++++----- .../explorer/sidebar/field.tsx | 24 +++++------ .../explorer/sidebar/sidebar.tsx | 8 ++-- .../components/event_analytics/home/home.tsx | 6 +-- .../hooks/use_fetch_patterns.ts | 4 +- .../hooks/use_fetch_visualizations.ts | 2 +- .../redux/slices/query_slice.ts | 2 +- .../redux/slices/search_meta_data_slice.ts | 21 +++++---- .../metrics/redux/slices/metrics_slice.ts | 18 ++++---- public/components/metrics/sidebar/sidebar.tsx | 25 ++++++----- public/framework/core_refs.ts | 1 + public/plugin.ts | 4 ++ .../data_fetchers/ppl/ppl_data_fetcher.ts | 2 +- server/index.ts | 25 +++++++++-- server/plugin.ts | 4 +- server/routes/query_assist/routes.ts | 16 ++++--- 26 files changed, 177 insertions(+), 152 deletions(-) diff --git a/common/constants/shared.ts b/common/constants/shared.ts index 0adfeade8..5c947842c 100644 --- a/common/constants/shared.ts +++ b/common/constants/shared.ts @@ -261,4 +261,4 @@ export const DIRECT_DUMMY_QUERY = 'select 1'; export const DEFAULT_START_TIME = 'now-15m'; export const QUERY_ASSIST_START_TIME = 'now-40y'; -export const QUERY_ASSIST_END_TIME = 'now'; \ No newline at end of file +export const QUERY_ASSIST_END_TIME = 'now'; diff --git a/public/components/common/search/__tests__/search.test.tsx b/public/components/common/search/__tests__/search.test.tsx index e80c236b1..dafa7567a 100644 --- a/public/components/common/search/__tests__/search.test.tsx +++ b/public/components/common/search/__tests__/search.test.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { configure, mount, shallow } from 'enzyme'; +import { configure, mount } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import React from 'react'; import { applyMiddleware, createStore } from '@reduxjs/toolkit'; @@ -13,7 +13,7 @@ import { Search } from '../search'; import thunk from 'redux-thunk'; import { initialTabId } from '../../../../framework/redux/store/shared_state'; -describe.only('Explorer Search component', () => { +describe('Explorer Search component', () => { configure({ adapter: new Adapter() }); const store = createStore(rootReducer, applyMiddleware(thunk)); diff --git a/public/components/common/search/query_assist_summarization.tsx b/public/components/common/search/query_assist_summarization.tsx index bb7d92e05..ca35e167d 100644 --- a/public/components/common/search/query_assist_summarization.tsx +++ b/public/components/common/search/query_assist_summarization.tsx @@ -16,8 +16,8 @@ import { EuiSpacer, EuiText, } from '@elastic/eui'; -import chatLogo from '../../datasources/icons/query-assistant-logo.svg'; import React from 'react'; +import chatLogo from '../../datasources/icons/query-assistant-logo.svg'; export function QueryAssistSummarization({ queryAssistantSummarization, diff --git a/public/components/common/search/search.tsx b/public/components/common/search/search.tsx index b2615c664..bc3658f8b 100644 --- a/public/components/common/search/search.tsx +++ b/public/components/common/search/search.tsx @@ -10,7 +10,6 @@ import { EuiButtonEmpty, EuiComboBox, EuiComboBoxOptionOption, - EuiContextMenuItem, EuiContextMenuPanel, EuiFlexGroup, EuiFlexItem, @@ -91,7 +90,6 @@ export const Search = (props: any) => { query, tempQuery, handleQueryChange, - handleQuerySearch, handleTimePickerChange, dslService, startTime, @@ -134,7 +132,7 @@ export const Search = (props: any) => { const dispatch = useDispatch(); const appLogEvents = tabId.match(APP_ANALYTICS_TAB_ID_REGEX); const [isSavePanelOpen, setIsSavePanelOpen] = useState(false); - const [isLanguagePopoverOpen, setLanguagePopoverOpen] = useState(false); + const [_isLanguagePopoverOpen, setLanguagePopoverOpen] = useState(false); const [isFlyoutVisible, setIsFlyoutVisible] = useState(false); const [queryLang, setQueryLang] = useState(QUERY_LANGUAGE.PPL); const [timeRange, setTimeRange] = useState([ @@ -151,9 +149,9 @@ export const Search = (props: any) => { const { data: pollingResult, - loading: pollingLoading, + loading: _pollingLoading, error: pollingError, - startPolling, + startPolling: _startPolling, stopPolling, } = usePolling((params) => { return sqlService.fetchWithJobId(params); @@ -222,10 +220,6 @@ export const Search = (props: any) => { closeLanguagePopover(); }; - const onLanguagePopoverClick = () => { - setLanguagePopoverOpen(!isLanguagePopoverOpen); - }; - const closeLanguagePopover = () => { setLanguagePopoverOpen(false); }; @@ -235,28 +229,7 @@ export const Search = (props: any) => { { value: QUERY_LANGUAGE.DQL, inputDisplay: DQL }, ]; - const languagePopOverItems = [ - handleQueryLanguageChange(QUERY_LANGUAGE.PPL)} - > - PPL - , - handleQueryLanguageChange(QUERY_LANGUAGE.DQL)} - > - DQL - , - ]; - - const languagePopOverButton = ( - - {queryLang} - - ); - - const onQuerySearch = (lang) => { + const onQuerySearch = () => { handleTimeRangePickerRefresh(); }; diff --git a/public/components/common/search/sql_search.tsx b/public/components/common/search/sql_search.tsx index 69e1f2610..a70746364 100644 --- a/public/components/common/search/sql_search.tsx +++ b/public/components/common/search/sql_search.tsx @@ -97,7 +97,7 @@ export const DirectSearch = (props: any) => { const { data: pollingResult, - loading: pollingLoading, + loading: _pollingLoading, error: pollingError, startPolling, stopPolling, @@ -139,7 +139,7 @@ export const DirectSearch = (props: any) => { ); - const handleQueryLanguageChange = (lang: string) => { + const handleQueryLanguageChange = (lang: QUERY_LANGUAGE) => { if (lang === 'DQL') { application!.navigateToUrl('../app/data-explorer/discover'); return; diff --git a/public/components/event_analytics/explorer/events_views/data_grid.tsx b/public/components/event_analytics/explorer/events_views/data_grid.tsx index 43d882c1d..65a99a958 100644 --- a/public/components/event_analytics/explorer/events_views/data_grid.tsx +++ b/public/components/event_analytics/explorer/events_views/data_grid.tsx @@ -3,31 +3,30 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useMemo, useState, useRef, Fragment, useCallback, useEffect } from 'react'; import { EuiDataGrid, + EuiDataGridColumn, + EuiDataGridSorting, EuiDescriptionList, EuiDescriptionListDescription, EuiDescriptionListTitle, - EuiDataGridColumn, - EuiDataGridSorting, EuiPanel, EuiDataGridProps, } from '@elastic/eui'; import moment from 'moment'; -import { MutableRefObject } from 'react'; -import { IExplorerFields, IField } from '../../../../../common/types/explorer'; +import React, { Fragment, MutableRefObject, useEffect, useRef, useState } from 'react'; +import { HttpSetup } from '../../../../../../../src/core/public'; import { DATE_DISPLAY_FORMAT, DEFAULT_EMPTY_EXPLORER_FIELDS, DEFAULT_SOURCE_COLUMN, DEFAULT_TIMESTAMP_COLUMN, } from '../../../../../common/constants/explorer'; -import { HttpSetup } from '../../../../../../../src/core/public'; +import { IExplorerFields, IField } from '../../../../../common/types/explorer'; import PPLService from '../../../../services/requests/ppl'; -import { FlyoutButton } from './docViewRow'; import { useFetchEvents } from '../../hooks'; import { redoQuery } from '../../utils/utils'; +import { FlyoutButton } from './docViewRow'; export interface DataGridProps { http: HttpSetup; diff --git a/public/components/event_analytics/explorer/explorer.tsx b/public/components/event_analytics/explorer/explorer.tsx index fcb84df1e..ae16b6b6b 100644 --- a/public/components/event_analytics/explorer/explorer.tsx +++ b/public/components/event_analytics/explorer/explorer.tsx @@ -78,6 +78,7 @@ import { getSavingCommonParams, uiSettingsService, } from '../../../../common/utils'; +import { coreRefs } from '../../../framework/core_refs'; import { initialTabId } from '../../../framework/redux/store/shared_state'; import { PPLDataFetcher } from '../../../services/data_fetchers/ppl/ppl_data_fetcher'; import { getSavedObjectsClient } from '../../../services/saved_objects/saved_object_client/client_factory'; @@ -115,7 +116,7 @@ import { change as updateVizConfig, } from '../redux/slices/viualization_config_slice'; import { getDefaultVisConfig } from '../utils'; -import { getContentTabTitle, getDateRange } from '../utils/utils'; +import { formatError, getContentTabTitle, getDateRange } from '../utils/utils'; import { DataSourceSelection } from './datasources/datasources_selection'; import { DirectQueryRunning } from './direct_query_running'; import { DataGrid } from './events_views/data_grid'; @@ -161,7 +162,7 @@ export const Explorer = ({ requestParams, }); const { - isEventsLoading: isPatternLoading, + isEventsLoading: _isPatternLoading, getPatterns, setDefaultPatternsField, } = useFetchPatterns({ @@ -181,7 +182,7 @@ export const Explorer = ({ const [selectedCustomPanelOptions, setSelectedCustomPanelOptions] = useState([]); const [selectedPanelName, setSelectedPanelName] = useState(''); const [curVisId, setCurVisId] = useState('bar'); - const [isPanelTextFieldInvalid, setIsPanelTextFieldInvalid] = useState(false); + const [isPanelTextFieldInvalid, _setIsPanelTextFieldInvalid] = useState(false); const [timeIntervalOptions, setTimeIntervalOptions] = useState(TIME_INTERVAL_OPTIONS); const [isOverridingTimestamp, setIsOverridingTimestamp] = useState(false); const [tempQuery, setTempQuery] = useState(query[RAW_QUERY]); @@ -214,8 +215,8 @@ export const Explorer = ({ value: string; }>(); const [subType, setSubType] = useState('visualization'); - const [metricMeasure, setMetricMeasure] = useState(''); - const [metricChecked, setMetricChecked] = useState(false); + const [_metricMeasure, setMetricMeasure] = useState(''); + const [_metricChecked, setMetricChecked] = useState(false); const queryRef = useRef(); const appBasedRef = useRef(''); appBasedRef.current = appBaseQuery; @@ -273,10 +274,11 @@ export const Explorer = ({ const getErrorHandler = (title: string) => { return (error: any) => { - // const formattedError = formatError(error.name, error.message, error.body.message); - // notifications.toasts.addError(formattedError, { - // title, - // }); + if (coreRefs.summarizeEnabled) return; + const formattedError = formatError(error.name, error.message, error.body.message); + notifications.toasts.addError(formattedError, { + title, + }); }; }; diff --git a/public/components/event_analytics/explorer/no_results.tsx b/public/components/event_analytics/explorer/no_results.tsx index 489a72ace..c4ce3a9b0 100644 --- a/public/components/event_analytics/explorer/no_results.tsx +++ b/public/components/event_analytics/explorer/no_results.tsx @@ -14,8 +14,8 @@ import { EuiText, EuiEmptyPrompt, } from '@elastic/eui'; -import { coreRefs } from '../../../framework/core_refs'; import { useSelector } from 'react-redux'; +import { coreRefs } from '../../../framework/core_refs'; import { selectQueries } from '../redux/slices/query_slice'; export const NoResults = ({ tabId }: any) => { diff --git a/public/components/event_analytics/explorer/query_assist/__tests__/input.test.tsx b/public/components/event_analytics/explorer/query_assist/__tests__/input.test.tsx index f6a9dd02d..7ced9cd28 100644 --- a/public/components/event_analytics/explorer/query_assist/__tests__/input.test.tsx +++ b/public/components/event_analytics/explorer/query_assist/__tests__/input.test.tsx @@ -85,7 +85,23 @@ describe(' spec', () => { ); }); + it('should not call summarize if disabled', async () => { + coreRefs.summarizeEnabled = false; + httpMock.post.mockRejectedValueOnce({ body: { statusCode: 429 } }); + + const { component } = renderQueryAssistInput(); + await waitFor(() => { + fireEvent.click(component.getByTestId('query-assist-generate-and-run-button')); + }); + + expect(httpMock.post).toBeCalledWith(QUERY_ASSIST_API.GENERATE_PPL, { + body: '{"question":"test-input","index":"selected-test-index"}', + }); + expect(httpMock.post).not.toBeCalledWith(QUERY_ASSIST_API.SUMMARIZE, expect.anything()); + }); + it('should call summarize for generate and run errors', async () => { + coreRefs.summarizeEnabled = true; httpMock.post.mockRejectedValueOnce({ body: { statusCode: 429 } }).mockResolvedValueOnce({ summary: 'too many requests', suggestedQuestions: ['1', '2'], diff --git a/public/components/event_analytics/explorer/query_assist/input.tsx b/public/components/event_analytics/explorer/query_assist/input.tsx index 58008819d..2a41afdee 100644 --- a/public/components/event_analytics/explorer/query_assist/input.tsx +++ b/public/components/event_analytics/explorer/query_assist/input.tsx @@ -23,6 +23,7 @@ import { ResponseError } from '@opensearch-project/opensearch/lib/errors'; import React, { useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { RAW_QUERY } from '../../../../../common/constants/explorer'; +import { QUERY_ASSIST_API } from '../../../../../common/constants/query_assist'; import { getOSDHttp } from '../../../../../common/utils'; import { coreRefs } from '../../../../framework/core_refs'; import chatLogo from '../../../datasources/icons/query-assistant-logo.svg'; @@ -34,7 +35,6 @@ import { } from '../../redux/slices/query_assistant_summarization_slice'; import { reset, selectQueryResult } from '../../redux/slices/query_result_slice'; import { changeQuery, selectQueries } from '../../redux/slices/query_slice'; -import { QUERY_ASSIST_API } from '../../../../../common/constants/query_assist'; interface SummarizationContext { question: string; @@ -87,21 +87,23 @@ export const QueryAssistInput: React.FC = (props) => { useEffect(() => { if ( - summaryData.responseForSummaryStatus === 'success' || - summaryData.responseForSummaryStatus === 'failure' - ) { - void (async () => { - await dispatch( - changeSummary({ - tabId: props.tabId, - data: { - summaryLoading: false, - }, - }) - ); - if (explorerData.total > 0) generateSummary(); - })(); - } + props.nlqInput.trim().length === 0 || + (summaryData.responseForSummaryStatus !== 'success' && + summaryData.responseForSummaryStatus !== 'failure') + ) + return; + void (async () => { + await dispatch( + changeSummary({ + tabId: props.tabId, + data: { + summaryLoading: false, + }, + }) + ); + if (explorerData.total > 0 || summaryData.responseForSummaryStatus === 'failure') + generateSummary(); + })(); }, [summaryData.responseForSummaryStatus]); const [barSelected, setBarSelected] = useState(false); @@ -173,6 +175,7 @@ export const QueryAssistInput: React.FC = (props) => { } }; const generateSummary = async (context?: Partial) => { + if (!coreRefs.summarizeEnabled) return; try { const isError = summaryData.responseForSummaryStatus === 'failure'; const summarizationContext: SummarizationContext = { @@ -333,7 +336,9 @@ export const QueryAssistInput: React.FC = (props) => { = (props) => { ({ ...jest.requireActual('react-redux'), @@ -67,7 +65,7 @@ describe('Siderbar component', () => { query={''} selectedPattern={''} isOverridingPattern={false} - handleOverridePattern={function (pattern: IField): void { + handleOverridePattern={function (): void { throw new Error('Function not implemented.'); }} tabId={initialTabId} @@ -110,7 +108,7 @@ describe('Siderbar component', () => { query={''} selectedPattern={''} isOverridingPattern={false} - handleOverridePattern={function (pattern: IField): void { + handleOverridePattern={function (): void { throw new Error('Function not implemented.'); }} /> diff --git a/public/components/event_analytics/explorer/sidebar/field.tsx b/public/components/event_analytics/explorer/sidebar/field.tsx index bae0e3d4a..2c08f0844 100644 --- a/public/components/event_analytics/explorer/sidebar/field.tsx +++ b/public/components/event_analytics/explorer/sidebar/field.tsx @@ -3,28 +3,26 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useState, useEffect } from 'react'; -import { i18n } from '@osd/i18n'; -import { isEqual, toUpper, upperFirst } from 'lodash'; import { - EuiPopover, + EuiBadge, EuiButtonIcon, - EuiToolTip, - EuiMark, - EuiLoadingSpinner, EuiFlexGroup, EuiFlexItem, - EuiTitle, + EuiLoadingSpinner, + EuiPopover, EuiText, - EuiBadge, + EuiTitle, + EuiToolTip, } from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import { isEqual, toUpper, upperFirst } from 'lodash'; +import React, { useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; -import { FieldButton } from '../../../common/field_button'; -import { FieldIcon } from '../../../common/field_icon'; -import { IField } from '../../../../../common/types/explorer'; -import { FieldInsights } from './field_insights'; import { DEFAULT_DATA_SOURCE_TYPE } from '../../../../../common/constants/data_sources'; +import { IField } from '../../../../../common/types/explorer'; +import { FieldIcon } from '../../../common/field_icon'; import { selectSearchMetaData } from '../../../event_analytics/redux/slices/search_meta_data_slice'; +import { FieldInsights } from './field_insights'; interface IFieldProps { query: string; diff --git a/public/components/event_analytics/explorer/sidebar/sidebar.tsx b/public/components/event_analytics/explorer/sidebar/sidebar.tsx index be7413250..d0eb9b353 100644 --- a/public/components/event_analytics/explorer/sidebar/sidebar.tsx +++ b/public/components/event_analytics/explorer/sidebar/sidebar.tsx @@ -8,13 +8,13 @@ import { EuiDraggable, EuiDroppable, EuiFieldSearch, - EuiTitle, - EuiSplitPanel, EuiPanel, + EuiSplitPanel, + EuiTitle, } from '@elastic/eui'; import { FormattedMessage, I18nProvider } from '@osd/i18n/react'; import { isEmpty } from 'lodash'; -import React, { useCallback, useEffect, useState } from 'react'; +import React, { useCallback, useState } from 'react'; import { batch, useDispatch } from 'react-redux'; import { AVAILABLE_FIELDS, SELECTED_FIELDS } from '../../../../../common/constants/explorer'; import { ExplorerFields, IExplorerFields, IField } from '../../../../../common/types/explorer'; @@ -50,7 +50,7 @@ export const Sidebar = (props: ISidebarProps) => { tabId, } = props; const dispatch = useDispatch(); - const [showFields, setShowFields] = useState(false); + const [showFields, _setShowFields] = useState(false); const [searchTerm, setSearchTerm] = useState(''); // method to return the type of a field from its name diff --git a/public/components/event_analytics/home/home.tsx b/public/components/event_analytics/home/home.tsx index d19512d0f..5c7ed46e5 100644 --- a/public/components/event_analytics/home/home.tsx +++ b/public/components/event_analytics/home/home.tsx @@ -25,7 +25,7 @@ import { EuiTitle, } from '@elastic/eui'; import React, { ReactElement, useEffect, useRef, useState } from 'react'; -import { connect, useDispatch } from 'react-redux'; +import { connect } from 'react-redux'; import { useHistory } from 'react-router-dom'; import { HttpStart } from '../../../../../../src/core/public'; import { CUSTOM_PANELS_API_PREFIX } from '../../../../common/constants/custom_panels'; @@ -70,9 +70,7 @@ interface IHomeProps { const EventAnalyticsHome = (props: IHomeProps) => { const { setToast, http } = props; const history = useHistory(); - const dispatch = useDispatch(); - const [searchQuery, setSearchQuery] = useState(''); - const [selectedDateRange, setSelectedDateRange] = useState(['now-40y', 'now']); + const [selectedDateRange, _setSelectedDateRange] = useState(['now-40y', 'now']); const [savedHistories, setSavedHistories] = useState([]); const [selectedHistories, setSelectedHistories] = useState([]); const [isActionsPopoverOpen, setIsActionsPopoverOpen] = useState(false); diff --git a/public/components/event_analytics/hooks/use_fetch_patterns.ts b/public/components/event_analytics/hooks/use_fetch_patterns.ts index 7a23aa317..90561ae08 100644 --- a/public/components/event_analytics/hooks/use_fetch_patterns.ts +++ b/public/components/event_analytics/hooks/use_fetch_patterns.ts @@ -125,7 +125,7 @@ export const useFetchPatterns = ({ pplService, requestParams }: IFetchPatternsPa })); dispatchOnPatterns({ patternTableData: formatToTableData }); }) - .catch((error) => { + .catch(() => { dispatch( resetPatterns({ tabId: requestParams.tabId, @@ -150,7 +150,7 @@ export const useFetchPatterns = ({ pplService, requestParams }: IFetchPatternsPa // Loop through array and find field with longest value let defaultPatternField = ''; let maxLength = 0; - textFields.forEach((field: IField, i: number) => { + textFields.forEach((field: IField) => { const curLength = res.jsonData[0][field.name].length; if (curLength > maxLength) { maxLength = curLength; diff --git a/public/components/event_analytics/hooks/use_fetch_visualizations.ts b/public/components/event_analytics/hooks/use_fetch_visualizations.ts index 0dcd94cf8..c124206b7 100644 --- a/public/components/event_analytics/hooks/use_fetch_visualizations.ts +++ b/public/components/event_analytics/hooks/use_fetch_visualizations.ts @@ -82,7 +82,7 @@ export const useFetchVisualizations = ({ }) ); }, - (error: Error) => { + () => { dispatch( resetCountDis({ tabId: requestParams.tabId, diff --git a/public/components/event_analytics/redux/slices/query_slice.ts b/public/components/event_analytics/redux/slices/query_slice.ts index bdbbaea60..5999cf7e6 100644 --- a/public/components/event_analytics/redux/slices/query_slice.ts +++ b/public/components/event_analytics/redux/slices/query_slice.ts @@ -79,7 +79,7 @@ export const queriesSlice = createSlice({ }; }, }, - extraReducers: (builder) => {}, + extraReducers: () => {}, }); export const { changeQuery, changeData, remove, init, reset } = queriesSlice.actions; diff --git a/public/components/event_analytics/redux/slices/search_meta_data_slice.ts b/public/components/event_analytics/redux/slices/search_meta_data_slice.ts index 1f7ed6ef8..96280b943 100644 --- a/public/components/event_analytics/redux/slices/search_meta_data_slice.ts +++ b/public/components/event_analytics/redux/slices/search_meta_data_slice.ts @@ -3,20 +3,25 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { PayloadAction, createSelector, createSlice } from '@reduxjs/toolkit'; +import { createSelector, createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { + DEFAULT_DATA_SOURCE_NAME, + DEFAULT_DATA_SOURCE_TYPE, +} from '../../../../../common/constants/data_sources'; import { REDUX_EXPL_SLICE_SEARCH_META_DATA } from '../../../../../common/constants/explorer'; import { DirectQueryLoadingStatus, SelectedDataSource } from '../../../../../common/types/explorer'; import { initialTabId } from '../../../../framework/redux/store/shared_state'; -import { DEFAULT_DATA_SOURCE_NAME, DEFAULT_DATA_SOURCE_TYPE } from '../../../../../common/constants/data_sources'; const searchMetaInitialState = { lang: 'PPL', - datasources: [{ - "label": DEFAULT_DATA_SOURCE_NAME, - "value": DEFAULT_DATA_SOURCE_NAME, - "type": DEFAULT_DATA_SOURCE_TYPE, - "name": DEFAULT_DATA_SOURCE_NAME - }], + datasources: [ + { + label: DEFAULT_DATA_SOURCE_NAME, + value: DEFAULT_DATA_SOURCE_NAME, + type: DEFAULT_DATA_SOURCE_TYPE, + name: DEFAULT_DATA_SOURCE_NAME, + }, + ], queryId: '', isPolling: false, }; diff --git a/public/components/metrics/redux/slices/metrics_slice.ts b/public/components/metrics/redux/slices/metrics_slice.ts index acb68479c..cda917916 100644 --- a/public/components/metrics/redux/slices/metrics_slice.ts +++ b/public/components/metrics/redux/slices/metrics_slice.ts @@ -3,32 +3,34 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { ouiPaletteColorBlindBehindText } from '@elastic/eui'; import { createSlice } from '@reduxjs/toolkit'; import { keyBy, mergeWith, pick, sortBy } from 'lodash'; -import { ouiPaletteColorBlindBehindText } from '@elastic/eui'; import { OBSERVABILITY_CUSTOM_METRIC, PPL_DATASOURCES_REQUEST, REDUX_SLICE_METRICS, SAVED_VISUALIZATION, } from '../../../../../common/constants/metrics'; -import { MetricType } from '../../../../../common/types/metrics'; -import { SavedObjectsActions } from '../../../../services/saved_objects/saved_object_client/saved_objects_actions'; -import { ObservabilitySavedVisualization } from '../../../../services/saved_objects/saved_object_client/types'; -import { pplServiceRequestor } from '../../helpers/utils'; -import { coreRefs } from '../../../../framework/core_refs'; import { + OBSERVABILITY_BASE, PPL_METRIC_SUBTYPE, PROMQL_METRIC_SUBTYPE, - OBSERVABILITY_BASE, } from '../../../../../common/constants/shared'; +import { MetricType } from '../../../../../common/types/metrics'; import { getOSDHttp, getPPLService } from '../../../../../common/utils'; +import { coreRefs } from '../../../../framework/core_refs'; +import { SavedObjectsActions } from '../../../../services/saved_objects/saved_object_client/saved_objects_actions'; +import { ObservabilitySavedVisualization } from '../../../../services/saved_objects/saved_object_client/types'; +import { pplServiceRequestor } from '../../helpers/utils'; export interface IconAttributes { color: string; } -const coloredIconsFrom = (dataSources: string[]): { [dataSource: string]: IconAttributes } => { +export const coloredIconsFrom = ( + dataSources: string[] +): { [dataSource: string]: IconAttributes } => { const colorCycle = ouiPaletteColorBlindBehindText({ sortBy: 'natural' }); const keyedIcons = dataSources.map((dataSource, index) => { return [ diff --git a/public/components/metrics/sidebar/sidebar.tsx b/public/components/metrics/sidebar/sidebar.tsx index 1a0adffa0..f0bfdfde6 100644 --- a/public/components/metrics/sidebar/sidebar.tsx +++ b/public/components/metrics/sidebar/sidebar.tsx @@ -3,36 +3,35 @@ * SPDX-License-Identifier: Apache-2.0 */ -import './sidebar.scss'; - -import React, { useEffect, useRef, useState, useMemo } from 'react'; import { EuiSpacer } from '@elastic/eui'; import { I18nProvider } from '@osd/i18n/react'; -import { batch, useDispatch, useSelector } from 'react-redux'; import { keyBy, sortBy } from 'lodash'; +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { batch, useDispatch, useSelector } from 'react-redux'; +import { OTEL_METRIC_SUBTYPE, PPL_METRIC_SUBTYPE } from '../../../../common/constants/shared'; +import { OptionType } from '../../../../common/types/metrics'; import { addSelectedMetric, availableMetricsSelector, clearSelectedMetrics, + coloredIconsFrom, + fetchOpenTelemetryDocumentNames, loadMetrics, + loadOTIndices, + mergeMetrics, + otelIndexSelector, removeSelectedMetric, selectedMetricsIdsSelector, selectedMetricsSelector, selectMetricByIdSelector, - otelIndexSelector, setDataSourceIcons, - coloredIconsFrom, - loadOTIndices, - fetchOpenTelemetryDocumentNames, - mergeMetrics, setSortedIds, } from '../redux/slices/metrics_slice'; -import { MetricsAccordion } from './metrics_accordion'; -import { SearchBar } from './search_bar'; import { DataSourcePicker } from './data_source_picker'; import { IndexPicker } from './index_picker'; -import { OptionType } from '../../../../common/types/metrics'; -import { OTEL_METRIC_SUBTYPE, PPL_METRIC_SUBTYPE } from '../../../../common/constants/shared'; +import { MetricsAccordion } from './metrics_accordion'; +import { SearchBar } from './search_bar'; +import './sidebar.scss'; interface SideBarMenuProps { selectedDataSource: OptionType[]; diff --git a/public/framework/core_refs.ts b/public/framework/core_refs.ts index 2ffef8488..4849d85f1 100644 --- a/public/framework/core_refs.ts +++ b/public/framework/core_refs.ts @@ -25,6 +25,7 @@ class CoreRefs { public chrome?: ChromeStart; public application?: ApplicationStart; public queryAssistEnabled?: boolean; + public summarizeEnabled?: boolean; public dashboard?: DashboardStart; public dashboardProviders?: unknown; private constructor() { diff --git a/public/plugin.ts b/public/plugin.ts index 339b8bb83..aef5db217 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -84,6 +84,9 @@ interface PublicConfig { query_assist: { enabled: boolean; }; + summarize: { + enabled: boolean; + }; } export class ObservabilityPlugin @@ -336,6 +339,7 @@ export class ObservabilityPlugin coreRefs.application = core.application; coreRefs.dashboard = startDeps.dashboard; coreRefs.queryAssistEnabled = this.config.query_assist.enabled; + coreRefs.summarizeEnabled = this.config.summarize.enabled; const { dataSourceService, dataSourceFactory } = startDeps.data.dataSources; diff --git a/public/services/data_fetchers/ppl/ppl_data_fetcher.ts b/public/services/data_fetchers/ppl/ppl_data_fetcher.ts index 108326d3e..984c89984 100644 --- a/public/services/data_fetchers/ppl/ppl_data_fetcher.ts +++ b/public/services/data_fetchers/ppl/ppl_data_fetcher.ts @@ -138,7 +138,7 @@ export class PPLDataFetcher extends DataFetcherBase implements IDataFetcher { } } - async setLogPattern(query: IQuery, index: string, finalQuery: string) { + async setLogPattern(query: IQuery, index: string, _finalQuery: string) { const { getErrorHandler, setDefaultPatternsField } = this.searchContext; // set pattern if (isEmpty(query[SELECTED_PATTERN_FIELD])) { diff --git a/server/index.ts b/server/index.ts index aaecf7e92..42810e059 100644 --- a/server/index.ts +++ b/server/index.ts @@ -17,9 +17,27 @@ const observabilityConfig = { schema: schema.object({ query_assist: schema.object({ enabled: schema.boolean({ defaultValue: false }), - ppl_agent_name: schema.maybe(schema.string()), - response_summary_agent_name: schema.maybe(schema.string()), - error_summary_agent_name: schema.maybe(schema.string()), + ppl_agent_name: schema.conditional( + schema.siblingRef('enabled'), + true, + schema.string(), + schema.maybe(schema.string()) + ), + }), + summarize: schema.object({ + enabled: schema.boolean({ defaultValue: false }), + response_summary_agent_name: schema.conditional( + schema.siblingRef('enabled'), + true, + schema.string(), + schema.maybe(schema.string()) + ), + error_summary_agent_name: schema.conditional( + schema.siblingRef('enabled'), + true, + schema.string(), + schema.maybe(schema.string()) + ), }), }), }; @@ -30,5 +48,6 @@ export const config: PluginConfigDescriptor = { schema: observabilityConfig.schema, exposeToBrowser: { query_assist: true, + summarize: true, }, }; diff --git a/server/plugin.ts b/server/plugin.ts index d67f5aaec..8efee2415 100644 --- a/server/plugin.ts +++ b/server/plugin.ts @@ -53,7 +53,7 @@ export class ObservabilityPlugin ); // @ts-ignore - core.http.registerRouteHandlerContext('observability_plugin', (context, request) => { + core.http.registerRouteHandlerContext('observability_plugin', (_context, _request) => { return { logger: this.logger, observabilityClient: openSearchObservabilityClient, @@ -139,7 +139,7 @@ export class ObservabilityPlugin return {}; } - public start(core: CoreStart) { + public start(_core: CoreStart) { this.logger.debug('Observability: Started'); return {}; } diff --git a/server/routes/query_assist/routes.ts b/server/routes/query_assist/routes.ts index a9bd90348..e99f5f972 100644 --- a/server/routes/query_assist/routes.ts +++ b/server/routes/query_assist/routes.ts @@ -10,16 +10,17 @@ import { IRouter, ResponseError, } from '../../../../../src/core/server'; +import { isResponseError } from '../../../../../src/core/server/opensearch/client/errors'; import { QUERY_ASSIST_API } from '../../../common/constants/query_assist'; import { generateFieldContext } from '../../common/helpers/query_assist/generate_field_context'; import { requestWithRetryAgentSearch } from './utils/agents'; export function registerQueryAssistRoutes(router: IRouter, config: ObservabilityConfig) { + const { ppl_agent_name: pplAgentName } = config.query_assist; const { - ppl_agent_name: pplAgentName, response_summary_agent_name: responseSummaryAgentName, error_summary_agent_name: errorSummaryAgentName, - } = config.query_assist; + } = config.summarize; router.post( { @@ -69,10 +70,13 @@ export function registerQueryAssistRoutes(router: IRouter, config: Observability .replace(/\bSPAN\(/g, 'span('); // https://github.com/opensearch-project/dashboards-observability/issues/759 return response.ok({ body: ppl }); } catch (error) { - return response.custom({ - statusCode: error.statusCode || 500, - body: error.message, - }); + // parse PPL query from error response if exists + // TODO remove after https://github.com/opensearch-project/skills/issues/138 + if (isResponseError(error) && error.body.error?.reason) { + const pplMatch = error.body.error.reason.match(/execute ppl:(.+), get error:/); + if (pplMatch[1]) return response.ok({ body: pplMatch[1] }); + } + return response.custom({ statusCode: error.statusCode || 500, body: error.message }); } } );