From d335fd8164dbd9ec50c5e4b19e81a43b33554001 Mon Sep 17 00:00:00 2001 From: Hannah Mudge Date: Wed, 26 Jun 2024 10:15:26 -0600 Subject: [PATCH] Handle cancel + save --- .../editor/open_saved_search_edit_flyout.tsx | 39 ++++++------------- .../editor/saved_search_edit_flyout.tsx | 12 +++--- .../editor/saved_search_editor_esql.tsx | 16 ++++++-- .../discover/public/embeddable/constants.ts | 16 ++++---- .../discover/public/embeddable/types.ts | 10 +---- 5 files changed, 40 insertions(+), 53 deletions(-) diff --git a/src/plugins/discover/public/embeddable/components/editor/open_saved_search_edit_flyout.tsx b/src/plugins/discover/public/embeddable/components/editor/open_saved_search_edit_flyout.tsx index c765ad84bd77f..41c1f292bb2c8 100644 --- a/src/plugins/discover/public/embeddable/components/editor/open_saved_search_edit_flyout.tsx +++ b/src/plugins/discover/public/embeddable/components/editor/open_saved_search_edit_flyout.tsx @@ -32,45 +32,30 @@ export const openSavedSearchEditFlyout = async ({ navigateToEditor?: () => Promise; }) => { const overlayTracker = tracksOverlays(api.parentApi) ? api.parentApi : undefined; - // const initialState = api.snapshotRuntimeState(); + const initialState = api.snapshotRuntimeState(); const isEsql = isEsqlMode(api.savedSearch$.getValue()); return new Promise(async (resolve, reject) => { try { - const onCancel = () => { + const onCancel = async () => { if (!isEditing && apiIsPresentationContainer(api.parentApi)) { api.parentApi.removePanel(api.uuid); + } else { + // Reset to initialState + const stateManager = api.getStateManager(); + const initialSearchSource = await services.data.search.searchSource.create( + initialState.serializedSearchSource + ); + stateManager.searchSource.next(initialSearchSource); + stateManager.columns.next(initialState.columns); } - // Reset to initialState in case user has changed the preview state - // if (deepEqual(initialState, newState)) { - // closeOverlay(overlay); - // return; - // } - - // if (hasChanged && fieldStatsControlsApi && initialState) { - // fieldStatsControlsApi.updateUserInput(initialState); - // } - flyoutSession.close(); overlayTracker?.clearOverlays(); }; const onSave = async () => { - // const esqlQuery = nextUpdate?.query?.esql; - // if (isDefined(esqlQuery)) { - // const indexPatternFromQuery = getIndexPatternFromESQLQuery(esqlQuery); - // const dv = await getOrCreateDataViewByIndexPattern( - // pluginStart.data.dataViews, - // indexPatternFromQuery, - // undefined - // ); - // if (dv?.id && nextUpdate.dataViewId !== dv.id) { - // nextUpdate.dataViewId = dv.id; - // } - // } - // resolve(nextUpdate); - // flyoutSession.close(); - // overlayTracker?.clearOverlays(); + flyoutSession.close(); + overlayTracker?.clearOverlays(); }; const flyoutSession = services.core.overlays.openFlyout( diff --git a/src/plugins/discover/public/embeddable/components/editor/saved_search_edit_flyout.tsx b/src/plugins/discover/public/embeddable/components/editor/saved_search_edit_flyout.tsx index 454f64b45453d..ce4b6b47081e7 100644 --- a/src/plugins/discover/public/embeddable/components/editor/saved_search_edit_flyout.tsx +++ b/src/plugins/discover/public/embeddable/components/editor/saved_search_edit_flyout.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React from 'react'; +import React, { useState } from 'react'; import { EuiButton, @@ -44,11 +44,13 @@ export default function SavedSearchEditorFlyout({ isEsql: boolean; isEditing: boolean; navigateToEditor?: () => Promise; - onCancel: () => void; + onCancel: () => Promise; onSave: () => Promise; stateManager: SearchEmbeddableStateManager; services: DiscoverServices; }) { + const [isValid, setIsValid] = useState(true); + return ( <> @@ -89,7 +89,7 @@ export default function SavedSearchEditorFlyout({ {isEsql ? ( - + ) : ( )} @@ -120,7 +120,7 @@ export default function SavedSearchEditorFlyout({ aria-label={i18n.translate('discover.embeddable.search.editor.applyFlyoutAriaLabel', { defaultMessage: 'Apply changes', })} - disabled={Boolean(isEditing) ? true : false} // TODO: Handle validation when creating + disabled={isEsql ? !isValid : false} iconType="check" > {i18n.translate('discover.embeddable.search.editor.applyFlyoutLabel', { diff --git a/src/plugins/discover/public/embeddable/components/editor/saved_search_editor_esql.tsx b/src/plugins/discover/public/embeddable/components/editor/saved_search_editor_esql.tsx index 4c5a08988ae2c..6d1ccb5b8c0ce 100644 --- a/src/plugins/discover/public/embeddable/components/editor/saved_search_editor_esql.tsx +++ b/src/plugins/discover/public/embeddable/components/editor/saved_search_editor_esql.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React, { useCallback, useRef, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing'; import { @@ -33,9 +33,11 @@ const getCreationOptions: UnifiedFieldListSidebarContainerProps['getCreationOpti export function SavedSearchEsqlEditor({ api, stateManager, + setIsValid, }: { api: SearchEmbeddableApi; stateManager: SearchEmbeddableStateManager; + setIsValid: (valid: boolean) => void; }) { const services = useDiscoverServices(); @@ -44,15 +46,23 @@ export function SavedSearchEsqlEditor({ savedSearch.searchSource.getField('query') as AggregateQuery ); const prevQuery = useRef(query); - const dataView = savedSearch.searchSource.getField('index'); + + const dataView = useMemo(() => { + return savedSearch.searchSource.getField('index'); + }, [savedSearch]); const onTextLangQuerySubmit = useCallback( async (q) => { if (q) { stateManager.searchSource.next(savedSearch.searchSource.setField('query', q)); + if (q.esql === '') { + setIsValid(false); + } else { + setIsValid(true); + } } }, - [savedSearch.searchSource, stateManager.searchSource] + [savedSearch.searchSource, stateManager.searchSource, setIsValid] ); return ( diff --git a/src/plugins/discover/public/embeddable/constants.ts b/src/plugins/discover/public/embeddable/constants.ts index bad212f18a953..920643ea3fa63 100644 --- a/src/plugins/discover/public/embeddable/constants.ts +++ b/src/plugins/discover/public/embeddable/constants.ts @@ -24,14 +24,14 @@ export const SEARCH_EMBEDDABLE_CELL_ACTIONS_TRIGGER: Trigger = { export const DEFAULT_HEADER_ROW_HEIGHT_LINES = 3; /** This constant refers to the parts of the saved search state that can be edited from a dashboard */ -export const EDITABLE_SAVED_SEARCH_KEYS: Readonly> = [ - 'sort', - 'columns', - 'rowHeight', - 'sampleSize', - 'rowsPerPage', - 'headerRowHeight', -] as const; +export const EDITABLE_SAVED_SEARCH_KEYS: Readonly< + Array< + keyof Pick< + SavedSearchAttributes, + 'sort' | 'columns' | 'rowHeight' | 'sampleSize' | 'rowsPerPage' | 'headerRowHeight' + > + > +> = ['sort', 'columns', 'rowHeight', 'sampleSize', 'rowsPerPage', 'headerRowHeight'] as const; /** This constant refers to the dashboard panel specific state */ export const EDITABLE_PANEL_KEYS = [ diff --git a/src/plugins/discover/public/embeddable/types.ts b/src/plugins/discover/public/embeddable/types.ts index 81b3012602ae1..b715682289a72 100644 --- a/src/plugins/discover/public/embeddable/types.ts +++ b/src/plugins/discover/public/embeddable/types.ts @@ -7,7 +7,6 @@ */ import { ISearchSource } from '@kbn/data-plugin/common'; -import { DataView } from '@kbn/data-views-plugin/common'; import { DataTableRecord } from '@kbn/discover-utils/types'; import type { DefaultEmbeddableApi } from '@kbn/embeddable-plugin/public'; import { @@ -33,14 +32,7 @@ import { EDITABLE_SAVED_SEARCH_KEYS } from './constants'; export type SearchEmbeddableState = Pick< SerializableSavedSearch, - | 'rowHeight' - | 'rowsPerPage' - | 'headerRowHeight' - | 'columns' - | 'sort' - | 'sampleSize' - | 'breakdownField' - | 'viewMode' + typeof EDITABLE_SAVED_SEARCH_KEYS[number] | 'breakdownField' | 'viewMode' > & { rows: DataTableRecord[]; columnsMeta: DataTableColumnsMeta | undefined;