diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts index 8b0334ab98c14..28ad6c531e255 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts @@ -6,7 +6,7 @@ import { SavedObjectReference } from 'kibana/public'; import { Ast } from '@kbn/interpreter/common'; -import { Datasource, DatasourcePublicAPI, Visualization } from '../../types'; +import { Datasource, DatasourcePublicAPI, FramePublicAPI, Visualization } from '../../types'; import { buildExpression } from './expression_helpers'; import { Document } from '../../persistence/saved_object_store'; import { VisualizeFieldContext } from '../../../../../../src/plugins/ui_actions/public'; @@ -91,3 +91,29 @@ export async function persistedStateToExpression( datasourceLayers, }); } + +export const validateDatasourceAndVisualization = ( + currentDataSource: Datasource | null, + currentDatasourceState: unknown | null, + currentVisualization: Visualization | null, + currentVisualizationState: unknown | undefined, + frameAPI: FramePublicAPI +): + | Array<{ + shortMessage: string; + longMessage: string; + }> + | undefined => { + const datasourceValidationErrors = currentDatasourceState + ? currentDataSource?.getErrorMessages(currentDatasourceState) + : undefined; + + const visualizationValidationErrors = currentVisualizationState + ? currentVisualization?.getErrorMessages(currentVisualizationState, frameAPI) + : undefined; + + if (datasourceValidationErrors || visualizationValidationErrors) { + return [...(datasourceValidationErrors || []), ...(visualizationValidationErrors || [])]; + } + return undefined; +}; diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx index c3712eaa3abb5..201c91ee91676 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/suggestion_panel.tsx @@ -34,6 +34,7 @@ import { import { prependDatasourceExpression } from './expression_helpers'; import { trackUiEvent, trackSuggestionEvent } from '../../lens_ui_telemetry'; import { DataPublicPluginStart } from '../../../../../../src/plugins/data/public'; +import { validateDatasourceAndVisualization } from './state_helpers'; const MAX_SUGGESTIONS_DISPLAYED = 5; @@ -188,13 +189,26 @@ export function SuggestionPanel({ activeVisualizationId: currentVisualizationId, visualizationState: currentVisualizationState, }) - .filter(({ visualizationId, visualizationState: suggestionVisualizationState }) => { - const suggestionVisualization = visualizationMap[visualizationId]; - // filter out visualizations with errors - return ( - suggestionVisualization.getErrorMessages(suggestionVisualizationState, frame) == null - ); - }) + .filter((suggestion) => !suggestion.hide) + .filter( + ({ + visualizationId, + visualizationState: suggestionVisualizationState, + datasourceState: suggestionDatasourceState, + datasourceId: suggetionDatasourceId, + }) => { + return ( + validateDatasourceAndVisualization( + suggetionDatasourceId ? datasourceMap[suggetionDatasourceId] : null, + suggestionDatasourceState, + visualizationMap[visualizationId], + suggestionVisualizationState, + frame + ) == null + ); + } + ) + .slice(0, MAX_SUGGESTIONS_DISPLAYED) .map((suggestion) => ({ ...suggestion, previewExpression: preparePreviewExpression( @@ -204,26 +218,15 @@ export function SuggestionPanel({ currentDatasourceStates, frame ), - })) - .filter((suggestion) => !suggestion.hide) - .slice(0, MAX_SUGGESTIONS_DISPLAYED); - - const activeDatasource = activeDatasourceId ? datasourceMap[activeDatasourceId] : null; - const datasourceValidationErrors = activeDatasourceId - ? activeDatasource?.getErrorMessages(currentDatasourceStates[activeDatasourceId]?.state) - : undefined; - - const visualizationValidationErrors = currentVisualizationId - ? visualizationMap[currentVisualizationId]?.getErrorMessages( - currentVisualizationState, - frame - ) - : undefined; - - const validationErrors = - datasourceValidationErrors || visualizationValidationErrors - ? [...(datasourceValidationErrors || []), ...(visualizationValidationErrors || [])] - : undefined; + })); + + const validationErrors = validateDatasourceAndVisualization( + activeDatasourceId ? datasourceMap[activeDatasourceId] : null, + activeDatasourceId && currentDatasourceStates[activeDatasourceId]?.state, + currentVisualizationId ? visualizationMap[currentVisualizationId] : null, + currentVisualizationState, + frame + ); const newStateExpression = currentVisualizationState && currentVisualizationId && !validationErrors diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index edd84f060e1e6..4605a7fefe138 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -51,6 +51,7 @@ import { import { WorkspacePanelWrapper } from './workspace_panel_wrapper'; import { DropIllustration } from '../../../assets/drop_illustration'; import { getOriginalRequestErrorMessage } from '../../error_helper'; +import { validateDatasourceAndVisualization } from '../state_helpers'; export interface WorkspacePanelProps { activeVisualizationId: string | null; @@ -134,25 +135,18 @@ export function WorkspacePanel({ ? visualizationMap[activeVisualizationId] : null; - const configurationValidationError = useMemo(() => { - const activeDatasource = activeDatasourceId ? datasourceMap[activeDatasourceId] : null; - const dataMessages = activeDatasourceId - ? activeDatasource?.getErrorMessages(datasourceStates[activeDatasourceId]?.state) - : undefined; - const vizMessages = activeVisualization?.getErrorMessages(visualizationState, framePublicAPI); - - if (vizMessages || dataMessages) { - // Data first, visualization next - return [...(dataMessages || []), ...(vizMessages || [])]; - } - }, [ - activeVisualization?.getErrorMessages, - visualizationState, - activeDatasourceId, - datasourceMap, - datasourceStates, - framePublicAPI, - ]); + const configurationValidationError = useMemo( + () => + validateDatasourceAndVisualization( + activeDatasourceId ? datasourceMap[activeDatasourceId] : null, + activeDatasourceId && datasourceStates[activeDatasourceId]?.state, + activeVisualization, + visualizationState, + framePublicAPI + ), + // eslint-disable-next-line react-hooks/exhaustive-deps + [activeVisualization, visualizationState, activeDatasourceId, datasourceMap, datasourceStates] + ); const expression = useMemo( () => {