From 2c9043ab431cebbbdeb77c96aa2a5c0bc5b0ddf4 Mon Sep 17 00:00:00 2001 From: Dmitry Tomashevich <39378793+dimaanj@users.noreply.github.com> Date: Fri, 25 Nov 2022 16:16:34 +0300 Subject: [PATCH] [Discover] Prevent agg based visualizations of Discover saved objects with adhoc data views (#145583) ## Summary Fixes #141812 This PR preventing using Discover saved objects with adhoc data views in aggregation based visualisations. ### Test notes - Create Saved search based on adhoc data view in Discover - Open new Agg based visualisations list and choose one - Created Saved search shouldn't appear in the list. ### Checklist - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --- .../migrations/check_registered_types.test.ts | 2 +- .../main/utils/persist_saved_search.ts | 2 + .../saved_objects/public/finder/index.ts | 6 ++- .../public/finder/saved_object_finder.tsx | 2 +- src/plugins/saved_objects/public/index.ts | 2 +- .../saved_searches/get_saved_searches.test.ts | 2 + .../saved_searches_utils.test.ts | 4 ++ .../saved_searches/saved_searches_utils.ts | 2 + .../public/services/saved_searches/types.ts | 2 + .../server/saved_objects/search.ts | 1 + .../search_selection/search_selection.tsx | 14 ++---- .../show_saved_object.test.ts | 49 +++++++++++++++++++ .../search_selection/show_saved_object.ts | 20 ++++++++ 13 files changed, 94 insertions(+), 14 deletions(-) create mode 100644 src/plugins/visualizations/public/wizard/search_selection/show_saved_object.test.ts create mode 100644 src/plugins/visualizations/public/wizard/search_selection/show_saved_object.ts diff --git a/src/core/server/integration_tests/saved_objects/migrations/check_registered_types.test.ts b/src/core/server/integration_tests/saved_objects/migrations/check_registered_types.test.ts index ba240714d897a..bf67572828796 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/check_registered_types.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/check_registered_types.test.ts @@ -124,7 +124,7 @@ describe('checking migration metadata changes on all registered SO types', () => "osquery-saved-query": "7b213b4b7a3e59350e99c50e8df9948662ed493a", "query": "4640ef356321500a678869f24117b7091a911cb6", "sample-data-telemetry": "8b10336d9efae6f3d5593c4cc89fb4abcdf84e04", - "search": "e7ba25ea37cb36b622db42c9590c6d8dfc838801", + "search": "d26771bcf7cd271162aab3a610b75249631ef6b1", "search-session": "ba383309da68a15be3765977f7a44c84f0ec7964", "search-telemetry": "beb3fc25488c753f2a6dcff1845d667558712b66", "security-rule": "e0dfdba5d66139d0300723b2e6672993cd4a11f3", diff --git a/src/plugins/discover/public/application/main/utils/persist_saved_search.ts b/src/plugins/discover/public/application/main/utils/persist_saved_search.ts index edc7d96f9decd..73859e46eaf24 100644 --- a/src/plugins/discover/public/application/main/utils/persist_saved_search.ts +++ b/src/plugins/discover/public/application/main/utils/persist_saved_search.ts @@ -67,6 +67,8 @@ export async function persistSavedSearch( savedSearch.isTextBasedQuery = isTextBasedQuery; } + savedSearch.usesAdHocDataView = !dataView.isPersisted(); + const { from, to } = services.timefilter.getTime(); const refreshInterval = services.timefilter.getRefreshInterval(); savedSearch.timeRange = diff --git a/src/plugins/saved_objects/public/finder/index.ts b/src/plugins/saved_objects/public/finder/index.ts index aaf6259daca1d..dc4213978aa52 100644 --- a/src/plugins/saved_objects/public/finder/index.ts +++ b/src/plugins/saved_objects/public/finder/index.ts @@ -6,5 +6,9 @@ * Side Public License, v 1. */ -export type { SavedObjectMetaData, SavedObjectFinderUiProps } from './saved_object_finder'; +export type { + SavedObjectMetaData, + SavedObjectFinderUiProps, + FinderAttributes, +} from './saved_object_finder'; export { SavedObjectFinderUi, getSavedObjectFinder } from './saved_object_finder'; diff --git a/src/plugins/saved_objects/public/finder/saved_object_finder.tsx b/src/plugins/saved_objects/public/finder/saved_object_finder.tsx index b3cf81cbbdf85..e45c4526ceac9 100644 --- a/src/plugins/saved_objects/public/finder/saved_object_finder.tsx +++ b/src/plugins/saved_objects/public/finder/saved_object_finder.tsx @@ -51,7 +51,7 @@ export interface SavedObjectMetaData { defaultSearchField?: string; } -interface FinderAttributes { +export interface FinderAttributes { title?: string; name?: string; type: string; diff --git a/src/plugins/saved_objects/public/index.ts b/src/plugins/saved_objects/public/index.ts index 5e6e67f7e4acc..2cfb84d608c67 100644 --- a/src/plugins/saved_objects/public/index.ts +++ b/src/plugins/saved_objects/public/index.ts @@ -10,7 +10,7 @@ import { SavedObjectsPublicPlugin } from './plugin'; export type { OnSaveProps, OriginSaveModalProps, SaveModalState, SaveResult } from './save_modal'; export { SavedObjectSaveModal, SavedObjectSaveModalOrigin, showSaveModal } from './save_modal'; -export type { SavedObjectFinderUiProps, SavedObjectMetaData } from './finder'; +export type { SavedObjectFinderUiProps, SavedObjectMetaData, FinderAttributes } from './finder'; export { getSavedObjectFinder, SavedObjectFinderUi } from './finder'; export type { SavedObjectDecorator, diff --git a/src/plugins/saved_search/public/services/saved_searches/get_saved_searches.test.ts b/src/plugins/saved_search/public/services/saved_searches/get_saved_searches.test.ts index ca405537c363d..f71763f6a25d3 100644 --- a/src/plugins/saved_search/public/services/saved_searches/get_saved_searches.test.ts +++ b/src/plugins/saved_search/public/services/saved_searches/get_saved_searches.test.ts @@ -154,6 +154,7 @@ describe('getSavedSearch', () => { "timeRange": undefined, "timeRestore": undefined, "title": "test1", + "usesAdHocDataView": undefined, "viewMode": undefined, } `); @@ -251,6 +252,7 @@ describe('getSavedSearch', () => { "timeRange": undefined, "timeRestore": undefined, "title": "test2", + "usesAdHocDataView": undefined, "viewMode": undefined, } `); diff --git a/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.test.ts b/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.test.ts index 55d2b7f99009d..9f227bc1afd04 100644 --- a/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.test.ts +++ b/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.test.ts @@ -28,6 +28,7 @@ describe('saved_searches_utils', () => { grid: {}, hideChart: true, isTextBasedQuery: false, + usesAdHocDataView: false, }; expect( @@ -81,6 +82,7 @@ describe('saved_searches_utils', () => { "timeRange": undefined, "timeRestore": undefined, "title": "saved search", + "usesAdHocDataView": false, "viewMode": undefined, } `); @@ -121,6 +123,7 @@ describe('saved_searches_utils', () => { grid: {}, hideChart: true, isTextBasedQuery: true, + usesAdHocDataView: false, }; expect(toSavedSearchAttributes(savedSearch, '{}')).toMatchInlineSnapshot(` @@ -149,6 +152,7 @@ describe('saved_searches_utils', () => { "timeRange": undefined, "timeRestore": false, "title": "title", + "usesAdHocDataView": false, "viewMode": undefined, } `); diff --git a/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.ts b/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.ts index 8ca6dde21d6fc..5d37355ea818d 100644 --- a/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.ts +++ b/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.ts @@ -45,6 +45,7 @@ export const fromSavedSearchAttributes = ( hideAggregatedPreview: attributes.hideAggregatedPreview, rowHeight: attributes.rowHeight, isTextBasedQuery: attributes.isTextBasedQuery, + usesAdHocDataView: attributes.usesAdHocDataView, timeRestore: attributes.timeRestore, timeRange: attributes.timeRange, refreshInterval: attributes.refreshInterval, @@ -66,6 +67,7 @@ export const toSavedSearchAttributes = ( hideAggregatedPreview: savedSearch.hideAggregatedPreview, rowHeight: savedSearch.rowHeight, isTextBasedQuery: savedSearch.isTextBasedQuery ?? false, + usesAdHocDataView: savedSearch.usesAdHocDataView, timeRestore: savedSearch.timeRestore ?? false, timeRange: savedSearch.timeRange, refreshInterval: savedSearch.refreshInterval, diff --git a/src/plugins/saved_search/public/services/saved_searches/types.ts b/src/plugins/saved_search/public/services/saved_searches/types.ts index 58972dd40bfb8..81dbe19517798 100644 --- a/src/plugins/saved_search/public/services/saved_searches/types.ts +++ b/src/plugins/saved_search/public/services/saved_searches/types.ts @@ -33,6 +33,7 @@ export interface SavedSearchAttributes { }; hideChart: boolean; isTextBasedQuery: boolean; + usesAdHocDataView?: boolean; kibanaSavedObjectMeta: { searchSourceJSON: string; }; @@ -73,6 +74,7 @@ export interface SavedSearch { hideAggregatedPreview?: boolean; rowHeight?: number; isTextBasedQuery?: boolean; + usesAdHocDataView?: boolean; // for restoring time range with a saved search timeRestore?: boolean; diff --git a/src/plugins/saved_search/server/saved_objects/search.ts b/src/plugins/saved_search/server/saved_objects/search.ts index dec1c852aee20..29130ac519334 100644 --- a/src/plugins/saved_search/server/saved_objects/search.ts +++ b/src/plugins/saved_search/server/saved_objects/search.ts @@ -39,6 +39,7 @@ export function getSavedSearchObjectType( viewMode: { type: 'keyword', index: false, doc_values: false }, hideChart: { type: 'boolean', index: false, doc_values: false }, isTextBasedQuery: { type: 'boolean', index: false, doc_values: false }, + usesAdHocDataView: { type: 'boolean', index: false, doc_values: false }, hideAggregatedPreview: { type: 'boolean', index: false, doc_values: false }, hits: { type: 'integer', index: false, doc_values: false }, kibanaSavedObjectMeta: { diff --git a/src/plugins/visualizations/public/wizard/search_selection/search_selection.tsx b/src/plugins/visualizations/public/wizard/search_selection/search_selection.tsx index 4316845b8972f..5771747794273 100644 --- a/src/plugins/visualizations/public/wizard/search_selection/search_selection.tsx +++ b/src/plugins/visualizations/public/wizard/search_selection/search_selection.tsx @@ -6,16 +6,16 @@ * Side Public License, v 1. */ +import React from 'react'; import { EuiModalBody, EuiModalHeader, EuiModalHeaderTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { SimpleSavedObject, SavedObjectAttributes } from '@kbn/core/public'; -import React from 'react'; import { IUiSettingsClient, SavedObjectsStart } from '@kbn/core/public'; import { SavedObjectFinderUi } from '@kbn/saved-objects-plugin/public'; import type { BaseVisType } from '../../vis_types'; import { DialogNavigation } from '../dialog_navigation'; +import { showSavedObject } from './show_saved_object'; interface SearchSelectionProps { onSearchSelected: (searchId: string, searchType: string) => void; @@ -24,9 +24,6 @@ interface SearchSelectionProps { savedObjects: SavedObjectsStart; goBack: () => void; } -interface SavedSearchesAttributes extends SavedObjectAttributes { - isTextBasedQuery: boolean; -} export class SearchSelection extends React.Component { private fixedPageSize: number = 8; @@ -71,11 +68,8 @@ export class SearchSelection extends React.Component { } ), // ignore the saved searches that have text-based languages queries - includeFields: ['isTextBasedQuery'], - showSavedObject: (savedObject) => { - const so = savedObject as unknown as SimpleSavedObject; - return !so.attributes.isTextBasedQuery; - }, + includeFields: ['isTextBasedQuery', 'usesAdHocDataView'], + showSavedObject, }, { type: 'index-pattern', diff --git a/src/plugins/visualizations/public/wizard/search_selection/show_saved_object.test.ts b/src/plugins/visualizations/public/wizard/search_selection/show_saved_object.test.ts new file mode 100644 index 0000000000000..3ec17d916fc17 --- /dev/null +++ b/src/plugins/visualizations/public/wizard/search_selection/show_saved_object.test.ts @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { SimpleSavedObject } from '@kbn/core/public'; +import type { FinderAttributes } from '@kbn/saved-objects-plugin/public'; +import { showSavedObject } from './show_saved_object'; + +describe('showSavedObject', () => { + it('should return true if the saved object is not a text based query', () => { + const savedObject = { + attributes: { isTextBasedQuery: false }, + }; + expect(showSavedObject(savedObject as unknown as SimpleSavedObject)).toBe( + true + ); + }); + + it('should return false if the saved object is a text based query', () => { + const savedObject = { + attributes: { isTextBasedQuery: true }, + }; + expect(showSavedObject(savedObject as unknown as SimpleSavedObject)).toBe( + false + ); + }); + + it('should return true if the saved object is not of an adhoc data view', () => { + const savedObject = { + attributes: { usesAdHocDataView: false }, + }; + expect(showSavedObject(savedObject as unknown as SimpleSavedObject)).toBe( + true + ); + }); + + it('should return false if the saved object is of an adhoc data view', () => { + const savedObject = { + attributes: { usesAdHocDataView: true }, + }; + expect(showSavedObject(savedObject as unknown as SimpleSavedObject)).toBe( + false + ); + }); +}); diff --git a/src/plugins/visualizations/public/wizard/search_selection/show_saved_object.ts b/src/plugins/visualizations/public/wizard/search_selection/show_saved_object.ts new file mode 100644 index 0000000000000..d3d2c15b72004 --- /dev/null +++ b/src/plugins/visualizations/public/wizard/search_selection/show_saved_object.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { SimpleSavedObject, SavedObjectAttributes } from '@kbn/core/public'; +import type { FinderAttributes } from '@kbn/saved-objects-plugin/public'; + +export interface SavedSearchesAttributes extends SavedObjectAttributes { + isTextBasedQuery: boolean; + usesAdHocDataView?: boolean; +} + +export const showSavedObject = (savedObject: SimpleSavedObject) => { + const so = savedObject as unknown as SimpleSavedObject; + return !so.attributes.isTextBasedQuery && !so.attributes.usesAdHocDataView; +};