diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.extractsearchsourcereferences.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.extractsearchsourcereferences.md
new file mode 100644
index 0000000000000..cd051cfeca6b0
--- /dev/null
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.extractsearchsourcereferences.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [extractSearchSourceReferences](./kibana-plugin-plugins-data-public.extractsearchsourcereferences.md)
+
+## extractSearchSourceReferences variable
+
+Signature:
+
+```typescript
+extractReferences: (state: SearchSourceFields) => [SearchSourceFields & {
+ indexRefName?: string | undefined;
+}, SavedObjectReference[]]
+```
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.injectsearchsourcereferences.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.injectsearchsourcereferences.md
new file mode 100644
index 0000000000000..b55f5b866244d
--- /dev/null
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.injectsearchsourcereferences.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [injectSearchSourceReferences](./kibana-plugin-plugins-data-public.injectsearchsourcereferences.md)
+
+## injectSearchSourceReferences variable
+
+Signature:
+
+```typescript
+injectReferences: (searchSourceFields: SearchSourceFields & {
+ indexRefName: string;
+}, references: SavedObjectReference[]) => SearchSourceFields
+```
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md
index 8b58957b9044a..02cc34baf7c45 100644
--- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md
@@ -101,11 +101,14 @@
| [esFilters](./kibana-plugin-plugins-data-public.esfilters.md) | |
| [esKuery](./kibana-plugin-plugins-data-public.eskuery.md) | |
| [esQuery](./kibana-plugin-plugins-data-public.esquery.md) | |
+| [extractSearchSourceReferences](./kibana-plugin-plugins-data-public.extractsearchsourcereferences.md) | |
| [fieldFormats](./kibana-plugin-plugins-data-public.fieldformats.md) | |
| [FilterBar](./kibana-plugin-plugins-data-public.filterbar.md) | |
| [getIndexPatternFieldListCreator](./kibana-plugin-plugins-data-public.getindexpatternfieldlistcreator.md) | |
| [getKbnTypeNames](./kibana-plugin-plugins-data-public.getkbntypenames.md) | Get the esTypes known by all kbnFieldTypes {Array} |
| [indexPatterns](./kibana-plugin-plugins-data-public.indexpatterns.md) | |
+| [injectSearchSourceReferences](./kibana-plugin-plugins-data-public.injectsearchsourcereferences.md) | |
+| [parseSearchSourceJSON](./kibana-plugin-plugins-data-public.parsesearchsourcejson.md) | |
| [QueryStringInput](./kibana-plugin-plugins-data-public.querystringinput.md) | |
| [search](./kibana-plugin-plugins-data-public.search.md) | |
| [SearchBar](./kibana-plugin-plugins-data-public.searchbar.md) | |
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.parsesearchsourcejson.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.parsesearchsourcejson.md
new file mode 100644
index 0000000000000..f5014c55fdaab
--- /dev/null
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.parsesearchsourcejson.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [parseSearchSourceJSON](./kibana-plugin-plugins-data-public.parsesearchsourcejson.md)
+
+## parseSearchSourceJSON variable
+
+Signature:
+
+```typescript
+parseSearchSourceJSON: (searchSourceJSON: string) => SearchSourceFields
+```
diff --git a/src/legacy/ui/public/new_platform/__mocks__/helpers.ts b/src/legacy/ui/public/new_platform/__mocks__/helpers.ts
index f9f4494929014..e3aa49baeae0d 100644
--- a/src/legacy/ui/public/new_platform/__mocks__/helpers.ts
+++ b/src/legacy/ui/public/new_platform/__mocks__/helpers.ts
@@ -32,6 +32,7 @@ import { chartPluginMock } from '../../../../../plugins/charts/public/mocks';
import { advancedSettingsMock } from '../../../../../plugins/advanced_settings/public/mocks';
import { savedObjectsManagementPluginMock } from '../../../../../plugins/saved_objects_management/public/mocks';
import { visualizationsPluginMock } from '../../../../../plugins/visualizations/public/mocks';
+import { discoverPluginMock } from '../../../../../plugins/discover/public/mocks';
/* eslint-enable @kbn/eslint/no-restricted-paths */
export const pluginsMock = {
@@ -48,6 +49,7 @@ export const pluginsMock = {
visualizations: visualizationsPluginMock.createSetupContract(),
kibanaLegacy: kibanaLegacyPluginMock.createSetupContract(),
savedObjectsManagement: savedObjectsManagementPluginMock.createSetupContract(),
+ discover: discoverPluginMock.createSetupContract(),
}),
createStart: () => ({
data: dataPluginMock.createStartContract(),
@@ -62,6 +64,7 @@ export const pluginsMock = {
visualizations: visualizationsPluginMock.createStartContract(),
kibanaLegacy: kibanaLegacyPluginMock.createStartContract(),
savedObjectsManagement: savedObjectsManagementPluginMock.createStartContract(),
+ discover: discoverPluginMock.createStartContract(),
}),
};
diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js
index 3caba24748bfa..332a0a0f9ca6e 100644
--- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js
+++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js
@@ -515,6 +515,7 @@ export const npStart = {
docViews: {
DocViewer: () => null,
},
+ savedSearchLoader: {},
},
},
};
diff --git a/src/legacy/ui/public/new_platform/set_services.ts b/src/legacy/ui/public/new_platform/set_services.ts
index 400f31e73ffa1..9cacb0c09d79a 100644
--- a/src/legacy/ui/public/new_platform/set_services.ts
+++ b/src/legacy/ui/public/new_platform/set_services.ts
@@ -57,6 +57,7 @@ export function setStartServices(npStart: NpStart) {
dataServices.setIndexPatterns(npStart.plugins.data.indexPatterns);
dataServices.setQueryService(npStart.plugins.data.query);
dataServices.setSearchService(npStart.plugins.data.search);
+
visualizationsServices.setI18n(npStart.core.i18n);
visualizationsServices.setTypes(
pick(npStart.plugins.visualizations, ['get', 'all', 'getAliases'])
@@ -82,4 +83,5 @@ export function setStartServices(npStart: NpStart) {
visualizationTypes: visualizationsServices.getTypes(),
});
visualizationsServices.setSavedVisualizationsLoader(savedVisualizationsLoader);
+ visualizationsServices.setSavedSearchLoader(npStart.plugins.discover.savedSearchLoader);
}
diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts
index 69dd97a881797..4a5b3fd5714db 100644
--- a/src/plugins/data/public/index.ts
+++ b/src/plugins/data/public/index.ts
@@ -358,6 +358,9 @@ export {
SearchResponse,
SearchError,
ISearchSource,
+ parseSearchSourceJSON,
+ injectSearchSourceReferences,
+ extractSearchSourceReferences,
SearchSourceFields,
EsQuerySortValue,
SortDirection,
diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md
index ee56ad60441f4..e157d2ac6a522 100644
--- a/src/plugins/data/public/public.api.md
+++ b/src/plugins/data/public/public.api.md
@@ -46,7 +46,6 @@ import * as React_2 from 'react';
import { Required } from '@kbn/utility-types';
import * as Rx from 'rxjs';
import { SavedObject as SavedObject_2 } from 'src/core/public';
-import { SavedObjectReference } from 'kibana/public';
import { SavedObjectsClientContract } from 'src/core/public';
import { SearchParams } from 'elasticsearch';
import { SearchResponse as SearchResponse_2 } from 'elasticsearch';
@@ -420,6 +419,14 @@ export type ExistsFilter = Filter & {
exists?: FilterExistsProperty;
};
+// Warning: (ae-forgotten-export) The symbol "SavedObjectReference" needs to be exported by the entry point index.d.ts
+// Warning: (ae-missing-release-tag) "extractReferences" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public (undocumented)
+export const extractSearchSourceReferences: (state: SearchSourceFields) => [SearchSourceFields & {
+ indexRefName?: string | undefined;
+}, SavedObjectReference[]];
+
// Warning: (ae-missing-release-tag) "FetchOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
@@ -1059,6 +1066,13 @@ export interface IndexPatternTypeMeta {
aggs?: Record;
}
+// Warning: (ae-missing-release-tag) "injectReferences" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public (undocumented)
+export const injectSearchSourceReferences: (searchSourceFields: SearchSourceFields & {
+ indexRefName: string;
+}, references: SavedObjectReference[]) => SearchSourceFields;
+
// Warning: (ae-missing-release-tag) "InputTimeRange" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
@@ -1273,6 +1287,11 @@ export interface OptionedValueProp {
// @public (undocumented)
export type ParsedInterval = ReturnType;
+// Warning: (ae-missing-release-tag) "parseSearchSourceJSON" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public (undocumented)
+export const parseSearchSourceJSON: (searchSourceJSON: string) => SearchSourceFields;
+
// Warning: (ae-missing-release-tag) "PhraseFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
@@ -1809,20 +1828,20 @@ export type TSearchStrategyProvider = (context: ISearc
// src/plugins/data/public/index.ts:237:27 - (ae-forgotten-export) The symbol "getFromSavedObject" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:237:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:237:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:374:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:374:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:374:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:374:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:376:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:377:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:386:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:387:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:388:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:392:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:393:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:396:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:397:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts
-// src/plugins/data/public/index.ts:400:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:377:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:377:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:377:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:377:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:379:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:380:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:389:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:390:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:391:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:395:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:396:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:399:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:400:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts
+// src/plugins/data/public/index.ts:403:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/query/state_sync/connect_to_query_state.ts:33:33 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/query/state_sync/connect_to_query_state.ts:37:1 - (ae-forgotten-export) The symbol "QueryStateChange" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickAction" needs to be exported by the entry point index.d.ts
diff --git a/src/plugins/data/public/search/expressions/esaggs.ts b/src/plugins/data/public/search/expressions/esaggs.ts
index eec75b0841133..d6901da99319a 100644
--- a/src/plugins/data/public/search/expressions/esaggs.ts
+++ b/src/plugins/data/public/search/expressions/esaggs.ts
@@ -282,7 +282,7 @@ export const esaggs = (): ExpressionFunctionDefinition {
},
search,
searchSource: {
- create: (fields?: SearchSourceFields) => new SearchSource(fields, searchSourceDependencies),
- fromJSON: createSearchSourceFromJSON(dependencies.indexPatterns, searchSourceDependencies),
+ create: createSearchSource(dependencies.indexPatterns, searchSourceDependencies),
+ createEmpty: () => {
+ return new SearchSource({}, searchSourceDependencies);
+ },
},
setInterceptor: (searchInterceptor: SearchInterceptor) => {
// TODO: should an intercepror have a destroy method?
diff --git a/src/plugins/data/public/search/search_source/create_search_source.test.ts b/src/plugins/data/public/search/search_source/create_search_source.test.ts
index efa63b0722e28..23ab5979595af 100644
--- a/src/plugins/data/public/search/search_source/create_search_source.test.ts
+++ b/src/plugins/data/public/search/search_source/create_search_source.test.ts
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { createSearchSourceFromJSON } from './create_search_source';
+import { createSearchSource as createSearchSourceFactory } from './create_search_source';
import { IIndexPattern } from '../../../common/index_patterns';
import { IndexPatternsContract } from '../../index_patterns/index_patterns';
import { Filter } from '../../../common/es_query/filters';
@@ -27,7 +27,7 @@ describe('createSearchSource', () => {
const indexPatternMock: IIndexPattern = {} as IIndexPattern;
let indexPatternContractMock: jest.Mocked;
let dependencies: any;
- let createSearchSource: ReturnType;
+ let createSearchSource: ReturnType;
beforeEach(() => {
const core = coreMock.createStart();
@@ -43,27 +43,17 @@ describe('createSearchSource', () => {
get: jest.fn().mockReturnValue(Promise.resolve(indexPatternMock)),
} as unknown) as jest.Mocked;
- createSearchSource = createSearchSourceFromJSON(indexPatternContractMock, dependencies);
+ createSearchSource = createSearchSourceFactory(indexPatternContractMock, dependencies);
});
- test('should fail if JSON is invalid', () => {
- expect(createSearchSource('{', [])).rejects.toThrow();
- expect(createSearchSource('0', [])).rejects.toThrow();
- expect(createSearchSource('"abcdefg"', [])).rejects.toThrow();
- });
-
- test('should set fields', async () => {
- const searchSource = await createSearchSource(
- JSON.stringify({
- highlightAll: true,
- query: {
- query: '',
- language: 'kuery',
- },
- }),
- []
- );
-
+ it('should set fields', async () => {
+ const searchSource = await createSearchSource({
+ highlightAll: true,
+ query: {
+ query: '',
+ language: 'kuery',
+ },
+ });
expect(searchSource.getOwnField('highlightAll')).toBe(true);
expect(searchSource.getOwnField('query')).toEqual({
query: '',
@@ -71,66 +61,32 @@ describe('createSearchSource', () => {
});
});
- test('should resolve referenced index pattern', async () => {
- const searchSource = await createSearchSource(
- JSON.stringify({
- indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index',
- }),
- [
+ it('should set filters and resolve referenced index patterns', async () => {
+ const searchSource = await createSearchSource({
+ filter: [
{
- id: '123-456',
- type: 'index-pattern',
- name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
- },
- ]
- );
-
- expect(indexPatternContractMock.get).toHaveBeenCalledWith('123-456');
- expect(searchSource.getOwnField('index')).toBe(indexPatternMock);
- });
-
- test('should set filters and resolve referenced index patterns', async () => {
- const searchSource = await createSearchSource(
- JSON.stringify({
- filter: [
- {
- meta: {
- alias: null,
- negate: false,
- disabled: false,
- type: 'phrase',
- key: 'category.keyword',
- params: {
- query: "Men's Clothing",
- },
- indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index',
+ meta: {
+ alias: null,
+ negate: false,
+ disabled: false,
+ type: 'phrase',
+ key: 'category.keyword',
+ params: {
+ query: "Men's Clothing",
},
- query: {
- match_phrase: {
- 'category.keyword': "Men's Clothing",
- },
- },
- $state: {
- store: 'appState',
+ index: '123-456',
+ },
+ query: {
+ match_phrase: {
+ 'category.keyword': "Men's Clothing",
},
},
- ],
- }),
- [
- {
- id: '123-456',
- type: 'index-pattern',
- name: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index',
},
- ]
- );
+ ],
+ });
const filters = searchSource.getOwnField('filter') as Filter[];
-
expect(filters[0]).toMatchInlineSnapshot(`
Object {
- "$state": Object {
- "store": "appState",
- },
"meta": Object {
"alias": null,
"disabled": false,
@@ -151,15 +107,11 @@ describe('createSearchSource', () => {
`);
});
- test('should migrate legacy queries on the fly', async () => {
- const searchSource = await createSearchSource(
- JSON.stringify({
- highlightAll: true,
- query: 'a:b',
- }),
- []
- );
-
+ it('should migrate legacy queries on the fly', async () => {
+ const searchSource = await createSearchSource({
+ highlightAll: true,
+ query: 'a:b' as any,
+ });
expect(searchSource.getOwnField('query')).toEqual({
query: 'a:b',
language: 'lucene',
diff --git a/src/plugins/data/public/search/search_source/create_search_source.ts b/src/plugins/data/public/search/search_source/create_search_source.ts
index cc98f433b3a03..3466d60e5dd7e 100644
--- a/src/plugins/data/public/search/search_source/create_search_source.ts
+++ b/src/plugins/data/public/search/search_source/create_search_source.ts
@@ -16,11 +16,8 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { transform, defaults, isFunction } from 'lodash';
-import { SavedObjectReference } from 'kibana/public';
import { migrateLegacyQuery } from '../../../../kibana_legacy/public';
-import { InvalidJSONProperty } from '../../../../kibana_utils/public';
-import { SearchSourceDependencies, SearchSource, ISearchSource } from './search_source';
+import { SearchSource, SearchSourceDependencies } from './search_source';
import { IndexPatternsContract } from '../../index_patterns/index_patterns';
import { SearchSourceFields } from './types';
@@ -33,6 +30,7 @@ import { SearchSourceFields } from './types';
* the start contract of the data plugin as part of the search service
*
* @param indexPatterns The index patterns contract of the data plugin
+ * @param searchSourceDependencies
*
* @return Wired utility function taking two parameters `searchSourceJson`, the json string
* returned by `serializeSearchSource` and `references`, a list of references including the ones
@@ -40,73 +38,20 @@ import { SearchSourceFields } from './types';
*
*
* @public */
-export const createSearchSourceFromJSON = (
+export const createSearchSource = (
indexPatterns: IndexPatternsContract,
searchSourceDependencies: SearchSourceDependencies
-) => async (
- searchSourceJson: string,
- references: SavedObjectReference[]
-): Promise => {
- const searchSource = new SearchSource({}, searchSourceDependencies);
+) => async (searchSourceFields: SearchSourceFields = {}) => {
+ const fields = { ...searchSourceFields };
- // if we have a searchSource, set its values based on the searchSourceJson field
- let searchSourceValues: Record;
- try {
- searchSourceValues = JSON.parse(searchSourceJson);
- } catch (e) {
- throw new InvalidJSONProperty(
- `Invalid JSON in search source. ${e.message} JSON: ${searchSourceJson}`
- );
+ // hydrating index pattern
+ if (fields.index && typeof fields.index === 'string') {
+ fields.index = await indexPatterns.get(searchSourceFields.index as any);
}
- // This detects a scenario where documents with invalid JSON properties have been imported into the saved object index.
- // (This happened in issue #20308)
- if (!searchSourceValues || typeof searchSourceValues !== 'object') {
- throw new InvalidJSONProperty('Invalid JSON in search source.');
- }
-
- // Inject index id if a reference is saved
- if (searchSourceValues.indexRefName) {
- const reference = references.find(ref => ref.name === searchSourceValues.indexRefName);
- if (!reference) {
- throw new Error(`Could not find reference for ${searchSourceValues.indexRefName}`);
- }
- searchSourceValues.index = reference.id;
- delete searchSourceValues.indexRefName;
- }
-
- if (searchSourceValues.filter && Array.isArray(searchSourceValues.filter)) {
- searchSourceValues.filter.forEach((filterRow: any) => {
- if (!filterRow.meta || !filterRow.meta.indexRefName) {
- return;
- }
- const reference = references.find((ref: any) => ref.name === filterRow.meta.indexRefName);
- if (!reference) {
- throw new Error(`Could not find reference for ${filterRow.meta.indexRefName}`);
- }
- filterRow.meta.index = reference.id;
- delete filterRow.meta.indexRefName;
- });
- }
-
- if (searchSourceValues.index && typeof searchSourceValues.index === 'string') {
- searchSourceValues.index = await indexPatterns.get(searchSourceValues.index);
- }
-
- const searchSourceFields = searchSource.getFields();
- const fnProps = transform(
- searchSourceFields,
- function(dynamic, val, name) {
- if (isFunction(val) && name) dynamic[name] = val;
- },
- {}
- );
-
- // This assignment might hide problems because the type of values passed from the parsed JSON
- // might not fit the SearchSourceFields interface.
- const newFields: SearchSourceFields = defaults(searchSourceValues, fnProps);
+ const searchSource = new SearchSource(fields, searchSourceDependencies);
- searchSource.setFields(newFields);
+ // todo: move to migration script .. create issue
const query = searchSource.getOwnField('query');
if (typeof query !== 'undefined') {
diff --git a/src/plugins/data/public/search/search_source/extract_references.ts b/src/plugins/data/public/search/search_source/extract_references.ts
new file mode 100644
index 0000000000000..f9987767a9688
--- /dev/null
+++ b/src/plugins/data/public/search/search_source/extract_references.ts
@@ -0,0 +1,70 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { SavedObjectReference } from '../../../../../core/types';
+import { Filter } from '../../../common/es_query/filters';
+import { SearchSourceFields } from './types';
+
+export const extractReferences = (
+ state: SearchSourceFields
+): [SearchSourceFields & { indexRefName?: string }, SavedObjectReference[]] => {
+ let searchSourceFields: SearchSourceFields & { indexRefName?: string } = { ...state };
+ const references: SavedObjectReference[] = [];
+ if (searchSourceFields.index) {
+ const indexId = searchSourceFields.index.id || ((searchSourceFields.index as any) as string);
+ const refName = 'kibanaSavedObjectMeta.searchSourceJSON.index';
+ references.push({
+ name: refName,
+ type: 'index-pattern',
+ id: indexId,
+ });
+ searchSourceFields = {
+ ...searchSourceFields,
+ indexRefName: refName,
+ index: undefined,
+ };
+ }
+
+ if (searchSourceFields.filter) {
+ searchSourceFields = {
+ ...searchSourceFields,
+ filter: (searchSourceFields.filter as Filter[]).map((filterRow, i) => {
+ if (!filterRow.meta || !filterRow.meta.index) {
+ return filterRow;
+ }
+ const refName = `kibanaSavedObjectMeta.searchSourceJSON.filter[${i}].meta.index`;
+ references.push({
+ name: refName,
+ type: 'index-pattern',
+ id: filterRow.meta.index,
+ });
+ return {
+ ...filterRow,
+ meta: {
+ ...filterRow.meta,
+ indexRefName: refName,
+ index: undefined,
+ },
+ };
+ }),
+ };
+ }
+
+ return [searchSourceFields, references];
+};
diff --git a/src/plugins/data/public/search/search_source/index.ts b/src/plugins/data/public/search/search_source/index.ts
index 9c4106b2dc616..48c0338f7e981 100644
--- a/src/plugins/data/public/search/search_source/index.ts
+++ b/src/plugins/data/public/search/search_source/index.ts
@@ -18,5 +18,8 @@
*/
export { SearchSource, ISearchSource, SearchSourceDependencies } from './search_source';
-export { createSearchSourceFromJSON } from './create_search_source';
+export { createSearchSource } from './create_search_source';
export { SortDirection, EsQuerySortValue, SearchSourceFields } from './types';
+export { injectReferences } from './inject_references';
+export { extractReferences } from './extract_references';
+export { parseSearchSourceJSON } from './parse_json';
diff --git a/src/plugins/data/public/search/search_source/inject_references.ts b/src/plugins/data/public/search/search_source/inject_references.ts
new file mode 100644
index 0000000000000..a567c33d2280b
--- /dev/null
+++ b/src/plugins/data/public/search/search_source/inject_references.ts
@@ -0,0 +1,55 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { SearchSourceFields } from './types';
+import { SavedObjectReference } from '../../../../../core/types';
+
+export const injectReferences = (
+ searchSourceFields: SearchSourceFields & { indexRefName: string },
+ references: SavedObjectReference[]
+) => {
+ const searchSourceReturnFields: SearchSourceFields = { ...searchSourceFields };
+ // Inject index id if a reference is saved
+ if (searchSourceFields.indexRefName) {
+ const reference = references.find(ref => ref.name === searchSourceFields.indexRefName);
+ if (!reference) {
+ throw new Error(`Could not find reference for ${searchSourceFields.indexRefName}`);
+ }
+ // @ts-ignore
+ searchSourceReturnFields.index = reference.id;
+ // @ts-ignore
+ delete searchSourceReturnFields.indexRefName;
+ }
+
+ if (searchSourceReturnFields.filter && Array.isArray(searchSourceReturnFields.filter)) {
+ searchSourceReturnFields.filter.forEach((filterRow: any) => {
+ if (!filterRow.meta || !filterRow.meta.indexRefName) {
+ return;
+ }
+ const reference = references.find((ref: any) => ref.name === filterRow.meta.indexRefName);
+ if (!reference) {
+ throw new Error(`Could not find reference for ${filterRow.meta.indexRefName}`);
+ }
+ filterRow.meta.index = reference.id;
+ delete filterRow.meta.indexRefName;
+ });
+ }
+
+ return searchSourceReturnFields;
+};
diff --git a/src/plugins/data/public/search/search_source/mocks.ts b/src/plugins/data/public/search/search_source/mocks.ts
index 157331ea87bb0..cf2d009e41b54 100644
--- a/src/plugins/data/public/search/search_source/mocks.ts
+++ b/src/plugins/data/public/search/search_source/mocks.ts
@@ -43,12 +43,13 @@ export const searchSourceInstanceMock: MockedKeys = {
getSearchRequestBody: jest.fn(),
destroy: jest.fn(),
history: [],
+ getSerializedFields: jest.fn(),
serialize: jest.fn(),
};
export const searchSourceMock = {
create: jest.fn().mockReturnValue(searchSourceInstanceMock),
- fromJSON: jest.fn().mockReturnValue(searchSourceInstanceMock),
+ createEmpty: jest.fn().mockReturnValue(searchSourceInstanceMock),
};
export const createSearchSourceMock = (fields?: SearchSourceFields) =>
diff --git a/src/plugins/data/public/search/search_source/parse_json.ts b/src/plugins/data/public/search/search_source/parse_json.ts
new file mode 100644
index 0000000000000..f0eb377cedc77
--- /dev/null
+++ b/src/plugins/data/public/search/search_source/parse_json.ts
@@ -0,0 +1,41 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { SearchSourceFields } from './types';
+import { InvalidJSONProperty } from '../../../../kibana_utils/public';
+
+export const parseSearchSourceJSON = (searchSourceJSON: string) => {
+ // if we have a searchSource, set its values based on the searchSourceJson field
+ let searchSourceValues: SearchSourceFields;
+ try {
+ searchSourceValues = JSON.parse(searchSourceJSON);
+ } catch (e) {
+ throw new InvalidJSONProperty(
+ `Invalid JSON in search source. ${e.message} JSON: ${searchSourceJSON}`
+ );
+ }
+
+ // This detects a scenario where documents with invalid JSON properties have been imported into the saved object index.
+ // (This happened in issue #20308)
+ if (!searchSourceValues || typeof searchSourceValues !== 'object') {
+ throw new InvalidJSONProperty('Invalid JSON in search source.');
+ }
+
+ return searchSourceValues;
+};
diff --git a/src/plugins/data/public/search/search_source/search_source.ts b/src/plugins/data/public/search/search_source/search_source.ts
index 091a27a6f418d..acbb193807623 100644
--- a/src/plugins/data/public/search/search_source/search_source.ts
+++ b/src/plugins/data/public/search/search_source/search_source.ts
@@ -69,9 +69,9 @@
* `appSearchSource`.
*/
-import { uniqueId, uniq, extend, pick, difference, set, omit, keys, isFunction } from 'lodash';
+import { uniqueId, uniq, extend, pick, difference, omit, set, keys, isFunction } from 'lodash';
import { map } from 'rxjs/operators';
-import { CoreStart, SavedObjectReference } from 'kibana/public';
+import { CoreStart } from 'kibana/public';
import { normalizeSortRequest } from './normalize_sort_request';
import { filterDocvalueFields } from './filter_docvalue_fields';
import { fieldWildcardFilter } from '../../../../kibana_utils/public';
@@ -82,6 +82,7 @@ import { FetchOptions, RequestFailure, getSearchParams, handleResponse } from '.
import { getEsQueryConfig, buildEsQuery, Filter } from '../../../common';
import { getHighlightRequest } from '../../../common/field_formats';
import { fetchSoon } from '../legacy';
+import { extractReferences } from './extract_references';
import { ISearchStartLegacy } from '../types';
export interface SearchSourceDependencies {
@@ -450,6 +451,25 @@ export class SearchSource {
return searchRequest;
}
+ public getSerializedFields() {
+ const { filter: originalFilters, ...searchSourceFields } = omit(this.getFields(), [
+ 'sort',
+ 'size',
+ ]);
+ let serializedSearchSourceFields: SearchSourceFields = {
+ ...searchSourceFields,
+ index: searchSourceFields.index ? searchSourceFields.index.id : undefined,
+ };
+ if (originalFilters) {
+ const filters = this.getFilters(originalFilters);
+ serializedSearchSourceFields = {
+ ...serializedSearchSourceFields,
+ filter: filters,
+ };
+ }
+ return serializedSearchSourceFields;
+ }
+
/**
* Serializes the instance to a JSON string and a set of referenced objects.
* Use this method to get a representation of the search source which can be stored in a saved object.
@@ -461,57 +481,8 @@ export class SearchSource {
* Using `createSearchSource`, the instance can be re-created.
* @public */
public serialize() {
- const references: SavedObjectReference[] = [];
-
- const {
- filter: originalFilters,
- ...searchSourceFields
- }: Omit = omit(this.getFields(), ['sort', 'size']);
- let serializedSearchSourceFields: Omit & {
- indexRefName?: string;
- filter?: Array & { meta: Filter['meta'] & { indexRefName?: string } }>;
- } = searchSourceFields;
- if (searchSourceFields.index) {
- const indexId = searchSourceFields.index.id!;
- const refName = 'kibanaSavedObjectMeta.searchSourceJSON.index';
- references.push({
- name: refName,
- type: 'index-pattern',
- id: indexId,
- });
- serializedSearchSourceFields = {
- ...serializedSearchSourceFields,
- indexRefName: refName,
- index: undefined,
- };
- }
- if (originalFilters) {
- const filters = this.getFilters(originalFilters);
- serializedSearchSourceFields = {
- ...serializedSearchSourceFields,
- filter: filters.map((filterRow, i) => {
- if (!filterRow.meta || !filterRow.meta.index) {
- return filterRow;
- }
- const refName = `kibanaSavedObjectMeta.searchSourceJSON.filter[${i}].meta.index`;
- references.push({
- name: refName,
- type: 'index-pattern',
- id: filterRow.meta.index,
- });
- return {
- ...filterRow,
- meta: {
- ...filterRow.meta,
- indexRefName: refName,
- index: undefined,
- },
- };
- }),
- };
- }
-
- return { searchSourceJSON: JSON.stringify(serializedSearchSourceFields), references };
+ const [searchSourceFields, references] = extractReferences(this.getSerializedFields());
+ return { searchSourceJSON: JSON.stringify(searchSourceFields), references };
}
private getFilters(filterField: SearchSourceFields['filter']): Filter[] {
diff --git a/src/plugins/data/public/search/types.ts b/src/plugins/data/public/search/types.ts
index 1687c8f983393..64b4f1c5c2983 100644
--- a/src/plugins/data/public/search/types.ts
+++ b/src/plugins/data/public/search/types.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import { CoreStart, SavedObjectReference } from 'kibana/public';
+import { CoreStart } from 'kibana/public';
import { SearchAggsSetup, SearchAggsStart } from './aggs';
import { ISearch, ISearchGeneric } from './i_search';
import { TStrategyTypes } from './strategy_types';
@@ -82,11 +82,8 @@ export interface ISearchStart {
setInterceptor: (searchInterceptor: SearchInterceptor) => void;
search: ISearchGeneric;
searchSource: {
- create: (fields?: SearchSourceFields) => ISearchSource;
- fromJSON: (
- searchSourceJson: string,
- references: SavedObjectReference[]
- ) => Promise;
+ create: (fields?: SearchSourceFields) => Promise;
+ createEmpty: () => ISearchSource;
};
__LEGACY: ISearchStartLegacy;
}
diff --git a/src/plugins/discover/public/application/angular/context/api/context.ts b/src/plugins/discover/public/application/angular/context/api/context.ts
index 0bca820f9a723..a47005b640538 100644
--- a/src/plugins/discover/public/application/angular/context/api/context.ts
+++ b/src/plugins/discover/public/application/angular/context/api/context.ts
@@ -113,8 +113,8 @@ function fetchContextProvider(indexPatterns: IndexPatternsContract) {
async function createSearchSource(indexPattern: IndexPattern, filters: Filter[]) {
const { data } = getServices();
- return data.search.searchSource
- .create()
+ const searchSource = await data.search.searchSource.create();
+ return searchSource
.setParent(undefined)
.setField('index', indexPattern)
.setField('filter', filters);
diff --git a/src/plugins/discover/public/application/angular/context/query/actions.js b/src/plugins/discover/public/application/angular/context/query/actions.js
index 1b1fa7138bfda..6f8d5fe64f831 100644
--- a/src/plugins/discover/public/application/angular/context/query/actions.js
+++ b/src/plugins/discover/public/application/angular/context/query/actions.js
@@ -30,7 +30,7 @@ import { MarkdownSimple } from '../../../../../../kibana_react/public';
export function QueryActionsProvider(Promise) {
const { filterManager, indexPatterns, data } = getServices();
- const fetchAnchor = fetchAnchorProvider(indexPatterns, data.search.searchSource.create());
+ const fetchAnchor = fetchAnchorProvider(indexPatterns, data.search.searchSource.createEmpty());
const { fetchSurroundingDocs } = fetchContextProvider(indexPatterns);
const { setPredecessorCount, setQueryParameters, setSuccessorCount } = getQueryParameterActions(
filterManager,
diff --git a/src/plugins/discover/public/application/angular/discover.js b/src/plugins/discover/public/application/angular/discover.js
index 2afd0322f8701..b6076f338d63f 100644
--- a/src/plugins/discover/public/application/angular/discover.js
+++ b/src/plugins/discover/public/application/angular/discover.js
@@ -1021,7 +1021,7 @@ function discoverController(
},
];
- $scope.vis = visualizations.createVis('histogram', {
+ $scope.vis = await visualizations.createVis('histogram', {
title: savedSearch.title,
params: {
addLegend: false,
@@ -1029,8 +1029,7 @@ function discoverController(
},
data: {
aggs: visStateAggs,
- indexPattern: $scope.searchSource.getField('index').id,
- searchSource: $scope.searchSource,
+ searchSource: $scope.searchSource.getSerializedFields(),
},
});
diff --git a/src/plugins/discover/public/mocks.ts b/src/plugins/discover/public/mocks.ts
index dd7da5e8bc254..c394fe2c11a71 100644
--- a/src/plugins/discover/public/mocks.ts
+++ b/src/plugins/discover/public/mocks.ts
@@ -33,9 +33,7 @@ const createSetupContract = (): Setup => {
const createStartContract = (): Start => {
const startContract: Start = {
- savedSearches: {
- createLoader: jest.fn(),
- },
+ savedSearchLoader: {} as any,
};
return startContract;
};
diff --git a/src/plugins/discover/public/plugin.ts b/src/plugins/discover/public/plugin.ts
index 807365cb26dc0..032483e4e34ba 100644
--- a/src/plugins/discover/public/plugin.ts
+++ b/src/plugins/discover/public/plugin.ts
@@ -39,7 +39,7 @@ import { KibanaLegacySetup, AngularRenderedAppUpdater } from 'src/plugins/kibana
import { HomePublicPluginSetup } from 'src/plugins/home/public';
import { Start as InspectorPublicPluginStart } from 'src/plugins/inspector/public';
import { DataPublicPluginStart, DataPublicPluginSetup, esFilters } from '../../data/public';
-import { SavedObjectLoader, SavedObjectKibanaServices } from '../../saved_objects/public';
+import { SavedObjectLoader } from '../../saved_objects/public';
import { createKbnUrlTracker } from '../../kibana_utils/public';
import { DocViewInput, DocViewInputFn } from './application/doc_views/doc_views_types';
@@ -73,13 +73,7 @@ export interface DiscoverSetup {
}
export interface DiscoverStart {
- savedSearches: {
- /**
- * Create a {@link SavedObjectLoader | loader} to handle the saved searches type.
- * @param services
- */
- createLoader(services: SavedObjectKibanaServices): SavedObjectLoader;
- };
+ savedSearchLoader: SavedObjectLoader;
}
/**
@@ -264,9 +258,13 @@ export class DiscoverPlugin
};
return {
- savedSearches: {
- createLoader: createSavedSearchesLoader,
- },
+ savedSearchLoader: createSavedSearchesLoader({
+ savedObjectsClient: core.savedObjects.client,
+ indexPatterns: plugins.data.indexPatterns,
+ search: plugins.data.search,
+ chrome: core.chrome,
+ overlays: core.overlays,
+ }),
};
}
diff --git a/src/plugins/input_control_vis/public/control/create_search_source.ts b/src/plugins/input_control_vis/public/control/create_search_source.ts
index d6772a7cba5b8..6cd16161c8a87 100644
--- a/src/plugins/input_control_vis/public/control/create_search_source.ts
+++ b/src/plugins/input_control_vis/public/control/create_search_source.ts
@@ -25,7 +25,7 @@ import {
DataPublicPluginStart,
} from 'src/plugins/data/public';
-export function createSearchSource(
+export async function createSearchSource(
{ create }: DataPublicPluginStart['search']['searchSource'],
initialState: SearchSourceFields | null,
indexPattern: IndexPattern,
@@ -34,7 +34,7 @@ export function createSearchSource(
filters: PhraseFilter[] = [],
timefilter: TimefilterContract
) {
- const searchSource = create(initialState || {});
+ const searchSource = await create(initialState || {});
// Do not not inherit from rootSearchSource to avoid picking up time and globals
searchSource.setParent(undefined);
diff --git a/src/plugins/input_control_vis/public/control/list_control_factory.ts b/src/plugins/input_control_vis/public/control/list_control_factory.ts
index 123ef83277e0b..87aa4a2486c49 100644
--- a/src/plugins/input_control_vis/public/control/list_control_factory.ts
+++ b/src/plugins/input_control_vis/public/control/list_control_factory.ts
@@ -147,7 +147,7 @@ export class ListControl extends Control {
direction: 'desc',
query,
});
- const searchSource = createSearchSource(
+ const searchSource = await createSearchSource(
this.searchSource,
initialSearchSourceState,
indexPattern,
diff --git a/src/plugins/input_control_vis/public/control/range_control_factory.ts b/src/plugins/input_control_vis/public/control/range_control_factory.ts
index 326756ad5ffc6..eac79ca5fcca8 100644
--- a/src/plugins/input_control_vis/public/control/range_control_factory.ts
+++ b/src/plugins/input_control_vis/public/control/range_control_factory.ts
@@ -84,7 +84,7 @@ export class RangeControl extends Control {
const fieldName = this.filterManager.fieldName;
const aggs = minMaxAgg(indexPattern.fields.getByName(fieldName));
- const searchSource = createSearchSource(
+ const searchSource = await createSearchSource(
this.searchSource,
null,
indexPattern,
diff --git a/src/plugins/saved_objects/public/saved_object/helpers/apply_es_resp.ts b/src/plugins/saved_objects/public/saved_object/helpers/apply_es_resp.ts
index df687a051fc7d..9d0e25132271c 100644
--- a/src/plugins/saved_objects/public/saved_object/helpers/apply_es_resp.ts
+++ b/src/plugins/saved_objects/public/saved_object/helpers/apply_es_resp.ts
@@ -19,7 +19,11 @@
import _ from 'lodash';
import { EsResponse, SavedObject, SavedObjectConfig, SavedObjectKibanaServices } from '../../types';
import { expandShorthand, SavedObjectNotFound } from '../../../../kibana_utils/public';
-import { IndexPattern } from '../../../../data/public';
+import {
+ IndexPattern,
+ injectSearchSourceReferences,
+ parseSearchSourceJSON,
+} from '../../../../data/public';
/**
* A given response of and ElasticSearch containing a plain saved object is applied to the given
@@ -63,12 +67,21 @@ export async function applyESResp(
_.assign(savedObject, savedObject._source);
savedObject.lastSavedTitle = savedObject.title;
- if (config.searchSource) {
+ if (meta.searchSourceJSON) {
try {
- savedObject.searchSource = await dependencies.search.searchSource.fromJSON(
- meta.searchSourceJSON,
- resp.references
- );
+ let searchSourceValues = parseSearchSourceJSON(meta.searchSourceJSON);
+
+ if (config.searchSource) {
+ searchSourceValues = injectSearchSourceReferences(
+ searchSourceValues as any,
+ resp.references
+ );
+ savedObject.searchSource = await dependencies.search.searchSource.create(
+ searchSourceValues
+ );
+ } else {
+ savedObject.searchSourceFields = searchSourceValues;
+ }
} catch (error) {
if (
error.constructor.name === 'SavedObjectNotFound' &&
diff --git a/src/plugins/saved_objects/public/saved_object/helpers/build_saved_object.ts b/src/plugins/saved_objects/public/saved_object/helpers/build_saved_object.ts
index e5b0e18e7b433..fdc8d79c9428a 100644
--- a/src/plugins/saved_objects/public/saved_object/helpers/build_saved_object.ts
+++ b/src/plugins/saved_objects/public/saved_object/helpers/build_saved_object.ts
@@ -55,7 +55,7 @@ export function buildSavedObject(
savedObject.defaults = config.defaults || {};
// optional search source which this object configures
savedObject.searchSource = config.searchSource
- ? services.search.searchSource.create()
+ ? services.search.searchSource.createEmpty()
: undefined;
// the id of the document
savedObject.id = config.id || void 0;
diff --git a/src/plugins/saved_objects/public/saved_object/helpers/serialize_saved_object.ts b/src/plugins/saved_objects/public/saved_object/helpers/serialize_saved_object.ts
index 78f9eeb8b5fb1..acb371b8af9c2 100644
--- a/src/plugins/saved_objects/public/saved_object/helpers/serialize_saved_object.ts
+++ b/src/plugins/saved_objects/public/saved_object/helpers/serialize_saved_object.ts
@@ -19,6 +19,7 @@
import _ from 'lodash';
import { SavedObject, SavedObjectConfig } from '../../types';
import { expandShorthand } from '../../../../kibana_utils/public';
+import { extractSearchSourceReferences } from '../../../../data/public';
export function serializeSavedObject(savedObject: SavedObject, config: SavedObjectConfig) {
// mapping definition for the fields that this object will expose
@@ -48,6 +49,15 @@ export function serializeSavedObject(savedObject: SavedObject, config: SavedObje
references.push(...searchSourceReferences);
}
+ if (savedObject.searchSourceFields) {
+ const [searchSourceFields, searchSourceReferences] = extractSearchSourceReferences(
+ savedObject.searchSourceFields
+ );
+ const searchSourceJSON = JSON.stringify(searchSourceFields);
+ attributes.kibanaSavedObjectMeta = { searchSourceJSON };
+ references.push(...searchSourceReferences);
+ }
+
if (savedObject.unresolvedIndexPatternReference) {
references.push(savedObject.unresolvedIndexPatternReference);
}
diff --git a/src/plugins/saved_objects/public/saved_object/saved_object.test.ts b/src/plugins/saved_objects/public/saved_object/saved_object.test.ts
index f7e67dbe3ee1d..66587a5d068c9 100644
--- a/src/plugins/saved_objects/public/saved_object/saved_object.test.ts
+++ b/src/plugins/saved_objects/public/saved_object/saved_object.test.ts
@@ -111,6 +111,7 @@ describe('Saved Object', () => {
searchSource: {
...dataStartMock.search.searchSource,
create: createSearchSourceMock,
+ createEmpty: createSearchSourceMock,
},
},
} as unknown) as SavedObjectKibanaServices);
@@ -572,46 +573,50 @@ describe('Saved Object', () => {
});
it('passes references to search source parsing function', async () => {
+ SavedObjectClass = createSavedObjectClass(({
+ savedObjectsClient: savedObjectsClientStub,
+ indexPatterns: dataStartMock.indexPatterns,
+ search: {
+ ...dataStartMock.search,
+ },
+ } as unknown) as SavedObjectKibanaServices);
const savedObject = new SavedObjectClass({ type: 'dashboard', searchSource: true });
- await savedObject.init!();
-
- const searchSourceJSON = JSON.stringify({
- indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index',
- filter: [
- {
- meta: {
- indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index',
+ return savedObject.init!().then(async () => {
+ const searchSourceJSON = JSON.stringify({
+ indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index',
+ filter: [
+ {
+ meta: {
+ indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index',
+ },
+ },
+ ],
+ });
+ const response = {
+ found: true,
+ _source: {
+ kibanaSavedObjectMeta: {
+ searchSourceJSON,
},
},
- ],
- });
- const response = {
- found: true,
- _source: {
- kibanaSavedObjectMeta: {
- searchSourceJSON,
- },
- },
- references: [
- {
- name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
- type: 'index-pattern',
- id: 'my-index-1',
- },
- {
- name: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index',
- type: 'index-pattern',
- id: 'my-index-2',
- },
- ],
- };
- const result = await savedObject.applyESResp(response);
-
- expect(result._source).toEqual({
- kibanaSavedObjectMeta: {
- searchSourceJSON:
- '{"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index","filter":[{"meta":{"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index"}}]}',
- },
+ references: [
+ {
+ name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
+ type: 'index-pattern',
+ id: 'my-index-1',
+ },
+ {
+ name: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index',
+ type: 'index-pattern',
+ id: 'my-index-2',
+ },
+ ],
+ };
+ await savedObject.applyESResp(response);
+ expect(dataStartMock.search.searchSource.create).toBeCalledWith({
+ filter: [{ meta: { index: 'my-index-2' } }],
+ index: 'my-index-1',
+ });
});
});
});
diff --git a/src/plugins/saved_objects/public/types.ts b/src/plugins/saved_objects/public/types.ts
index 3184038040952..973a493c0a15e 100644
--- a/src/plugins/saved_objects/public/types.ts
+++ b/src/plugins/saved_objects/public/types.ts
@@ -29,6 +29,7 @@ import {
IIndexPattern,
IndexPatternsContract,
ISearchSource,
+ SearchSourceFields,
} from '../../data/public';
export interface SavedObject {
@@ -52,6 +53,7 @@ export interface SavedObject {
migrationVersion?: Record;
save: (saveOptions: SavedObjectSaveOpts) => Promise;
searchSource?: ISearchSource;
+ searchSourceFields?: SearchSourceFields;
showInRecentlyAccessed: boolean;
title: string;
unresolvedIndexPatternReference?: SavedObjectReference;
diff --git a/src/plugins/saved_objects_management/public/lib/resolve_saved_objects.ts b/src/plugins/saved_objects_management/public/lib/resolve_saved_objects.ts
index d4764b8949a60..8da8a5b1cebbc 100644
--- a/src/plugins/saved_objects_management/public/lib/resolve_saved_objects.ts
+++ b/src/plugins/saved_objects_management/public/lib/resolve_saved_objects.ts
@@ -21,7 +21,12 @@ import { i18n } from '@kbn/i18n';
import { cloneDeep } from 'lodash';
import { OverlayStart, SavedObjectReference } from 'src/core/public';
import { SavedObject, SavedObjectLoader } from '../../../saved_objects/public';
-import { IndexPatternsContract, IIndexPattern, DataPublicPluginStart } from '../../../data/public';
+import {
+ DataPublicPluginStart,
+ IndexPatternsContract,
+ IIndexPattern,
+ injectSearchSourceReferences,
+} from '../../../data/public';
type SavedObjectsRawDoc = Record;
@@ -207,13 +212,17 @@ export async function resolveIndexPatternConflicts(
return reference;
});
+ const serializedSearchSourceWithInjectedReferences = injectSearchSourceReferences(
+ serializedSearchSource,
+ replacedReferences
+ );
+
if (!allResolved) {
// The user decided to skip this conflict so do nothing
return;
}
- obj.searchSource = await dependencies.search.searchSource.fromJSON(
- JSON.stringify(serializedSearchSource),
- replacedReferences
+ obj.searchSource = await dependencies.search.searchSource.create(
+ serializedSearchSourceWithInjectedReferences
);
if (await saveObject(obj, overwriteAll)) {
importCount++;
diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap
index 3b7f48f366400..25362c067b4f9 100644
--- a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap
+++ b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap
@@ -280,7 +280,7 @@ exports[`SavedObjectsTable import should show the flyout 1`] = `
"search": [MockFunction],
"searchSource": Object {
"create": [MockFunction],
- "fromJSON": [MockFunction],
+ "createEmpty": [MockFunction],
},
"setInterceptor": [MockFunction],
}
diff --git a/src/plugins/saved_objects_management/public/register_services.ts b/src/plugins/saved_objects_management/public/register_services.ts
index a34b632b78f6c..320169fb01b35 100644
--- a/src/plugins/saved_objects_management/public/register_services.ts
+++ b/src/plugins/saved_objects_management/public/register_services.ts
@@ -25,7 +25,7 @@ export const registerServices = async (
registry: ISavedObjectsManagementServiceRegistry,
getStartServices: StartServicesAccessor
) => {
- const [coreStart, { dashboard, data, visualizations, discover }] = await getStartServices();
+ const [, { dashboard, visualizations, discover }] = await getStartServices();
if (dashboard) {
registry.register({
@@ -47,13 +47,7 @@ export const registerServices = async (
registry.register({
id: 'savedSearches',
title: 'searches',
- service: discover.savedSearches.createLoader({
- savedObjectsClient: coreStart.savedObjects.client,
- indexPatterns: data.indexPatterns,
- search: data.search,
- chrome: coreStart.chrome,
- overlays: coreStart.overlays,
- }),
+ service: discover.savedSearchLoader,
});
}
};
diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx b/src/plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx
index c6d43a4ef2f80..6c4a971858840 100644
--- a/src/plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx
+++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx
@@ -122,7 +122,9 @@ export class VisualizeEmbeddableFactory
try {
const savedObject = await savedVisualizations.get(savedObjectId);
- const vis = new Vis(savedObject.visState.type, await convertToSerializedVis(savedObject));
+ const visState = convertToSerializedVis(savedObject);
+ const vis = new Vis(savedObject.visState.type, visState);
+ await vis.setState(visState);
return createVisEmbeddableFromObject(this.deps)(vis, input, parent);
} catch (e) {
console.error(e); // eslint-disable-line no-console
diff --git a/src/plugins/visualizations/public/legacy/build_pipeline.test.ts b/src/plugins/visualizations/public/legacy/build_pipeline.test.ts
index 5476ce6df0390..9130581963800 100644
--- a/src/plugins/visualizations/public/legacy/build_pipeline.test.ts
+++ b/src/plugins/visualizations/public/legacy/build_pipeline.test.ts
@@ -398,6 +398,7 @@ describe('visualize loader pipeline helpers: build pipeline', () => {
return aggs;
},
} as any,
+ searchSource: {} as any,
},
isHierarchical: () => {
return false;
@@ -473,6 +474,7 @@ describe('visualize loader pipeline helpers: build pipeline', () => {
return aggs;
},
} as any,
+ searchSource: {} as any,
},
isHierarchical: () => {
return false;
diff --git a/src/plugins/visualizations/public/plugin.ts b/src/plugins/visualizations/public/plugin.ts
index 29d66ea963a66..1bd50c882e2ca 100644
--- a/src/plugins/visualizations/public/plugin.ts
+++ b/src/plugins/visualizations/public/plugin.ts
@@ -43,6 +43,7 @@ import {
setAggs,
setChrome,
setOverlays,
+ setSavedSearchLoader,
} from './services';
import {
VISUALIZE_EMBEDDABLE_TYPE,
@@ -70,6 +71,7 @@ import {
convertFromSerializedVis,
convertToSerializedVis,
} from './saved_visualizations/_saved_vis';
+import { createSavedSearchesLoader } from '../../discover/public';
/**
* Interface for this plugin's returned setup/start contracts.
@@ -81,7 +83,7 @@ export type VisualizationsSetup = TypesSetup;
export interface VisualizationsStart extends TypesStart {
savedVisualizationsLoader: SavedVisualizationsLoader;
- createVis: (visType: string, visState?: SerializedVis) => Vis;
+ createVis: (visType: string, visState: SerializedVis) => Promise;
convertToSerializedVis: typeof convertToSerializedVis;
convertFromSerializedVis: typeof convertFromSerializedVis;
showNewVisModal: typeof showNewVisModal;
@@ -174,7 +176,14 @@ export class VisualizationsPlugin
visualizationTypes: types,
});
setSavedVisualizationsLoader(savedVisualizationsLoader);
-
+ const savedSearchLoader = createSavedSearchesLoader({
+ savedObjectsClient: core.savedObjects.client,
+ indexPatterns: data.indexPatterns,
+ search: data.search,
+ chrome: core.chrome,
+ overlays: core.overlays,
+ });
+ setSavedSearchLoader(savedSearchLoader);
return {
...types,
showNewVisModal,
@@ -183,7 +192,11 @@ export class VisualizationsPlugin
* @param {IIndexPattern} indexPattern - index pattern to use
* @param {VisState} visState - visualization configuration
*/
- createVis: (visType: string, visState?: SerializedVis) => new Vis(visType, visState),
+ createVis: async (visType: string, visState: SerializedVis) => {
+ const vis = new Vis(visType);
+ await vis.setState(visState);
+ return vis;
+ },
convertToSerializedVis,
convertFromSerializedVis,
savedVisualizationsLoader,
diff --git a/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts b/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts
index 8bc98ca4b4784..81e551b9abdcb 100644
--- a/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts
+++ b/src/plugins/visualizations/public/saved_visualizations/_saved_vis.ts
@@ -32,32 +32,25 @@ import {
// @ts-ignore
import { updateOldState } from '../legacy/vis_update_state';
import { extractReferences, injectReferences } from './saved_visualization_references';
-import { IIndexPattern, ISearchSource } from '../../../../plugins/data/public';
+import { IIndexPattern } from '../../../../plugins/data/public';
import { ISavedVis, SerializedVis } from '../types';
-import { createSavedSearchesLoader } from '../../../../plugins/discover/public';
-import { getChrome, getOverlays, getIndexPatterns, getSavedObjects, getSearch } from '../services';
+import { createSavedSearchesLoader } from '../../../discover/public';
-export const convertToSerializedVis = async (savedVis: ISavedVis): Promise => {
- const { visState } = savedVis;
- const searchSource =
- savedVis.searchSource && (await getSearchSource(savedVis.searchSource, savedVis.savedSearchId));
+export const convertToSerializedVis = (savedVis: ISavedVis): SerializedVis => {
+ const { id, title, description, visState, uiStateJSON, searchSourceFields } = savedVis;
- const indexPattern =
- searchSource && searchSource.getField('index') ? searchSource.getField('index')!.id : undefined;
-
- const aggs = indexPattern ? visState.aggs || [] : visState.aggs;
+ const aggs = searchSourceFields && searchSourceFields.index ? visState.aggs || [] : visState.aggs;
return {
- id: savedVis.id,
- title: savedVis.title,
+ id,
+ title,
type: visState.type,
- description: savedVis.description,
+ description,
params: visState.params,
- uiState: JSON.parse(savedVis.uiStateJSON || '{}'),
+ uiState: JSON.parse(uiStateJSON || '{}'),
data: {
- indexPattern,
aggs,
- searchSource,
+ searchSource: searchSourceFields!,
savedSearchId: savedVis.savedSearchId,
},
};
@@ -74,36 +67,14 @@ export const convertFromSerializedVis = (vis: SerializedVis): ISavedVis => {
params: vis.params,
},
uiStateJSON: JSON.stringify(vis.uiState),
- searchSource: vis.data.searchSource!,
+ searchSourceFields: vis.data.searchSource,
savedSearchId: vis.data.savedSearchId,
};
};
-const getSearchSource = async (inputSearchSource: ISearchSource, savedSearchId?: string) => {
- const search = getSearch();
-
- const searchSource = inputSearchSource.createCopy
- ? inputSearchSource.createCopy()
- : search.searchSource.create({ ...(inputSearchSource as any).fields });
-
- if (savedSearchId) {
- const savedSearch = await createSavedSearchesLoader({
- search,
- savedObjectsClient: getSavedObjects().client,
- indexPatterns: getIndexPatterns(),
- chrome: getChrome(),
- overlays: getOverlays(),
- }).get(savedSearchId);
-
- searchSource.setParent(savedSearch.searchSource);
- }
-
- searchSource!.setField('size', 0);
- return searchSource;
-};
-
export function createSavedVisClass(services: SavedObjectKibanaServices) {
const SavedObjectClass = createSavedObjectClass(services);
+ const savedSearch = createSavedSearchesLoader(services);
class SavedVis extends SavedObjectClass {
public static type: string = 'visualization';
@@ -117,7 +88,6 @@ export function createSavedVisClass(services: SavedObjectKibanaServices) {
};
// Order these fields to the top, the rest are alphabetical
public static fieldOrder = ['title', 'description'];
- public static searchSource = true;
constructor(opts: Record | string = {}) {
if (typeof opts !== 'object') {
@@ -128,7 +98,6 @@ export function createSavedVisClass(services: SavedObjectKibanaServices) {
super({
type: SavedVis.type,
mapping: SavedVis.mapping,
- searchSource: SavedVis.searchSource,
extractReferences,
injectReferences,
id: (opts.id as string) || '',
@@ -144,11 +113,11 @@ export function createSavedVisClass(services: SavedObjectKibanaServices) {
afterESResp: async (savedObject: SavedObject) => {
const savedVis = (savedObject as any) as ISavedVis;
savedVis.visState = await updateOldState(savedVis.visState);
- if (savedVis.savedSearchId && savedVis.searchSource) {
- savedObject.searchSource = await getSearchSource(
- savedVis.searchSource,
- savedVis.savedSearchId
- );
+ if (savedVis.searchSourceFields?.index) {
+ await services.indexPatterns.get(savedVis.searchSourceFields.index as any);
+ }
+ if (savedVis.savedSearchId) {
+ await savedSearch.get(savedVis.savedSearchId);
}
return (savedVis as any) as SavedObject;
},
diff --git a/src/plugins/visualizations/public/saved_visualizations/saved_visualization_references.ts b/src/plugins/visualizations/public/saved_visualizations/saved_visualization_references.ts
index a14595524100b..d28853694b653 100644
--- a/src/plugins/visualizations/public/saved_visualizations/saved_visualization_references.ts
+++ b/src/plugins/visualizations/public/saved_visualizations/saved_visualization_references.ts
@@ -18,6 +18,7 @@
*/
import { SavedObjectAttributes, SavedObjectReference } from '../../../../core/public';
import { VisSavedObject } from '../types';
+import { injectSearchSourceReferences, extractSearchSourceReferences } from '../../../data/public';
export function extractReferences({
attributes,
@@ -29,6 +30,14 @@ export function extractReferences({
const updatedAttributes = { ...attributes };
const updatedReferences = [...references];
+ if (updatedAttributes.searchSourceFields) {
+ const [searchSource, searchSourceReferences] = extractSearchSourceReferences(
+ updatedAttributes.searchSourceFields as any
+ );
+ updatedAttributes.searchSourceFields = searchSource;
+ searchSourceReferences.forEach(r => updatedReferences.push(r));
+ }
+
// Extract saved search
if (updatedAttributes.savedSearchId) {
updatedReferences.push({
@@ -66,6 +75,12 @@ export function extractReferences({
}
export function injectReferences(savedObject: VisSavedObject, references: SavedObjectReference[]) {
+ if (savedObject.searchSourceFields) {
+ savedObject.searchSourceFields = injectSearchSourceReferences(
+ savedObject.searchSourceFields as any,
+ references
+ );
+ }
if (savedObject.savedSearchRefName) {
const savedSearchReference = references.find(
reference => reference.name === savedObject.savedSearchRefName
diff --git a/src/plugins/visualizations/public/services.ts b/src/plugins/visualizations/public/services.ts
index 618c61dff176a..22cdefcee6036 100644
--- a/src/plugins/visualizations/public/services.ts
+++ b/src/plugins/visualizations/public/services.ts
@@ -38,6 +38,7 @@ import { UsageCollectionSetup } from '../../../plugins/usage_collection/public';
import { ExpressionsStart } from '../../../plugins/expressions/public';
import { UiActionsStart } from '../../../plugins/ui_actions/public';
import { SavedVisualizationsLoader } from './saved_visualizations';
+import { SavedObjectLoader } from '../../saved_objects/public';
export const [getUISettings, setUISettings] = createGetterSetter('UISettings');
@@ -84,3 +85,7 @@ export const [getAggs, setAggs] = createGetterSetter('Overlays');
export const [getChrome, setChrome] = createGetterSetter('Chrome');
+
+export const [getSavedSearchLoader, setSavedSearchLoader] = createGetterSetter(
+ 'savedSearchLoader'
+);
diff --git a/src/plugins/visualizations/public/types.ts b/src/plugins/visualizations/public/types.ts
index 54528a33414c3..3455d88b6ce9e 100644
--- a/src/plugins/visualizations/public/types.ts
+++ b/src/plugins/visualizations/public/types.ts
@@ -18,7 +18,7 @@
*/
import { SavedObject } from '../../../plugins/saved_objects/public';
-import { ISearchSource, AggConfigOptions } from '../../../plugins/data/public';
+import { AggConfigOptions, SearchSourceFields } from '../../../plugins/data/public';
import { SerializedVis, Vis, VisParams } from './vis';
export { Vis, SerializedVis, VisParams };
@@ -45,7 +45,7 @@ export interface ISavedVis {
title: string;
description?: string;
visState: SavedVisState;
- searchSource?: ISearchSource;
+ searchSourceFields?: SearchSourceFields;
uiStateJSON?: string;
savedSearchRefName?: string;
savedSearchId?: string;
diff --git a/src/plugins/visualizations/public/vis.test.ts b/src/plugins/visualizations/public/vis.test.ts
index fc9327903fc90..aba735656b7d9 100644
--- a/src/plugins/visualizations/public/vis.test.ts
+++ b/src/plugins/visualizations/public/vis.test.ts
@@ -18,8 +18,6 @@
*/
import { Vis } from './vis';
-// @ts-ignore
-import fixturesStubbedLogstashIndexPatternProvider from '../../../fixtures/stubbed_logstash_index_pattern';
jest.mock('./services', () => {
class MockVisualizationController {
@@ -36,7 +34,10 @@ jest.mock('./services', () => {
// eslint-disable-next-line
const { BaseVisType } = require('./vis_types/base_vis_type');
-
+ // eslint-disable-next-line
+ const { SearchSource } = require('../../data/public/search/search_source');
+ // eslint-disable-next-line
+ const fixturesStubbedLogstashIndexPatternProvider = require('../../../fixtures/stubbed_logstash_index_pattern');
const visType = new BaseVisType({
name: 'pie',
title: 'pie',
@@ -51,6 +52,13 @@ jest.mock('./services', () => {
aggs: cfg.map((aggConfig: any) => ({ ...aggConfig, toJSON: () => aggConfig })),
}),
}),
+ getSearch: () => ({
+ searchSource: {
+ create: () => {
+ return new SearchSource({ index: fixturesStubbedLogstashIndexPatternProvider });
+ },
+ },
+ }),
};
});
@@ -66,19 +74,15 @@ describe('Vis Class', function() {
{ type: 'terms' as any, schema: 'segment', params: { field: 'geo.src' } },
],
searchSource: {
- getField: (name: string) => {
- if (name === 'index') {
- return fixturesStubbedLogstashIndexPatternProvider();
- }
- },
- createCopy: jest.fn(),
+ index: '123',
},
},
params: { isDonut: true },
};
- beforeEach(function() {
+ beforeEach(async function() {
vis = new Vis('test', stateFixture as any);
+ await vis.setState(stateFixture as any);
});
const verifyVis = function(visToVerify: Vis) {
diff --git a/src/plugins/visualizations/public/vis.ts b/src/plugins/visualizations/public/vis.ts
index 009dd71b9a912..916467ac08f4f 100644
--- a/src/plugins/visualizations/public/vis.ts
+++ b/src/plugins/visualizations/public/vis.ts
@@ -28,21 +28,22 @@
*/
import { isFunction, defaults, cloneDeep } from 'lodash';
+import { Assign } from '@kbn/utility-types';
import { PersistedState } from './persisted_state';
-import { getTypes, getAggs } from './services';
+import { getTypes, getAggs, getSearch, getSavedSearchLoader } from './services';
import { VisType } from './vis_types';
import {
IAggConfigs,
IndexPattern,
ISearchSource,
AggConfigOptions,
+ SearchSourceFields,
} from '../../../plugins/data/public';
export interface SerializedVisData {
expression?: string;
aggs: AggConfigOptions[];
- indexPattern?: string;
- searchSource?: ISearchSource;
+ searchSource: SearchSourceFields;
savedSearchId?: string;
}
@@ -68,6 +69,19 @@ export interface VisParams {
[key: string]: any;
}
+const getSearchSource = async (inputSearchSource: ISearchSource, savedSearchId?: string) => {
+ const searchSource = inputSearchSource.createCopy();
+ if (savedSearchId) {
+ const savedSearch = await getSavedSearchLoader().get(savedSearchId);
+
+ searchSource.setParent(savedSearch.searchSource);
+ }
+ searchSource.setField('size', 0);
+ return searchSource;
+};
+
+type PartialVisState = Assign }>;
+
export class Vis {
public readonly type: VisType;
public readonly id?: string;
@@ -86,8 +100,6 @@ export class Vis {
this.params = this.getParams(visState.params);
this.uiState = new PersistedState(visState.uiState);
this.id = visState.id;
-
- this.setState(visState || {});
}
private getType(visType: string) {
@@ -102,7 +114,7 @@ export class Vis {
return defaults({}, cloneDeep(params || {}), cloneDeep(this.type.visConfig.defaults || {}));
}
- setState(state: SerializedVis) {
+ async setState(state: PartialVisState) {
let typeChanged = false;
if (state.type && this.type.name !== state.type) {
// @ts-ignore
@@ -120,19 +132,24 @@ export class Vis {
}
if (state.data && state.data.searchSource) {
- this.data.searchSource = state.data.searchSource!;
+ this.data.searchSource = await getSearch().searchSource.create(state.data.searchSource!);
this.data.indexPattern = this.data.searchSource.getField('index');
}
if (state.data && state.data.savedSearchId) {
this.data.savedSearchId = state.data.savedSearchId;
+ if (this.data.searchSource) {
+ this.data.searchSource = await getSearchSource(
+ this.data.searchSource,
+ this.data.savedSearchId
+ );
+ this.data.indexPattern = this.data.searchSource.getField('index');
+ }
}
- if (state.data && state.data.aggs) {
- const configStates = this.initializeDefaultsFromSchemas(
- cloneDeep(state.data.aggs),
- this.type.schemas.all || []
- );
+ if (state.data && (state.data.aggs || !this.data.aggs)) {
+ const aggs = state.data.aggs ? cloneDeep(state.data.aggs) : [];
+ const configStates = this.initializeDefaultsFromSchemas(aggs, this.type.schemas.all || []);
if (!this.data.indexPattern) {
- if (state.data.aggs.length) {
+ if (aggs.length) {
throw new Error('trying to initialize aggs without index pattern');
}
return;
@@ -142,22 +159,31 @@ export class Vis {
}
clone() {
- return new Vis(this.type.name, this.serialize());
+ const { data, ...restOfSerialized } = this.serialize();
+ const vis = new Vis(this.type.name, restOfSerialized as any);
+ vis.setState({ ...restOfSerialized, data: {} });
+ const aggs = this.data.indexPattern
+ ? getAggs().createAggConfigs(this.data.indexPattern, data.aggs)
+ : undefined;
+ vis.data = {
+ ...this.data,
+ aggs,
+ };
+ return vis;
}
serialize(): SerializedVis {
const aggs = this.data.aggs ? this.data.aggs.aggs.map(agg => agg.toJSON()) : [];
- const indexPattern = this.data.searchSource && this.data.searchSource.getField('index');
return {
id: this.id,
title: this.title,
+ description: this.description,
type: this.type.name,
params: cloneDeep(this.params) as any,
uiState: this.uiState.toJSON(),
data: {
aggs: aggs as any,
- indexPattern: indexPattern ? indexPattern.id : undefined,
- searchSource: this.data.searchSource!.createCopy(),
+ searchSource: this.data.searchSource ? this.data.searchSource.getSerializedFields() : {},
savedSearchId: this.data.savedSearchId,
},
};
diff --git a/src/plugins/visualize/public/application/editor/editor.js b/src/plugins/visualize/public/application/editor/editor.js
index bd699c762371c..78e5c92c5eab8 100644
--- a/src/plugins/visualize/public/application/editor/editor.js
+++ b/src/plugins/visualize/public/application/editor/editor.js
@@ -645,8 +645,7 @@ function VisualizeAppController($scope, $route, $injector, $timeout, kbnUrlState
title: savedVis.title,
type: savedVis.type || stateContainer.getState().vis.type,
});
- savedVis.searchSource.setField('query', stateContainer.getState().query);
- savedVis.searchSource.setField('filter', stateContainer.getState().filters);
+ savedVis.searchSourceFields = searchSource.getSerializedFields();
savedVis.visState = stateContainer.getState().vis;
savedVis.uiStateJSON = angular.toJson($scope.uiState.toJSON());
$appStatus.dirty = false;
diff --git a/src/plugins/visualize/public/application/legacy_app.js b/src/plugins/visualize/public/application/legacy_app.js
index e14057cab6ca9..d1c81e67be1b0 100644
--- a/src/plugins/visualize/public/application/legacy_app.js
+++ b/src/plugins/visualize/public/application/legacy_app.js
@@ -45,9 +45,9 @@ const getResolvedResults = deps => {
return savedVis => {
results.savedVis = savedVis;
+ const serializedVis = visualizations.convertToSerializedVis(savedVis);
return visualizations
- .convertToSerializedVis(savedVis)
- .then(serializedVis => visualizations.createVis(serializedVis.type, serializedVis))
+ .createVis(serializedVis.type, serializedVis)
.then(vis => {
if (vis.type.setup) {
return vis.type.setup(vis).catch(() => vis);
@@ -171,6 +171,10 @@ export function initVisualizeApp(app, deps) {
return data.indexPatterns
.ensureDefaultIndexPattern(history)
.then(() => savedVisualizations.get($route.current.params))
+ .then(savedVis => {
+ savedVis.searchSourceFields = { index: $route.current.params.indexPattern };
+ return savedVis;
+ })
.then(getResolvedResults(deps))
.then(delay)
.catch(
diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.js b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.js
index a412c49faceac..21fd8b205b033 100644
--- a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.js
+++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.js
@@ -399,7 +399,7 @@ export class ESSearchSource extends AbstractESSource {
}
const searchService = getSearchService();
- const searchSource = searchService.searchSource.create();
+ const searchSource = searchService.searchSource.createEmpty();
searchSource.setField('index', indexPattern);
searchSource.setField('size', 1);
diff --git a/x-pack/plugins/maps/public/classes/sources/es_source/es_source.js b/x-pack/plugins/maps/public/classes/sources/es_source/es_source.js
index 87733e347aa2a..b3341a1061d68 100644
--- a/x-pack/plugins/maps/public/classes/sources/es_source/es_source.js
+++ b/x-pack/plugins/maps/public/classes/sources/es_source/es_source.js
@@ -125,7 +125,7 @@ export class AbstractESSource extends AbstractVectorSource {
allFilters.push(getTimeFilter().createFilter(indexPattern, searchFilters.timeFilters));
}
const searchService = getSearchService();
- const searchSource = searchService.searchSource.create(initialSearchContext);
+ const searchSource = await searchService.searchSource.create(initialSearchContext);
searchSource.setField('index', indexPattern);
searchSource.setField('size', limit);
@@ -135,7 +135,7 @@ export class AbstractESSource extends AbstractVectorSource {
}
if (searchFilters.sourceQuery) {
- const layerSearchSource = searchService.searchSource.create();
+ const layerSearchSource = searchService.searchSource.createEmpty();
layerSearchSource.setField('index', indexPattern);
layerSearchSource.setField('query', searchFilters.sourceQuery);
@@ -296,7 +296,7 @@ export class AbstractESSource extends AbstractVectorSource {
const indexPattern = await this.getIndexPattern();
const searchService = getSearchService();
- const searchSource = searchService.searchSource.create();
+ const searchSource = searchService.searchSource.createEmpty();
searchSource.setField('index', indexPattern);
searchSource.setField('size', 0);