mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
parent
81de77cacd
commit
3078bfa788
41 changed files with 688 additions and 276 deletions
|
@ -0,0 +1,15 @@
|
||||||
|
<!-- 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) > [createSearchSource](./kibana-plugin-plugins-data-public.createsearchsource.md)
|
||||||
|
|
||||||
|
## createSearchSource variable
|
||||||
|
|
||||||
|
Deserializes a json string and a set of referenced objects to a `SearchSource` instance. Use this method to re-create the search source serialized using `searchSource.serialize`<!-- -->.
|
||||||
|
|
||||||
|
This function is a factory function that returns the actual utility when calling it with the required service dependency (index patterns contract). A pre-wired version is also exposed in the start contract of the data plugin as part of the search service
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
createSearchSource: (indexPatterns: Pick<import("../../index_patterns/index_patterns").IndexPatternsService, "get" | "clearCache" | "getFieldsForTimePattern" | "getFieldsForWildcard" | "getIds" | "getTitles" | "getFields" | "getCache" | "getDefault" | "make">) => (searchSourceJson: string, references: SavedObjectReference[]) => Promise<SearchSource>
|
||||||
|
```
|
|
@ -102,6 +102,7 @@
|
||||||
| [castEsToKbnFieldTypeName](./kibana-plugin-plugins-data-public.castestokbnfieldtypename.md) | Get the KbnFieldType name for an esType string |
|
| [castEsToKbnFieldTypeName](./kibana-plugin-plugins-data-public.castestokbnfieldtypename.md) | Get the KbnFieldType name for an esType string |
|
||||||
| [connectToQueryState](./kibana-plugin-plugins-data-public.connecttoquerystate.md) | Helper to setup two-way syncing of global data and a state container |
|
| [connectToQueryState](./kibana-plugin-plugins-data-public.connecttoquerystate.md) | Helper to setup two-way syncing of global data and a state container |
|
||||||
| [createSavedQueryService](./kibana-plugin-plugins-data-public.createsavedqueryservice.md) | |
|
| [createSavedQueryService](./kibana-plugin-plugins-data-public.createsavedqueryservice.md) | |
|
||||||
|
| [createSearchSource](./kibana-plugin-plugins-data-public.createsearchsource.md) | Deserializes a json string and a set of referenced objects to a <code>SearchSource</code> instance. Use this method to re-create the search source serialized using <code>searchSource.serialize</code>.<!-- -->This function is a factory function that returns the actual utility when calling it with the required service dependency (index patterns contract). A pre-wired version is also exposed in the start contract of the data plugin as part of the search service |
|
||||||
| [ES\_SEARCH\_STRATEGY](./kibana-plugin-plugins-data-public.es_search_strategy.md) | |
|
| [ES\_SEARCH\_STRATEGY](./kibana-plugin-plugins-data-public.es_search_strategy.md) | |
|
||||||
| [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) | |
|
||||||
|
|
|
@ -38,6 +38,7 @@ export declare class SearchSource
|
||||||
| [getParent()](./kibana-plugin-plugins-data-public.searchsource.getparent.md) | | Get the parent of this SearchSource {<!-- -->undefined\|searchSource<!-- -->} |
|
| [getParent()](./kibana-plugin-plugins-data-public.searchsource.getparent.md) | | Get the parent of this SearchSource {<!-- -->undefined\|searchSource<!-- -->} |
|
||||||
| [getSearchRequestBody()](./kibana-plugin-plugins-data-public.searchsource.getsearchrequestbody.md) | | |
|
| [getSearchRequestBody()](./kibana-plugin-plugins-data-public.searchsource.getsearchrequestbody.md) | | |
|
||||||
| [onRequestStart(handler)](./kibana-plugin-plugins-data-public.searchsource.onrequeststart.md) | | Add a handler that will be notified whenever requests start |
|
| [onRequestStart(handler)](./kibana-plugin-plugins-data-public.searchsource.onrequeststart.md) | | Add a handler that will be notified whenever requests start |
|
||||||
|
| [serialize()](./kibana-plugin-plugins-data-public.searchsource.serialize.md) | | 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.<!-- -->The references returned by this function can be mixed with other references in the same object, however make sure there are no name-collisions. The references will be named <code>kibanaSavedObjectMeta.searchSourceJSON.index</code> and <code>kibanaSavedObjectMeta.searchSourceJSON.filter[<number>].meta.index</code>.<!-- -->Using <code>createSearchSource</code>, the instance can be re-created. |
|
||||||
| [setField(field, value)](./kibana-plugin-plugins-data-public.searchsource.setfield.md) | | |
|
| [setField(field, value)](./kibana-plugin-plugins-data-public.searchsource.setfield.md) | | |
|
||||||
| [setFields(newFields)](./kibana-plugin-plugins-data-public.searchsource.setfields.md) | | |
|
| [setFields(newFields)](./kibana-plugin-plugins-data-public.searchsource.setfields.md) | | |
|
||||||
| [setParent(parent, options)](./kibana-plugin-plugins-data-public.searchsource.setparent.md) | | Set a searchSource that this source should inherit from |
|
| [setParent(parent, options)](./kibana-plugin-plugins-data-public.searchsource.setparent.md) | | Set a searchSource that this source should inherit from |
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
<!-- 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) > [SearchSource](./kibana-plugin-plugins-data-public.searchsource.md) > [serialize](./kibana-plugin-plugins-data-public.searchsource.serialize.md)
|
||||||
|
|
||||||
|
## SearchSource.serialize() method
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
The references returned by this function can be mixed with other references in the same object, however make sure there are no name-collisions. The references will be named `kibanaSavedObjectMeta.searchSourceJSON.index` and `kibanaSavedObjectMeta.searchSourceJSON.filter[<number>].meta.index`<!-- -->.
|
||||||
|
|
||||||
|
Using `createSearchSource`<!-- -->, the instance can be re-created.
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
serialize(): {
|
||||||
|
searchSourceJSON: string;
|
||||||
|
references: SavedObjectReference[];
|
||||||
|
};
|
||||||
|
```
|
||||||
|
<b>Returns:</b>
|
||||||
|
|
||||||
|
`{
|
||||||
|
searchSourceJSON: string;
|
||||||
|
references: SavedObjectReference[];
|
||||||
|
}`
|
||||||
|
|
|
@ -72,6 +72,7 @@ export async function buildServices(
|
||||||
const services = {
|
const services = {
|
||||||
savedObjectsClient: core.savedObjects.client,
|
savedObjectsClient: core.savedObjects.client,
|
||||||
indexPatterns: plugins.data.indexPatterns,
|
indexPatterns: plugins.data.indexPatterns,
|
||||||
|
search: plugins.data.search,
|
||||||
chrome: core.chrome,
|
chrome: core.chrome,
|
||||||
overlays: core.overlays,
|
overlays: core.overlays,
|
||||||
};
|
};
|
||||||
|
|
|
@ -56,6 +56,7 @@ export const savedObjectManagementRegistry: ISavedObjectsManagementRegistry = {
|
||||||
const services = {
|
const services = {
|
||||||
savedObjectsClient: npStart.core.savedObjects.client,
|
savedObjectsClient: npStart.core.savedObjects.client,
|
||||||
indexPatterns: npStart.plugins.data.indexPatterns,
|
indexPatterns: npStart.plugins.data.indexPatterns,
|
||||||
|
search: npStart.plugins.data.search,
|
||||||
chrome: npStart.core.chrome,
|
chrome: npStart.core.chrome,
|
||||||
overlays: npStart.core.overlays,
|
overlays: npStart.core.overlays,
|
||||||
};
|
};
|
||||||
|
|
|
@ -519,7 +519,8 @@ describe('Flyout', () => {
|
||||||
expect(resolveIndexPatternConflicts).toHaveBeenCalledWith(
|
expect(resolveIndexPatternConflicts).toHaveBeenCalledWith(
|
||||||
component.instance().resolutions,
|
component.instance().resolutions,
|
||||||
mockConflictedIndexPatterns,
|
mockConflictedIndexPatterns,
|
||||||
true
|
true,
|
||||||
|
defaultProps.indexPatterns
|
||||||
);
|
);
|
||||||
expect(saveObjects).toHaveBeenCalledWith(
|
expect(saveObjects).toHaveBeenCalledWith(
|
||||||
mockConflictedSavedObjectsLinkedToSavedSearches,
|
mockConflictedSavedObjectsLinkedToSavedSearches,
|
||||||
|
|
|
@ -358,7 +358,8 @@ export class Flyout extends Component {
|
||||||
importCount += await resolveIndexPatternConflicts(
|
importCount += await resolveIndexPatternConflicts(
|
||||||
resolutions,
|
resolutions,
|
||||||
conflictedIndexPatterns,
|
conflictedIndexPatterns,
|
||||||
isOverwriteAllChecked
|
isOverwriteAllChecked,
|
||||||
|
this.props.indexPatterns
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
|
|
|
@ -84,7 +84,7 @@ describe('resolveSavedObjects', () => {
|
||||||
},
|
},
|
||||||
} as unknown) as IndexPatternsContract;
|
} as unknown) as IndexPatternsContract;
|
||||||
|
|
||||||
const services = [
|
const services = ([
|
||||||
{
|
{
|
||||||
type: 'search',
|
type: 'search',
|
||||||
get: async () => {
|
get: async () => {
|
||||||
|
@ -124,7 +124,7 @@ describe('resolveSavedObjects', () => {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
] as SavedObjectLoader[];
|
] as unknown) as SavedObjectLoader[];
|
||||||
|
|
||||||
const overwriteAll = false;
|
const overwriteAll = false;
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@ describe('resolveSavedObjects', () => {
|
||||||
},
|
},
|
||||||
} as unknown) as IndexPatternsContract;
|
} as unknown) as IndexPatternsContract;
|
||||||
|
|
||||||
const services = [
|
const services = ([
|
||||||
{
|
{
|
||||||
type: 'search',
|
type: 'search',
|
||||||
get: async () => {
|
get: async () => {
|
||||||
|
@ -217,7 +217,7 @@ describe('resolveSavedObjects', () => {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
] as SavedObjectLoader[];
|
] as unknown) as SavedObjectLoader[];
|
||||||
|
|
||||||
const overwriteAll = false;
|
const overwriteAll = false;
|
||||||
|
|
||||||
|
@ -237,33 +237,38 @@ describe('resolveSavedObjects', () => {
|
||||||
|
|
||||||
describe('resolveIndexPatternConflicts', () => {
|
describe('resolveIndexPatternConflicts', () => {
|
||||||
it('should resave resolutions', async () => {
|
it('should resave resolutions', async () => {
|
||||||
const hydrateIndexPattern = jest.fn();
|
|
||||||
const save = jest.fn();
|
const save = jest.fn();
|
||||||
|
|
||||||
const conflictedIndexPatterns = [
|
const conflictedIndexPatterns = ([
|
||||||
{
|
{
|
||||||
obj: {
|
obj: {
|
||||||
searchSource: {
|
save,
|
||||||
getOwnField: (field: string) => {
|
},
|
||||||
return field === 'index' ? '1' : undefined;
|
doc: {
|
||||||
|
_source: {
|
||||||
|
kibanaSavedObjectMeta: {
|
||||||
|
searchSourceJSON: JSON.stringify({
|
||||||
|
index: '1',
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
hydrateIndexPattern,
|
|
||||||
save,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
obj: {
|
obj: {
|
||||||
searchSource: {
|
|
||||||
getOwnField: (field: string) => {
|
|
||||||
return field === 'index' ? '3' : undefined;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
hydrateIndexPattern,
|
|
||||||
save,
|
save,
|
||||||
},
|
},
|
||||||
|
doc: {
|
||||||
|
_source: {
|
||||||
|
kibanaSavedObjectMeta: {
|
||||||
|
searchSourceJSON: JSON.stringify({
|
||||||
|
index: '3',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
];
|
] as unknown) as Array<{ obj: SavedObject; doc: any }>;
|
||||||
|
|
||||||
const resolutions = [
|
const resolutions = [
|
||||||
{
|
{
|
||||||
|
@ -282,43 +287,49 @@ describe('resolveSavedObjects', () => {
|
||||||
|
|
||||||
const overwriteAll = false;
|
const overwriteAll = false;
|
||||||
|
|
||||||
await resolveIndexPatternConflicts(resolutions, conflictedIndexPatterns, overwriteAll);
|
await resolveIndexPatternConflicts(resolutions, conflictedIndexPatterns, overwriteAll, ({
|
||||||
expect(hydrateIndexPattern.mock.calls.length).toBe(2);
|
get: (id: string) => Promise.resolve({ id }),
|
||||||
|
} as unknown) as IndexPatternsContract);
|
||||||
|
expect(conflictedIndexPatterns[0].obj.searchSource!.getField('index')!.id).toEqual('2');
|
||||||
|
expect(conflictedIndexPatterns[1].obj.searchSource!.getField('index')!.id).toEqual('4');
|
||||||
expect(save.mock.calls.length).toBe(2);
|
expect(save.mock.calls.length).toBe(2);
|
||||||
expect(save).toHaveBeenCalledWith({ confirmOverwrite: !overwriteAll });
|
expect(save).toHaveBeenCalledWith({ confirmOverwrite: !overwriteAll });
|
||||||
expect(hydrateIndexPattern).toHaveBeenCalledWith('2');
|
|
||||||
expect(hydrateIndexPattern).toHaveBeenCalledWith('4');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should resolve filter index conflicts', async () => {
|
it('should resolve filter index conflicts', async () => {
|
||||||
const hydrateIndexPattern = jest.fn();
|
|
||||||
const save = jest.fn();
|
const save = jest.fn();
|
||||||
|
|
||||||
const conflictedIndexPatterns = [
|
const conflictedIndexPatterns = ([
|
||||||
{
|
{
|
||||||
obj: {
|
obj: {
|
||||||
searchSource: {
|
|
||||||
getOwnField: (field: string) => {
|
|
||||||
return field === 'index' ? '1' : [{ meta: { index: 'filterIndex' } }];
|
|
||||||
},
|
|
||||||
setField: jest.fn(),
|
|
||||||
},
|
|
||||||
hydrateIndexPattern,
|
|
||||||
save,
|
save,
|
||||||
},
|
},
|
||||||
|
doc: {
|
||||||
|
_source: {
|
||||||
|
kibanaSavedObjectMeta: {
|
||||||
|
searchSourceJSON: JSON.stringify({
|
||||||
|
index: '1',
|
||||||
|
filter: [{ meta: { index: 'filterIndex' } }],
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
obj: {
|
obj: {
|
||||||
searchSource: {
|
|
||||||
getOwnField: (field: string) => {
|
|
||||||
return field === 'index' ? '3' : undefined;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
hydrateIndexPattern,
|
|
||||||
save,
|
save,
|
||||||
},
|
},
|
||||||
|
doc: {
|
||||||
|
_source: {
|
||||||
|
kibanaSavedObjectMeta: {
|
||||||
|
searchSourceJSON: JSON.stringify({
|
||||||
|
index: '3',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
];
|
] as unknown) as Array<{ obj: SavedObject; doc: any }>;
|
||||||
|
|
||||||
const resolutions = [
|
const resolutions = [
|
||||||
{
|
{
|
||||||
|
@ -337,9 +348,11 @@ describe('resolveSavedObjects', () => {
|
||||||
|
|
||||||
const overwriteAll = false;
|
const overwriteAll = false;
|
||||||
|
|
||||||
await resolveIndexPatternConflicts(resolutions, conflictedIndexPatterns, overwriteAll);
|
await resolveIndexPatternConflicts(resolutions, conflictedIndexPatterns, overwriteAll, ({
|
||||||
|
get: (id: string) => Promise.resolve({ id }),
|
||||||
|
} as unknown) as IndexPatternsContract);
|
||||||
|
|
||||||
expect(conflictedIndexPatterns[0].obj.searchSource.setField).toHaveBeenCalledWith('filter', [
|
expect(conflictedIndexPatterns[0].obj.searchSource!.getField('filter')).toEqual([
|
||||||
{ meta: { index: 'newFilterIndex' } },
|
{ meta: { index: 'newFilterIndex' } },
|
||||||
]);
|
]);
|
||||||
expect(save.mock.calls.length).toBe(2);
|
expect(save.mock.calls.length).toBe(2);
|
||||||
|
|
|
@ -18,12 +18,17 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { OverlayStart } from 'src/core/public';
|
import { cloneDeep } from 'lodash';
|
||||||
|
import { OverlayStart, SavedObjectReference } from 'src/core/public';
|
||||||
import {
|
import {
|
||||||
SavedObject,
|
SavedObject,
|
||||||
SavedObjectLoader,
|
SavedObjectLoader,
|
||||||
} from '../../../../../../../../plugins/saved_objects/public';
|
} from '../../../../../../../../plugins/saved_objects/public';
|
||||||
import { IndexPatternsContract, IIndexPattern } from '../../../../../../../../plugins/data/public';
|
import {
|
||||||
|
IndexPatternsContract,
|
||||||
|
IIndexPattern,
|
||||||
|
createSearchSource,
|
||||||
|
} from '../../../../../../../../plugins/data/public';
|
||||||
|
|
||||||
type SavedObjectsRawDoc = Record<string, any>;
|
type SavedObjectsRawDoc = Record<string, any>;
|
||||||
|
|
||||||
|
@ -126,7 +131,7 @@ async function importIndexPattern(
|
||||||
async function importDocument(obj: SavedObject, doc: SavedObjectsRawDoc, overwriteAll: boolean) {
|
async function importDocument(obj: SavedObject, doc: SavedObjectsRawDoc, overwriteAll: boolean) {
|
||||||
await obj.applyESResp({
|
await obj.applyESResp({
|
||||||
references: doc._references || [],
|
references: doc._references || [],
|
||||||
...doc,
|
...cloneDeep(doc),
|
||||||
});
|
});
|
||||||
return await obj.save({ confirmOverwrite: !overwriteAll });
|
return await obj.save({ confirmOverwrite: !overwriteAll });
|
||||||
}
|
}
|
||||||
|
@ -160,41 +165,57 @@ async function awaitEachItemInParallel<T, R>(list: T[], op: (item: T) => R) {
|
||||||
export async function resolveIndexPatternConflicts(
|
export async function resolveIndexPatternConflicts(
|
||||||
resolutions: Array<{ oldId: string; newId: string }>,
|
resolutions: Array<{ oldId: string; newId: string }>,
|
||||||
conflictedIndexPatterns: any[],
|
conflictedIndexPatterns: any[],
|
||||||
overwriteAll: boolean
|
overwriteAll: boolean,
|
||||||
|
indexPatterns: IndexPatternsContract
|
||||||
) {
|
) {
|
||||||
let importCount = 0;
|
let importCount = 0;
|
||||||
|
|
||||||
await awaitEachItemInParallel(conflictedIndexPatterns, async ({ obj }) => {
|
await awaitEachItemInParallel(conflictedIndexPatterns, async ({ obj, doc }) => {
|
||||||
// Resolve search index reference:
|
const serializedSearchSource = JSON.parse(
|
||||||
let oldIndexId = obj.searchSource.getOwnField('index');
|
doc._source.kibanaSavedObjectMeta?.searchSourceJSON || '{}'
|
||||||
// Depending on the object, this can either be the raw id or the actual index pattern object
|
);
|
||||||
if (typeof oldIndexId !== 'string') {
|
const oldIndexId = serializedSearchSource.index;
|
||||||
oldIndexId = oldIndexId.id;
|
let allResolved = true;
|
||||||
}
|
const inlineResolution = resolutions.find(({ oldId }) => oldId === oldIndexId);
|
||||||
let resolution = resolutions.find(({ oldId }) => oldId === oldIndexId);
|
if (inlineResolution) {
|
||||||
if (resolution) {
|
serializedSearchSource.index = inlineResolution.newId;
|
||||||
const newIndexId = resolution.newId;
|
} else {
|
||||||
await obj.hydrateIndexPattern(newIndexId);
|
allResolved = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve filter index reference:
|
// Resolve filter index reference:
|
||||||
const filter = (obj.searchSource.getOwnField('filter') || []).map((f: any) => {
|
const filter = (serializedSearchSource.filter || []).map((f: any) => {
|
||||||
if (!(f.meta && f.meta.index)) {
|
if (!(f.meta && f.meta.index)) {
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
resolution = resolutions.find(({ oldId }) => oldId === f.meta.index);
|
const resolution = resolutions.find(({ oldId }) => oldId === f.meta.index);
|
||||||
return resolution ? { ...f, ...{ meta: { ...f.meta, index: resolution.newId } } } : f;
|
return resolution ? { ...f, ...{ meta: { ...f.meta, index: resolution.newId } } } : f;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (filter.length > 0) {
|
if (filter.length > 0) {
|
||||||
obj.searchSource.setField('filter', filter);
|
serializedSearchSource.filter = filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resolution) {
|
const replacedReferences = (doc._references || []).map((reference: SavedObjectReference) => {
|
||||||
|
const resolution = resolutions.find(({ oldId }) => oldId === reference.id);
|
||||||
|
if (resolution) {
|
||||||
|
return { ...reference, id: resolution.newId };
|
||||||
|
} else {
|
||||||
|
allResolved = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reference;
|
||||||
|
});
|
||||||
|
|
||||||
|
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 createSearchSource(indexPatterns)(
|
||||||
|
JSON.stringify(serializedSearchSource),
|
||||||
|
replacedReferences
|
||||||
|
);
|
||||||
if (await saveObject(obj, overwriteAll)) {
|
if (await saveObject(obj, overwriteAll)) {
|
||||||
importCount++;
|
importCount++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,7 @@ const getResolvedResults = deps => {
|
||||||
return createSavedSearchesLoader({
|
return createSavedSearchesLoader({
|
||||||
savedObjectsClient: core.savedObjects.client,
|
savedObjectsClient: core.savedObjects.client,
|
||||||
indexPatterns: data.indexPatterns,
|
indexPatterns: data.indexPatterns,
|
||||||
|
search: data.search,
|
||||||
chrome: core.chrome,
|
chrome: core.chrome,
|
||||||
overlays: core.overlays,
|
overlays: core.overlays,
|
||||||
}).get(results.vis.data.savedSearchId);
|
}).get(results.vis.data.savedSearchId);
|
||||||
|
|
|
@ -28,6 +28,7 @@ const savedObjectsClient = npStart.core.savedObjects.client;
|
||||||
const services = {
|
const services = {
|
||||||
savedObjectsClient,
|
savedObjectsClient,
|
||||||
indexPatterns: npStart.plugins.data.indexPatterns,
|
indexPatterns: npStart.plugins.data.indexPatterns,
|
||||||
|
search: npStart.plugins.data.search,
|
||||||
chrome: npStart.core.chrome,
|
chrome: npStart.core.chrome,
|
||||||
overlays: npStart.core.overlays,
|
overlays: npStart.core.overlays,
|
||||||
};
|
};
|
||||||
|
|
|
@ -72,9 +72,11 @@ export function setStartServices(npStart: NpStart) {
|
||||||
visualizationsServices.setAggs(npStart.plugins.data.search.aggs);
|
visualizationsServices.setAggs(npStart.plugins.data.search.aggs);
|
||||||
visualizationsServices.setOverlays(npStart.core.overlays);
|
visualizationsServices.setOverlays(npStart.core.overlays);
|
||||||
visualizationsServices.setChrome(npStart.core.chrome);
|
visualizationsServices.setChrome(npStart.core.chrome);
|
||||||
|
visualizationsServices.setSearch(npStart.plugins.data.search);
|
||||||
const savedVisualizationsLoader = createSavedVisLoader({
|
const savedVisualizationsLoader = createSavedVisLoader({
|
||||||
savedObjectsClient: npStart.core.savedObjects.client,
|
savedObjectsClient: npStart.core.savedObjects.client,
|
||||||
indexPatterns: npStart.plugins.data.indexPatterns,
|
indexPatterns: npStart.plugins.data.indexPatterns,
|
||||||
|
search: npStart.plugins.data.search,
|
||||||
chrome: npStart.core.chrome,
|
chrome: npStart.core.chrome,
|
||||||
overlays: npStart.core.overlays,
|
overlays: npStart.core.overlays,
|
||||||
visualizationTypes: visualizationsServices.getTypes(),
|
visualizationTypes: visualizationsServices.getTypes(),
|
||||||
|
|
|
@ -284,7 +284,7 @@ export class DashboardPlugin
|
||||||
const { notifications } = core;
|
const { notifications } = core;
|
||||||
const {
|
const {
|
||||||
uiActions,
|
uiActions,
|
||||||
data: { indexPatterns },
|
data: { indexPatterns, search },
|
||||||
} = plugins;
|
} = plugins;
|
||||||
|
|
||||||
const SavedObjectFinder = getSavedObjectFinder(core.savedObjects, core.uiSettings);
|
const SavedObjectFinder = getSavedObjectFinder(core.savedObjects, core.uiSettings);
|
||||||
|
@ -300,6 +300,7 @@ export class DashboardPlugin
|
||||||
const savedDashboardLoader = createSavedDashboardLoader({
|
const savedDashboardLoader = createSavedDashboardLoader({
|
||||||
savedObjectsClient: core.savedObjects.client,
|
savedObjectsClient: core.savedObjects.client,
|
||||||
indexPatterns,
|
indexPatterns,
|
||||||
|
search,
|
||||||
chrome: core.chrome,
|
chrome: core.chrome,
|
||||||
overlays: core.overlays,
|
overlays: core.overlays,
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,13 +18,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { SavedObjectsClientContract, ChromeStart, OverlayStart } from 'kibana/public';
|
import { SavedObjectsClientContract, ChromeStart, OverlayStart } from 'kibana/public';
|
||||||
import { IndexPatternsContract } from '../../../../plugins/data/public';
|
import { DataPublicPluginStart, IndexPatternsContract } from '../../../../plugins/data/public';
|
||||||
import { SavedObjectLoader } from '../../../../plugins/saved_objects/public';
|
import { SavedObjectLoader } from '../../../../plugins/saved_objects/public';
|
||||||
import { createSavedDashboardClass } from './saved_dashboard';
|
import { createSavedDashboardClass } from './saved_dashboard';
|
||||||
|
|
||||||
interface Services {
|
interface Services {
|
||||||
savedObjectsClient: SavedObjectsClientContract;
|
savedObjectsClient: SavedObjectsClientContract;
|
||||||
indexPatterns: IndexPatternsContract;
|
indexPatterns: IndexPatternsContract;
|
||||||
|
search: DataPublicPluginStart['search'];
|
||||||
chrome: ChromeStart;
|
chrome: ChromeStart;
|
||||||
overlays: OverlayStart;
|
overlays: OverlayStart;
|
||||||
}
|
}
|
||||||
|
|
|
@ -366,6 +366,7 @@ export {
|
||||||
SearchStrategyProvider,
|
SearchStrategyProvider,
|
||||||
ISearchSource,
|
ISearchSource,
|
||||||
SearchSource,
|
SearchSource,
|
||||||
|
createSearchSource,
|
||||||
SearchSourceFields,
|
SearchSourceFields,
|
||||||
EsQuerySortValue,
|
EsQuerySortValue,
|
||||||
SortDirection,
|
SortDirection,
|
||||||
|
|
|
@ -155,7 +155,7 @@ export class DataPublicPlugin implements Plugin<DataPublicPluginSetup, DataPubli
|
||||||
const query = this.queryService.start(savedObjects);
|
const query = this.queryService.start(savedObjects);
|
||||||
setQueryService(query);
|
setQueryService(query);
|
||||||
|
|
||||||
const search = this.searchService.start(core);
|
const search = this.searchService.start(core, indexPatterns);
|
||||||
setSearchService(search);
|
setSearchService(search);
|
||||||
|
|
||||||
uiActions.attachAction(APPLY_FILTER_TRIGGER, uiActions.getAction(ACTION_GLOBAL_APPLY_FILTER));
|
uiActions.attachAction(APPLY_FILTER_TRIGGER, uiActions.getAction(ACTION_GLOBAL_APPLY_FILTER));
|
||||||
|
|
|
@ -45,6 +45,7 @@ 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';
|
||||||
|
@ -209,6 +210,9 @@ export const connectToQueryState: <S extends QueryState>({ timefilter: { timefil
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export const createSavedQueryService: (savedObjectsClient: Pick<import("../../../../../core/public").SavedObjectsClient, "update" | "find" | "get" | "delete" | "create" | "bulkCreate" | "bulkGet" | "bulkUpdate">) => SavedQueryService;
|
export const createSavedQueryService: (savedObjectsClient: Pick<import("../../../../../core/public").SavedObjectsClient, "update" | "find" | "get" | "delete" | "create" | "bulkCreate" | "bulkGet" | "bulkUpdate">) => SavedQueryService;
|
||||||
|
|
||||||
|
// @public
|
||||||
|
export const createSearchSource: (indexPatterns: Pick<import("../../index_patterns/index_patterns").IndexPatternsService, "get" | "clearCache" | "getFieldsForTimePattern" | "getFieldsForWildcard" | "getIds" | "getTitles" | "getFields" | "getCache" | "getDefault" | "make">) => (searchSourceJson: string, references: SavedObjectReference[]) => Promise<SearchSource>;
|
||||||
|
|
||||||
// Warning: (ae-missing-release-tag) "CustomFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
// Warning: (ae-missing-release-tag) "CustomFilter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||||
//
|
//
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
|
@ -1677,6 +1681,10 @@ export class SearchSource {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
history: SearchRequest[];
|
history: SearchRequest[];
|
||||||
onRequestStart(handler: (searchSource: ISearchSource, options?: FetchOptions) => Promise<unknown>): void;
|
onRequestStart(handler: (searchSource: ISearchSource, options?: FetchOptions) => Promise<unknown>): void;
|
||||||
|
serialize(): {
|
||||||
|
searchSourceJSON: string;
|
||||||
|
references: SavedObjectReference[];
|
||||||
|
};
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
setField<K extends keyof SearchSourceFields>(field: K, value: SearchSourceFields[K]): this;
|
setField<K extends keyof SearchSourceFields>(field: K, value: SearchSourceFields[K]): this;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
|
@ -1891,21 +1899,21 @@ export type TSearchStrategyProvider<T extends TStrategyTypes> = (context: ISearc
|
||||||
// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "getRoutes" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "getRoutes" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/index.ts:382:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/index.ts:382:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/index.ts:382:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/index.ts:382:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/index.ts:383:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/index.ts:387:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/index.ts:388:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/index.ts:388:1 - (ae-forgotten-export) The symbol "convertDateRangeToString" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/index.ts:389:1 - (ae-forgotten-export) The symbol "convertDateRangeToString" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/index.ts:390:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/index.ts:391:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/index.ts:399:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/index.ts:400:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/index.ts:400:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/index.ts:401:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/index.ts:401:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/index.ts:402:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/index.ts:404:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/index.ts:405:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/index.ts:405:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/index.ts:406:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/index.ts:408:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/index.ts:409:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/index.ts:409:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/index.ts:410:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/index.ts:412:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/index.ts:413: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 "createFiltersFromEvent" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromEvent" needs to be exported by the entry point index.d.ts
|
||||||
|
|
|
@ -54,6 +54,7 @@ export {
|
||||||
SearchSourceFields,
|
SearchSourceFields,
|
||||||
EsQuerySortValue,
|
EsQuerySortValue,
|
||||||
SortDirection,
|
SortDirection,
|
||||||
|
createSearchSource,
|
||||||
} from './search_source';
|
} from './search_source';
|
||||||
|
|
||||||
export { SearchInterceptor } from './search_interceptor';
|
export { SearchInterceptor } from './search_interceptor';
|
||||||
|
|
|
@ -33,6 +33,7 @@ export const searchStartMock: jest.Mocked<ISearchStart> = {
|
||||||
aggs: searchAggsStartMock(),
|
aggs: searchAggsStartMock(),
|
||||||
setInterceptor: jest.fn(),
|
setInterceptor: jest.fn(),
|
||||||
search: jest.fn(),
|
search: jest.fn(),
|
||||||
|
createSearchSource: jest.fn(),
|
||||||
__LEGACY: {
|
__LEGACY: {
|
||||||
AggConfig: jest.fn() as any,
|
AggConfig: jest.fn() as any,
|
||||||
AggType: jest.fn(),
|
AggType: jest.fn(),
|
||||||
|
|
|
@ -25,6 +25,8 @@ import { TStrategyTypes } from './strategy_types';
|
||||||
import { getEsClient, LegacyApiCaller } from './es_client';
|
import { getEsClient, LegacyApiCaller } from './es_client';
|
||||||
import { ES_SEARCH_STRATEGY, DEFAULT_SEARCH_STRATEGY } from '../../common/search';
|
import { ES_SEARCH_STRATEGY, DEFAULT_SEARCH_STRATEGY } from '../../common/search';
|
||||||
import { esSearchStrategyProvider } from './es_search/es_search_strategy';
|
import { esSearchStrategyProvider } from './es_search/es_search_strategy';
|
||||||
|
import { IndexPatternsContract } from '../index_patterns/index_patterns';
|
||||||
|
import { createSearchSource } from './search_source';
|
||||||
import { QuerySetup } from '../query/query_service';
|
import { QuerySetup } from '../query/query_service';
|
||||||
import { GetInternalStartServicesFn } from '../types';
|
import { GetInternalStartServicesFn } from '../types';
|
||||||
import { SearchInterceptor } from './search_interceptor';
|
import { SearchInterceptor } from './search_interceptor';
|
||||||
|
@ -108,7 +110,7 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public start(core: CoreStart): ISearchStart {
|
public start(core: CoreStart, indexPatterns: IndexPatternsContract): ISearchStart {
|
||||||
/**
|
/**
|
||||||
* A global object that intercepts all searches and provides convenience methods for cancelling
|
* A global object that intercepts all searches and provides convenience methods for cancelling
|
||||||
* all pending search requests, as well as getting the number of pending search requests.
|
* all pending search requests, as well as getting the number of pending search requests.
|
||||||
|
@ -145,6 +147,7 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
||||||
// TODO: should an intercepror have a destroy method?
|
// TODO: should an intercepror have a destroy method?
|
||||||
this.searchInterceptor = searchInterceptor;
|
this.searchInterceptor = searchInterceptor;
|
||||||
},
|
},
|
||||||
|
createSearchSource: createSearchSource(indexPatterns),
|
||||||
__LEGACY: {
|
__LEGACY: {
|
||||||
esClient: this.esClient!,
|
esClient: this.esClient!,
|
||||||
AggConfig,
|
AggConfig,
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
* 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 { createSearchSource as createSearchSourceFactory } from './create_search_source';
|
||||||
|
import { IIndexPattern } from '../../../common/index_patterns';
|
||||||
|
import { IndexPatternsContract } from '../../index_patterns/index_patterns';
|
||||||
|
import { Filter } from '../../../common/es_query/filters';
|
||||||
|
|
||||||
|
describe('createSearchSource', function() {
|
||||||
|
let createSearchSource: ReturnType<typeof createSearchSourceFactory>;
|
||||||
|
const indexPatternMock: IIndexPattern = {} as IIndexPattern;
|
||||||
|
let indexPatternContractMock: jest.Mocked<IndexPatternsContract>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
indexPatternContractMock = ({
|
||||||
|
get: jest.fn().mockReturnValue(Promise.resolve(indexPatternMock)),
|
||||||
|
} as unknown) as jest.Mocked<IndexPatternsContract>;
|
||||||
|
createSearchSource = createSearchSourceFactory(indexPatternContractMock);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail if JSON is invalid', () => {
|
||||||
|
expect(createSearchSource('{', [])).rejects.toThrow();
|
||||||
|
expect(createSearchSource('0', [])).rejects.toThrow();
|
||||||
|
expect(createSearchSource('"abcdefg"', [])).rejects.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('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('query')).toEqual({
|
||||||
|
query: '',
|
||||||
|
language: 'kuery',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should resolve referenced index pattern', async () => {
|
||||||
|
const searchSource = await createSearchSource(
|
||||||
|
JSON.stringify({
|
||||||
|
indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||||
|
}),
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: '123-456',
|
||||||
|
type: 'index-pattern',
|
||||||
|
name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
expect(indexPatternContractMock.get).toHaveBeenCalledWith('123-456');
|
||||||
|
expect(searchSource.getOwnField('index')).toBe(indexPatternMock);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('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: {
|
||||||
|
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[];
|
||||||
|
expect(filters[0]).toMatchInlineSnapshot(`
|
||||||
|
Object {
|
||||||
|
"$state": Object {
|
||||||
|
"store": "appState",
|
||||||
|
},
|
||||||
|
"meta": Object {
|
||||||
|
"alias": null,
|
||||||
|
"disabled": false,
|
||||||
|
"index": "123-456",
|
||||||
|
"key": "category.keyword",
|
||||||
|
"negate": false,
|
||||||
|
"params": Object {
|
||||||
|
"query": "Men's Clothing",
|
||||||
|
},
|
||||||
|
"type": "phrase",
|
||||||
|
},
|
||||||
|
"query": Object {
|
||||||
|
"match_phrase": Object {
|
||||||
|
"category.keyword": "Men's Clothing",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should migrate legacy queries on the fly', async () => {
|
||||||
|
const searchSource = await createSearchSource(
|
||||||
|
JSON.stringify({
|
||||||
|
highlightAll: true,
|
||||||
|
query: 'a:b',
|
||||||
|
}),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
expect(searchSource.getOwnField('query')).toEqual({
|
||||||
|
query: 'a:b',
|
||||||
|
language: 'lucene',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,113 @@
|
||||||
|
/*
|
||||||
|
* 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 _ from 'lodash';
|
||||||
|
import { SavedObjectReference } from 'kibana/public';
|
||||||
|
import { migrateLegacyQuery } from '../../../../kibana_legacy/public';
|
||||||
|
import { InvalidJSONProperty } from '../../../../kibana_utils/public';
|
||||||
|
import { SearchSource } from './search_source';
|
||||||
|
import { IndexPatternsContract } from '../../index_patterns/index_patterns';
|
||||||
|
import { SearchSourceFields } from './types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserializes a json string and a set of referenced objects to a `SearchSource` instance.
|
||||||
|
* Use this method to re-create the search source serialized using `searchSource.serialize`.
|
||||||
|
*
|
||||||
|
* This function is a factory function that returns the actual utility when calling it with the
|
||||||
|
* required service dependency (index patterns contract). A pre-wired version is also exposed in
|
||||||
|
* the start contract of the data plugin as part of the search service
|
||||||
|
*
|
||||||
|
* @param indexPatterns The index patterns contract of the data plugin
|
||||||
|
*
|
||||||
|
* @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`.
|
||||||
|
*
|
||||||
|
* @public */
|
||||||
|
export const createSearchSource = (indexPatterns: IndexPatternsContract) => async (
|
||||||
|
searchSourceJson: string,
|
||||||
|
references: SavedObjectReference[]
|
||||||
|
) => {
|
||||||
|
const searchSource = new SearchSource();
|
||||||
|
|
||||||
|
// if we have a searchSource, set its values based on the searchSourceJson field
|
||||||
|
let searchSourceValues: Record<string, unknown>;
|
||||||
|
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.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inject index id if a reference is saved
|
||||||
|
if (searchSourceValues.indexRefName) {
|
||||||
|
const reference = references.find(ref => ref.name === searchSourceValues.indexRefName);
|
||||||
|
if (!reference) {
|
||||||
|
throw new Error(`Could not find reference for ${searchSourceValues.indexRefName}`);
|
||||||
|
}
|
||||||
|
searchSourceValues.index = reference.id;
|
||||||
|
delete searchSourceValues.indexRefName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchSourceValues.filter && Array.isArray(searchSourceValues.filter)) {
|
||||||
|
searchSourceValues.filter.forEach((filterRow: any) => {
|
||||||
|
if (!filterRow.meta || !filterRow.meta.indexRefName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const reference = references.find((ref: any) => ref.name === filterRow.meta.indexRefName);
|
||||||
|
if (!reference) {
|
||||||
|
throw new Error(`Could not find reference for ${filterRow.meta.indexRefName}`);
|
||||||
|
}
|
||||||
|
filterRow.meta.index = reference.id;
|
||||||
|
delete filterRow.meta.indexRefName;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchSourceValues.index && typeof searchSourceValues.index === 'string') {
|
||||||
|
searchSourceValues.index = await indexPatterns.get(searchSourceValues.index);
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchSourceFields = searchSource.getFields();
|
||||||
|
const fnProps = _.transform(
|
||||||
|
searchSourceFields,
|
||||||
|
function(dynamic, val, name) {
|
||||||
|
if (_.isFunction(val) && name) dynamic[name] = val;
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
// This assignment might hide problems because the type of values passed from the parsed JSON
|
||||||
|
// might not fit the SearchSourceFields interface.
|
||||||
|
const newFields: SearchSourceFields = _.defaults(searchSourceValues, fnProps);
|
||||||
|
|
||||||
|
searchSource.setFields(newFields);
|
||||||
|
const query = searchSource.getOwnField('query');
|
||||||
|
|
||||||
|
if (typeof query !== 'undefined') {
|
||||||
|
searchSource.setField('query', migrateLegacyQuery(query));
|
||||||
|
}
|
||||||
|
|
||||||
|
return searchSource;
|
||||||
|
};
|
|
@ -18,4 +18,5 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export * from './search_source';
|
export * from './search_source';
|
||||||
|
export { createSearchSource } from './create_search_source';
|
||||||
export { SortDirection, EsQuerySortValue, SearchSourceFields } from './types';
|
export { SortDirection, EsQuerySortValue, SearchSourceFields } from './types';
|
||||||
|
|
|
@ -37,4 +37,5 @@ export const searchSourceMock: MockedKeys<ISearchSource> = {
|
||||||
getSearchRequestBody: jest.fn(),
|
getSearchRequestBody: jest.fn(),
|
||||||
destroy: jest.fn(),
|
destroy: jest.fn(),
|
||||||
history: [],
|
history: [],
|
||||||
|
serialize: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { SearchSource } from './search_source';
|
import { SearchSource } from './search_source';
|
||||||
import { IndexPattern } from '../..';
|
import { IndexPattern, SortDirection } from '../..';
|
||||||
import { mockDataServices } from '../aggs/test_helpers';
|
import { mockDataServices } from '../aggs/test_helpers';
|
||||||
|
|
||||||
jest.mock('../fetch', () => ({
|
jest.mock('../fetch', () => ({
|
||||||
|
@ -150,4 +150,77 @@ describe('SearchSource', function() {
|
||||||
expect(parentFn).toBeCalledWith(searchSource, options);
|
expect(parentFn).toBeCalledWith(searchSource, options);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#serialize', function() {
|
||||||
|
it('should reference index patterns', () => {
|
||||||
|
const indexPattern123 = { id: '123' } as IndexPattern;
|
||||||
|
const searchSource = new SearchSource();
|
||||||
|
searchSource.setField('index', indexPattern123);
|
||||||
|
const { searchSourceJSON, references } = searchSource.serialize();
|
||||||
|
expect(references[0].id).toEqual('123');
|
||||||
|
expect(references[0].type).toEqual('index-pattern');
|
||||||
|
expect(JSON.parse(searchSourceJSON).indexRefName).toEqual(references[0].name);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add other fields', () => {
|
||||||
|
const searchSource = new SearchSource();
|
||||||
|
searchSource.setField('highlightAll', true);
|
||||||
|
searchSource.setField('from', 123456);
|
||||||
|
const { searchSourceJSON } = searchSource.serialize();
|
||||||
|
expect(JSON.parse(searchSourceJSON).highlightAll).toEqual(true);
|
||||||
|
expect(JSON.parse(searchSourceJSON).from).toEqual(123456);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should omit sort and size', () => {
|
||||||
|
const searchSource = new SearchSource();
|
||||||
|
searchSource.setField('highlightAll', true);
|
||||||
|
searchSource.setField('from', 123456);
|
||||||
|
searchSource.setField('sort', { field: SortDirection.asc });
|
||||||
|
searchSource.setField('size', 200);
|
||||||
|
const { searchSourceJSON } = searchSource.serialize();
|
||||||
|
expect(Object.keys(JSON.parse(searchSourceJSON))).toEqual(['highlightAll', 'from']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should serialize filters', () => {
|
||||||
|
const searchSource = new SearchSource();
|
||||||
|
const filter = [
|
||||||
|
{
|
||||||
|
query: 'query',
|
||||||
|
meta: {
|
||||||
|
alias: 'alias',
|
||||||
|
disabled: false,
|
||||||
|
negate: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
searchSource.setField('filter', filter);
|
||||||
|
const { searchSourceJSON } = searchSource.serialize();
|
||||||
|
expect(JSON.parse(searchSourceJSON).filter).toEqual(filter);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reference index patterns in filters separately from index field', () => {
|
||||||
|
const searchSource = new SearchSource();
|
||||||
|
const indexPattern123 = { id: '123' } as IndexPattern;
|
||||||
|
searchSource.setField('index', indexPattern123);
|
||||||
|
const filter = [
|
||||||
|
{
|
||||||
|
query: 'query',
|
||||||
|
meta: {
|
||||||
|
alias: 'alias',
|
||||||
|
disabled: false,
|
||||||
|
negate: false,
|
||||||
|
index: '456',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
searchSource.setField('filter', filter);
|
||||||
|
const { searchSourceJSON, references } = searchSource.serialize();
|
||||||
|
expect(references[0].id).toEqual('123');
|
||||||
|
expect(references[0].type).toEqual('index-pattern');
|
||||||
|
expect(JSON.parse(searchSourceJSON).indexRefName).toEqual(references[0].name);
|
||||||
|
expect(references[1].id).toEqual('456');
|
||||||
|
expect(references[1].type).toEqual('index-pattern');
|
||||||
|
expect(JSON.parse(searchSourceJSON).filter[0].meta.indexRefName).toEqual(references[1].name);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -70,6 +70,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
import { SavedObjectReference } 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';
|
||||||
|
@ -419,4 +420,85 @@ export class SearchSource {
|
||||||
|
|
||||||
return searchRequest;
|
return searchRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* The references returned by this function can be mixed with other references in the same object,
|
||||||
|
* however make sure there are no name-collisions. The references will be named `kibanaSavedObjectMeta.searchSourceJSON.index`
|
||||||
|
* and `kibanaSavedObjectMeta.searchSourceJSON.filter[<number>].meta.index`.
|
||||||
|
*
|
||||||
|
* Using `createSearchSource`, the instance can be re-created.
|
||||||
|
* @param searchSource The search source to serialize
|
||||||
|
* @public */
|
||||||
|
public serialize() {
|
||||||
|
const references: SavedObjectReference[] = [];
|
||||||
|
|
||||||
|
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[] {
|
||||||
|
if (!filterField) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(filterField)) {
|
||||||
|
return filterField;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_.isFunction(filterField)) {
|
||||||
|
return this.getFilters(filterField());
|
||||||
|
}
|
||||||
|
|
||||||
|
return [filterField];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { CoreStart } from 'kibana/public';
|
import { CoreStart } from 'kibana/public';
|
||||||
|
import { createSearchSource } from './search_source';
|
||||||
import { SearchAggsSetup, SearchAggsStart, SearchAggsStartLegacy } from './aggs';
|
import { SearchAggsSetup, SearchAggsStart, SearchAggsStartLegacy } from './aggs';
|
||||||
import { ISearch, ISearchGeneric } from './i_search';
|
import { ISearch, ISearchGeneric } from './i_search';
|
||||||
import { TStrategyTypes } from './strategy_types';
|
import { TStrategyTypes } from './strategy_types';
|
||||||
|
@ -89,5 +90,6 @@ export interface ISearchStart {
|
||||||
aggs: SearchAggsStart;
|
aggs: SearchAggsStart;
|
||||||
setInterceptor: (searchInterceptor: SearchInterceptor) => void;
|
setInterceptor: (searchInterceptor: SearchInterceptor) => void;
|
||||||
search: ISearchGeneric;
|
search: ISearchGeneric;
|
||||||
|
createSearchSource: ReturnType<typeof createSearchSource>;
|
||||||
__LEGACY: ISearchStartLegacy & SearchAggsStartLegacy;
|
__LEGACY: ISearchStartLegacy & SearchAggsStartLegacy;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ export class SavedObjectsPublicPlugin
|
||||||
SavedObjectClass: createSavedObjectClass({
|
SavedObjectClass: createSavedObjectClass({
|
||||||
indexPatterns: data.indexPatterns,
|
indexPatterns: data.indexPatterns,
|
||||||
savedObjectsClient: core.savedObjects.client,
|
savedObjectsClient: core.savedObjects.client,
|
||||||
|
search: data.search,
|
||||||
chrome: core.chrome,
|
chrome: core.chrome,
|
||||||
overlays: core.overlays,
|
overlays: core.overlays,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -18,9 +18,8 @@
|
||||||
*/
|
*/
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { EsResponse, SavedObject, SavedObjectConfig } from '../../types';
|
import { EsResponse, SavedObject, SavedObjectConfig } from '../../types';
|
||||||
import { parseSearchSource } from './parse_search_source';
|
|
||||||
import { expandShorthand, SavedObjectNotFound } from '../../../../kibana_utils/public';
|
import { expandShorthand, SavedObjectNotFound } from '../../../../kibana_utils/public';
|
||||||
import { IndexPattern } from '../../../../data/public';
|
import { DataPublicPluginStart, IndexPattern } 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
|
||||||
|
@ -29,13 +28,13 @@ import { IndexPattern } from '../../../../data/public';
|
||||||
export async function applyESResp(
|
export async function applyESResp(
|
||||||
resp: EsResponse,
|
resp: EsResponse,
|
||||||
savedObject: SavedObject,
|
savedObject: SavedObject,
|
||||||
config: SavedObjectConfig
|
config: SavedObjectConfig,
|
||||||
|
createSearchSource: DataPublicPluginStart['search']['createSearchSource']
|
||||||
) {
|
) {
|
||||||
const mapping = expandShorthand(config.mapping);
|
const mapping = expandShorthand(config.mapping);
|
||||||
const esType = config.type || '';
|
const esType = config.type || '';
|
||||||
savedObject._source = _.cloneDeep(resp._source);
|
savedObject._source = _.cloneDeep(resp._source);
|
||||||
const injectReferences = config.injectReferences;
|
const injectReferences = config.injectReferences;
|
||||||
const hydrateIndexPattern = savedObject.hydrateIndexPattern!;
|
|
||||||
if (typeof resp.found === 'boolean' && !resp.found) {
|
if (typeof resp.found === 'boolean' && !resp.found) {
|
||||||
throw new SavedObjectNotFound(esType, savedObject.id || '');
|
throw new SavedObjectNotFound(esType, savedObject.id || '');
|
||||||
}
|
}
|
||||||
|
@ -64,13 +63,34 @@ export async function applyESResp(
|
||||||
_.assign(savedObject, savedObject._source);
|
_.assign(savedObject, savedObject._source);
|
||||||
savedObject.lastSavedTitle = savedObject.title;
|
savedObject.lastSavedTitle = savedObject.title;
|
||||||
|
|
||||||
await parseSearchSource(savedObject, esType, meta.searchSourceJSON, resp.references);
|
if (config.searchSource) {
|
||||||
await hydrateIndexPattern();
|
try {
|
||||||
|
savedObject.searchSource = await createSearchSource(meta.searchSourceJSON, resp.references);
|
||||||
|
} catch (error) {
|
||||||
|
if (
|
||||||
|
error.constructor.name === 'SavedObjectNotFound' &&
|
||||||
|
error.savedObjectType === 'index-pattern'
|
||||||
|
) {
|
||||||
|
// if parsing the search source fails because the index pattern wasn't found,
|
||||||
|
// remember the reference - this is required for error handling on legacy imports
|
||||||
|
savedObject.unresolvedIndexPatternReference = {
|
||||||
|
name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||||
|
id: JSON.parse(meta.searchSourceJSON).index,
|
||||||
|
type: 'index-pattern',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (injectReferences && resp.references && resp.references.length > 0) {
|
if (injectReferences && resp.references && resp.references.length > 0) {
|
||||||
injectReferences(savedObject, resp.references);
|
injectReferences(savedObject, resp.references);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof config.afterESResp === 'function') {
|
if (typeof config.afterESResp === 'function') {
|
||||||
savedObject = await config.afterESResp(savedObject);
|
savedObject = await config.afterESResp(savedObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
return savedObject;
|
return savedObject;
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,8 @@ export function buildSavedObject(
|
||||||
*/
|
*/
|
||||||
savedObject.init = _.once(() => intializeSavedObject(savedObject, savedObjectsClient, config));
|
savedObject.init = _.once(() => intializeSavedObject(savedObject, savedObjectsClient, config));
|
||||||
|
|
||||||
savedObject.applyESResp = (resp: EsResponse) => applyESResp(resp, savedObject, config);
|
savedObject.applyESResp = (resp: EsResponse) =>
|
||||||
|
applyESResp(resp, savedObject, config, services.search.createSearchSource);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialize this object
|
* Serialize this object
|
||||||
|
|
|
@ -31,25 +31,19 @@ export async function hydrateIndexPattern(
|
||||||
indexPatterns: IndexPatternsContract,
|
indexPatterns: IndexPatternsContract,
|
||||||
config: SavedObjectConfig
|
config: SavedObjectConfig
|
||||||
) {
|
) {
|
||||||
const clearSavedIndexPattern = !!config.clearSavedIndexPattern;
|
|
||||||
const indexPattern = config.indexPattern;
|
const indexPattern = config.indexPattern;
|
||||||
|
|
||||||
if (!savedObject.searchSource) {
|
if (!savedObject.searchSource) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clearSavedIndexPattern) {
|
const index = id || indexPattern || savedObject.searchSource.getOwnField('index');
|
||||||
savedObject.searchSource!.setField('index', undefined);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const index = id || indexPattern || savedObject.searchSource!.getOwnField('index');
|
|
||||||
|
|
||||||
if (typeof index !== 'string' || !index) {
|
if (typeof index !== 'string' || !index) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const indexObj = await indexPatterns.get(index);
|
const indexObj = await indexPatterns.get(index);
|
||||||
savedObject.searchSource!.setField('index', indexObj);
|
savedObject.searchSource.setField('index', indexObj);
|
||||||
return indexObj;
|
return indexObj;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,97 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 _ from 'lodash';
|
|
||||||
import { migrateLegacyQuery } from '../../../../kibana_legacy/public';
|
|
||||||
import { SavedObject } from '../../types';
|
|
||||||
import { InvalidJSONProperty } from '../../../../kibana_utils/public';
|
|
||||||
|
|
||||||
export function parseSearchSource(
|
|
||||||
savedObject: SavedObject,
|
|
||||||
esType: string,
|
|
||||||
searchSourceJson: string,
|
|
||||||
references: any[]
|
|
||||||
) {
|
|
||||||
if (!savedObject.searchSource) return;
|
|
||||||
|
|
||||||
// if we have a searchSource, set its values based on the searchSourceJson field
|
|
||||||
let searchSourceValues: Record<string, any>;
|
|
||||||
try {
|
|
||||||
searchSourceValues = JSON.parse(searchSourceJson);
|
|
||||||
} catch (e) {
|
|
||||||
throw new InvalidJSONProperty(
|
|
||||||
`Invalid JSON in ${esType} "${savedObject.id}". ${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 searchSourceJSON in ${esType} "${savedObject.id}".`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inject index id if a reference is saved
|
|
||||||
if (searchSourceValues.indexRefName) {
|
|
||||||
const reference = references.find(
|
|
||||||
(ref: Record<string, any>) => ref.name === searchSourceValues.indexRefName
|
|
||||||
);
|
|
||||||
if (!reference) {
|
|
||||||
throw new Error(
|
|
||||||
`Could not find reference for ${
|
|
||||||
searchSourceValues.indexRefName
|
|
||||||
} on ${savedObject.getEsType()} ${savedObject.id}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
searchSourceValues.index = reference.id;
|
|
||||||
delete searchSourceValues.indexRefName;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (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
|
|
||||||
} on ${savedObject.getEsType()}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
filterRow.meta.index = reference.id;
|
|
||||||
delete filterRow.meta.indexRefName;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const searchSourceFields = savedObject.searchSource.getFields();
|
|
||||||
const fnProps = _.transform(
|
|
||||||
searchSourceFields,
|
|
||||||
function(dynamic: Record<string, any>, val: any, name: string | undefined) {
|
|
||||||
if (_.isFunction(val) && name) dynamic[name] = val;
|
|
||||||
},
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
|
|
||||||
savedObject.searchSource.setFields(_.defaults(searchSourceValues, fnProps));
|
|
||||||
const query = savedObject.searchSource.getOwnField('query');
|
|
||||||
|
|
||||||
if (typeof query !== 'undefined') {
|
|
||||||
savedObject.searchSource.setField('query', migrateLegacyQuery(query));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -17,7 +17,6 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import angular from 'angular';
|
|
||||||
import { SavedObject, SavedObjectConfig } from '../../types';
|
import { SavedObject, SavedObjectConfig } from '../../types';
|
||||||
import { expandShorthand } from '../../../../kibana_utils/public';
|
import { expandShorthand } from '../../../../kibana_utils/public';
|
||||||
|
|
||||||
|
@ -41,57 +40,16 @@ export function serializeSavedObject(savedObject: SavedObject, config: SavedObje
|
||||||
});
|
});
|
||||||
|
|
||||||
if (savedObject.searchSource) {
|
if (savedObject.searchSource) {
|
||||||
let searchSourceFields: Record<string, any> = _.omit(savedObject.searchSource.getFields(), [
|
const {
|
||||||
'sort',
|
searchSourceJSON,
|
||||||
'size',
|
references: searchSourceReferences,
|
||||||
]);
|
} = savedObject.searchSource.serialize();
|
||||||
if (searchSourceFields.index) {
|
attributes.kibanaSavedObjectMeta = { searchSourceJSON };
|
||||||
// searchSourceFields.index will normally be an IndexPattern, but can be a string in two scenarios:
|
references.push(...searchSourceReferences);
|
||||||
// (1) `init()` (and by extension `hydrateIndexPattern()`) hasn't been called on Saved Object
|
}
|
||||||
// (2) The IndexPattern doesn't exist, so we fail to resolve it in `hydrateIndexPattern()`
|
|
||||||
const indexId =
|
if (savedObject.unresolvedIndexPatternReference) {
|
||||||
typeof searchSourceFields.index === 'string'
|
references.push(savedObject.unresolvedIndexPatternReference);
|
||||||
? searchSourceFields.index
|
|
||||||
: searchSourceFields.index.id;
|
|
||||||
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.map((filterRow: any, i: number) => {
|
|
||||||
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,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
attributes.kibanaSavedObjectMeta = {
|
|
||||||
searchSourceJSON: angular.toJson(searchSourceFields),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return { attributes, references };
|
return { attributes, references };
|
||||||
|
|
|
@ -103,9 +103,11 @@ describe('Saved Object', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
(dataStartMock.search.createSearchSource as jest.Mock).mockReset();
|
||||||
SavedObjectClass = createSavedObjectClass({
|
SavedObjectClass = createSavedObjectClass({
|
||||||
savedObjectsClient: savedObjectsClientStub,
|
savedObjectsClient: savedObjectsClientStub,
|
||||||
indexPatterns: dataStartMock.indexPatterns,
|
indexPatterns: dataStartMock.indexPatterns,
|
||||||
|
search: dataStartMock.search,
|
||||||
} as SavedObjectKibanaServices);
|
} as SavedObjectKibanaServices);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -269,7 +271,7 @@ describe('Saved Object', () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('when index exists in searchSourceJSON', () => {
|
it('when search source references saved object', () => {
|
||||||
const id = '123';
|
const id = '123';
|
||||||
stubESResponse(getMockedDocResponse(id));
|
stubESResponse(getMockedDocResponse(id));
|
||||||
return createInitializedSavedObject({ type: 'dashboard', searchSource: true }).then(
|
return createInitializedSavedObject({ type: 'dashboard', searchSource: true }).then(
|
||||||
|
@ -409,18 +411,17 @@ describe('Saved Object', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throws error invalid JSON is detected', async () => {
|
it('forwards thrown exceptions from createSearchSource', async () => {
|
||||||
|
(dataStartMock.search.createSearchSource as jest.Mock).mockImplementation(() => {
|
||||||
|
throw new InvalidJSONProperty('');
|
||||||
|
});
|
||||||
const savedObject = await createInitializedSavedObject({
|
const savedObject = await createInitializedSavedObject({
|
||||||
type: 'dashboard',
|
type: 'dashboard',
|
||||||
searchSource: true,
|
searchSource: true,
|
||||||
});
|
});
|
||||||
const response = {
|
const response = {
|
||||||
found: true,
|
found: true,
|
||||||
_source: {
|
_source: {},
|
||||||
kibanaSavedObjectMeta: {
|
|
||||||
searchSourceJSON: '"{\\n \\"filter\\": []\\n}"',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -586,23 +587,24 @@ describe('Saved Object', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('injects references from searchSourceJSON', async () => {
|
it('passes references to search source parsing function', async () => {
|
||||||
const savedObject = new SavedObjectClass({ type: 'dashboard', searchSource: true });
|
const savedObject = new SavedObjectClass({ type: 'dashboard', searchSource: true });
|
||||||
return savedObject.init!().then(() => {
|
return savedObject.init!().then(() => {
|
||||||
|
const searchSourceJSON = JSON.stringify({
|
||||||
|
indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||||
|
filter: [
|
||||||
|
{
|
||||||
|
meta: {
|
||||||
|
indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
const response = {
|
const response = {
|
||||||
found: true,
|
found: true,
|
||||||
_source: {
|
_source: {
|
||||||
kibanaSavedObjectMeta: {
|
kibanaSavedObjectMeta: {
|
||||||
searchSourceJSON: JSON.stringify({
|
searchSourceJSON,
|
||||||
indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
|
||||||
filter: [
|
|
||||||
{
|
|
||||||
meta: {
|
|
||||||
indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
references: [
|
references: [
|
||||||
|
@ -619,16 +621,10 @@ describe('Saved Object', () => {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
savedObject.applyESResp(response);
|
savedObject.applyESResp(response);
|
||||||
expect(savedObject.searchSource!.getFields()).toEqual({
|
expect(dataStartMock.search.createSearchSource).toBeCalledWith(
|
||||||
index: 'my-index-1',
|
searchSourceJSON,
|
||||||
filter: [
|
response.references
|
||||||
{
|
);
|
||||||
meta: {
|
|
||||||
index: 'my-index-2',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -24,7 +24,12 @@ import {
|
||||||
SavedObjectAttributes,
|
SavedObjectAttributes,
|
||||||
SavedObjectReference,
|
SavedObjectReference,
|
||||||
} from 'kibana/public';
|
} from 'kibana/public';
|
||||||
import { IIndexPattern, IndexPatternsContract, ISearchSource } from '../../data/public';
|
import {
|
||||||
|
DataPublicPluginStart,
|
||||||
|
IIndexPattern,
|
||||||
|
IndexPatternsContract,
|
||||||
|
ISearchSource,
|
||||||
|
} from '../../data/public';
|
||||||
|
|
||||||
export interface SavedObject {
|
export interface SavedObject {
|
||||||
_serialize: () => { attributes: SavedObjectAttributes; references: SavedObjectReference[] };
|
_serialize: () => { attributes: SavedObjectAttributes; references: SavedObjectReference[] };
|
||||||
|
@ -49,6 +54,7 @@ export interface SavedObject {
|
||||||
searchSource?: ISearchSource;
|
searchSource?: ISearchSource;
|
||||||
showInRecentlyAccessed: boolean;
|
showInRecentlyAccessed: boolean;
|
||||||
title: string;
|
title: string;
|
||||||
|
unresolvedIndexPatternReference?: SavedObjectReference;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SavedObjectSaveOpts {
|
export interface SavedObjectSaveOpts {
|
||||||
|
@ -65,6 +71,7 @@ export interface SavedObjectCreationOpts {
|
||||||
export interface SavedObjectKibanaServices {
|
export interface SavedObjectKibanaServices {
|
||||||
savedObjectsClient: SavedObjectsClientContract;
|
savedObjectsClient: SavedObjectsClientContract;
|
||||||
indexPatterns: IndexPatternsContract;
|
indexPatterns: IndexPatternsContract;
|
||||||
|
search: DataPublicPluginStart['search'];
|
||||||
chrome: ChromeStart;
|
chrome: ChromeStart;
|
||||||
overlays: OverlayStart;
|
overlays: OverlayStart;
|
||||||
}
|
}
|
||||||
|
@ -72,7 +79,6 @@ export interface SavedObjectKibanaServices {
|
||||||
export interface SavedObjectConfig {
|
export interface SavedObjectConfig {
|
||||||
// is only used by visualize
|
// is only used by visualize
|
||||||
afterESResp?: (savedObject: SavedObject) => Promise<SavedObject>;
|
afterESResp?: (savedObject: SavedObject) => Promise<SavedObject>;
|
||||||
clearSavedIndexPattern?: boolean;
|
|
||||||
defaults?: any;
|
defaults?: any;
|
||||||
extractReferences?: (opts: {
|
extractReferences?: (opts: {
|
||||||
attributes: SavedObjectAttributes;
|
attributes: SavedObjectAttributes;
|
||||||
|
|
|
@ -26,6 +26,7 @@ import {
|
||||||
setCapabilities,
|
setCapabilities,
|
||||||
setHttp,
|
setHttp,
|
||||||
setIndexPatterns,
|
setIndexPatterns,
|
||||||
|
setSearch,
|
||||||
setSavedObjects,
|
setSavedObjects,
|
||||||
setUsageCollector,
|
setUsageCollector,
|
||||||
setFilterManager,
|
setFilterManager,
|
||||||
|
@ -140,6 +141,7 @@ export class VisualizationsPlugin
|
||||||
setHttp(core.http);
|
setHttp(core.http);
|
||||||
setSavedObjects(core.savedObjects);
|
setSavedObjects(core.savedObjects);
|
||||||
setIndexPatterns(data.indexPatterns);
|
setIndexPatterns(data.indexPatterns);
|
||||||
|
setSearch(data.search);
|
||||||
setFilterManager(data.query.filterManager);
|
setFilterManager(data.query.filterManager);
|
||||||
setExpressions(expressions);
|
setExpressions(expressions);
|
||||||
setUiActions(uiActions);
|
setUiActions(uiActions);
|
||||||
|
@ -150,6 +152,7 @@ export class VisualizationsPlugin
|
||||||
const savedVisualizationsLoader = createSavedVisLoader({
|
const savedVisualizationsLoader = createSavedVisLoader({
|
||||||
savedObjectsClient: core.savedObjects.client,
|
savedObjectsClient: core.savedObjects.client,
|
||||||
indexPatterns: data.indexPatterns,
|
indexPatterns: data.indexPatterns,
|
||||||
|
search: data.search,
|
||||||
chrome: core.chrome,
|
chrome: core.chrome,
|
||||||
overlays: core.overlays,
|
overlays: core.overlays,
|
||||||
visualizationTypes: types,
|
visualizationTypes: types,
|
||||||
|
|
|
@ -35,7 +35,7 @@ import { extractReferences, injectReferences } from './saved_visualization_refer
|
||||||
import { IIndexPattern, ISearchSource, SearchSource } from '../../../../plugins/data/public';
|
import { IIndexPattern, ISearchSource, SearchSource } from '../../../../plugins/data/public';
|
||||||
import { ISavedVis, SerializedVis } from '../types';
|
import { ISavedVis, SerializedVis } from '../types';
|
||||||
import { createSavedSearchesLoader } from '../../../../plugins/discover/public';
|
import { createSavedSearchesLoader } from '../../../../plugins/discover/public';
|
||||||
import { getChrome, getOverlays, getIndexPatterns, getSavedObjects } from '../services';
|
import { getChrome, getOverlays, getIndexPatterns, getSavedObjects, getSearch } from '../services';
|
||||||
|
|
||||||
export const convertToSerializedVis = async (savedVis: ISavedVis): Promise<SerializedVis> => {
|
export const convertToSerializedVis = async (savedVis: ISavedVis): Promise<SerializedVis> => {
|
||||||
const { visState } = savedVis;
|
const { visState } = savedVis;
|
||||||
|
@ -87,6 +87,7 @@ const getSearchSource = async (inputSearchSource: ISearchSource, savedSearchId?:
|
||||||
const savedSearch = await createSavedSearchesLoader({
|
const savedSearch = await createSavedSearchesLoader({
|
||||||
savedObjectsClient: getSavedObjects().client,
|
savedObjectsClient: getSavedObjects().client,
|
||||||
indexPatterns: getIndexPatterns(),
|
indexPatterns: getIndexPatterns(),
|
||||||
|
search: getSearch(),
|
||||||
chrome: getChrome(),
|
chrome: getChrome(),
|
||||||
overlays: getOverlays(),
|
overlays: getOverlays(),
|
||||||
}).get(savedSearchId);
|
}).get(savedSearchId);
|
||||||
|
|
|
@ -63,6 +63,8 @@ export const [getIndexPatterns, setIndexPatterns] = createGetterSetter<IndexPatt
|
||||||
'IndexPatterns'
|
'IndexPatterns'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const [getSearch, setSearch] = createGetterSetter<DataPublicPluginStart['search']>('Search');
|
||||||
|
|
||||||
export const [getUsageCollector, setUsageCollector] = createGetterSetter<UsageCollectionSetup>(
|
export const [getUsageCollector, setUsageCollector] = createGetterSetter<UsageCollectionSetup>(
|
||||||
'UsageCollection'
|
'UsageCollection'
|
||||||
);
|
);
|
||||||
|
|
|
@ -17,6 +17,7 @@ module.service('gisMapSavedObjectLoader', function() {
|
||||||
const services = {
|
const services = {
|
||||||
savedObjectsClient,
|
savedObjectsClient,
|
||||||
indexPatterns: npStart.plugins.data.indexPatterns,
|
indexPatterns: npStart.plugins.data.indexPatterns,
|
||||||
|
search: npStart.plugins.data.search,
|
||||||
chrome: npStart.core.chrome,
|
chrome: npStart.core.chrome,
|
||||||
overlays: npStart.core.overlays,
|
overlays: npStart.core.overlays,
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,6 +29,7 @@ export const useSearchItems = (defaultSavedObjectId: string | undefined) => {
|
||||||
const savedSearches = createSavedSearchesLoader({
|
const savedSearches = createSavedSearchesLoader({
|
||||||
savedObjectsClient,
|
savedObjectsClient,
|
||||||
indexPatterns,
|
indexPatterns,
|
||||||
|
search: appDeps.data.search,
|
||||||
chrome: appDeps.chrome,
|
chrome: appDeps.chrome,
|
||||||
overlays: appDeps.overlays,
|
overlays: appDeps.overlays,
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue