mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
making vis (completely) serializable (#64207)
This commit is contained in:
parent
3f43763bc3
commit
15c0644c97
50 changed files with 572 additions and 402 deletions
|
@ -0,0 +1,13 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [extractSearchSourceReferences](./kibana-plugin-plugins-data-public.extractsearchsourcereferences.md)
|
||||||
|
|
||||||
|
## extractSearchSourceReferences variable
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
extractReferences: (state: SearchSourceFields) => [SearchSourceFields & {
|
||||||
|
indexRefName?: string | undefined;
|
||||||
|
}, SavedObjectReference[]]
|
||||||
|
```
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [injectSearchSourceReferences](./kibana-plugin-plugins-data-public.injectsearchsourcereferences.md)
|
||||||
|
|
||||||
|
## injectSearchSourceReferences variable
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
injectReferences: (searchSourceFields: SearchSourceFields & {
|
||||||
|
indexRefName: string;
|
||||||
|
}, references: SavedObjectReference[]) => SearchSourceFields
|
||||||
|
```
|
|
@ -101,11 +101,14 @@
|
||||||
| [esFilters](./kibana-plugin-plugins-data-public.esfilters.md) | |
|
| [esFilters](./kibana-plugin-plugins-data-public.esfilters.md) | |
|
||||||
| [esKuery](./kibana-plugin-plugins-data-public.eskuery.md) | |
|
| [esKuery](./kibana-plugin-plugins-data-public.eskuery.md) | |
|
||||||
| [esQuery](./kibana-plugin-plugins-data-public.esquery.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) | |
|
| [fieldFormats](./kibana-plugin-plugins-data-public.fieldformats.md) | |
|
||||||
| [FilterBar](./kibana-plugin-plugins-data-public.filterbar.md) | |
|
| [FilterBar](./kibana-plugin-plugins-data-public.filterbar.md) | |
|
||||||
| [getIndexPatternFieldListCreator](./kibana-plugin-plugins-data-public.getindexpatternfieldlistcreator.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<string>} |
|
| [getKbnTypeNames](./kibana-plugin-plugins-data-public.getkbntypenames.md) | Get the esTypes known by all kbnFieldTypes {<!-- -->Array<string>} |
|
||||||
| [indexPatterns](./kibana-plugin-plugins-data-public.indexpatterns.md) | |
|
| [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) | |
|
| [QueryStringInput](./kibana-plugin-plugins-data-public.querystringinput.md) | |
|
||||||
| [search](./kibana-plugin-plugins-data-public.search.md) | |
|
| [search](./kibana-plugin-plugins-data-public.search.md) | |
|
||||||
| [SearchBar](./kibana-plugin-plugins-data-public.searchbar.md) | |
|
| [SearchBar](./kibana-plugin-plugins-data-public.searchbar.md) | |
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [parseSearchSourceJSON](./kibana-plugin-plugins-data-public.parsesearchsourcejson.md)
|
||||||
|
|
||||||
|
## parseSearchSourceJSON variable
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
parseSearchSourceJSON: (searchSourceJSON: string) => SearchSourceFields
|
||||||
|
```
|
|
@ -32,6 +32,7 @@ import { chartPluginMock } from '../../../../../plugins/charts/public/mocks';
|
||||||
import { advancedSettingsMock } from '../../../../../plugins/advanced_settings/public/mocks';
|
import { advancedSettingsMock } from '../../../../../plugins/advanced_settings/public/mocks';
|
||||||
import { savedObjectsManagementPluginMock } from '../../../../../plugins/saved_objects_management/public/mocks';
|
import { savedObjectsManagementPluginMock } from '../../../../../plugins/saved_objects_management/public/mocks';
|
||||||
import { visualizationsPluginMock } from '../../../../../plugins/visualizations/public/mocks';
|
import { visualizationsPluginMock } from '../../../../../plugins/visualizations/public/mocks';
|
||||||
|
import { discoverPluginMock } from '../../../../../plugins/discover/public/mocks';
|
||||||
/* eslint-enable @kbn/eslint/no-restricted-paths */
|
/* eslint-enable @kbn/eslint/no-restricted-paths */
|
||||||
|
|
||||||
export const pluginsMock = {
|
export const pluginsMock = {
|
||||||
|
@ -48,6 +49,7 @@ export const pluginsMock = {
|
||||||
visualizations: visualizationsPluginMock.createSetupContract(),
|
visualizations: visualizationsPluginMock.createSetupContract(),
|
||||||
kibanaLegacy: kibanaLegacyPluginMock.createSetupContract(),
|
kibanaLegacy: kibanaLegacyPluginMock.createSetupContract(),
|
||||||
savedObjectsManagement: savedObjectsManagementPluginMock.createSetupContract(),
|
savedObjectsManagement: savedObjectsManagementPluginMock.createSetupContract(),
|
||||||
|
discover: discoverPluginMock.createSetupContract(),
|
||||||
}),
|
}),
|
||||||
createStart: () => ({
|
createStart: () => ({
|
||||||
data: dataPluginMock.createStartContract(),
|
data: dataPluginMock.createStartContract(),
|
||||||
|
@ -62,6 +64,7 @@ export const pluginsMock = {
|
||||||
visualizations: visualizationsPluginMock.createStartContract(),
|
visualizations: visualizationsPluginMock.createStartContract(),
|
||||||
kibanaLegacy: kibanaLegacyPluginMock.createStartContract(),
|
kibanaLegacy: kibanaLegacyPluginMock.createStartContract(),
|
||||||
savedObjectsManagement: savedObjectsManagementPluginMock.createStartContract(),
|
savedObjectsManagement: savedObjectsManagementPluginMock.createStartContract(),
|
||||||
|
discover: discoverPluginMock.createStartContract(),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -515,6 +515,7 @@ export const npStart = {
|
||||||
docViews: {
|
docViews: {
|
||||||
DocViewer: () => null,
|
DocViewer: () => null,
|
||||||
},
|
},
|
||||||
|
savedSearchLoader: {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -57,6 +57,7 @@ export function setStartServices(npStart: NpStart) {
|
||||||
dataServices.setIndexPatterns(npStart.plugins.data.indexPatterns);
|
dataServices.setIndexPatterns(npStart.plugins.data.indexPatterns);
|
||||||
dataServices.setQueryService(npStart.plugins.data.query);
|
dataServices.setQueryService(npStart.plugins.data.query);
|
||||||
dataServices.setSearchService(npStart.plugins.data.search);
|
dataServices.setSearchService(npStart.plugins.data.search);
|
||||||
|
|
||||||
visualizationsServices.setI18n(npStart.core.i18n);
|
visualizationsServices.setI18n(npStart.core.i18n);
|
||||||
visualizationsServices.setTypes(
|
visualizationsServices.setTypes(
|
||||||
pick(npStart.plugins.visualizations, ['get', 'all', 'getAliases'])
|
pick(npStart.plugins.visualizations, ['get', 'all', 'getAliases'])
|
||||||
|
@ -82,4 +83,5 @@ export function setStartServices(npStart: NpStart) {
|
||||||
visualizationTypes: visualizationsServices.getTypes(),
|
visualizationTypes: visualizationsServices.getTypes(),
|
||||||
});
|
});
|
||||||
visualizationsServices.setSavedVisualizationsLoader(savedVisualizationsLoader);
|
visualizationsServices.setSavedVisualizationsLoader(savedVisualizationsLoader);
|
||||||
|
visualizationsServices.setSavedSearchLoader(npStart.plugins.discover.savedSearchLoader);
|
||||||
}
|
}
|
||||||
|
|
|
@ -358,6 +358,9 @@ export {
|
||||||
SearchResponse,
|
SearchResponse,
|
||||||
SearchError,
|
SearchError,
|
||||||
ISearchSource,
|
ISearchSource,
|
||||||
|
parseSearchSourceJSON,
|
||||||
|
injectSearchSourceReferences,
|
||||||
|
extractSearchSourceReferences,
|
||||||
SearchSourceFields,
|
SearchSourceFields,
|
||||||
EsQuerySortValue,
|
EsQuerySortValue,
|
||||||
SortDirection,
|
SortDirection,
|
||||||
|
|
|
@ -46,7 +46,6 @@ import * as React_2 from 'react';
|
||||||
import { Required } from '@kbn/utility-types';
|
import { Required } from '@kbn/utility-types';
|
||||||
import * as Rx from 'rxjs';
|
import * as Rx from 'rxjs';
|
||||||
import { SavedObject as SavedObject_2 } from 'src/core/public';
|
import { SavedObject as SavedObject_2 } from 'src/core/public';
|
||||||
import { SavedObjectReference } from 'kibana/public';
|
|
||||||
import { SavedObjectsClientContract } from 'src/core/public';
|
import { SavedObjectsClientContract } from 'src/core/public';
|
||||||
import { SearchParams } from 'elasticsearch';
|
import { SearchParams } from 'elasticsearch';
|
||||||
import { SearchResponse as SearchResponse_2 } from 'elasticsearch';
|
import { SearchResponse as SearchResponse_2 } from 'elasticsearch';
|
||||||
|
@ -420,6 +419,14 @@ export type ExistsFilter = Filter & {
|
||||||
exists?: FilterExistsProperty;
|
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)
|
// 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)
|
// @public (undocumented)
|
||||||
|
@ -1059,6 +1066,13 @@ export interface IndexPatternTypeMeta {
|
||||||
aggs?: Record<string, IndexPatternAggRestrictions>;
|
aggs?: Record<string, IndexPatternAggRestrictions>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
// 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)
|
// @public (undocumented)
|
||||||
|
@ -1273,6 +1287,11 @@ export interface OptionedValueProp {
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export type ParsedInterval = ReturnType<typeof parseEsInterval>;
|
export type ParsedInterval = ReturnType<typeof parseEsInterval>;
|
||||||
|
|
||||||
|
// 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)
|
// 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)
|
// @public (undocumented)
|
||||||
|
@ -1809,20 +1828,20 @@ export type TSearchStrategyProvider<T extends TStrategyTypes> = (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 "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 "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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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 "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: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: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 "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: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: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/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
|
// 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
|
||||||
|
|
|
@ -282,7 +282,7 @@ export const esaggs = (): ExpressionFunctionDefinition<typeof name, Input, Argum
|
||||||
const aggs = searchService.aggs.createAggConfigs(indexPattern, aggConfigsState);
|
const aggs = searchService.aggs.createAggConfigs(indexPattern, aggConfigsState);
|
||||||
|
|
||||||
// we should move searchSource creation inside courier request handler
|
// we should move searchSource creation inside courier request handler
|
||||||
const searchSource = searchService.searchSource.create();
|
const searchSource = await searchService.searchSource.create();
|
||||||
|
|
||||||
searchSource.setField('index', indexPattern);
|
searchSource.setField('index', indexPattern);
|
||||||
searchSource.setField('size', 0);
|
searchSource.setField('size', 0);
|
||||||
|
|
|
@ -59,6 +59,9 @@ export {
|
||||||
SearchSourceFields,
|
SearchSourceFields,
|
||||||
EsQuerySortValue,
|
EsQuerySortValue,
|
||||||
SortDirection,
|
SortDirection,
|
||||||
|
extractReferences as extractSearchSourceReferences,
|
||||||
|
injectReferences as injectSearchSourceReferences,
|
||||||
|
parseSearchSourceJSON,
|
||||||
} from './search_source';
|
} from './search_source';
|
||||||
|
|
||||||
export { SearchInterceptor } from './search_interceptor';
|
export { SearchInterceptor } from './search_interceptor';
|
||||||
|
|
|
@ -21,12 +21,7 @@ import { Plugin, CoreSetup, CoreStart, PackageInfo } from '../../../../core/publ
|
||||||
import { ExpressionsSetup } from '../../../../plugins/expressions/public';
|
import { ExpressionsSetup } from '../../../../plugins/expressions/public';
|
||||||
|
|
||||||
import { SYNC_SEARCH_STRATEGY, syncSearchStrategyProvider } from './sync_search_strategy';
|
import { SYNC_SEARCH_STRATEGY, syncSearchStrategyProvider } from './sync_search_strategy';
|
||||||
import {
|
import { createSearchSource, SearchSource, SearchSourceDependencies } from './search_source';
|
||||||
createSearchSourceFromJSON,
|
|
||||||
SearchSource,
|
|
||||||
SearchSourceDependencies,
|
|
||||||
SearchSourceFields,
|
|
||||||
} from './search_source';
|
|
||||||
import { ISearchSetup, ISearchStart, TSearchStrategyProvider, TSearchStrategiesMap } from './types';
|
import { ISearchSetup, ISearchStart, TSearchStrategyProvider, TSearchStrategiesMap } from './types';
|
||||||
import { TStrategyTypes } from './strategy_types';
|
import { TStrategyTypes } from './strategy_types';
|
||||||
import { getEsClient, LegacyApiCaller } from './legacy';
|
import { getEsClient, LegacyApiCaller } from './legacy';
|
||||||
|
@ -171,8 +166,10 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
||||||
},
|
},
|
||||||
search,
|
search,
|
||||||
searchSource: {
|
searchSource: {
|
||||||
create: (fields?: SearchSourceFields) => new SearchSource(fields, searchSourceDependencies),
|
create: createSearchSource(dependencies.indexPatterns, searchSourceDependencies),
|
||||||
fromJSON: createSearchSourceFromJSON(dependencies.indexPatterns, searchSourceDependencies),
|
createEmpty: () => {
|
||||||
|
return new SearchSource({}, searchSourceDependencies);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
setInterceptor: (searchInterceptor: SearchInterceptor) => {
|
setInterceptor: (searchInterceptor: SearchInterceptor) => {
|
||||||
// TODO: should an intercepror have a destroy method?
|
// TODO: should an intercepror have a destroy method?
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import { createSearchSourceFromJSON } from './create_search_source';
|
import { createSearchSource as createSearchSourceFactory } from './create_search_source';
|
||||||
import { IIndexPattern } from '../../../common/index_patterns';
|
import { IIndexPattern } from '../../../common/index_patterns';
|
||||||
import { IndexPatternsContract } from '../../index_patterns/index_patterns';
|
import { IndexPatternsContract } from '../../index_patterns/index_patterns';
|
||||||
import { Filter } from '../../../common/es_query/filters';
|
import { Filter } from '../../../common/es_query/filters';
|
||||||
|
@ -27,7 +27,7 @@ describe('createSearchSource', () => {
|
||||||
const indexPatternMock: IIndexPattern = {} as IIndexPattern;
|
const indexPatternMock: IIndexPattern = {} as IIndexPattern;
|
||||||
let indexPatternContractMock: jest.Mocked<IndexPatternsContract>;
|
let indexPatternContractMock: jest.Mocked<IndexPatternsContract>;
|
||||||
let dependencies: any;
|
let dependencies: any;
|
||||||
let createSearchSource: ReturnType<typeof createSearchSourceFromJSON>;
|
let createSearchSource: ReturnType<typeof createSearchSourceFactory>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const core = coreMock.createStart();
|
const core = coreMock.createStart();
|
||||||
|
@ -43,27 +43,17 @@ describe('createSearchSource', () => {
|
||||||
get: jest.fn().mockReturnValue(Promise.resolve(indexPatternMock)),
|
get: jest.fn().mockReturnValue(Promise.resolve(indexPatternMock)),
|
||||||
} as unknown) as jest.Mocked<IndexPatternsContract>;
|
} as unknown) as jest.Mocked<IndexPatternsContract>;
|
||||||
|
|
||||||
createSearchSource = createSearchSourceFromJSON(indexPatternContractMock, dependencies);
|
createSearchSource = createSearchSourceFactory(indexPatternContractMock, dependencies);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should fail if JSON is invalid', () => {
|
it('should set fields', async () => {
|
||||||
expect(createSearchSource('{', [])).rejects.toThrow();
|
const searchSource = await createSearchSource({
|
||||||
expect(createSearchSource('0', [])).rejects.toThrow();
|
highlightAll: true,
|
||||||
expect(createSearchSource('"abcdefg"', [])).rejects.toThrow();
|
query: {
|
||||||
});
|
query: '',
|
||||||
|
language: 'kuery',
|
||||||
test('should set fields', async () => {
|
},
|
||||||
const searchSource = await createSearchSource(
|
});
|
||||||
JSON.stringify({
|
|
||||||
highlightAll: true,
|
|
||||||
query: {
|
|
||||||
query: '',
|
|
||||||
language: 'kuery',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(searchSource.getOwnField('highlightAll')).toBe(true);
|
expect(searchSource.getOwnField('highlightAll')).toBe(true);
|
||||||
expect(searchSource.getOwnField('query')).toEqual({
|
expect(searchSource.getOwnField('query')).toEqual({
|
||||||
query: '',
|
query: '',
|
||||||
|
@ -71,66 +61,32 @@ describe('createSearchSource', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should resolve referenced index pattern', async () => {
|
it('should set filters and resolve referenced index patterns', async () => {
|
||||||
const searchSource = await createSearchSource(
|
const searchSource = await createSearchSource({
|
||||||
JSON.stringify({
|
filter: [
|
||||||
indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
|
||||||
}),
|
|
||||||
[
|
|
||||||
{
|
{
|
||||||
id: '123-456',
|
meta: {
|
||||||
type: 'index-pattern',
|
alias: null,
|
||||||
name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
negate: false,
|
||||||
},
|
disabled: false,
|
||||||
]
|
type: 'phrase',
|
||||||
);
|
key: 'category.keyword',
|
||||||
|
params: {
|
||||||
expect(indexPatternContractMock.get).toHaveBeenCalledWith('123-456');
|
query: "Men's Clothing",
|
||||||
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',
|
|
||||||
},
|
},
|
||||||
query: {
|
index: '123-456',
|
||||||
match_phrase: {
|
},
|
||||||
'category.keyword': "Men's Clothing",
|
query: {
|
||||||
},
|
match_phrase: {
|
||||||
},
|
'category.keyword': "Men's Clothing",
|
||||||
$state: {
|
|
||||||
store: 'appState',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
|
||||||
}),
|
|
||||||
[
|
|
||||||
{
|
|
||||||
id: '123-456',
|
|
||||||
type: 'index-pattern',
|
|
||||||
name: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index',
|
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
);
|
});
|
||||||
const filters = searchSource.getOwnField('filter') as Filter[];
|
const filters = searchSource.getOwnField('filter') as Filter[];
|
||||||
|
|
||||||
expect(filters[0]).toMatchInlineSnapshot(`
|
expect(filters[0]).toMatchInlineSnapshot(`
|
||||||
Object {
|
Object {
|
||||||
"$state": Object {
|
|
||||||
"store": "appState",
|
|
||||||
},
|
|
||||||
"meta": Object {
|
"meta": Object {
|
||||||
"alias": null,
|
"alias": null,
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
|
@ -151,15 +107,11 @@ describe('createSearchSource', () => {
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should migrate legacy queries on the fly', async () => {
|
it('should migrate legacy queries on the fly', async () => {
|
||||||
const searchSource = await createSearchSource(
|
const searchSource = await createSearchSource({
|
||||||
JSON.stringify({
|
highlightAll: true,
|
||||||
highlightAll: true,
|
query: 'a:b' as any,
|
||||||
query: 'a:b',
|
});
|
||||||
}),
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(searchSource.getOwnField('query')).toEqual({
|
expect(searchSource.getOwnField('query')).toEqual({
|
||||||
query: 'a:b',
|
query: 'a:b',
|
||||||
language: 'lucene',
|
language: 'lucene',
|
||||||
|
|
|
@ -16,11 +16,8 @@
|
||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import { transform, defaults, isFunction } from 'lodash';
|
|
||||||
import { SavedObjectReference } from 'kibana/public';
|
|
||||||
import { migrateLegacyQuery } from '../../../../kibana_legacy/public';
|
import { migrateLegacyQuery } from '../../../../kibana_legacy/public';
|
||||||
import { InvalidJSONProperty } from '../../../../kibana_utils/public';
|
import { SearchSource, SearchSourceDependencies } from './search_source';
|
||||||
import { SearchSourceDependencies, SearchSource, ISearchSource } from './search_source';
|
|
||||||
import { IndexPatternsContract } from '../../index_patterns/index_patterns';
|
import { IndexPatternsContract } from '../../index_patterns/index_patterns';
|
||||||
import { SearchSourceFields } from './types';
|
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
|
* the start contract of the data plugin as part of the search service
|
||||||
*
|
*
|
||||||
* @param indexPatterns The index patterns contract of the data plugin
|
* @param indexPatterns The index patterns contract of the data plugin
|
||||||
|
* @param searchSourceDependencies
|
||||||
*
|
*
|
||||||
* @return Wired utility function taking two parameters `searchSourceJson`, the json string
|
* @return Wired utility function taking two parameters `searchSourceJson`, the json string
|
||||||
* returned by `serializeSearchSource` and `references`, a list of references including the ones
|
* returned by `serializeSearchSource` and `references`, a list of references including the ones
|
||||||
|
@ -40,73 +38,20 @@ import { SearchSourceFields } from './types';
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @public */
|
* @public */
|
||||||
export const createSearchSourceFromJSON = (
|
export const createSearchSource = (
|
||||||
indexPatterns: IndexPatternsContract,
|
indexPatterns: IndexPatternsContract,
|
||||||
searchSourceDependencies: SearchSourceDependencies
|
searchSourceDependencies: SearchSourceDependencies
|
||||||
) => async (
|
) => async (searchSourceFields: SearchSourceFields = {}) => {
|
||||||
searchSourceJson: string,
|
const fields = { ...searchSourceFields };
|
||||||
references: SavedObjectReference[]
|
|
||||||
): Promise<ISearchSource> => {
|
|
||||||
const searchSource = new SearchSource({}, searchSourceDependencies);
|
|
||||||
|
|
||||||
// if we have a searchSource, set its values based on the searchSourceJson field
|
// hydrating index pattern
|
||||||
let searchSourceValues: Record<string, unknown>;
|
if (fields.index && typeof fields.index === 'string') {
|
||||||
try {
|
fields.index = await indexPatterns.get(searchSourceFields.index as any);
|
||||||
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.
|
const searchSource = new SearchSource(fields, searchSourceDependencies);
|
||||||
// (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
|
// todo: move to migration script .. create issue
|
||||||
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);
|
|
||||||
|
|
||||||
searchSource.setFields(newFields);
|
|
||||||
const query = searchSource.getOwnField('query');
|
const query = searchSource.getOwnField('query');
|
||||||
|
|
||||||
if (typeof query !== 'undefined') {
|
if (typeof query !== 'undefined') {
|
||||||
|
|
|
@ -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];
|
||||||
|
};
|
|
@ -18,5 +18,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export { SearchSource, ISearchSource, SearchSourceDependencies } from './search_source';
|
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 { SortDirection, EsQuerySortValue, SearchSourceFields } from './types';
|
||||||
|
export { injectReferences } from './inject_references';
|
||||||
|
export { extractReferences } from './extract_references';
|
||||||
|
export { parseSearchSourceJSON } from './parse_json';
|
||||||
|
|
|
@ -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;
|
||||||
|
};
|
|
@ -43,12 +43,13 @@ export const searchSourceInstanceMock: MockedKeys<ISearchSource> = {
|
||||||
getSearchRequestBody: jest.fn(),
|
getSearchRequestBody: jest.fn(),
|
||||||
destroy: jest.fn(),
|
destroy: jest.fn(),
|
||||||
history: [],
|
history: [],
|
||||||
|
getSerializedFields: jest.fn(),
|
||||||
serialize: jest.fn(),
|
serialize: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const searchSourceMock = {
|
export const searchSourceMock = {
|
||||||
create: jest.fn().mockReturnValue(searchSourceInstanceMock),
|
create: jest.fn().mockReturnValue(searchSourceInstanceMock),
|
||||||
fromJSON: jest.fn().mockReturnValue(searchSourceInstanceMock),
|
createEmpty: jest.fn().mockReturnValue(searchSourceInstanceMock),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createSearchSourceMock = (fields?: SearchSourceFields) =>
|
export const createSearchSourceMock = (fields?: SearchSourceFields) =>
|
||||||
|
|
41
src/plugins/data/public/search/search_source/parse_json.ts
Normal file
41
src/plugins/data/public/search/search_source/parse_json.ts
Normal file
|
@ -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;
|
||||||
|
};
|
|
@ -69,9 +69,9 @@
|
||||||
* `appSearchSource`.
|
* `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 { map } from 'rxjs/operators';
|
||||||
import { CoreStart, SavedObjectReference } from 'kibana/public';
|
import { CoreStart } from 'kibana/public';
|
||||||
import { normalizeSortRequest } from './normalize_sort_request';
|
import { normalizeSortRequest } from './normalize_sort_request';
|
||||||
import { filterDocvalueFields } from './filter_docvalue_fields';
|
import { filterDocvalueFields } from './filter_docvalue_fields';
|
||||||
import { fieldWildcardFilter } from '../../../../kibana_utils/public';
|
import { fieldWildcardFilter } from '../../../../kibana_utils/public';
|
||||||
|
@ -82,6 +82,7 @@ import { FetchOptions, RequestFailure, getSearchParams, handleResponse } from '.
|
||||||
import { getEsQueryConfig, buildEsQuery, Filter } from '../../../common';
|
import { getEsQueryConfig, buildEsQuery, Filter } from '../../../common';
|
||||||
import { getHighlightRequest } from '../../../common/field_formats';
|
import { getHighlightRequest } from '../../../common/field_formats';
|
||||||
import { fetchSoon } from '../legacy';
|
import { fetchSoon } from '../legacy';
|
||||||
|
import { extractReferences } from './extract_references';
|
||||||
import { ISearchStartLegacy } from '../types';
|
import { ISearchStartLegacy } from '../types';
|
||||||
|
|
||||||
export interface SearchSourceDependencies {
|
export interface SearchSourceDependencies {
|
||||||
|
@ -450,6 +451,25 @@ export class SearchSource {
|
||||||
return searchRequest;
|
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.
|
* 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.
|
* 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.
|
* Using `createSearchSource`, the instance can be re-created.
|
||||||
* @public */
|
* @public */
|
||||||
public serialize() {
|
public serialize() {
|
||||||
const references: SavedObjectReference[] = [];
|
const [searchSourceFields, references] = extractReferences(this.getSerializedFields());
|
||||||
|
return { searchSourceJSON: JSON.stringify(searchSourceFields), references };
|
||||||
const {
|
|
||||||
filter: originalFilters,
|
|
||||||
...searchSourceFields
|
|
||||||
}: Omit<SearchSourceFields, 'sort' | 'size'> = omit(this.getFields(), ['sort', 'size']);
|
|
||||||
let serializedSearchSourceFields: Omit<SearchSourceFields, 'sort' | 'size' | 'filter'> & {
|
|
||||||
indexRefName?: string;
|
|
||||||
filter?: Array<Omit<Filter, 'meta'> & { 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 };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private getFilters(filterField: SearchSourceFields['filter']): Filter[] {
|
private getFilters(filterField: SearchSourceFields['filter']): Filter[] {
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { CoreStart, SavedObjectReference } from 'kibana/public';
|
import { CoreStart } from 'kibana/public';
|
||||||
import { SearchAggsSetup, SearchAggsStart } from './aggs';
|
import { SearchAggsSetup, SearchAggsStart } from './aggs';
|
||||||
import { ISearch, ISearchGeneric } from './i_search';
|
import { ISearch, ISearchGeneric } from './i_search';
|
||||||
import { TStrategyTypes } from './strategy_types';
|
import { TStrategyTypes } from './strategy_types';
|
||||||
|
@ -82,11 +82,8 @@ export interface ISearchStart {
|
||||||
setInterceptor: (searchInterceptor: SearchInterceptor) => void;
|
setInterceptor: (searchInterceptor: SearchInterceptor) => void;
|
||||||
search: ISearchGeneric;
|
search: ISearchGeneric;
|
||||||
searchSource: {
|
searchSource: {
|
||||||
create: (fields?: SearchSourceFields) => ISearchSource;
|
create: (fields?: SearchSourceFields) => Promise<ISearchSource>;
|
||||||
fromJSON: (
|
createEmpty: () => ISearchSource;
|
||||||
searchSourceJson: string,
|
|
||||||
references: SavedObjectReference[]
|
|
||||||
) => Promise<ISearchSource>;
|
|
||||||
};
|
};
|
||||||
__LEGACY: ISearchStartLegacy;
|
__LEGACY: ISearchStartLegacy;
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,8 +113,8 @@ function fetchContextProvider(indexPatterns: IndexPatternsContract) {
|
||||||
async function createSearchSource(indexPattern: IndexPattern, filters: Filter[]) {
|
async function createSearchSource(indexPattern: IndexPattern, filters: Filter[]) {
|
||||||
const { data } = getServices();
|
const { data } = getServices();
|
||||||
|
|
||||||
return data.search.searchSource
|
const searchSource = await data.search.searchSource.create();
|
||||||
.create()
|
return searchSource
|
||||||
.setParent(undefined)
|
.setParent(undefined)
|
||||||
.setField('index', indexPattern)
|
.setField('index', indexPattern)
|
||||||
.setField('filter', filters);
|
.setField('filter', filters);
|
||||||
|
|
|
@ -30,7 +30,7 @@ import { MarkdownSimple } from '../../../../../../kibana_react/public';
|
||||||
|
|
||||||
export function QueryActionsProvider(Promise) {
|
export function QueryActionsProvider(Promise) {
|
||||||
const { filterManager, indexPatterns, data } = getServices();
|
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 { fetchSurroundingDocs } = fetchContextProvider(indexPatterns);
|
||||||
const { setPredecessorCount, setQueryParameters, setSuccessorCount } = getQueryParameterActions(
|
const { setPredecessorCount, setQueryParameters, setSuccessorCount } = getQueryParameterActions(
|
||||||
filterManager,
|
filterManager,
|
||||||
|
|
|
@ -1021,7 +1021,7 @@ function discoverController(
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
$scope.vis = visualizations.createVis('histogram', {
|
$scope.vis = await visualizations.createVis('histogram', {
|
||||||
title: savedSearch.title,
|
title: savedSearch.title,
|
||||||
params: {
|
params: {
|
||||||
addLegend: false,
|
addLegend: false,
|
||||||
|
@ -1029,8 +1029,7 @@ function discoverController(
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
aggs: visStateAggs,
|
aggs: visStateAggs,
|
||||||
indexPattern: $scope.searchSource.getField('index').id,
|
searchSource: $scope.searchSource.getSerializedFields(),
|
||||||
searchSource: $scope.searchSource,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -33,9 +33,7 @@ const createSetupContract = (): Setup => {
|
||||||
|
|
||||||
const createStartContract = (): Start => {
|
const createStartContract = (): Start => {
|
||||||
const startContract: Start = {
|
const startContract: Start = {
|
||||||
savedSearches: {
|
savedSearchLoader: {} as any,
|
||||||
createLoader: jest.fn(),
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
return startContract;
|
return startContract;
|
||||||
};
|
};
|
||||||
|
|
|
@ -39,7 +39,7 @@ import { KibanaLegacySetup, AngularRenderedAppUpdater } from 'src/plugins/kibana
|
||||||
import { HomePublicPluginSetup } from 'src/plugins/home/public';
|
import { HomePublicPluginSetup } from 'src/plugins/home/public';
|
||||||
import { Start as InspectorPublicPluginStart } from 'src/plugins/inspector/public';
|
import { Start as InspectorPublicPluginStart } from 'src/plugins/inspector/public';
|
||||||
import { DataPublicPluginStart, DataPublicPluginSetup, esFilters } from '../../data/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 { createKbnUrlTracker } from '../../kibana_utils/public';
|
||||||
|
|
||||||
import { DocViewInput, DocViewInputFn } from './application/doc_views/doc_views_types';
|
import { DocViewInput, DocViewInputFn } from './application/doc_views/doc_views_types';
|
||||||
|
@ -73,13 +73,7 @@ export interface DiscoverSetup {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DiscoverStart {
|
export interface DiscoverStart {
|
||||||
savedSearches: {
|
savedSearchLoader: SavedObjectLoader;
|
||||||
/**
|
|
||||||
* Create a {@link SavedObjectLoader | loader} to handle the saved searches type.
|
|
||||||
* @param services
|
|
||||||
*/
|
|
||||||
createLoader(services: SavedObjectKibanaServices): SavedObjectLoader;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -264,9 +258,13 @@ export class DiscoverPlugin
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
savedSearches: {
|
savedSearchLoader: createSavedSearchesLoader({
|
||||||
createLoader: createSavedSearchesLoader,
|
savedObjectsClient: core.savedObjects.client,
|
||||||
},
|
indexPatterns: plugins.data.indexPatterns,
|
||||||
|
search: plugins.data.search,
|
||||||
|
chrome: core.chrome,
|
||||||
|
overlays: core.overlays,
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ import {
|
||||||
DataPublicPluginStart,
|
DataPublicPluginStart,
|
||||||
} from 'src/plugins/data/public';
|
} from 'src/plugins/data/public';
|
||||||
|
|
||||||
export function createSearchSource(
|
export async function createSearchSource(
|
||||||
{ create }: DataPublicPluginStart['search']['searchSource'],
|
{ create }: DataPublicPluginStart['search']['searchSource'],
|
||||||
initialState: SearchSourceFields | null,
|
initialState: SearchSourceFields | null,
|
||||||
indexPattern: IndexPattern,
|
indexPattern: IndexPattern,
|
||||||
|
@ -34,7 +34,7 @@ export function createSearchSource(
|
||||||
filters: PhraseFilter[] = [],
|
filters: PhraseFilter[] = [],
|
||||||
timefilter: TimefilterContract
|
timefilter: TimefilterContract
|
||||||
) {
|
) {
|
||||||
const searchSource = create(initialState || {});
|
const searchSource = await create(initialState || {});
|
||||||
|
|
||||||
// Do not not inherit from rootSearchSource to avoid picking up time and globals
|
// Do not not inherit from rootSearchSource to avoid picking up time and globals
|
||||||
searchSource.setParent(undefined);
|
searchSource.setParent(undefined);
|
||||||
|
|
|
@ -147,7 +147,7 @@ export class ListControl extends Control<PhraseFilterManager> {
|
||||||
direction: 'desc',
|
direction: 'desc',
|
||||||
query,
|
query,
|
||||||
});
|
});
|
||||||
const searchSource = createSearchSource(
|
const searchSource = await createSearchSource(
|
||||||
this.searchSource,
|
this.searchSource,
|
||||||
initialSearchSourceState,
|
initialSearchSourceState,
|
||||||
indexPattern,
|
indexPattern,
|
||||||
|
|
|
@ -84,7 +84,7 @@ export class RangeControl extends Control<RangeFilterManager> {
|
||||||
|
|
||||||
const fieldName = this.filterManager.fieldName;
|
const fieldName = this.filterManager.fieldName;
|
||||||
const aggs = minMaxAgg(indexPattern.fields.getByName(fieldName));
|
const aggs = minMaxAgg(indexPattern.fields.getByName(fieldName));
|
||||||
const searchSource = createSearchSource(
|
const searchSource = await createSearchSource(
|
||||||
this.searchSource,
|
this.searchSource,
|
||||||
null,
|
null,
|
||||||
indexPattern,
|
indexPattern,
|
||||||
|
|
|
@ -19,7 +19,11 @@
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { EsResponse, SavedObject, SavedObjectConfig, SavedObjectKibanaServices } from '../../types';
|
import { EsResponse, SavedObject, SavedObjectConfig, SavedObjectKibanaServices } from '../../types';
|
||||||
import { expandShorthand, SavedObjectNotFound } from '../../../../kibana_utils/public';
|
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
|
* 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);
|
_.assign(savedObject, savedObject._source);
|
||||||
savedObject.lastSavedTitle = savedObject.title;
|
savedObject.lastSavedTitle = savedObject.title;
|
||||||
|
|
||||||
if (config.searchSource) {
|
if (meta.searchSourceJSON) {
|
||||||
try {
|
try {
|
||||||
savedObject.searchSource = await dependencies.search.searchSource.fromJSON(
|
let searchSourceValues = parseSearchSourceJSON(meta.searchSourceJSON);
|
||||||
meta.searchSourceJSON,
|
|
||||||
resp.references
|
if (config.searchSource) {
|
||||||
);
|
searchSourceValues = injectSearchSourceReferences(
|
||||||
|
searchSourceValues as any,
|
||||||
|
resp.references
|
||||||
|
);
|
||||||
|
savedObject.searchSource = await dependencies.search.searchSource.create(
|
||||||
|
searchSourceValues
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
savedObject.searchSourceFields = searchSourceValues;
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (
|
if (
|
||||||
error.constructor.name === 'SavedObjectNotFound' &&
|
error.constructor.name === 'SavedObjectNotFound' &&
|
||||||
|
|
|
@ -55,7 +55,7 @@ export function buildSavedObject(
|
||||||
savedObject.defaults = config.defaults || {};
|
savedObject.defaults = config.defaults || {};
|
||||||
// optional search source which this object configures
|
// optional search source which this object configures
|
||||||
savedObject.searchSource = config.searchSource
|
savedObject.searchSource = config.searchSource
|
||||||
? services.search.searchSource.create()
|
? services.search.searchSource.createEmpty()
|
||||||
: undefined;
|
: undefined;
|
||||||
// the id of the document
|
// the id of the document
|
||||||
savedObject.id = config.id || void 0;
|
savedObject.id = config.id || void 0;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { SavedObject, SavedObjectConfig } from '../../types';
|
import { SavedObject, SavedObjectConfig } from '../../types';
|
||||||
import { expandShorthand } from '../../../../kibana_utils/public';
|
import { expandShorthand } from '../../../../kibana_utils/public';
|
||||||
|
import { extractSearchSourceReferences } from '../../../../data/public';
|
||||||
|
|
||||||
export function serializeSavedObject(savedObject: SavedObject, config: SavedObjectConfig) {
|
export function serializeSavedObject(savedObject: SavedObject, config: SavedObjectConfig) {
|
||||||
// mapping definition for the fields that this object will expose
|
// mapping definition for the fields that this object will expose
|
||||||
|
@ -48,6 +49,15 @@ export function serializeSavedObject(savedObject: SavedObject, config: SavedObje
|
||||||
references.push(...searchSourceReferences);
|
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) {
|
if (savedObject.unresolvedIndexPatternReference) {
|
||||||
references.push(savedObject.unresolvedIndexPatternReference);
|
references.push(savedObject.unresolvedIndexPatternReference);
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,7 @@ describe('Saved Object', () => {
|
||||||
searchSource: {
|
searchSource: {
|
||||||
...dataStartMock.search.searchSource,
|
...dataStartMock.search.searchSource,
|
||||||
create: createSearchSourceMock,
|
create: createSearchSourceMock,
|
||||||
|
createEmpty: createSearchSourceMock,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as unknown) as SavedObjectKibanaServices);
|
} as unknown) as SavedObjectKibanaServices);
|
||||||
|
@ -572,46 +573,50 @@ describe('Saved Object', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('passes references to search source parsing function', async () => {
|
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 });
|
const savedObject = new SavedObjectClass({ type: 'dashboard', searchSource: true });
|
||||||
await savedObject.init!();
|
return savedObject.init!().then(async () => {
|
||||||
|
const searchSourceJSON = JSON.stringify({
|
||||||
const searchSourceJSON = JSON.stringify({
|
indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||||
indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
filter: [
|
||||||
filter: [
|
{
|
||||||
{
|
meta: {
|
||||||
meta: {
|
indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index',
|
||||||
indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index',
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const response = {
|
||||||
|
found: true,
|
||||||
|
_source: {
|
||||||
|
kibanaSavedObjectMeta: {
|
||||||
|
searchSourceJSON,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
references: [
|
||||||
});
|
{
|
||||||
const response = {
|
name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||||
found: true,
|
type: 'index-pattern',
|
||||||
_source: {
|
id: 'my-index-1',
|
||||||
kibanaSavedObjectMeta: {
|
},
|
||||||
searchSourceJSON,
|
{
|
||||||
},
|
name: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index',
|
||||||
},
|
type: 'index-pattern',
|
||||||
references: [
|
id: 'my-index-2',
|
||||||
{
|
},
|
||||||
name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
],
|
||||||
type: 'index-pattern',
|
};
|
||||||
id: 'my-index-1',
|
await savedObject.applyESResp(response);
|
||||||
},
|
expect(dataStartMock.search.searchSource.create).toBeCalledWith({
|
||||||
{
|
filter: [{ meta: { index: 'my-index-2' } }],
|
||||||
name: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index',
|
index: 'my-index-1',
|
||||||
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"}}]}',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -29,6 +29,7 @@ import {
|
||||||
IIndexPattern,
|
IIndexPattern,
|
||||||
IndexPatternsContract,
|
IndexPatternsContract,
|
||||||
ISearchSource,
|
ISearchSource,
|
||||||
|
SearchSourceFields,
|
||||||
} from '../../data/public';
|
} from '../../data/public';
|
||||||
|
|
||||||
export interface SavedObject {
|
export interface SavedObject {
|
||||||
|
@ -52,6 +53,7 @@ export interface SavedObject {
|
||||||
migrationVersion?: Record<string, any>;
|
migrationVersion?: Record<string, any>;
|
||||||
save: (saveOptions: SavedObjectSaveOpts) => Promise<string>;
|
save: (saveOptions: SavedObjectSaveOpts) => Promise<string>;
|
||||||
searchSource?: ISearchSource;
|
searchSource?: ISearchSource;
|
||||||
|
searchSourceFields?: SearchSourceFields;
|
||||||
showInRecentlyAccessed: boolean;
|
showInRecentlyAccessed: boolean;
|
||||||
title: string;
|
title: string;
|
||||||
unresolvedIndexPatternReference?: SavedObjectReference;
|
unresolvedIndexPatternReference?: SavedObjectReference;
|
||||||
|
|
|
@ -21,7 +21,12 @@ import { i18n } from '@kbn/i18n';
|
||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import { OverlayStart, SavedObjectReference } from 'src/core/public';
|
import { OverlayStart, SavedObjectReference } from 'src/core/public';
|
||||||
import { SavedObject, SavedObjectLoader } from '../../../saved_objects/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<string, any>;
|
type SavedObjectsRawDoc = Record<string, any>;
|
||||||
|
|
||||||
|
@ -207,13 +212,17 @@ export async function resolveIndexPatternConflicts(
|
||||||
return reference;
|
return reference;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const serializedSearchSourceWithInjectedReferences = injectSearchSourceReferences(
|
||||||
|
serializedSearchSource,
|
||||||
|
replacedReferences
|
||||||
|
);
|
||||||
|
|
||||||
if (!allResolved) {
|
if (!allResolved) {
|
||||||
// The user decided to skip this conflict so do nothing
|
// The user decided to skip this conflict so do nothing
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
obj.searchSource = await dependencies.search.searchSource.fromJSON(
|
obj.searchSource = await dependencies.search.searchSource.create(
|
||||||
JSON.stringify(serializedSearchSource),
|
serializedSearchSourceWithInjectedReferences
|
||||||
replacedReferences
|
|
||||||
);
|
);
|
||||||
if (await saveObject(obj, overwriteAll)) {
|
if (await saveObject(obj, overwriteAll)) {
|
||||||
importCount++;
|
importCount++;
|
||||||
|
|
|
@ -280,7 +280,7 @@ exports[`SavedObjectsTable import should show the flyout 1`] = `
|
||||||
"search": [MockFunction],
|
"search": [MockFunction],
|
||||||
"searchSource": Object {
|
"searchSource": Object {
|
||||||
"create": [MockFunction],
|
"create": [MockFunction],
|
||||||
"fromJSON": [MockFunction],
|
"createEmpty": [MockFunction],
|
||||||
},
|
},
|
||||||
"setInterceptor": [MockFunction],
|
"setInterceptor": [MockFunction],
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ export const registerServices = async (
|
||||||
registry: ISavedObjectsManagementServiceRegistry,
|
registry: ISavedObjectsManagementServiceRegistry,
|
||||||
getStartServices: StartServicesAccessor<StartDependencies, SavedObjectsManagementPluginStart>
|
getStartServices: StartServicesAccessor<StartDependencies, SavedObjectsManagementPluginStart>
|
||||||
) => {
|
) => {
|
||||||
const [coreStart, { dashboard, data, visualizations, discover }] = await getStartServices();
|
const [, { dashboard, visualizations, discover }] = await getStartServices();
|
||||||
|
|
||||||
if (dashboard) {
|
if (dashboard) {
|
||||||
registry.register({
|
registry.register({
|
||||||
|
@ -47,13 +47,7 @@ export const registerServices = async (
|
||||||
registry.register({
|
registry.register({
|
||||||
id: 'savedSearches',
|
id: 'savedSearches',
|
||||||
title: 'searches',
|
title: 'searches',
|
||||||
service: discover.savedSearches.createLoader({
|
service: discover.savedSearchLoader,
|
||||||
savedObjectsClient: coreStart.savedObjects.client,
|
|
||||||
indexPatterns: data.indexPatterns,
|
|
||||||
search: data.search,
|
|
||||||
chrome: coreStart.chrome,
|
|
||||||
overlays: coreStart.overlays,
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -122,7 +122,9 @@ export class VisualizeEmbeddableFactory
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const savedObject = await savedVisualizations.get(savedObjectId);
|
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);
|
return createVisEmbeddableFromObject(this.deps)(vis, input, parent);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e); // eslint-disable-line no-console
|
console.error(e); // eslint-disable-line no-console
|
||||||
|
|
|
@ -398,6 +398,7 @@ describe('visualize loader pipeline helpers: build pipeline', () => {
|
||||||
return aggs;
|
return aggs;
|
||||||
},
|
},
|
||||||
} as any,
|
} as any,
|
||||||
|
searchSource: {} as any,
|
||||||
},
|
},
|
||||||
isHierarchical: () => {
|
isHierarchical: () => {
|
||||||
return false;
|
return false;
|
||||||
|
@ -473,6 +474,7 @@ describe('visualize loader pipeline helpers: build pipeline', () => {
|
||||||
return aggs;
|
return aggs;
|
||||||
},
|
},
|
||||||
} as any,
|
} as any,
|
||||||
|
searchSource: {} as any,
|
||||||
},
|
},
|
||||||
isHierarchical: () => {
|
isHierarchical: () => {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -43,6 +43,7 @@ import {
|
||||||
setAggs,
|
setAggs,
|
||||||
setChrome,
|
setChrome,
|
||||||
setOverlays,
|
setOverlays,
|
||||||
|
setSavedSearchLoader,
|
||||||
} from './services';
|
} from './services';
|
||||||
import {
|
import {
|
||||||
VISUALIZE_EMBEDDABLE_TYPE,
|
VISUALIZE_EMBEDDABLE_TYPE,
|
||||||
|
@ -70,6 +71,7 @@ import {
|
||||||
convertFromSerializedVis,
|
convertFromSerializedVis,
|
||||||
convertToSerializedVis,
|
convertToSerializedVis,
|
||||||
} from './saved_visualizations/_saved_vis';
|
} from './saved_visualizations/_saved_vis';
|
||||||
|
import { createSavedSearchesLoader } from '../../discover/public';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for this plugin's returned setup/start contracts.
|
* Interface for this plugin's returned setup/start contracts.
|
||||||
|
@ -81,7 +83,7 @@ export type VisualizationsSetup = TypesSetup;
|
||||||
|
|
||||||
export interface VisualizationsStart extends TypesStart {
|
export interface VisualizationsStart extends TypesStart {
|
||||||
savedVisualizationsLoader: SavedVisualizationsLoader;
|
savedVisualizationsLoader: SavedVisualizationsLoader;
|
||||||
createVis: (visType: string, visState?: SerializedVis) => Vis;
|
createVis: (visType: string, visState: SerializedVis) => Promise<Vis>;
|
||||||
convertToSerializedVis: typeof convertToSerializedVis;
|
convertToSerializedVis: typeof convertToSerializedVis;
|
||||||
convertFromSerializedVis: typeof convertFromSerializedVis;
|
convertFromSerializedVis: typeof convertFromSerializedVis;
|
||||||
showNewVisModal: typeof showNewVisModal;
|
showNewVisModal: typeof showNewVisModal;
|
||||||
|
@ -174,7 +176,14 @@ export class VisualizationsPlugin
|
||||||
visualizationTypes: types,
|
visualizationTypes: types,
|
||||||
});
|
});
|
||||||
setSavedVisualizationsLoader(savedVisualizationsLoader);
|
setSavedVisualizationsLoader(savedVisualizationsLoader);
|
||||||
|
const savedSearchLoader = createSavedSearchesLoader({
|
||||||
|
savedObjectsClient: core.savedObjects.client,
|
||||||
|
indexPatterns: data.indexPatterns,
|
||||||
|
search: data.search,
|
||||||
|
chrome: core.chrome,
|
||||||
|
overlays: core.overlays,
|
||||||
|
});
|
||||||
|
setSavedSearchLoader(savedSearchLoader);
|
||||||
return {
|
return {
|
||||||
...types,
|
...types,
|
||||||
showNewVisModal,
|
showNewVisModal,
|
||||||
|
@ -183,7 +192,11 @@ export class VisualizationsPlugin
|
||||||
* @param {IIndexPattern} indexPattern - index pattern to use
|
* @param {IIndexPattern} indexPattern - index pattern to use
|
||||||
* @param {VisState} visState - visualization configuration
|
* @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,
|
convertToSerializedVis,
|
||||||
convertFromSerializedVis,
|
convertFromSerializedVis,
|
||||||
savedVisualizationsLoader,
|
savedVisualizationsLoader,
|
||||||
|
|
|
@ -32,32 +32,25 @@ import {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { updateOldState } from '../legacy/vis_update_state';
|
import { updateOldState } from '../legacy/vis_update_state';
|
||||||
import { extractReferences, injectReferences } from './saved_visualization_references';
|
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 { ISavedVis, SerializedVis } from '../types';
|
||||||
import { createSavedSearchesLoader } from '../../../../plugins/discover/public';
|
import { createSavedSearchesLoader } from '../../../discover/public';
|
||||||
import { getChrome, getOverlays, getIndexPatterns, getSavedObjects, getSearch } from '../services';
|
|
||||||
|
|
||||||
export const convertToSerializedVis = async (savedVis: ISavedVis): Promise<SerializedVis> => {
|
export const convertToSerializedVis = (savedVis: ISavedVis): SerializedVis => {
|
||||||
const { visState } = savedVis;
|
const { id, title, description, visState, uiStateJSON, searchSourceFields } = savedVis;
|
||||||
const searchSource =
|
|
||||||
savedVis.searchSource && (await getSearchSource(savedVis.searchSource, savedVis.savedSearchId));
|
|
||||||
|
|
||||||
const indexPattern =
|
const aggs = searchSourceFields && searchSourceFields.index ? visState.aggs || [] : visState.aggs;
|
||||||
searchSource && searchSource.getField('index') ? searchSource.getField('index')!.id : undefined;
|
|
||||||
|
|
||||||
const aggs = indexPattern ? visState.aggs || [] : visState.aggs;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: savedVis.id,
|
id,
|
||||||
title: savedVis.title,
|
title,
|
||||||
type: visState.type,
|
type: visState.type,
|
||||||
description: savedVis.description,
|
description,
|
||||||
params: visState.params,
|
params: visState.params,
|
||||||
uiState: JSON.parse(savedVis.uiStateJSON || '{}'),
|
uiState: JSON.parse(uiStateJSON || '{}'),
|
||||||
data: {
|
data: {
|
||||||
indexPattern,
|
|
||||||
aggs,
|
aggs,
|
||||||
searchSource,
|
searchSource: searchSourceFields!,
|
||||||
savedSearchId: savedVis.savedSearchId,
|
savedSearchId: savedVis.savedSearchId,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -74,36 +67,14 @@ export const convertFromSerializedVis = (vis: SerializedVis): ISavedVis => {
|
||||||
params: vis.params,
|
params: vis.params,
|
||||||
},
|
},
|
||||||
uiStateJSON: JSON.stringify(vis.uiState),
|
uiStateJSON: JSON.stringify(vis.uiState),
|
||||||
searchSource: vis.data.searchSource!,
|
searchSourceFields: vis.data.searchSource,
|
||||||
savedSearchId: vis.data.savedSearchId,
|
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) {
|
export function createSavedVisClass(services: SavedObjectKibanaServices) {
|
||||||
const SavedObjectClass = createSavedObjectClass(services);
|
const SavedObjectClass = createSavedObjectClass(services);
|
||||||
|
const savedSearch = createSavedSearchesLoader(services);
|
||||||
|
|
||||||
class SavedVis extends SavedObjectClass {
|
class SavedVis extends SavedObjectClass {
|
||||||
public static type: string = 'visualization';
|
public static type: string = 'visualization';
|
||||||
|
@ -117,7 +88,6 @@ export function createSavedVisClass(services: SavedObjectKibanaServices) {
|
||||||
};
|
};
|
||||||
// Order these fields to the top, the rest are alphabetical
|
// Order these fields to the top, the rest are alphabetical
|
||||||
public static fieldOrder = ['title', 'description'];
|
public static fieldOrder = ['title', 'description'];
|
||||||
public static searchSource = true;
|
|
||||||
|
|
||||||
constructor(opts: Record<string, unknown> | string = {}) {
|
constructor(opts: Record<string, unknown> | string = {}) {
|
||||||
if (typeof opts !== 'object') {
|
if (typeof opts !== 'object') {
|
||||||
|
@ -128,7 +98,6 @@ export function createSavedVisClass(services: SavedObjectKibanaServices) {
|
||||||
super({
|
super({
|
||||||
type: SavedVis.type,
|
type: SavedVis.type,
|
||||||
mapping: SavedVis.mapping,
|
mapping: SavedVis.mapping,
|
||||||
searchSource: SavedVis.searchSource,
|
|
||||||
extractReferences,
|
extractReferences,
|
||||||
injectReferences,
|
injectReferences,
|
||||||
id: (opts.id as string) || '',
|
id: (opts.id as string) || '',
|
||||||
|
@ -144,11 +113,11 @@ export function createSavedVisClass(services: SavedObjectKibanaServices) {
|
||||||
afterESResp: async (savedObject: SavedObject) => {
|
afterESResp: async (savedObject: SavedObject) => {
|
||||||
const savedVis = (savedObject as any) as ISavedVis;
|
const savedVis = (savedObject as any) as ISavedVis;
|
||||||
savedVis.visState = await updateOldState(savedVis.visState);
|
savedVis.visState = await updateOldState(savedVis.visState);
|
||||||
if (savedVis.savedSearchId && savedVis.searchSource) {
|
if (savedVis.searchSourceFields?.index) {
|
||||||
savedObject.searchSource = await getSearchSource(
|
await services.indexPatterns.get(savedVis.searchSourceFields.index as any);
|
||||||
savedVis.searchSource,
|
}
|
||||||
savedVis.savedSearchId
|
if (savedVis.savedSearchId) {
|
||||||
);
|
await savedSearch.get(savedVis.savedSearchId);
|
||||||
}
|
}
|
||||||
return (savedVis as any) as SavedObject;
|
return (savedVis as any) as SavedObject;
|
||||||
},
|
},
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
import { SavedObjectAttributes, SavedObjectReference } from '../../../../core/public';
|
import { SavedObjectAttributes, SavedObjectReference } from '../../../../core/public';
|
||||||
import { VisSavedObject } from '../types';
|
import { VisSavedObject } from '../types';
|
||||||
|
import { injectSearchSourceReferences, extractSearchSourceReferences } from '../../../data/public';
|
||||||
|
|
||||||
export function extractReferences({
|
export function extractReferences({
|
||||||
attributes,
|
attributes,
|
||||||
|
@ -29,6 +30,14 @@ export function extractReferences({
|
||||||
const updatedAttributes = { ...attributes };
|
const updatedAttributes = { ...attributes };
|
||||||
const updatedReferences = [...references];
|
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
|
// Extract saved search
|
||||||
if (updatedAttributes.savedSearchId) {
|
if (updatedAttributes.savedSearchId) {
|
||||||
updatedReferences.push({
|
updatedReferences.push({
|
||||||
|
@ -66,6 +75,12 @@ export function extractReferences({
|
||||||
}
|
}
|
||||||
|
|
||||||
export function injectReferences(savedObject: VisSavedObject, references: SavedObjectReference[]) {
|
export function injectReferences(savedObject: VisSavedObject, references: SavedObjectReference[]) {
|
||||||
|
if (savedObject.searchSourceFields) {
|
||||||
|
savedObject.searchSourceFields = injectSearchSourceReferences(
|
||||||
|
savedObject.searchSourceFields as any,
|
||||||
|
references
|
||||||
|
);
|
||||||
|
}
|
||||||
if (savedObject.savedSearchRefName) {
|
if (savedObject.savedSearchRefName) {
|
||||||
const savedSearchReference = references.find(
|
const savedSearchReference = references.find(
|
||||||
reference => reference.name === savedObject.savedSearchRefName
|
reference => reference.name === savedObject.savedSearchRefName
|
||||||
|
|
|
@ -38,6 +38,7 @@ import { UsageCollectionSetup } from '../../../plugins/usage_collection/public';
|
||||||
import { ExpressionsStart } from '../../../plugins/expressions/public';
|
import { ExpressionsStart } from '../../../plugins/expressions/public';
|
||||||
import { UiActionsStart } from '../../../plugins/ui_actions/public';
|
import { UiActionsStart } from '../../../plugins/ui_actions/public';
|
||||||
import { SavedVisualizationsLoader } from './saved_visualizations';
|
import { SavedVisualizationsLoader } from './saved_visualizations';
|
||||||
|
import { SavedObjectLoader } from '../../saved_objects/public';
|
||||||
|
|
||||||
export const [getUISettings, setUISettings] = createGetterSetter<IUiSettingsClient>('UISettings');
|
export const [getUISettings, setUISettings] = createGetterSetter<IUiSettingsClient>('UISettings');
|
||||||
|
|
||||||
|
@ -84,3 +85,7 @@ export const [getAggs, setAggs] = createGetterSetter<DataPublicPluginStart['sear
|
||||||
export const [getOverlays, setOverlays] = createGetterSetter<OverlayStart>('Overlays');
|
export const [getOverlays, setOverlays] = createGetterSetter<OverlayStart>('Overlays');
|
||||||
|
|
||||||
export const [getChrome, setChrome] = createGetterSetter<ChromeStart>('Chrome');
|
export const [getChrome, setChrome] = createGetterSetter<ChromeStart>('Chrome');
|
||||||
|
|
||||||
|
export const [getSavedSearchLoader, setSavedSearchLoader] = createGetterSetter<SavedObjectLoader>(
|
||||||
|
'savedSearchLoader'
|
||||||
|
);
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { SavedObject } from '../../../plugins/saved_objects/public';
|
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';
|
import { SerializedVis, Vis, VisParams } from './vis';
|
||||||
|
|
||||||
export { Vis, SerializedVis, VisParams };
|
export { Vis, SerializedVis, VisParams };
|
||||||
|
@ -45,7 +45,7 @@ export interface ISavedVis {
|
||||||
title: string;
|
title: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
visState: SavedVisState;
|
visState: SavedVisState;
|
||||||
searchSource?: ISearchSource;
|
searchSourceFields?: SearchSourceFields;
|
||||||
uiStateJSON?: string;
|
uiStateJSON?: string;
|
||||||
savedSearchRefName?: string;
|
savedSearchRefName?: string;
|
||||||
savedSearchId?: string;
|
savedSearchId?: string;
|
||||||
|
|
|
@ -18,8 +18,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Vis } from './vis';
|
import { Vis } from './vis';
|
||||||
// @ts-ignore
|
|
||||||
import fixturesStubbedLogstashIndexPatternProvider from '../../../fixtures/stubbed_logstash_index_pattern';
|
|
||||||
|
|
||||||
jest.mock('./services', () => {
|
jest.mock('./services', () => {
|
||||||
class MockVisualizationController {
|
class MockVisualizationController {
|
||||||
|
@ -36,7 +34,10 @@ jest.mock('./services', () => {
|
||||||
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
const { BaseVisType } = require('./vis_types/base_vis_type');
|
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({
|
const visType = new BaseVisType({
|
||||||
name: 'pie',
|
name: 'pie',
|
||||||
title: 'pie',
|
title: 'pie',
|
||||||
|
@ -51,6 +52,13 @@ jest.mock('./services', () => {
|
||||||
aggs: cfg.map((aggConfig: any) => ({ ...aggConfig, toJSON: () => aggConfig })),
|
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' } },
|
{ type: 'terms' as any, schema: 'segment', params: { field: 'geo.src' } },
|
||||||
],
|
],
|
||||||
searchSource: {
|
searchSource: {
|
||||||
getField: (name: string) => {
|
index: '123',
|
||||||
if (name === 'index') {
|
|
||||||
return fixturesStubbedLogstashIndexPatternProvider();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
createCopy: jest.fn(),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
params: { isDonut: true },
|
params: { isDonut: true },
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(async function() {
|
||||||
vis = new Vis('test', stateFixture as any);
|
vis = new Vis('test', stateFixture as any);
|
||||||
|
await vis.setState(stateFixture as any);
|
||||||
});
|
});
|
||||||
|
|
||||||
const verifyVis = function(visToVerify: Vis) {
|
const verifyVis = function(visToVerify: Vis) {
|
||||||
|
|
|
@ -28,21 +28,22 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { isFunction, defaults, cloneDeep } from 'lodash';
|
import { isFunction, defaults, cloneDeep } from 'lodash';
|
||||||
|
import { Assign } from '@kbn/utility-types';
|
||||||
import { PersistedState } from './persisted_state';
|
import { PersistedState } from './persisted_state';
|
||||||
import { getTypes, getAggs } from './services';
|
import { getTypes, getAggs, getSearch, getSavedSearchLoader } from './services';
|
||||||
import { VisType } from './vis_types';
|
import { VisType } from './vis_types';
|
||||||
import {
|
import {
|
||||||
IAggConfigs,
|
IAggConfigs,
|
||||||
IndexPattern,
|
IndexPattern,
|
||||||
ISearchSource,
|
ISearchSource,
|
||||||
AggConfigOptions,
|
AggConfigOptions,
|
||||||
|
SearchSourceFields,
|
||||||
} from '../../../plugins/data/public';
|
} from '../../../plugins/data/public';
|
||||||
|
|
||||||
export interface SerializedVisData {
|
export interface SerializedVisData {
|
||||||
expression?: string;
|
expression?: string;
|
||||||
aggs: AggConfigOptions[];
|
aggs: AggConfigOptions[];
|
||||||
indexPattern?: string;
|
searchSource: SearchSourceFields;
|
||||||
searchSource?: ISearchSource;
|
|
||||||
savedSearchId?: string;
|
savedSearchId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +69,19 @@ export interface VisParams {
|
||||||
[key: string]: any;
|
[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<SerializedVis, { data: Partial<SerializedVisData> }>;
|
||||||
|
|
||||||
export class Vis {
|
export class Vis {
|
||||||
public readonly type: VisType;
|
public readonly type: VisType;
|
||||||
public readonly id?: string;
|
public readonly id?: string;
|
||||||
|
@ -86,8 +100,6 @@ export class Vis {
|
||||||
this.params = this.getParams(visState.params);
|
this.params = this.getParams(visState.params);
|
||||||
this.uiState = new PersistedState(visState.uiState);
|
this.uiState = new PersistedState(visState.uiState);
|
||||||
this.id = visState.id;
|
this.id = visState.id;
|
||||||
|
|
||||||
this.setState(visState || {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private getType(visType: string) {
|
private getType(visType: string) {
|
||||||
|
@ -102,7 +114,7 @@ export class Vis {
|
||||||
return defaults({}, cloneDeep(params || {}), cloneDeep(this.type.visConfig.defaults || {}));
|
return defaults({}, cloneDeep(params || {}), cloneDeep(this.type.visConfig.defaults || {}));
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(state: SerializedVis) {
|
async setState(state: PartialVisState) {
|
||||||
let typeChanged = false;
|
let typeChanged = false;
|
||||||
if (state.type && this.type.name !== state.type) {
|
if (state.type && this.type.name !== state.type) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -120,19 +132,24 @@ export class Vis {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.data && state.data.searchSource) {
|
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');
|
this.data.indexPattern = this.data.searchSource.getField('index');
|
||||||
}
|
}
|
||||||
if (state.data && state.data.savedSearchId) {
|
if (state.data && state.data.savedSearchId) {
|
||||||
this.data.savedSearchId = 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) {
|
if (state.data && (state.data.aggs || !this.data.aggs)) {
|
||||||
const configStates = this.initializeDefaultsFromSchemas(
|
const aggs = state.data.aggs ? cloneDeep(state.data.aggs) : [];
|
||||||
cloneDeep(state.data.aggs),
|
const configStates = this.initializeDefaultsFromSchemas(aggs, this.type.schemas.all || []);
|
||||||
this.type.schemas.all || []
|
|
||||||
);
|
|
||||||
if (!this.data.indexPattern) {
|
if (!this.data.indexPattern) {
|
||||||
if (state.data.aggs.length) {
|
if (aggs.length) {
|
||||||
throw new Error('trying to initialize aggs without index pattern');
|
throw new Error('trying to initialize aggs without index pattern');
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -142,22 +159,31 @@ export class Vis {
|
||||||
}
|
}
|
||||||
|
|
||||||
clone() {
|
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 {
|
serialize(): SerializedVis {
|
||||||
const aggs = this.data.aggs ? this.data.aggs.aggs.map(agg => agg.toJSON()) : [];
|
const aggs = this.data.aggs ? this.data.aggs.aggs.map(agg => agg.toJSON()) : [];
|
||||||
const indexPattern = this.data.searchSource && this.data.searchSource.getField('index');
|
|
||||||
return {
|
return {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
title: this.title,
|
title: this.title,
|
||||||
|
description: this.description,
|
||||||
type: this.type.name,
|
type: this.type.name,
|
||||||
params: cloneDeep(this.params) as any,
|
params: cloneDeep(this.params) as any,
|
||||||
uiState: this.uiState.toJSON(),
|
uiState: this.uiState.toJSON(),
|
||||||
data: {
|
data: {
|
||||||
aggs: aggs as any,
|
aggs: aggs as any,
|
||||||
indexPattern: indexPattern ? indexPattern.id : undefined,
|
searchSource: this.data.searchSource ? this.data.searchSource.getSerializedFields() : {},
|
||||||
searchSource: this.data.searchSource!.createCopy(),
|
|
||||||
savedSearchId: this.data.savedSearchId,
|
savedSearchId: this.data.savedSearchId,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -645,8 +645,7 @@ function VisualizeAppController($scope, $route, $injector, $timeout, kbnUrlState
|
||||||
title: savedVis.title,
|
title: savedVis.title,
|
||||||
type: savedVis.type || stateContainer.getState().vis.type,
|
type: savedVis.type || stateContainer.getState().vis.type,
|
||||||
});
|
});
|
||||||
savedVis.searchSource.setField('query', stateContainer.getState().query);
|
savedVis.searchSourceFields = searchSource.getSerializedFields();
|
||||||
savedVis.searchSource.setField('filter', stateContainer.getState().filters);
|
|
||||||
savedVis.visState = stateContainer.getState().vis;
|
savedVis.visState = stateContainer.getState().vis;
|
||||||
savedVis.uiStateJSON = angular.toJson($scope.uiState.toJSON());
|
savedVis.uiStateJSON = angular.toJson($scope.uiState.toJSON());
|
||||||
$appStatus.dirty = false;
|
$appStatus.dirty = false;
|
||||||
|
|
|
@ -45,9 +45,9 @@ const getResolvedResults = deps => {
|
||||||
|
|
||||||
return savedVis => {
|
return savedVis => {
|
||||||
results.savedVis = savedVis;
|
results.savedVis = savedVis;
|
||||||
|
const serializedVis = visualizations.convertToSerializedVis(savedVis);
|
||||||
return visualizations
|
return visualizations
|
||||||
.convertToSerializedVis(savedVis)
|
.createVis(serializedVis.type, serializedVis)
|
||||||
.then(serializedVis => visualizations.createVis(serializedVis.type, serializedVis))
|
|
||||||
.then(vis => {
|
.then(vis => {
|
||||||
if (vis.type.setup) {
|
if (vis.type.setup) {
|
||||||
return vis.type.setup(vis).catch(() => vis);
|
return vis.type.setup(vis).catch(() => vis);
|
||||||
|
@ -171,6 +171,10 @@ export function initVisualizeApp(app, deps) {
|
||||||
return data.indexPatterns
|
return data.indexPatterns
|
||||||
.ensureDefaultIndexPattern(history)
|
.ensureDefaultIndexPattern(history)
|
||||||
.then(() => savedVisualizations.get($route.current.params))
|
.then(() => savedVisualizations.get($route.current.params))
|
||||||
|
.then(savedVis => {
|
||||||
|
savedVis.searchSourceFields = { index: $route.current.params.indexPattern };
|
||||||
|
return savedVis;
|
||||||
|
})
|
||||||
.then(getResolvedResults(deps))
|
.then(getResolvedResults(deps))
|
||||||
.then(delay)
|
.then(delay)
|
||||||
.catch(
|
.catch(
|
||||||
|
|
|
@ -399,7 +399,7 @@ export class ESSearchSource extends AbstractESSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchService = getSearchService();
|
const searchService = getSearchService();
|
||||||
const searchSource = searchService.searchSource.create();
|
const searchSource = searchService.searchSource.createEmpty();
|
||||||
|
|
||||||
searchSource.setField('index', indexPattern);
|
searchSource.setField('index', indexPattern);
|
||||||
searchSource.setField('size', 1);
|
searchSource.setField('size', 1);
|
||||||
|
|
|
@ -125,7 +125,7 @@ export class AbstractESSource extends AbstractVectorSource {
|
||||||
allFilters.push(getTimeFilter().createFilter(indexPattern, searchFilters.timeFilters));
|
allFilters.push(getTimeFilter().createFilter(indexPattern, searchFilters.timeFilters));
|
||||||
}
|
}
|
||||||
const searchService = getSearchService();
|
const searchService = getSearchService();
|
||||||
const searchSource = searchService.searchSource.create(initialSearchContext);
|
const searchSource = await searchService.searchSource.create(initialSearchContext);
|
||||||
|
|
||||||
searchSource.setField('index', indexPattern);
|
searchSource.setField('index', indexPattern);
|
||||||
searchSource.setField('size', limit);
|
searchSource.setField('size', limit);
|
||||||
|
@ -135,7 +135,7 @@ export class AbstractESSource extends AbstractVectorSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchFilters.sourceQuery) {
|
if (searchFilters.sourceQuery) {
|
||||||
const layerSearchSource = searchService.searchSource.create();
|
const layerSearchSource = searchService.searchSource.createEmpty();
|
||||||
|
|
||||||
layerSearchSource.setField('index', indexPattern);
|
layerSearchSource.setField('index', indexPattern);
|
||||||
layerSearchSource.setField('query', searchFilters.sourceQuery);
|
layerSearchSource.setField('query', searchFilters.sourceQuery);
|
||||||
|
@ -296,7 +296,7 @@ export class AbstractESSource extends AbstractVectorSource {
|
||||||
|
|
||||||
const indexPattern = await this.getIndexPattern();
|
const indexPattern = await this.getIndexPattern();
|
||||||
const searchService = getSearchService();
|
const searchService = getSearchService();
|
||||||
const searchSource = searchService.searchSource.create();
|
const searchSource = searchService.searchSource.createEmpty();
|
||||||
|
|
||||||
searchSource.setField('index', indexPattern);
|
searchSource.setField('index', indexPattern);
|
||||||
searchSource.setField('size', 0);
|
searchSource.setField('size', 0);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue