diff --git a/src/platform/plugins/shared/esql/moon.yml b/src/platform/plugins/shared/esql/moon.yml index 6448c5a6a92bb..2b4e64a9a08dd 100644 --- a/src/platform/plugins/shared/esql/moon.yml +++ b/src/platform/plugins/shared/esql/moon.yml @@ -29,7 +29,6 @@ dependsOn: - '@kbn/fields-metadata-plugin' - '@kbn/usage-collection-plugin' - '@kbn/kibana-utils-plugin' - - '@kbn/monaco' - '@kbn/search-types' - '@kbn/react-kibana-context-render' - '@kbn/core-test-helpers-kbn-server' @@ -61,6 +60,7 @@ dependsOn: - '@kbn/logging-mocks' - '@kbn/agent-builder-genai-utils' - '@kbn/agent-builder-server' + - '@kbn/code-editor' tags: - plugin - prod diff --git a/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/helpers.test.ts b/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/helpers.test.ts index 1738e5f8c63f3..0811d0e14ae95 100644 --- a/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/helpers.test.ts +++ b/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/helpers.test.ts @@ -6,7 +6,7 @@ * your election, the "Elastic License 2.0", the "GNU Affero General Public * License v3.0 only", or the "Server Side Public License, v 1". */ -import type { monaco } from '@kbn/monaco'; +import type { monaco } from '@kbn/code-editor'; import type { ESQLControlVariable } from '@kbn/esql-types'; import { ESQLVariableType } from '@kbn/esql-types'; import { diff --git a/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/helpers.ts b/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/helpers.ts index 214f52f6a062a..d849f80ec7489 100644 --- a/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/helpers.ts +++ b/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/helpers.ts @@ -6,7 +6,7 @@ * your election, the "Elastic License 2.0", the "GNU Affero General Public * License v3.0 only", or the "Server Side Public License, v 1". */ -import type { monaco } from '@kbn/monaco'; +import type { monaco } from '@kbn/code-editor'; import type { ESQLControlVariable } from '@kbn/esql-types'; import { ESQLVariableType, VariableNamePrefix } from '@kbn/esql-types'; import { TIME_SPAN_UNITS } from '@elastic/esql'; diff --git a/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/identifier_control_form.test.tsx b/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/identifier_control_form.test.tsx index 7a20e5fa392fc..587f42565ab16 100644 --- a/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/identifier_control_form.test.tsx +++ b/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/identifier_control_form.test.tsx @@ -12,7 +12,7 @@ import { render, within, fireEvent } from '@testing-library/react'; import { coreMock } from '@kbn/core/public/mocks'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import type { monaco } from '@kbn/monaco'; +import type { monaco } from '@kbn/code-editor'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; import type { OptionsListESQLControlState } from '@kbn/controls-schemas'; import { ControlTriggerSource, ESQLVariableType, EsqlControlType } from '@kbn/esql-types'; diff --git a/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/identifier_control_form.tsx b/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/identifier_control_form.tsx index 21a5ff1d99e79..69bdcb270ef46 100644 --- a/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/identifier_control_form.tsx +++ b/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/identifier_control_form.tsx @@ -13,7 +13,7 @@ import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import { isEqual } from 'lodash'; import { EuiComboBox, EuiFormRow, type EuiComboBoxOptionOption } from '@elastic/eui'; -import type { monaco } from '@kbn/monaco'; +import type { monaco } from '@kbn/code-editor'; import type { ISearchGeneric } from '@kbn/search-types'; import type { ESQLControlVariable, StaticESQLControl } from '@kbn/esql-types'; import { ESQLVariableType, EsqlControlType } from '@kbn/esql-types'; diff --git a/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/index.tsx b/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/index.tsx index 82e6cd44f9966..a8a99a7a38279 100644 --- a/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/index.tsx +++ b/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/index.tsx @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import React, { useCallback, useMemo, useState, useEffect } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import { EuiFlyoutBody } from '@elastic/eui'; import type { ESQLEditorTelemetryService } from '@kbn/esql-editor'; import type { TimeRange } from '@kbn/es-query'; @@ -23,7 +23,7 @@ import { import type { OptionsListESQLControlState } from '@kbn/controls-schemas'; import { getValuesFromQueryField } from '@kbn/esql-utils'; import type { ISearchGeneric } from '@kbn/search-types'; -import type { monaco } from '@kbn/monaco'; +import type { monaco } from '@kbn/code-editor'; import { ValueControlForm } from './value_control_form'; import { Header, ControlType, VariableName, Footer } from './shared_form_components'; import { IdentifierControlForm } from './identifier_control_form'; @@ -121,7 +121,7 @@ export function ESQLControlsFlyout({ const [variableName, setVariableName] = useState(suggestedVariableName); const [variableType, setVariableType] = useState(initialVariableType); - const [formIsInvalid, setFormIsInvalid] = useState(false); + const [isValid, setIsValid] = useState(false); const [controlState, setControlState] = useState( initialState ); @@ -151,24 +151,28 @@ export function ESQLControlsFlyout({ [controlFlyoutType, variableNamePrefix, variableType] ); - useEffect(() => { + const formIsInvalid = useMemo(() => { const variableNameWithoutQuestionmark = variableName.replace(/^\?+/, ''); const variableExists = checkVariableExistence(esqlVariables, variableName) && !isControlInEditMode; const { available_options } = { available_options: [], ...controlState }; - setFormIsInvalid( + const isInvalid = controlFlyoutType === EsqlControlType.VALUES_FROM_QUERY && !isValid; + + return ( !variableNameWithoutQuestionmark || - variableExists || - !areValuesValid || - !available_options.length + variableExists || + !areValuesValid || + isInvalid || + !available_options.length ); }, [ isControlInEditMode, areValuesValid, controlState, + controlFlyoutType, esqlVariables, variableName, - variableType, + isValid, ]); const onFlyoutTypeChange = useCallback((controlType: EsqlControlType) => { @@ -229,6 +233,7 @@ export function ESQLControlsFlyout({ variableType={variableType} initialState={initialState} setControlState={setControlState} + setIsValid={setIsValid} search={search} valuesRetrieval={valuesField} timeRange={timeRange} diff --git a/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/value_control_form.test.tsx b/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/value_control_form.test.tsx index f5e11b13ae8c6..f5963ac0e8e73 100644 --- a/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/value_control_form.test.tsx +++ b/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/value_control_form.test.tsx @@ -11,7 +11,7 @@ import React from 'react'; import { render, within, fireEvent, waitFor } from '@testing-library/react'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; import type { IUiSettingsClient } from '@kbn/core/public'; -import type { monaco } from '@kbn/monaco'; +import type { monaco } from '@kbn/code-editor'; import { coreMock } from '@kbn/core/public/mocks'; import type { OptionsListESQLControlState } from '@kbn/controls-schemas'; import { ControlTriggerSource, ESQLVariableType, EsqlControlType } from '@kbn/esql-types'; @@ -38,7 +38,7 @@ jest.mock('@kbn/esql-utils', () => { }, }, ], - values: [], + values: [['v1'], ['v2']], }, }), getIndexPatternFromESQLQuery: jest.fn().mockReturnValue('index1'), @@ -364,6 +364,27 @@ describe('ValueControlForm', () => { expect(await findByTestId('esqlNoValuesForControlCallout')).toBeInTheDocument(); }); + + it('should disable the save button until the values preview is successfully validated', async () => { + const { getByTestId } = render( + + + + + + ); + + const saveButton = getByTestId('saveEsqlControlsFlyoutButton'); + expect(saveButton).toBeDisabled(); + + await waitFor(() => { + expect(saveButton).not.toBeDisabled(); + }); + }); }); }); }); diff --git a/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/value_control_form.tsx b/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/value_control_form.tsx index 30ca13842cdc0..e6805f9d24e8b 100644 --- a/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/value_control_form.tsx +++ b/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/value_control_form.tsx @@ -53,6 +53,7 @@ interface ValueControlFormProps { controlFlyoutType: EsqlControlType; queryString: string; setControlState: (state: OptionsListESQLControlState) => void; + setIsValid: (isValid: boolean) => void; initialState?: OptionsListESQLControlState; valuesRetrieval?: string; timeRange?: TimeRange; @@ -61,8 +62,8 @@ interface ValueControlFormProps { const SUGGESTED_INTERVAL_VALUES = ['5 minutes', '1 hour', '1 day', '1 week', '1 month']; const INITIAL_EMPTY_STATE_QUERY = `/** Example -To get the agent field values use: -FROM logs-* +To get the agent field values use: +FROM logs-* | WHERE @timestamp <=?_tend and @timestamp >?_tstart | STATS BY agent */`; @@ -75,6 +76,7 @@ export function ValueControlForm({ controlFlyoutType, search, setControlState, + setIsValid, valuesRetrieval, timeRange, esqlVariables, @@ -212,16 +214,21 @@ export function ValueControlForm({ setSelectedValues(options); setAvailableValuesOptions(options); setEsqlQueryErrors([]); + setIsValid(true); + } else { + setIsValid(false); } + setValuesQuery(query); } catch (e) { if (e instanceof DOMException && e.name === 'AbortError') { return; } + setIsValid(false); setEsqlQueryErrors([e]); } }, - [isMounted, search, timeRange, esqlVariables, core.uiSettings] + [isMounted, search, timeRange, esqlVariables, core.uiSettings, setIsValid] ); const setSuggestedQuery = useCallback(async () => { @@ -320,6 +327,7 @@ export function ValueControlForm({ { + setIsValid(false); setValuesQuery(q.esql); }} disableAutoFocus={true} diff --git a/src/platform/plugins/shared/esql/public/triggers/esql_controls/esql_control_action.ts b/src/platform/plugins/shared/esql/public/triggers/esql_controls/esql_control_action.ts index 961582dbd55fc..fcaa72212b9b4 100644 --- a/src/platform/plugins/shared/esql/public/triggers/esql_controls/esql_control_action.ts +++ b/src/platform/plugins/shared/esql/public/triggers/esql_controls/esql_control_action.ts @@ -20,7 +20,7 @@ import { TelemetryControlCancelledReason, } from '@kbn/esql-types'; import type { OptionsListESQLControlState } from '@kbn/controls-schemas'; -import type { monaco } from '@kbn/monaco'; +import type { monaco } from '@kbn/code-editor'; import { ENABLE_ESQL } from '@kbn/esql-utils'; import { dismissAllFlyoutsExceptFor, DiscoverFlyouts } from '@kbn/discover-utils'; import { openLazyFlyout } from '@kbn/presentation-util'; diff --git a/src/platform/plugins/shared/esql/public/triggers/esql_controls/esql_control_helpers.tsx b/src/platform/plugins/shared/esql/public/triggers/esql_controls/esql_control_helpers.tsx index 6d3f5d7a0b399..b868fe322b87e 100644 --- a/src/platform/plugins/shared/esql/public/triggers/esql_controls/esql_control_helpers.tsx +++ b/src/platform/plugins/shared/esql/public/triggers/esql_controls/esql_control_helpers.tsx @@ -18,7 +18,7 @@ import { type ControlTriggerSource, } from '@kbn/esql-types'; import type { OptionsListESQLControlState } from '@kbn/controls-schemas'; -import type { monaco } from '@kbn/monaco'; +import type { monaco } from '@kbn/code-editor'; import type { ESQLEditorTelemetryService } from '@kbn/esql-editor'; import { untilPluginStartServicesReady } from '../../kibana_services'; import { ESQLControlsFlyout } from './control_flyout'; diff --git a/src/platform/plugins/shared/esql/tsconfig.json b/src/platform/plugins/shared/esql/tsconfig.json index 132d1a1b0e920..e7e7c43b9bb2b 100644 --- a/src/platform/plugins/shared/esql/tsconfig.json +++ b/src/platform/plugins/shared/esql/tsconfig.json @@ -21,7 +21,6 @@ "@kbn/fields-metadata-plugin", "@kbn/usage-collection-plugin", "@kbn/kibana-utils-plugin", - "@kbn/monaco", "@kbn/search-types", "@kbn/react-kibana-context-render", "@kbn/core-test-helpers-kbn-server", @@ -53,6 +52,7 @@ "@kbn/logging-mocks", "@kbn/agent-builder-genai-utils", "@kbn/agent-builder-server", + "@kbn/code-editor", ], "exclude": [ "target/**/*",