mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[saved search] Content management integration (#158006)
## Summary - Saved searches use content management api - Saved search plugin provides proper plugin api instead of static exports - Discover no longer re-exports static content from saved search plugin - ML no longer works directly with the saved search saved object - saved object conflicts are thrown via the api, rather than the api consumer - Content management api logs failed requests a bit better, helpful for tests failing in CI Closes https://github.com/elastic/kibana/issues/157078 --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
4e38817a4d
commit
22ccf83d66
123 changed files with 1100 additions and 770 deletions
37
src/plugins/content_management/public/mocks.ts
Normal file
37
src/plugins/content_management/public/mocks.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
import { ContentManagementPublicStart, ContentManagementPublicSetup } from './types';
|
||||
|
||||
const createSetupContract = (): ContentManagementPublicSetup => {
|
||||
return {
|
||||
registry: {
|
||||
register: jest.fn(),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const createStartContract = (): ContentManagementPublicStart => {
|
||||
return {
|
||||
client: {
|
||||
get: jest.fn(),
|
||||
create: jest.fn(),
|
||||
update: jest.fn(),
|
||||
delete: jest.fn(),
|
||||
search: jest.fn(),
|
||||
} as unknown as ContentManagementPublicStart['client'],
|
||||
registry: {
|
||||
get: jest.fn(),
|
||||
getAll: jest.fn(),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const contentManagementMock = {
|
||||
createSetupContract,
|
||||
createStartContract,
|
||||
};
|
|
@ -62,9 +62,15 @@ export class RpcClient implements CrudClient {
|
|||
}
|
||||
|
||||
private sendMessage = async <O = unknown>(name: ProcedureName, input: any): Promise<O> => {
|
||||
const { result } = await this.http.post<{ result: O }>(`${API_ENDPOINT}/${name}`, {
|
||||
body: JSON.stringify(input),
|
||||
});
|
||||
return result;
|
||||
try {
|
||||
const response = await this.http.post<{ result: O }>(`${API_ENDPOINT}/${name}`, {
|
||||
body: JSON.stringify(input),
|
||||
});
|
||||
return response.result;
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`Content management client error: ${e.body.message}`);
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"savedObjects",
|
||||
"savedObjectsFinder",
|
||||
"savedObjectsManagement",
|
||||
"savedSearch",
|
||||
"dataViewFieldEditor",
|
||||
"dataViewEditor",
|
||||
"expressions",
|
||||
|
@ -39,8 +40,7 @@
|
|||
"requiredBundles": [
|
||||
"kibanaUtils",
|
||||
"kibanaReact",
|
||||
"unifiedSearch",
|
||||
"savedSearch"
|
||||
"unifiedSearch"
|
||||
],
|
||||
"extraPublicDirs": [
|
||||
"common"
|
||||
|
|
|
@ -10,6 +10,7 @@ import { EUI_CHARTS_THEME_LIGHT } from '@elastic/eui/dist/eui_charts_theme';
|
|||
import { DiscoverServices } from '../build_services';
|
||||
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
|
||||
import { expressionsPluginMock } from '@kbn/expressions-plugin/public/mocks';
|
||||
import { savedSearchPluginMock } from '@kbn/saved-search-plugin/public/mocks';
|
||||
import { chromeServiceMock, coreMock, docLinksServiceMock } from '@kbn/core/public/mocks';
|
||||
import {
|
||||
CONTEXT_STEP_SETTING,
|
||||
|
@ -190,6 +191,7 @@ export function createDiscoverServicesMock(): DiscoverServices {
|
|||
updateTagsReferences: jest.fn(),
|
||||
},
|
||||
},
|
||||
savedSearch: savedSearchPluginMock.createStartContract(),
|
||||
dataViews: dataPlugin.dataViews,
|
||||
timefilter: dataPlugin.query.timefilter.timefilter,
|
||||
lens: {
|
||||
|
|
|
@ -12,6 +12,7 @@ import { BehaviorSubject, Observable, Subject } from 'rxjs';
|
|||
import { RequestAdapter } from '@kbn/inspector-plugin/common';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { createHashHistory } from 'history';
|
||||
import { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { FetchStatus } from '../../../../types';
|
||||
import {
|
||||
AvailableFields$,
|
||||
|
@ -22,7 +23,6 @@ import {
|
|||
} from '../../../services/discover_data_state_container';
|
||||
import { buildDataTableRecordList } from '../../../../../utils/build_data_record';
|
||||
import { esHits } from '../../../../../__mocks__/es_hits';
|
||||
import { SavedSearch } from '../../../../..';
|
||||
import { DiscoverLayoutProps } from '../discover_layout';
|
||||
import {
|
||||
DiscoverStateContainer,
|
||||
|
|
|
@ -6,17 +6,6 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SavedObjectSaveOpts } from '@kbn/saved-objects-plugin/public';
|
||||
|
||||
const mockSaveSavedSearch = jest.fn().mockResolvedValue('123');
|
||||
jest.mock('@kbn/saved-search-plugin/public', () => {
|
||||
const actualPlugin = jest.requireActual('@kbn/saved-search-plugin/public');
|
||||
return {
|
||||
...actualPlugin,
|
||||
saveSavedSearch: (val: SavedSearch, opts?: SavedObjectSaveOpts) =>
|
||||
mockSaveSavedSearch(val, opts),
|
||||
};
|
||||
});
|
||||
import { getSavedSearchContainer, isEqualSavedSearch } from './discover_saved_search_container';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { discoverServiceMock } from '../../../__mocks__/services';
|
||||
|
@ -92,32 +81,7 @@ describe('DiscoverSavedSearchContainer', () => {
|
|||
discoverServiceMock.data.search.searchSource.create = jest
|
||||
.fn()
|
||||
.mockReturnValue(savedSearchMock.searchSource);
|
||||
discoverServiceMock.core.savedObjects.client.resolve = jest.fn().mockReturnValue({
|
||||
saved_object: {
|
||||
attributes: {
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON:
|
||||
'{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}',
|
||||
},
|
||||
title: 'The saved search that will save the world',
|
||||
sort: [],
|
||||
columns: ['test123'],
|
||||
description: 'description',
|
||||
hideChart: false,
|
||||
},
|
||||
id: 'the-saved-search-id',
|
||||
type: 'search',
|
||||
references: [
|
||||
{
|
||||
name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||
id: 'the-data-view-id',
|
||||
type: 'index-pattern',
|
||||
},
|
||||
],
|
||||
namespaces: ['default'],
|
||||
},
|
||||
outcome: 'exactMatch',
|
||||
});
|
||||
discoverServiceMock.savedSearch.get = jest.fn().mockReturnValue(savedSearchMock);
|
||||
|
||||
it('loads a saved search', async () => {
|
||||
const savedSearchContainer = getSavedSearchContainer({
|
||||
|
@ -143,7 +107,10 @@ describe('DiscoverSavedSearchContainer', () => {
|
|||
};
|
||||
|
||||
await savedSearchContainer.persist(savedSearchToPersist, saveOptions);
|
||||
expect(mockSaveSavedSearch).toHaveBeenCalledWith(savedSearchToPersist, saveOptions);
|
||||
expect(discoverServiceMock.savedSearch.save).toHaveBeenCalledWith(
|
||||
savedSearchToPersist,
|
||||
saveOptions
|
||||
);
|
||||
});
|
||||
|
||||
it('sets the initial and current saved search to the persisted saved search', async () => {
|
||||
|
@ -152,6 +119,9 @@ describe('DiscoverSavedSearchContainer', () => {
|
|||
...savedSearch,
|
||||
title,
|
||||
};
|
||||
|
||||
discoverServiceMock.savedSearch.save = jest.fn().mockResolvedValue('123');
|
||||
|
||||
const savedSearchContainer = getSavedSearchContainer({
|
||||
services: discoverServiceMock,
|
||||
});
|
||||
|
@ -200,7 +170,7 @@ describe('DiscoverSavedSearchContainer', () => {
|
|||
});
|
||||
|
||||
it('Error thrown on persistence layer bubbling up, no changes to the initial saved search ', async () => {
|
||||
mockSaveSavedSearch.mockImplementation(() => {
|
||||
discoverServiceMock.savedSearch.save = jest.fn().mockImplementation(() => {
|
||||
throw new Error('oh-noes');
|
||||
});
|
||||
|
||||
|
|
|
@ -6,12 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import {
|
||||
getNewSavedSearch,
|
||||
getSavedSearch,
|
||||
SavedSearch,
|
||||
saveSavedSearch,
|
||||
} from '@kbn/saved-search-plugin/public';
|
||||
import { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import type { DataView } from '@kbn/data-views-plugin/common';
|
||||
import { SavedObjectSaveOpts } from '@kbn/saved-objects-plugin/public';
|
||||
|
@ -114,7 +109,7 @@ export function getSavedSearchContainer({
|
|||
}: {
|
||||
services: DiscoverServices;
|
||||
}): DiscoverSavedSearchContainer {
|
||||
const initialSavedSearch = getNewSavedSearch(services.data);
|
||||
const initialSavedSearch = services.savedSearch.getNew();
|
||||
const savedSearchInitial$ = new BehaviorSubject(initialSavedSearch);
|
||||
const savedSearchCurrent$ = new BehaviorSubject(copySavedSearch(initialSavedSearch));
|
||||
const hasChanged$ = new BehaviorSubject(false);
|
||||
|
@ -135,7 +130,7 @@ export function getSavedSearchContainer({
|
|||
const newSavedSearch = async (nextDataView: DataView | undefined) => {
|
||||
addLog('[savedSearch] new', { nextDataView });
|
||||
const dataView = nextDataView ?? getState().searchSource.getField('index');
|
||||
const nextSavedSearch = await getNewSavedSearch(services.data);
|
||||
const nextSavedSearch = services.savedSearch.getNew();
|
||||
nextSavedSearch.searchSource.setField('index', dataView);
|
||||
const newAppState = getDefaultAppState(nextSavedSearch, services);
|
||||
const nextSavedSearchToSet = updateSavedSearch({
|
||||
|
@ -151,12 +146,7 @@ export function getSavedSearchContainer({
|
|||
addLog('[savedSearch] persist', { nextSavedSearch, saveOptions });
|
||||
updateSavedSearch({ savedSearch: nextSavedSearch, services }, true);
|
||||
|
||||
const id = await saveSavedSearch(
|
||||
nextSavedSearch,
|
||||
saveOptions || {},
|
||||
services.core.savedObjects.client,
|
||||
services.savedObjectsTagging
|
||||
);
|
||||
const id = await services.savedSearch.save(nextSavedSearch, saveOptions || {});
|
||||
|
||||
if (id) {
|
||||
set(nextSavedSearch);
|
||||
|
@ -191,12 +181,9 @@ export function getSavedSearchContainer({
|
|||
|
||||
const load = async (id: string, dataView: DataView | undefined): Promise<SavedSearch> => {
|
||||
addLog('[savedSearch] load', { id, dataView });
|
||||
const loadedSavedSearch = await getSavedSearch(id, {
|
||||
search: services.data.search,
|
||||
savedObjectsClient: services.core.savedObjects.client,
|
||||
spaces: services.spaces,
|
||||
savedObjectsTagging: services.savedObjectsTagging,
|
||||
});
|
||||
|
||||
const loadedSavedSearch = await services.savedSearch.get(id);
|
||||
|
||||
if (!loadedSavedSearch.searchSource.getField('index') && dataView) {
|
||||
loadedSavedSearch.searchSource.setField('index', dataView);
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ import { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public';
|
|||
import { IndexPatternFieldEditorStart } from '@kbn/data-view-field-editor-plugin/public';
|
||||
import { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
|
||||
import { EmbeddableStart } from '@kbn/embeddable-plugin/public';
|
||||
import { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public';
|
||||
|
||||
import type { SpacesApi } from '@kbn/spaces-plugin/public';
|
||||
import { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public';
|
||||
|
@ -99,6 +100,7 @@ export interface DiscoverServices {
|
|||
charts: ChartsPluginStart;
|
||||
savedObjectsManagement: SavedObjectsManagementPluginStart;
|
||||
savedObjectsTagging?: SavedObjectsTaggingApi;
|
||||
savedSearch: SavedSearchPublicPluginStart;
|
||||
unifiedSearch: UnifiedSearchPublicPluginStart;
|
||||
lens: LensPublicStart;
|
||||
}
|
||||
|
@ -154,6 +156,7 @@ export const buildServices = memoize(function (
|
|||
charts: plugins.charts,
|
||||
savedObjectsTagging: plugins.savedObjectsTaggingOss?.getTaggingApi(),
|
||||
savedObjectsManagement: plugins.savedObjectsManagement,
|
||||
savedSearch: plugins.savedSearch,
|
||||
unifiedSearch: plugins.unifiedSearch,
|
||||
lens: plugins.lens,
|
||||
};
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
import { ReactElement } from 'react';
|
||||
import { FilterManager } from '@kbn/data-plugin/public';
|
||||
import { createFilterManagerMock } from '@kbn/data-plugin/public/query/filter_manager/filter_manager.mock';
|
||||
import { getSavedSearchUrl, SearchInput } from '..';
|
||||
import { SearchInput } from '..';
|
||||
import { getSavedSearchUrl } from '@kbn/saved-search-plugin/public';
|
||||
import { DiscoverServices } from '../build_services';
|
||||
import { dataViewMock } from '../__mocks__/data_view';
|
||||
import { discoverServiceMock } from '../__mocks__/services';
|
||||
|
|
|
@ -8,18 +8,10 @@
|
|||
|
||||
import { discoverServiceMock } from '../__mocks__/services';
|
||||
import { SearchEmbeddableFactory, type StartServices } from './search_embeddable_factory';
|
||||
import { getSavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { createSearchSourceMock } from '@kbn/data-plugin/public/mocks';
|
||||
import { dataViewMock } from '../__mocks__/data_view';
|
||||
import { ErrorEmbeddable } from '@kbn/embeddable-plugin/public';
|
||||
|
||||
jest.mock('@kbn/saved-search-plugin/public', () => {
|
||||
return {
|
||||
...jest.requireActual('@kbn/saved-search-plugin/public'),
|
||||
getSavedSearch: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('@kbn/embeddable-plugin/public', () => {
|
||||
return {
|
||||
...jest.requireActual('@kbn/embeddable-plugin/public'),
|
||||
|
@ -35,7 +27,6 @@ const input = {
|
|||
rowsPerPage: 50,
|
||||
};
|
||||
|
||||
const getSavedSearchMock = getSavedSearch as unknown as jest.Mock;
|
||||
const ErrorEmbeddableMock = ErrorEmbeddable as unknown as jest.Mock;
|
||||
|
||||
describe('SearchEmbeddableFactory', () => {
|
||||
|
@ -45,7 +36,9 @@ describe('SearchEmbeddableFactory', () => {
|
|||
sort: [['message', 'asc']] as Array<[string, string]>,
|
||||
searchSource: createSearchSourceMock({ index: dataViewMock }, undefined),
|
||||
};
|
||||
getSavedSearchMock.mockResolvedValue(savedSearchMock);
|
||||
|
||||
const mockGet = jest.fn().mockResolvedValue(savedSearchMock);
|
||||
discoverServiceMock.savedSearch.get = mockGet;
|
||||
|
||||
const factory = new SearchEmbeddableFactory(
|
||||
() => Promise.resolve({ executeTriggerActions: jest.fn() } as unknown as StartServices),
|
||||
|
@ -53,12 +46,13 @@ describe('SearchEmbeddableFactory', () => {
|
|||
);
|
||||
const embeddable = await factory.createFromSavedObject('saved-object-id', input);
|
||||
|
||||
expect(getSavedSearchMock.mock.calls[0][0]).toEqual('saved-object-id');
|
||||
expect(mockGet.mock.calls[0][0]).toEqual('saved-object-id');
|
||||
expect(embeddable).toBeDefined();
|
||||
});
|
||||
|
||||
it('should throw an error when saved search could not be found', async () => {
|
||||
getSavedSearchMock.mockRejectedValue('Could not find saved search');
|
||||
const mockGet = jest.fn().mockRejectedValue('Could not find saved search');
|
||||
discoverServiceMock.savedSearch.get = mockGet;
|
||||
|
||||
const factory = new SearchEmbeddableFactory(
|
||||
() => Promise.resolve({ executeTriggerActions: jest.fn() } as unknown as StartServices),
|
||||
|
|
|
@ -16,11 +16,7 @@ import {
|
|||
|
||||
import type { TimeRange } from '@kbn/es-query';
|
||||
|
||||
import {
|
||||
getSavedSearch,
|
||||
getSavedSearchUrl,
|
||||
throwErrorOnSavedSearchUrlConflict,
|
||||
} from '@kbn/saved-search-plugin/public';
|
||||
import { getSavedSearchUrl } from '@kbn/saved-search-plugin/public';
|
||||
import { SearchInput, SearchOutput } from './types';
|
||||
import { SEARCH_EMBEDDABLE_TYPE } from './constants';
|
||||
import { SavedSearchEmbeddable } from './saved_search_embeddable';
|
||||
|
@ -72,14 +68,7 @@ export class SearchEmbeddableFactory
|
|||
const url = getSavedSearchUrl(savedObjectId);
|
||||
const editUrl = services.addBasePath(`/app/discover${url}`);
|
||||
try {
|
||||
const savedSearch = await getSavedSearch(savedObjectId, {
|
||||
search: services.data.search,
|
||||
savedObjectsClient: services.core.savedObjects.client,
|
||||
spaces: services.spaces,
|
||||
savedObjectsTagging: services.savedObjectsTagging,
|
||||
});
|
||||
|
||||
await throwErrorOnSavedSearchUrlConflict(savedSearch);
|
||||
const savedSearch = await services.savedSearch.get(savedObjectId);
|
||||
|
||||
const dataView = savedSearch.searchSource.getField('index');
|
||||
const { executeTriggerActions } = await this.getStartServices();
|
||||
|
|
|
@ -17,13 +17,3 @@ export function plugin(initializerContext: PluginInitializerContext) {
|
|||
export type { ISearchEmbeddable, SearchInput } from './embeddable';
|
||||
export { SEARCH_EMBEDDABLE_TYPE } from './embeddable';
|
||||
export { loadSharingDataHelpers } from './utils';
|
||||
|
||||
// re-export types and static functions to give other plugins time to migrate away
|
||||
export {
|
||||
type SavedSearch,
|
||||
getSavedSearch,
|
||||
getSavedSearchFullPathUrl,
|
||||
getSavedSearchUrl,
|
||||
getSavedSearchUrlConflictMessage,
|
||||
throwErrorOnSavedSearchUrlConflict,
|
||||
} from '@kbn/saved-search-plugin/public';
|
||||
|
|
|
@ -39,6 +39,7 @@ import { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public';
|
|||
import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public';
|
||||
import type { SavedObjectTaggingOssPluginStart } from '@kbn/saved-objects-tagging-oss-plugin/public';
|
||||
import type { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public';
|
||||
import type { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public';
|
||||
import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
|
||||
import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public';
|
||||
import type { LensPublicStart } from '@kbn/lens-plugin/public';
|
||||
|
@ -193,6 +194,7 @@ export interface DiscoverStartPlugins {
|
|||
expressions: ExpressionsStart;
|
||||
savedObjectsTaggingOss?: SavedObjectTaggingOssPluginStart;
|
||||
savedObjectsManagement: SavedObjectsManagementPluginStart;
|
||||
savedSearch: SavedSearchPublicPluginStart;
|
||||
unifiedSearch: UnifiedSearchPublicPluginStart;
|
||||
lens: LensPublicStart;
|
||||
}
|
||||
|
|
13
src/plugins/saved_search/common/constants.ts
Normal file
13
src/plugins/saved_search/common/constants.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export const SavedSearchType = 'search';
|
||||
|
||||
export const LATEST_VERSION = 1;
|
||||
|
||||
export type SavedSearchContentType = typeof SavedSearchType;
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type {
|
||||
ContentManagementServicesDefinition as ServicesDefinition,
|
||||
Version,
|
||||
} from '@kbn/object-versioning';
|
||||
|
||||
// We export the versionned service definition from this file and not the barrel to avoid adding
|
||||
// the schemas in the "public" js bundle
|
||||
|
||||
import { serviceDefinition as v1 } from './v1/cm_services';
|
||||
|
||||
export const cmServicesDefinition: { [version: Version]: ServicesDefinition } = {
|
||||
1: v1,
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export * from './v1';
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import type { ContentManagementServicesDefinition as ServicesDefinition } from '@kbn/object-versioning';
|
||||
import {
|
||||
savedObjectSchema,
|
||||
objectTypeToGetResultSchema,
|
||||
createOptionsSchemas,
|
||||
updateOptionsSchema,
|
||||
createResultSchema,
|
||||
} from '@kbn/content-management-utils';
|
||||
|
||||
const sortSchema = schema.arrayOf(schema.string(), { minSize: 2, maxSize: 2 });
|
||||
|
||||
const savedSearchAttributesSchema = schema.object(
|
||||
{
|
||||
title: schema.string(),
|
||||
sort: schema.oneOf([sortSchema, schema.arrayOf(sortSchema)]),
|
||||
columns: schema.arrayOf(schema.string()),
|
||||
description: schema.string(),
|
||||
grid: schema.object({
|
||||
columns: schema.maybe(
|
||||
schema.recordOf(
|
||||
schema.string(),
|
||||
schema.object({
|
||||
width: schema.maybe(schema.number()),
|
||||
})
|
||||
)
|
||||
),
|
||||
}),
|
||||
hideChart: schema.maybe(schema.boolean()),
|
||||
isTextBasedQuery: schema.maybe(schema.boolean()),
|
||||
usesAdHocDataView: schema.maybe(schema.boolean()),
|
||||
kibanaSavedObjectMeta: schema.object({
|
||||
searchSourceJSON: schema.string(),
|
||||
}),
|
||||
viewMode: schema.maybe(
|
||||
schema.oneOf([schema.literal('documents'), schema.literal('aggregated')])
|
||||
),
|
||||
hideAggregatedPreview: schema.maybe(schema.boolean()),
|
||||
rowHeight: schema.maybe(schema.number()),
|
||||
hits: schema.maybe(schema.number()),
|
||||
timeRestore: schema.maybe(schema.boolean()),
|
||||
timeRange: schema.maybe(
|
||||
schema.object({
|
||||
from: schema.string(),
|
||||
to: schema.string(),
|
||||
})
|
||||
),
|
||||
refreshInterval: schema.maybe(
|
||||
schema.object({
|
||||
pause: schema.boolean(),
|
||||
value: schema.number(),
|
||||
})
|
||||
),
|
||||
rowsPerPage: schema.maybe(schema.number()),
|
||||
breakdownField: schema.maybe(schema.string()),
|
||||
version: schema.maybe(schema.number()),
|
||||
},
|
||||
{ unknowns: 'forbid' }
|
||||
);
|
||||
|
||||
const savedSearchSavedObjectSchema = savedObjectSchema(savedSearchAttributesSchema);
|
||||
|
||||
const savedSearchCreateOptionsSchema = schema.maybe(
|
||||
schema.object({
|
||||
id: createOptionsSchemas.id,
|
||||
references: createOptionsSchemas.references,
|
||||
overwrite: createOptionsSchemas.overwrite,
|
||||
})
|
||||
);
|
||||
|
||||
const savedSearchUpdateOptionsSchema = schema.maybe(
|
||||
schema.object({
|
||||
references: updateOptionsSchema.references,
|
||||
})
|
||||
);
|
||||
const savedSearchSearchOptionsSchema = schema.maybe(
|
||||
schema.object({
|
||||
searchFields: schema.maybe(schema.arrayOf(schema.string())),
|
||||
fields: schema.maybe(schema.arrayOf(schema.string())),
|
||||
})
|
||||
);
|
||||
|
||||
// Content management service definition.
|
||||
// We need it for BWC support between different versions of the content
|
||||
export const serviceDefinition: ServicesDefinition = {
|
||||
get: {
|
||||
out: {
|
||||
result: {
|
||||
schema: objectTypeToGetResultSchema(savedSearchSavedObjectSchema),
|
||||
},
|
||||
},
|
||||
},
|
||||
create: {
|
||||
in: {
|
||||
options: {
|
||||
schema: savedSearchCreateOptionsSchema,
|
||||
},
|
||||
data: {
|
||||
schema: savedSearchAttributesSchema,
|
||||
},
|
||||
},
|
||||
out: {
|
||||
result: {
|
||||
schema: createResultSchema(savedSearchSavedObjectSchema),
|
||||
},
|
||||
},
|
||||
},
|
||||
update: {
|
||||
in: {
|
||||
options: {
|
||||
schema: savedSearchUpdateOptionsSchema,
|
||||
},
|
||||
data: {
|
||||
schema: savedSearchAttributesSchema,
|
||||
},
|
||||
},
|
||||
},
|
||||
search: {
|
||||
in: {
|
||||
options: {
|
||||
schema: savedSearchSearchOptionsSchema,
|
||||
},
|
||||
},
|
||||
},
|
||||
mSearch: {
|
||||
out: {
|
||||
result: {
|
||||
schema: savedSearchSavedObjectSchema,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export { LATEST_VERSION, type SavedSearchContentType, SavedSearchType } from '../../constants';
|
||||
|
||||
export type { SavedSearchCrudTypes } from './types';
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type {
|
||||
ContentManagementCrudTypes,
|
||||
SavedObjectCreateOptions,
|
||||
SavedObjectSearchOptions,
|
||||
SavedObjectUpdateOptions,
|
||||
} from '@kbn/content-management-utils';
|
||||
import { SavedSearchAttributes } from '../../types';
|
||||
import { SavedSearchContentType } from '../../constants';
|
||||
|
||||
interface SavedSearchCreateOptions {
|
||||
id?: SavedObjectCreateOptions['id'];
|
||||
overwrite?: SavedObjectCreateOptions['overwrite'];
|
||||
references?: SavedObjectCreateOptions['references'];
|
||||
}
|
||||
|
||||
interface SavedSearchUpdateOptions {
|
||||
references?: SavedObjectUpdateOptions['references'];
|
||||
}
|
||||
|
||||
interface SavedSearchSearchOptions {
|
||||
searchFields?: SavedObjectSearchOptions['searchFields'];
|
||||
fields?: SavedObjectSearchOptions['fields'];
|
||||
}
|
||||
|
||||
export type SavedSearchCrudTypes = ContentManagementCrudTypes<
|
||||
SavedSearchContentType,
|
||||
SavedSearchAttributes,
|
||||
SavedSearchCreateOptions,
|
||||
SavedSearchUpdateOptions,
|
||||
SavedSearchSearchOptions
|
||||
>;
|
|
@ -20,3 +20,6 @@ export enum VIEW_MODE {
|
|||
DOCUMENT_LEVEL = 'documents',
|
||||
AGGREGATED_LEVEL = 'aggregated',
|
||||
}
|
||||
|
||||
export { SavedSearchType } from './constants';
|
||||
export { LATEST_VERSION } from './constants';
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
import type { ISearchSource, RefreshInterval, TimeRange } from '@kbn/data-plugin/common';
|
||||
import type { SavedObjectReference } from '@kbn/core-saved-objects-server';
|
||||
import { VIEW_MODE } from '.';
|
||||
|
||||
export interface DiscoverGridSettings {
|
||||
|
@ -73,4 +74,5 @@ export interface SavedSearch {
|
|||
|
||||
rowsPerPage?: number;
|
||||
breakdownField?: string;
|
||||
references?: SavedObjectReference[];
|
||||
}
|
||||
|
|
|
@ -8,10 +8,14 @@
|
|||
"server": true,
|
||||
"browser": true,
|
||||
"requiredPlugins": [
|
||||
"data"
|
||||
"data",
|
||||
"contentManagement"
|
||||
],
|
||||
"optionalPlugins": [
|
||||
"spaces",
|
||||
"savedObjectsTaggingOss"
|
||||
],
|
||||
"requiredBundles": [
|
||||
"kibanaUtils"
|
||||
],
|
||||
"extraPublicDirs": [
|
||||
"common"
|
||||
|
|
|
@ -8,20 +8,13 @@
|
|||
|
||||
export type { SortOrder } from '../common/types';
|
||||
export type { SavedSearch, SaveSavedSearchOptions } from './services/saved_searches';
|
||||
export {
|
||||
getSavedSearch,
|
||||
getSavedSearchFullPathUrl,
|
||||
getSavedSearchUrl,
|
||||
getSavedSearchUrlConflictMessage,
|
||||
throwErrorOnSavedSearchUrlConflict,
|
||||
saveSavedSearch,
|
||||
getNewSavedSearch,
|
||||
} from './services/saved_searches';
|
||||
|
||||
export { getSavedSearchFullPathUrl, getSavedSearchUrl } from './services/saved_searches';
|
||||
|
||||
export { VIEW_MODE } from '../common';
|
||||
import { SavedSearchPublicPlugin } from './plugin';
|
||||
export type { SavedSearchPublicPluginStart } from './plugin';
|
||||
|
||||
export function plugin() {
|
||||
return {
|
||||
setup: () => {},
|
||||
start: () => {},
|
||||
};
|
||||
return new SavedSearchPublicPlugin();
|
||||
}
|
||||
|
|
48
src/plugins/saved_search/public/mocks.ts
Normal file
48
src/plugins/saved_search/public/mocks.ts
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { of } from 'rxjs';
|
||||
import { SearchSource, IKibanaSearchResponse } from '@kbn/data-plugin/public';
|
||||
import { SearchSourceDependencies } from '@kbn/data-plugin/common/search';
|
||||
import type { SearchResponse } from '@elastic/elasticsearch/lib/api/types';
|
||||
|
||||
const createEmptySearchSource = jest.fn(() => {
|
||||
const deps = {
|
||||
getConfig: jest.fn(),
|
||||
} as unknown as SearchSourceDependencies;
|
||||
const searchSource = new SearchSource({}, deps);
|
||||
searchSource.fetch$ = jest.fn().mockReturnValue(of({ rawResponse: { hits: { total: 2 } } }));
|
||||
searchSource.createChild = jest.fn((options = {}) => {
|
||||
const childSearchSource = new SearchSource({}, deps);
|
||||
childSearchSource.setParent(searchSource, options);
|
||||
childSearchSource.fetch$ = <T>() =>
|
||||
of({ rawResponse: { hits: { hits: [] } } } as unknown as IKibanaSearchResponse<
|
||||
SearchResponse<T>
|
||||
>);
|
||||
return childSearchSource;
|
||||
});
|
||||
return searchSource;
|
||||
});
|
||||
|
||||
const savedSearchStartMock = () => ({
|
||||
get: jest.fn().mockImplementation(() => ({
|
||||
id: 'savedSearch',
|
||||
title: 'savedSearchTitle',
|
||||
searchSource: createEmptySearchSource(),
|
||||
})),
|
||||
getAll: jest.fn(),
|
||||
getNew: jest.fn().mockImplementation(() => ({
|
||||
searchSource: createEmptySearchSource(),
|
||||
})),
|
||||
save: jest.fn(),
|
||||
find: jest.fn(),
|
||||
});
|
||||
|
||||
export const savedSearchPluginMock = {
|
||||
createStartContract: savedSearchStartMock,
|
||||
};
|
99
src/plugins/saved_search/public/plugin.ts
Normal file
99
src/plugins/saved_search/public/plugin.ts
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { CoreSetup, CoreStart, Plugin } from '@kbn/core/public';
|
||||
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import type { SpacesApi } from '@kbn/spaces-plugin/public';
|
||||
import type { SavedObjectTaggingOssPluginStart } from '@kbn/saved-objects-tagging-oss-plugin/public';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type {
|
||||
ContentManagementPublicSetup,
|
||||
ContentManagementPublicStart,
|
||||
} from '@kbn/content-management-plugin/public';
|
||||
import type { SOWithMetadata } from '@kbn/content-management-utils';
|
||||
import {
|
||||
getSavedSearch,
|
||||
saveSavedSearch,
|
||||
SaveSavedSearchOptions,
|
||||
getNewSavedSearch,
|
||||
} from './services/saved_searches';
|
||||
import { SavedSearch, SavedSearchAttributes } from '../common/types';
|
||||
import { SavedSearchType, LATEST_VERSION } from '../common';
|
||||
import { SavedSearchesService } from './services/saved_searches/saved_searches_service';
|
||||
|
||||
/**
|
||||
* Saved search plugin public Setup contract
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface SavedSearchPublicPluginSetup {}
|
||||
|
||||
/**
|
||||
* Saved search plugin public Setup contract
|
||||
*/
|
||||
export interface SavedSearchPublicPluginStart {
|
||||
get: (savedSearchId: string) => ReturnType<typeof getSavedSearch>;
|
||||
getNew: () => ReturnType<typeof getNewSavedSearch>;
|
||||
getAll: () => Promise<Array<SOWithMetadata<SavedSearchAttributes>>>;
|
||||
save: (
|
||||
savedSearch: SavedSearch,
|
||||
options?: SaveSavedSearchOptions
|
||||
) => ReturnType<typeof saveSavedSearch>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saved search plugin public Setup contract
|
||||
*/
|
||||
export interface SavedSearchPublicSetupDependencies {
|
||||
contentManagement: ContentManagementPublicSetup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saved search plugin public Setup contract
|
||||
*/
|
||||
export interface SavedSearchPublicStartDependencies {
|
||||
data: DataPublicPluginStart;
|
||||
spaces?: SpacesApi;
|
||||
savedObjectsTaggingOss?: SavedObjectTaggingOssPluginStart;
|
||||
contentManagement: ContentManagementPublicStart;
|
||||
}
|
||||
|
||||
export class SavedSearchPublicPlugin
|
||||
implements
|
||||
Plugin<
|
||||
SavedSearchPublicPluginSetup,
|
||||
SavedSearchPublicPluginStart,
|
||||
SavedSearchPublicSetupDependencies,
|
||||
SavedSearchPublicStartDependencies
|
||||
>
|
||||
{
|
||||
public setup(core: CoreSetup, { contentManagement }: SavedSearchPublicSetupDependencies) {
|
||||
contentManagement.registry.register({
|
||||
id: SavedSearchType,
|
||||
version: {
|
||||
latest: LATEST_VERSION,
|
||||
},
|
||||
name: i18n.translate('savedSearch.contentManagementType', {
|
||||
defaultMessage: 'Saved search',
|
||||
}),
|
||||
});
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
public start(
|
||||
core: CoreStart,
|
||||
{
|
||||
data: { search },
|
||||
spaces,
|
||||
savedObjectsTaggingOss,
|
||||
contentManagement: { client: contentManagement },
|
||||
}: SavedSearchPublicStartDependencies
|
||||
): SavedSearchPublicPluginStart {
|
||||
return new SavedSearchesService({ search, spaces, savedObjectsTaggingOss, contentManagement });
|
||||
}
|
||||
}
|
|
@ -5,10 +5,10 @@
|
|||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
import type { SavedObjectsStart } from '@kbn/core/public';
|
||||
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import { contentManagementMock } from '@kbn/content-management-plugin/public/mocks';
|
||||
import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public';
|
||||
|
||||
import { savedObjectsServiceMock } from '@kbn/core/public/mocks';
|
||||
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
|
||||
|
||||
import { getSavedSearch } from './get_saved_searches';
|
||||
|
@ -16,42 +16,24 @@ import { SavedObjectsTaggingApi } from '@kbn/saved-objects-tagging-oss-plugin/pu
|
|||
|
||||
describe('getSavedSearch', () => {
|
||||
let search: DataPublicPluginStart['search'];
|
||||
let savedObjectsClient: SavedObjectsStart['client'];
|
||||
let cmClient: ContentManagementPublicStart['client'];
|
||||
|
||||
beforeEach(() => {
|
||||
savedObjectsClient = savedObjectsServiceMock.createStartContract().client;
|
||||
cmClient = contentManagementMock.createStartContract().client;
|
||||
search = dataPluginMock.createStartContract().search;
|
||||
});
|
||||
|
||||
test('should return empty saved search in case of no id', async () => {
|
||||
const savedSearch = await getSavedSearch(undefined, {
|
||||
savedObjectsClient,
|
||||
search,
|
||||
});
|
||||
|
||||
expect(search.searchSource.createEmpty).toHaveBeenCalled();
|
||||
expect(savedSearch).toHaveProperty('searchSource');
|
||||
});
|
||||
|
||||
test('should throw an error if so not found', async () => {
|
||||
let errorMessage = 'No error thrown.';
|
||||
savedObjectsClient.resolve = jest.fn().mockReturnValue({
|
||||
saved_object: {
|
||||
attributes: {},
|
||||
error: {
|
||||
statusCode: 404,
|
||||
error: 'Not Found',
|
||||
message: 'Saved object [search/ccf1af80-2297-11ec-86e0-1155ffb9c7a7] not found',
|
||||
},
|
||||
id: 'ccf1af80-2297-11ec-86e0-1155ffb9c7a7',
|
||||
type: 'search',
|
||||
references: [],
|
||||
},
|
||||
cmClient.get = jest.fn().mockReturnValue({
|
||||
statusCode: 404,
|
||||
error: 'Not Found',
|
||||
message: 'Saved object [ccf1af80-2297-11ec-86e0-1155ffb9c7a7] not found',
|
||||
});
|
||||
|
||||
try {
|
||||
await getSavedSearch('ccf1af80-2297-11ec-86e0-1155ffb9c7a7', {
|
||||
savedObjectsClient,
|
||||
contentManagement: cmClient,
|
||||
search,
|
||||
});
|
||||
} catch (error) {
|
||||
|
@ -64,8 +46,8 @@ describe('getSavedSearch', () => {
|
|||
});
|
||||
|
||||
test('should find saved search', async () => {
|
||||
savedObjectsClient.resolve = jest.fn().mockReturnValue({
|
||||
saved_object: {
|
||||
cmClient.get = jest.fn().mockReturnValue({
|
||||
item: {
|
||||
attributes: {
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON:
|
||||
|
@ -89,15 +71,17 @@ describe('getSavedSearch', () => {
|
|||
],
|
||||
namespaces: ['default'],
|
||||
},
|
||||
outcome: 'exactMatch',
|
||||
meta: {
|
||||
outcome: 'exactMatch',
|
||||
},
|
||||
});
|
||||
|
||||
const savedSearch = await getSavedSearch('ccf1af80-2297-11ec-86e0-1155ffb9c7a7', {
|
||||
savedObjectsClient,
|
||||
contentManagement: cmClient,
|
||||
search,
|
||||
});
|
||||
|
||||
expect(savedObjectsClient.resolve).toHaveBeenCalled();
|
||||
expect(cmClient.get).toHaveBeenCalled();
|
||||
expect(savedSearch).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"breakdownField": undefined,
|
||||
|
@ -110,6 +94,13 @@ describe('getSavedSearch', () => {
|
|||
"hideChart": false,
|
||||
"id": "ccf1af80-2297-11ec-86e0-1155ffb9c7a7",
|
||||
"isTextBasedQuery": undefined,
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "ff959d40-b880-11e8-a6d9-e546fe2bba5f",
|
||||
"name": "kibanaSavedObjectMeta.searchSourceJSON.index",
|
||||
"type": "index-pattern",
|
||||
},
|
||||
],
|
||||
"refreshInterval": undefined,
|
||||
"rowHeight": undefined,
|
||||
"rowsPerPage": undefined,
|
||||
|
@ -140,9 +131,6 @@ describe('getSavedSearch', () => {
|
|||
"toExpressionAst": [MockFunction],
|
||||
},
|
||||
"sharingSavedObjectProps": Object {
|
||||
"aliasPurpose": undefined,
|
||||
"aliasTargetId": undefined,
|
||||
"errorJSON": undefined,
|
||||
"outcome": "exactMatch",
|
||||
},
|
||||
"sort": Array [
|
||||
|
@ -162,8 +150,8 @@ describe('getSavedSearch', () => {
|
|||
});
|
||||
|
||||
test('should find saved search with sql mode', async () => {
|
||||
savedObjectsClient.resolve = jest.fn().mockReturnValue({
|
||||
saved_object: {
|
||||
cmClient.get = jest.fn().mockReturnValue({
|
||||
item: {
|
||||
attributes: {
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON:
|
||||
|
@ -188,15 +176,17 @@ describe('getSavedSearch', () => {
|
|||
],
|
||||
namespaces: ['default'],
|
||||
},
|
||||
outcome: 'exactMatch',
|
||||
meta: {
|
||||
outcome: 'exactMatch',
|
||||
},
|
||||
});
|
||||
|
||||
const savedSearch = await getSavedSearch('ccf1af80-2297-11ec-86e0-1155ffb9c7a7', {
|
||||
savedObjectsClient,
|
||||
contentManagement: cmClient,
|
||||
search,
|
||||
});
|
||||
|
||||
expect(savedObjectsClient.resolve).toHaveBeenCalled();
|
||||
expect(cmClient.get).toHaveBeenCalled();
|
||||
expect(savedSearch).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"breakdownField": undefined,
|
||||
|
@ -209,6 +199,13 @@ describe('getSavedSearch', () => {
|
|||
"hideChart": true,
|
||||
"id": "ccf1af80-2297-11ec-86e0-1155ffb9c7a7",
|
||||
"isTextBasedQuery": true,
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "ff959d40-b880-11e8-a6d9-e546fe2bba5f",
|
||||
"name": "kibanaSavedObjectMeta.searchSourceJSON.index",
|
||||
"type": "index-pattern",
|
||||
},
|
||||
],
|
||||
"refreshInterval": undefined,
|
||||
"rowHeight": undefined,
|
||||
"rowsPerPage": undefined,
|
||||
|
@ -239,9 +236,6 @@ describe('getSavedSearch', () => {
|
|||
"toExpressionAst": [MockFunction],
|
||||
},
|
||||
"sharingSavedObjectProps": Object {
|
||||
"aliasPurpose": undefined,
|
||||
"aliasTargetId": undefined,
|
||||
"errorJSON": undefined,
|
||||
"outcome": "exactMatch",
|
||||
},
|
||||
"sort": Array [
|
||||
|
@ -261,8 +255,8 @@ describe('getSavedSearch', () => {
|
|||
});
|
||||
|
||||
it('should call savedObjectsTagging.ui.getTagIdsFromReferences', async () => {
|
||||
savedObjectsClient.resolve = jest.fn().mockReturnValue({
|
||||
saved_object: {
|
||||
cmClient.get = jest.fn().mockReturnValue({
|
||||
item: {
|
||||
attributes: {
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON:
|
||||
|
@ -292,7 +286,9 @@ describe('getSavedSearch', () => {
|
|||
],
|
||||
namespaces: ['default'],
|
||||
},
|
||||
outcome: 'exactMatch',
|
||||
meta: {
|
||||
outcome: 'exactMatch',
|
||||
},
|
||||
});
|
||||
const savedObjectsTagging = {
|
||||
ui: {
|
||||
|
@ -300,7 +296,7 @@ describe('getSavedSearch', () => {
|
|||
},
|
||||
} as unknown as SavedObjectsTaggingApi;
|
||||
await getSavedSearch('ccf1af80-2297-11ec-86e0-1155ffb9c7a7', {
|
||||
savedObjectsClient,
|
||||
contentManagement: cmClient,
|
||||
search,
|
||||
savedObjectsTagging,
|
||||
});
|
||||
|
|
|
@ -6,38 +6,60 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { SavedObjectsClientContract } from '@kbn/core/public';
|
||||
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import { injectSearchSourceReferences, parseSearchSourceJSON } from '@kbn/data-plugin/public';
|
||||
import { SavedObjectNotFound } from '@kbn/kibana-utils-plugin/public';
|
||||
import type { SpacesApi } from '@kbn/spaces-plugin/public';
|
||||
import type { SavedObjectsTaggingApi } from '@kbn/saved-objects-tagging-oss-plugin/public';
|
||||
import type { SavedSearchAttributes } from '../../../common';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public';
|
||||
import type { SavedSearch } from './types';
|
||||
import { SAVED_SEARCH_TYPE } from './constants';
|
||||
import { fromSavedSearchAttributes } from './saved_searches_utils';
|
||||
import type { SavedSearchCrudTypes } from '../../../common/content_management';
|
||||
|
||||
interface GetSavedSearchDependencies {
|
||||
search: DataPublicPluginStart['search'];
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
contentManagement: ContentManagementPublicStart['client'];
|
||||
spaces?: SpacesApi;
|
||||
savedObjectsTagging?: SavedObjectsTaggingApi;
|
||||
}
|
||||
|
||||
const findSavedSearch = async (
|
||||
savedSearchId: string,
|
||||
{ search, savedObjectsClient, spaces, savedObjectsTagging }: GetSavedSearchDependencies
|
||||
) => {
|
||||
const so = await savedObjectsClient.resolve<SavedSearchAttributes>(
|
||||
SAVED_SEARCH_TYPE,
|
||||
savedSearchId
|
||||
);
|
||||
const getSavedSearchUrlConflictMessage = async (json: string) =>
|
||||
i18n.translate('savedSearch.legacyURLConflict.errorMessage', {
|
||||
defaultMessage: `This search has the same URL as a legacy alias. Disable the alias to resolve this error : {json}`,
|
||||
values: { json },
|
||||
});
|
||||
|
||||
if (!so.saved_object || so.saved_object.error) {
|
||||
throw new SavedObjectNotFound(SAVED_SEARCH_TYPE, savedSearchId);
|
||||
export const getSavedSearch = async (
|
||||
savedSearchId: string,
|
||||
{ search, spaces, savedObjectsTagging, contentManagement }: GetSavedSearchDependencies
|
||||
) => {
|
||||
const so = await contentManagement.get<
|
||||
SavedSearchCrudTypes['GetIn'],
|
||||
SavedSearchCrudTypes['GetOut']
|
||||
>({
|
||||
contentTypeId: SAVED_SEARCH_TYPE,
|
||||
id: savedSearchId,
|
||||
});
|
||||
|
||||
// @ts-expect-error
|
||||
if (so.error) {
|
||||
throw new Error(`Could not locate that search (id: ${savedSearchId})`);
|
||||
}
|
||||
|
||||
const savedSearch = so.saved_object;
|
||||
if (so.meta.outcome === 'conflict') {
|
||||
throw new Error(
|
||||
await getSavedSearchUrlConflictMessage(
|
||||
JSON.stringify({
|
||||
targetType: SAVED_SEARCH_TYPE,
|
||||
sourceId: savedSearchId,
|
||||
targetSpace: (await spaces?.getActiveSpace())?.id,
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const savedSearch = so.item;
|
||||
|
||||
const parsedSearchSourceJSON = parseSearchSourceJSON(
|
||||
savedSearch.attributes.kibanaSavedObjectMeta?.searchSourceJSON ?? '{}'
|
||||
|
@ -52,28 +74,17 @@ const findSavedSearch = async (
|
|||
? savedObjectsTagging.ui.getTagIdsFromReferences(savedSearch.references)
|
||||
: undefined;
|
||||
|
||||
return fromSavedSearchAttributes(
|
||||
const returnVal = fromSavedSearchAttributes(
|
||||
savedSearchId,
|
||||
savedSearch.attributes,
|
||||
tags,
|
||||
savedSearch.references,
|
||||
await search.searchSource.create(searchSourceValues),
|
||||
{
|
||||
outcome: so.outcome,
|
||||
aliasTargetId: so.alias_target_id,
|
||||
aliasPurpose: so.alias_purpose,
|
||||
errorJSON:
|
||||
so.outcome === 'conflict' && spaces
|
||||
? JSON.stringify({
|
||||
targetType: SAVED_SEARCH_TYPE,
|
||||
sourceId: savedSearchId,
|
||||
targetSpace: (await spaces.getActiveSpace()).id,
|
||||
})
|
||||
: undefined,
|
||||
}
|
||||
so.meta
|
||||
);
|
||||
};
|
||||
|
||||
/** @public **/
|
||||
return returnVal;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a new saved search
|
||||
|
@ -87,16 +98,3 @@ export const getNewSavedSearch = ({
|
|||
}): SavedSearch => ({
|
||||
searchSource: search.searchSource.createEmpty(),
|
||||
});
|
||||
/**
|
||||
* Returns a persisted or a new saved search
|
||||
* @param savedSearchId - when undefined a new saved search is returned
|
||||
* @param dependencies
|
||||
*/
|
||||
export const getSavedSearch = async (
|
||||
savedSearchId: string | undefined,
|
||||
dependencies: GetSavedSearchDependencies
|
||||
) => {
|
||||
return savedSearchId
|
||||
? findSavedSearch(savedSearchId, dependencies)
|
||||
: getNewSavedSearch(dependencies);
|
||||
};
|
||||
|
|
|
@ -7,12 +7,7 @@
|
|||
*/
|
||||
|
||||
export { getSavedSearch, getNewSavedSearch } from './get_saved_searches';
|
||||
export {
|
||||
getSavedSearchUrl,
|
||||
getSavedSearchFullPathUrl,
|
||||
getSavedSearchUrlConflictMessage,
|
||||
throwErrorOnSavedSearchUrlConflict,
|
||||
} from './saved_searches_utils';
|
||||
export { getSavedSearchUrl, getSavedSearchFullPathUrl } from './saved_searches_utils';
|
||||
export type { SaveSavedSearchOptions } from './save_saved_searches';
|
||||
export { saveSavedSearch } from './save_saved_searches';
|
||||
export { SAVED_SEARCH_TYPE } from './constants';
|
||||
|
|
|
@ -6,23 +6,21 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { SavedObjectsStart } from '@kbn/core/public';
|
||||
|
||||
import { savedObjectsServiceMock } from '@kbn/core/public/mocks';
|
||||
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
|
||||
|
||||
import { saveSavedSearch } from './save_saved_searches';
|
||||
import type { SavedSearch } from './types';
|
||||
import type { SavedObjectsTaggingApi } from '@kbn/saved-objects-tagging-oss-plugin/public';
|
||||
import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public';
|
||||
import { contentManagementMock } from '@kbn/content-management-plugin/public/mocks';
|
||||
|
||||
describe('saveSavedSearch', () => {
|
||||
let savedObjectsClient: SavedObjectsStart['client'];
|
||||
let cmApi: ContentManagementPublicStart['client'];
|
||||
let savedSearch: SavedSearch;
|
||||
|
||||
beforeEach(() => {
|
||||
savedObjectsClient = savedObjectsServiceMock.createStartContract().client;
|
||||
cmApi = contentManagementMock.createStartContract().client;
|
||||
const searchSource = dataPluginMock.createStartContract().search.searchSource.createEmpty();
|
||||
|
||||
savedSearch = {
|
||||
id: 'id',
|
||||
title: 'title',
|
||||
|
@ -41,8 +39,14 @@ describe('saveSavedSearch', () => {
|
|||
|
||||
describe('onTitleDuplicate', () => {
|
||||
test('should check for title duplicating', async () => {
|
||||
savedObjectsClient.find = jest.fn().mockReturnValue({
|
||||
savedObjects: [{ get: () => 'title' }],
|
||||
cmApi.search = jest.fn().mockReturnValue({
|
||||
hits: [
|
||||
{
|
||||
attributes: {
|
||||
title: 'title',
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
const onTitleDuplicate = jest.fn();
|
||||
|
||||
|
@ -52,7 +56,7 @@ describe('saveSavedSearch', () => {
|
|||
onTitleDuplicate,
|
||||
copyOnSave: true,
|
||||
},
|
||||
savedObjectsClient,
|
||||
cmApi,
|
||||
undefined
|
||||
);
|
||||
|
||||
|
@ -60,8 +64,19 @@ describe('saveSavedSearch', () => {
|
|||
});
|
||||
|
||||
test('should not check for title duplicating for saving existing search', async () => {
|
||||
savedObjectsClient.find = jest.fn().mockReturnValue({
|
||||
savedObjects: [{ get: () => 'title' }],
|
||||
cmApi.search = jest.fn().mockReturnValue({
|
||||
hits: [
|
||||
{
|
||||
attributes: {
|
||||
title: 'title',
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
cmApi.update = jest.fn().mockReturnValue({
|
||||
item: {
|
||||
id: 'id',
|
||||
},
|
||||
});
|
||||
const onTitleDuplicate = jest.fn();
|
||||
|
||||
|
@ -71,7 +86,7 @@ describe('saveSavedSearch', () => {
|
|||
onTitleDuplicate,
|
||||
copyOnSave: false,
|
||||
},
|
||||
savedObjectsClient,
|
||||
cmApi,
|
||||
undefined
|
||||
);
|
||||
|
||||
|
@ -80,49 +95,92 @@ describe('saveSavedSearch', () => {
|
|||
});
|
||||
|
||||
test('should call savedObjectsClient.create for saving new search', async () => {
|
||||
cmApi.search = jest.fn().mockReturnValue({
|
||||
hits: [
|
||||
{
|
||||
attributes: {
|
||||
title: 'title',
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
cmApi.create = jest.fn().mockReturnValue({
|
||||
item: {
|
||||
id: 'id',
|
||||
},
|
||||
});
|
||||
|
||||
delete savedSearch.id;
|
||||
|
||||
await saveSavedSearch(savedSearch, {}, savedObjectsClient, undefined);
|
||||
await saveSavedSearch(savedSearch, {}, cmApi, undefined);
|
||||
|
||||
expect(savedObjectsClient.create).toHaveBeenCalledWith(
|
||||
'search',
|
||||
{
|
||||
expect(cmApi.create).toHaveBeenCalledWith({
|
||||
contentTypeId: 'search',
|
||||
data: {
|
||||
breakdownField: undefined,
|
||||
columns: [],
|
||||
description: '',
|
||||
grid: {},
|
||||
isTextBasedQuery: false,
|
||||
hideAggregatedPreview: undefined,
|
||||
hideChart: false,
|
||||
isTextBasedQuery: false,
|
||||
kibanaSavedObjectMeta: { searchSourceJSON: '{}' },
|
||||
refreshInterval: undefined,
|
||||
rowHeight: undefined,
|
||||
rowsPerPage: undefined,
|
||||
sort: [],
|
||||
title: 'title',
|
||||
timeRange: undefined,
|
||||
timeRestore: false,
|
||||
title: 'title',
|
||||
usesAdHocDataView: undefined,
|
||||
viewMode: undefined,
|
||||
},
|
||||
{ references: [] }
|
||||
);
|
||||
options: { references: [] },
|
||||
});
|
||||
});
|
||||
|
||||
test('should call savedObjectsClient.update for saving existing search', async () => {
|
||||
await saveSavedSearch(savedSearch, {}, savedObjectsClient, undefined);
|
||||
cmApi.update = jest.fn().mockReturnValue({
|
||||
item: {
|
||||
id: 'id',
|
||||
},
|
||||
});
|
||||
|
||||
expect(savedObjectsClient.update).toHaveBeenCalledWith(
|
||||
'search',
|
||||
'id',
|
||||
{
|
||||
await saveSavedSearch(savedSearch, {}, cmApi, undefined);
|
||||
|
||||
expect(cmApi.update).toHaveBeenCalledWith({
|
||||
contentTypeId: 'search',
|
||||
data: {
|
||||
breakdownField: undefined,
|
||||
columns: [],
|
||||
description: '',
|
||||
grid: {},
|
||||
hideAggregatedPreview: undefined,
|
||||
isTextBasedQuery: false,
|
||||
hideChart: false,
|
||||
kibanaSavedObjectMeta: { searchSourceJSON: '{}' },
|
||||
refreshInterval: undefined,
|
||||
rowHeight: undefined,
|
||||
rowsPerPage: undefined,
|
||||
timeRange: undefined,
|
||||
sort: [],
|
||||
title: 'title',
|
||||
timeRestore: false,
|
||||
usesAdHocDataView: undefined,
|
||||
viewMode: undefined,
|
||||
},
|
||||
{ references: [] }
|
||||
);
|
||||
id: 'id',
|
||||
options: { references: [] },
|
||||
});
|
||||
});
|
||||
|
||||
test('should call savedObjectsTagging.ui.updateTagsReferences', async () => {
|
||||
cmApi.update = jest.fn().mockReturnValue({
|
||||
item: {
|
||||
id: 'id',
|
||||
},
|
||||
});
|
||||
|
||||
const savedObjectsTagging = {
|
||||
ui: {
|
||||
updateTagsReferences: jest.fn((_, tags) => tags),
|
||||
|
@ -131,7 +189,7 @@ describe('saveSavedSearch', () => {
|
|||
await saveSavedSearch(
|
||||
{ ...savedSearch, tags: ['tag-1', 'tag-2'] },
|
||||
{},
|
||||
savedObjectsClient,
|
||||
cmApi,
|
||||
savedObjectsTagging
|
||||
);
|
||||
|
||||
|
@ -139,21 +197,29 @@ describe('saveSavedSearch', () => {
|
|||
[],
|
||||
['tag-1', 'tag-2']
|
||||
);
|
||||
expect(savedObjectsClient.update).toHaveBeenCalledWith(
|
||||
'search',
|
||||
'id',
|
||||
{
|
||||
expect(cmApi.update).toHaveBeenCalledWith({
|
||||
contentTypeId: 'search',
|
||||
data: {
|
||||
breakdownField: undefined,
|
||||
columns: [],
|
||||
description: '',
|
||||
grid: {},
|
||||
isTextBasedQuery: false,
|
||||
hideAggregatedPreview: undefined,
|
||||
hideChart: false,
|
||||
isTextBasedQuery: false,
|
||||
kibanaSavedObjectMeta: { searchSourceJSON: '{}' },
|
||||
refreshInterval: undefined,
|
||||
rowHeight: undefined,
|
||||
rowsPerPage: undefined,
|
||||
sort: [],
|
||||
title: 'title',
|
||||
timeRange: undefined,
|
||||
timeRestore: false,
|
||||
title: 'title',
|
||||
usesAdHocDataView: undefined,
|
||||
viewMode: undefined,
|
||||
},
|
||||
{ references: ['tag-1', 'tag-2'] }
|
||||
);
|
||||
id: 'id',
|
||||
options: { references: ['tag-1', 'tag-2'] },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,12 +5,13 @@
|
|||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
import type { SavedObjectsClientContract, SavedObjectsStart } from '@kbn/core/public';
|
||||
|
||||
import type { SavedObjectsTaggingApi } from '@kbn/saved-objects-tagging-oss-plugin/public';
|
||||
import type { SavedSearchAttributes } from '../../../common';
|
||||
import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public';
|
||||
import type { SavedSearch } from './types';
|
||||
import { SAVED_SEARCH_TYPE } from './constants';
|
||||
import { toSavedSearchAttributes } from './saved_searches_utils';
|
||||
import type { SavedSearchCrudTypes } from '../../../common/content_management';
|
||||
|
||||
export interface SaveSavedSearchOptions {
|
||||
onTitleDuplicate?: () => void;
|
||||
|
@ -20,30 +21,34 @@ export interface SaveSavedSearchOptions {
|
|||
|
||||
const hasDuplicatedTitle = async (
|
||||
title: string,
|
||||
savedObjectsClient: SavedObjectsStart['client']
|
||||
contentManagement: ContentManagementPublicStart['client']
|
||||
): Promise<boolean | void> => {
|
||||
if (!title) {
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await savedObjectsClient.find({
|
||||
type: SAVED_SEARCH_TYPE,
|
||||
perPage: 10,
|
||||
search: `"${title}"`,
|
||||
searchFields: ['title'],
|
||||
fields: ['title'],
|
||||
const response = await contentManagement.search<
|
||||
SavedSearchCrudTypes['SearchIn'],
|
||||
SavedSearchCrudTypes['SearchOut']
|
||||
>({
|
||||
contentTypeId: SAVED_SEARCH_TYPE,
|
||||
query: {
|
||||
text: `"${title}"`,
|
||||
},
|
||||
options: {
|
||||
searchFields: ['title'],
|
||||
fields: ['title'],
|
||||
},
|
||||
});
|
||||
|
||||
return response.savedObjects.some(
|
||||
(obj) => obj.get('title').toLowerCase() === title.toLowerCase()
|
||||
);
|
||||
return response.hits.some((obj) => obj.attributes.title.toLowerCase() === title.toLowerCase());
|
||||
};
|
||||
|
||||
/** @internal **/
|
||||
export const saveSavedSearch = async (
|
||||
savedSearch: SavedSearch,
|
||||
options: SaveSavedSearchOptions,
|
||||
savedObjectsClient: SavedObjectsClientContract,
|
||||
contentManagement: ContentManagementPublicStart['client'],
|
||||
savedObjectsTagging: SavedObjectsTaggingApi | undefined
|
||||
): Promise<string | undefined> => {
|
||||
const isNew = options.copyOnSave || !savedSearch.id;
|
||||
|
@ -53,7 +58,7 @@ export const saveSavedSearch = async (
|
|||
isNew &&
|
||||
!options.isTitleDuplicateConfirmed &&
|
||||
options.onTitleDuplicate &&
|
||||
(await hasDuplicatedTitle(savedSearch.title, savedObjectsClient))
|
||||
(await hasDuplicatedTitle(savedSearch.title, contentManagement))
|
||||
) {
|
||||
options.onTitleDuplicate();
|
||||
return;
|
||||
|
@ -65,21 +70,27 @@ export const saveSavedSearch = async (
|
|||
? savedObjectsTagging.ui.updateTagsReferences(originalReferences, savedSearch.tags ?? [])
|
||||
: originalReferences;
|
||||
const resp = isNew
|
||||
? await savedObjectsClient.create<SavedSearchAttributes>(
|
||||
SAVED_SEARCH_TYPE,
|
||||
toSavedSearchAttributes(savedSearch, searchSourceJSON),
|
||||
{
|
||||
? await contentManagement.create<
|
||||
SavedSearchCrudTypes['CreateIn'],
|
||||
SavedSearchCrudTypes['CreateOut']
|
||||
>({
|
||||
contentTypeId: SAVED_SEARCH_TYPE,
|
||||
data: toSavedSearchAttributes(savedSearch, searchSourceJSON),
|
||||
options: {
|
||||
references,
|
||||
}
|
||||
)
|
||||
: await savedObjectsClient.update<SavedSearchAttributes>(
|
||||
SAVED_SEARCH_TYPE,
|
||||
savedSearch.id!,
|
||||
toSavedSearchAttributes(savedSearch, searchSourceJSON),
|
||||
{
|
||||
},
|
||||
})
|
||||
: await contentManagement.update<
|
||||
SavedSearchCrudTypes['UpdateIn'],
|
||||
SavedSearchCrudTypes['UpdateOut']
|
||||
>({
|
||||
contentTypeId: SAVED_SEARCH_TYPE,
|
||||
id: savedSearch.id!,
|
||||
data: toSavedSearchAttributes(savedSearch, searchSourceJSON),
|
||||
options: {
|
||||
references,
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
return resp?.id;
|
||||
return resp.item.id;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public';
|
||||
import type { SpacesApi } from '@kbn/spaces-plugin/public';
|
||||
import type { SavedObjectTaggingOssPluginStart } from '@kbn/saved-objects-tagging-oss-plugin/public';
|
||||
import { getSavedSearch, saveSavedSearch, SaveSavedSearchOptions, getNewSavedSearch } from '.';
|
||||
import type { SavedSearchCrudTypes } from '../../../common/content_management';
|
||||
import { SavedSearchType } from '../../../common';
|
||||
import type { SavedSearch } from '../../../common/types';
|
||||
|
||||
interface SavedSearchesServiceDeps {
|
||||
search: DataPublicPluginStart['search'];
|
||||
contentManagement: ContentManagementPublicStart['client'];
|
||||
spaces?: SpacesApi;
|
||||
savedObjectsTaggingOss?: SavedObjectTaggingOssPluginStart;
|
||||
}
|
||||
|
||||
export class SavedSearchesService {
|
||||
constructor(private deps: SavedSearchesServiceDeps) {}
|
||||
|
||||
get = (savedSearchId: string) => {
|
||||
const { search, contentManagement, spaces, savedObjectsTaggingOss } = this.deps;
|
||||
return getSavedSearch(savedSearchId, {
|
||||
search,
|
||||
contentManagement,
|
||||
spaces,
|
||||
savedObjectsTagging: savedObjectsTaggingOss?.getTaggingApi(),
|
||||
});
|
||||
};
|
||||
getAll = async () => {
|
||||
const { contentManagement } = this.deps;
|
||||
const result = await contentManagement.search<
|
||||
SavedSearchCrudTypes['SearchIn'],
|
||||
SavedSearchCrudTypes['SearchOut']
|
||||
>({
|
||||
contentTypeId: SavedSearchType,
|
||||
query: {},
|
||||
});
|
||||
return result.hits;
|
||||
};
|
||||
getNew = () => getNewSavedSearch({ search: this.deps.search });
|
||||
|
||||
find = async (search: string) => {
|
||||
const { contentManagement } = this.deps;
|
||||
const result = await contentManagement.search<
|
||||
SavedSearchCrudTypes['SearchIn'],
|
||||
SavedSearchCrudTypes['SearchOut']
|
||||
>({
|
||||
contentTypeId: SavedSearchType,
|
||||
query: {
|
||||
text: search,
|
||||
},
|
||||
options: {
|
||||
searchFields: ['title'],
|
||||
fields: ['title'],
|
||||
},
|
||||
});
|
||||
return result.hits;
|
||||
};
|
||||
|
||||
save = (savedSearch: SavedSearch, options: SaveSavedSearchOptions = {}) => {
|
||||
const { contentManagement, savedObjectsTaggingOss } = this.deps;
|
||||
return saveSavedSearch(
|
||||
savedSearch,
|
||||
options,
|
||||
contentManagement,
|
||||
savedObjectsTaggingOss?.getTaggingApi()
|
||||
);
|
||||
};
|
||||
}
|
|
@ -6,11 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import {
|
||||
fromSavedSearchAttributes,
|
||||
toSavedSearchAttributes,
|
||||
throwErrorOnSavedSearchUrlConflict,
|
||||
} from './saved_searches_utils';
|
||||
import { fromSavedSearchAttributes, toSavedSearchAttributes } from './saved_searches_utils';
|
||||
|
||||
import { createSearchSourceMock } from '@kbn/data-plugin/public/mocks';
|
||||
|
||||
|
@ -37,6 +33,7 @@ describe('saved_searches_utils', () => {
|
|||
'id',
|
||||
attributes,
|
||||
['tags-1', 'tags-2'],
|
||||
[],
|
||||
createSearchSourceMock(),
|
||||
{}
|
||||
)
|
||||
|
@ -53,6 +50,7 @@ describe('saved_searches_utils', () => {
|
|||
"hideChart": true,
|
||||
"id": "id",
|
||||
"isTextBasedQuery": false,
|
||||
"references": Array [],
|
||||
"refreshInterval": undefined,
|
||||
"rowHeight": undefined,
|
||||
"rowsPerPage": undefined,
|
||||
|
@ -91,28 +89,6 @@ describe('saved_searches_utils', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('throwErrorOnSavedSearchUrlConflict', () => {
|
||||
test('should throw an error on url conflict', async () => {
|
||||
let error = 'no error';
|
||||
|
||||
try {
|
||||
await throwErrorOnSavedSearchUrlConflict({
|
||||
id: 'id',
|
||||
sharingSavedObjectProps: {
|
||||
outcome: 'conflict',
|
||||
errorJSON: '{}',
|
||||
},
|
||||
} as SavedSearch);
|
||||
} catch (e) {
|
||||
error = e.message;
|
||||
}
|
||||
|
||||
expect(error).toBe(
|
||||
'This search has the same URL as a legacy alias. Disable the alias to resolve this error : {}'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('toSavedSearchAttributes', () => {
|
||||
test('should serialize SavedSearch attributes', () => {
|
||||
const savedSearch: SavedSearch = {
|
||||
|
|
|
@ -5,37 +5,26 @@
|
|||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { pick } from 'lodash';
|
||||
import type { SavedObjectReference } from '@kbn/core-saved-objects-server';
|
||||
import type { SavedSearchAttributes } from '../../../common';
|
||||
import { fromSavedSearchAttributes as fromSavedSearchAttributesCommon } from '../../../common';
|
||||
import type { SavedSearch } from './types';
|
||||
|
||||
export { getSavedSearchUrl, getSavedSearchFullPathUrl } from '../../../common';
|
||||
|
||||
export const getSavedSearchUrlConflictMessage = async (savedSearch: SavedSearch) =>
|
||||
i18n.translate('savedSearch.legacyURLConflict.errorMessage', {
|
||||
defaultMessage: `This search has the same URL as a legacy alias. Disable the alias to resolve this error : {json}`,
|
||||
values: {
|
||||
json: savedSearch.sharingSavedObjectProps?.errorJSON,
|
||||
},
|
||||
});
|
||||
|
||||
export const throwErrorOnSavedSearchUrlConflict = async (savedSearch: SavedSearch) => {
|
||||
if (savedSearch.sharingSavedObjectProps?.errorJSON) {
|
||||
throw new Error(await getSavedSearchUrlConflictMessage(savedSearch));
|
||||
}
|
||||
};
|
||||
|
||||
export const fromSavedSearchAttributes = (
|
||||
id: string,
|
||||
attributes: SavedSearchAttributes,
|
||||
tags: string[] | undefined,
|
||||
references: SavedObjectReference[] | undefined,
|
||||
searchSource: SavedSearch['searchSource'],
|
||||
sharingSavedObjectProps: SavedSearch['sharingSavedObjectProps']
|
||||
): SavedSearch => ({
|
||||
...fromSavedSearchAttributesCommon(id, attributes, tags, searchSource),
|
||||
sharingSavedObjectProps,
|
||||
references,
|
||||
});
|
||||
|
||||
export const toSavedSearchAttributes = (
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export { SavedSearchStorage } from './saved_search_storage';
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SOContentStorage } from '@kbn/content-management-utils';
|
||||
|
||||
import type { SavedSearchCrudTypes } from '../../common/content_management';
|
||||
import { SavedSearchType } from '../../common/content_management';
|
||||
import { cmServicesDefinition } from '../../common/content_management/cm_services';
|
||||
|
||||
export class SavedSearchStorage extends SOContentStorage<SavedSearchCrudTypes> {
|
||||
constructor() {
|
||||
super({
|
||||
savedObjectType: SavedSearchType,
|
||||
cmServicesDefinition,
|
||||
enableMSearch: true,
|
||||
allowedSavedObjectAttributes: [
|
||||
'title',
|
||||
'sort',
|
||||
'columns',
|
||||
'description',
|
||||
'grid',
|
||||
'hideChart',
|
||||
'isTextBasedQuery',
|
||||
'usesAdHocDataView',
|
||||
'kibanaSavedObjectMeta',
|
||||
'viewMode',
|
||||
'hideAggregatedPreview',
|
||||
'rowHeight',
|
||||
'timeRestore',
|
||||
'timeRange',
|
||||
'refreshInterval',
|
||||
'rowsPerPage',
|
||||
'breakdownField',
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
|
@ -8,15 +8,27 @@
|
|||
|
||||
import { CoreSetup, CoreStart, Plugin } from '@kbn/core/server';
|
||||
import type { PluginSetup as DataPluginSetup } from '@kbn/data-plugin/server';
|
||||
import type { ContentManagementServerSetup } from '@kbn/content-management-plugin/server';
|
||||
import { getSavedSearchObjectType } from './saved_objects';
|
||||
import { SavedSearchType, LATEST_VERSION } from '../common';
|
||||
import { SavedSearchStorage } from './content_management';
|
||||
|
||||
export class SavedSearchServerPlugin implements Plugin<object, object> {
|
||||
public setup(
|
||||
core: CoreSetup,
|
||||
plugins: {
|
||||
data: DataPluginSetup;
|
||||
contentManagement: ContentManagementServerSetup;
|
||||
}
|
||||
) {
|
||||
plugins.contentManagement.register({
|
||||
id: SavedSearchType,
|
||||
storage: new SavedSearchStorage(),
|
||||
version: {
|
||||
latest: LATEST_VERSION,
|
||||
},
|
||||
});
|
||||
|
||||
const getSearchSourceMigrations = plugins.data.search.searchSource.getAllMigrations.bind(
|
||||
plugins.data.search.searchSource
|
||||
);
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
"@kbn/config-schema",
|
||||
"@kbn/core-saved-objects-server",
|
||||
"@kbn/core-saved-objects-utils-server",
|
||||
"@kbn/object-versioning",
|
||||
"@kbn/content-management-utils",
|
||||
"@kbn/content-management-plugin",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
"kibanaReact",
|
||||
"data",
|
||||
"fieldFormats",
|
||||
"discover",
|
||||
"esUiShared",
|
||||
"visualizations"
|
||||
"visualizations",
|
||||
"savedSearch"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ import {
|
|||
} from '@kbn/visualizations-plugin/public';
|
||||
import type { Schema } from '@kbn/visualizations-plugin/public';
|
||||
import type { TimeRange } from '@kbn/es-query';
|
||||
import { SavedSearch } from '@kbn/discover-plugin/public';
|
||||
import { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { DefaultEditorNavBar } from './navbar';
|
||||
import { DefaultEditorControls } from './controls';
|
||||
import { setStateParamValue, useEditorReducer, useEditorFormState, discardChanges } from './state';
|
||||
|
|
|
@ -25,7 +25,7 @@ import { FormattedMessage } from '@kbn/i18n-react';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { Vis } from '@kbn/visualizations-plugin/public';
|
||||
import { SavedSearch, getSavedSearchUrl } from '@kbn/discover-plugin/public';
|
||||
import { SavedSearch, getSavedSearchUrl } from '@kbn/saved-search-plugin/public';
|
||||
import { ApplicationStart } from '@kbn/core/public';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
"@kbn/core",
|
||||
"@kbn/data-plugin",
|
||||
"@kbn/visualizations-plugin",
|
||||
"@kbn/discover-plugin",
|
||||
"@kbn/kibana-utils-plugin",
|
||||
"@kbn/kibana-react-plugin",
|
||||
"@kbn/field-formats-plugin",
|
||||
|
@ -27,6 +26,7 @@
|
|||
"@kbn/monaco",
|
||||
"@kbn/es-ui-shared-plugin",
|
||||
"@kbn/utility-types",
|
||||
"@kbn/saved-search-plugin",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
"usageCollection",
|
||||
"savedObjectsFinder",
|
||||
"savedObjectsManagement",
|
||||
"savedSearch",
|
||||
"contentManagement",
|
||||
],
|
||||
"optionalPlugins": [
|
||||
|
@ -36,7 +37,6 @@
|
|||
],
|
||||
"requiredBundles": [
|
||||
"kibanaUtils",
|
||||
"savedSearch",
|
||||
"kibanaReact",
|
||||
"charts"
|
||||
],
|
||||
|
|
|
@ -25,6 +25,7 @@ import { screenshotModePluginMock } from '@kbn/screenshot-mode-plugin/public/moc
|
|||
import { fieldFormatsServiceMock } from '@kbn/field-formats-plugin/public/mocks';
|
||||
import { unifiedSearchPluginMock } from '@kbn/unified-search-plugin/public/mocks';
|
||||
import { savedObjectsManagementPluginMock } from '@kbn/saved-objects-management-plugin/public/mocks';
|
||||
import { savedSearchPluginMock } from '@kbn/saved-search-plugin/public/mocks';
|
||||
import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public';
|
||||
import { VisualizationsPlugin } from './plugin';
|
||||
import { Schemas } from './vis_types';
|
||||
|
@ -77,6 +78,7 @@ const createInstance = async () => {
|
|||
savedObjectsClient: coreMock.createStart().savedObjects.client,
|
||||
savedObjects: savedObjectsPluginMock.createStartContract(),
|
||||
savedObjectsTaggingOss: savedObjectTaggingOssPluginMock.createStart(),
|
||||
savedSearch: savedSearchPluginMock.createStartContract(),
|
||||
navigation: navigationPluginMock.createStartContract(),
|
||||
presentationUtil: presentationUtilPluginMock.createStartContract(coreMock.createStart()),
|
||||
urlForwarding: urlForwardingPluginMock.createStartContract(),
|
||||
|
|
|
@ -58,6 +58,7 @@ import type { HomePublicPluginSetup } from '@kbn/home-plugin/public';
|
|||
import type { SpacesPluginStart } from '@kbn/spaces-plugin/public';
|
||||
import type { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public';
|
||||
import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public';
|
||||
import type { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public';
|
||||
import {
|
||||
ContentManagementPublicSetup,
|
||||
ContentManagementPublicStart,
|
||||
|
@ -105,6 +106,7 @@ import {
|
|||
setUsageCollection,
|
||||
setSavedObjectsManagement,
|
||||
setContentManagement,
|
||||
setSavedSearch,
|
||||
} from './services';
|
||||
import { VisualizeConstants } from '../common/constants';
|
||||
import { EditInLensAction } from './actions/edit_in_lens_action';
|
||||
|
@ -148,6 +150,7 @@ export interface VisualizationsStartDeps {
|
|||
presentationUtil: PresentationUtilPluginStart;
|
||||
savedObjects: SavedObjectsStart;
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
savedSearch: SavedSearchPublicPluginStart;
|
||||
spaces?: SpacesPluginStart;
|
||||
savedObjectsTaggingOss?: SavedObjectTaggingOssPluginStart;
|
||||
share?: SharePluginStart;
|
||||
|
@ -313,6 +316,7 @@ export class VisualizationsPlugin
|
|||
restorePreviousUrl,
|
||||
setHeaderActionMenu: params.setHeaderActionMenu,
|
||||
savedObjectsTagging: pluginsStart.savedObjectsTaggingOss?.getTaggingApi(),
|
||||
savedSearch: pluginsStart.savedSearch,
|
||||
presentationUtil: pluginsStart.presentationUtil,
|
||||
getKibanaVersion: () => this.initializerContext.env.packageInfo.version,
|
||||
spaces: pluginsStart.spaces,
|
||||
|
@ -401,6 +405,7 @@ export class VisualizationsPlugin
|
|||
usageCollection,
|
||||
savedObjectsManagement,
|
||||
contentManagement,
|
||||
savedSearch,
|
||||
}: VisualizationsStartDeps
|
||||
): VisualizationsStart {
|
||||
const types = this.types.start();
|
||||
|
@ -423,6 +428,7 @@ export class VisualizationsPlugin
|
|||
setUsageCollection(usageCollection);
|
||||
setSavedObjectsManagement(savedObjectsManagement);
|
||||
setContentManagement(contentManagement);
|
||||
setSavedSearch(savedSearch);
|
||||
|
||||
if (spaces) {
|
||||
setSpaces(spaces);
|
||||
|
|
|
@ -29,6 +29,7 @@ import type { SpacesPluginStart } from '@kbn/spaces-plugin/public';
|
|||
import type { SavedObjectTaggingOssPluginStart } from '@kbn/saved-objects-tagging-oss-plugin/public';
|
||||
import type { UsageCollectionStart } from '@kbn/usage-collection-plugin/public';
|
||||
import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public';
|
||||
import type { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public';
|
||||
import type { TypesStart } from './vis_types';
|
||||
|
||||
export const [getUISettings, setUISettings] = createGetterSetter<IUiSettingsClient>('UISettings');
|
||||
|
@ -84,3 +85,6 @@ export const [getSavedObjectsManagement, setSavedObjectsManagement] =
|
|||
|
||||
export const [getContentManagement, setContentManagement] =
|
||||
createGetterSetter<ContentManagementPublicStart>('SavedObjectsManagement');
|
||||
|
||||
export const [getSavedSearch, setSavedSearch] =
|
||||
createGetterSetter<SavedSearchPublicPluginStart>('SavedSearch');
|
||||
|
|
|
@ -22,21 +22,9 @@ import { i18n } from '@kbn/i18n';
|
|||
|
||||
import { IAggConfigs, ISearchSource, AggConfigSerialized } from '@kbn/data-plugin/public';
|
||||
import { DataView } from '@kbn/data-views-plugin/public';
|
||||
import {
|
||||
getSavedSearch,
|
||||
SavedSearch,
|
||||
throwErrorOnSavedSearchUrlConflict,
|
||||
} from '@kbn/saved-search-plugin/public';
|
||||
import { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { PersistedState } from './persisted_state';
|
||||
import {
|
||||
getTypes,
|
||||
getAggs,
|
||||
getSearch,
|
||||
getSavedObjects,
|
||||
getSpaces,
|
||||
getFieldsFormats,
|
||||
getSavedObjectTagging,
|
||||
} from './services';
|
||||
import { getTypes, getAggs, getSearch, getFieldsFormats, getSavedSearch } from './services';
|
||||
import { BaseVisType } from './vis_types';
|
||||
import { SerializedVis, SerializedVisData, VisParams } from '../common/types';
|
||||
|
||||
|
@ -55,18 +43,11 @@ const getSearchSource = async (inputSearchSource: ISearchSource, savedSearchId?:
|
|||
let savedSearch: SavedSearch;
|
||||
|
||||
try {
|
||||
savedSearch = await getSavedSearch(savedSearchId, {
|
||||
search: getSearch(),
|
||||
savedObjectsClient: getSavedObjects().client,
|
||||
spaces: getSpaces(),
|
||||
savedObjectsTagging: getSavedObjectTagging()?.getTaggingApi(),
|
||||
});
|
||||
savedSearch = await getSavedSearch().get(savedSearchId);
|
||||
} catch (e) {
|
||||
return inputSearchSource;
|
||||
}
|
||||
|
||||
await throwErrorOnSavedSearchUrlConflict(savedSearch);
|
||||
|
||||
if (savedSearch?.searchSource) {
|
||||
inputSearchSource.setParent(savedSearch.searchSource);
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ import type { UrlForwardingStart } from '@kbn/url-forwarding-plugin/public';
|
|||
import type { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/public';
|
||||
import type { SpacesPluginStart } from '@kbn/spaces-plugin/public';
|
||||
import type { SavedObjectsTaggingApi } from '@kbn/saved-objects-tagging-oss-plugin/public';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import type { SavedSearch, SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public';
|
||||
import type {
|
||||
Vis,
|
||||
VisualizeEmbeddableContract,
|
||||
|
@ -107,6 +107,7 @@ export interface VisualizeServices extends CoreStart {
|
|||
scopedHistory: ScopedHistory;
|
||||
setHeaderActionMenu: AppMountParameters['setHeaderActionMenu'];
|
||||
savedObjectsTagging?: SavedObjectsTaggingApi;
|
||||
savedSearch: SavedSearchPublicPluginStart;
|
||||
presentationUtil: PresentationUtilPluginStart;
|
||||
getKibanaVersion: () => string;
|
||||
spaces?: SpacesPluginStart;
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { getSavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import type { VisualizeInput, VisSavedObject, Vis, VisParams } from '../..';
|
||||
import {
|
||||
getVisualizationInstance,
|
||||
|
@ -38,15 +37,6 @@ jest.mock('../../vis_async', () => ({
|
|||
}));
|
||||
const { createVisAsync } = jest.requireMock('../../vis_async');
|
||||
|
||||
jest.mock('@kbn/saved-search-plugin/public', () => ({
|
||||
getSavedSearch: jest.fn().mockResolvedValue({
|
||||
id: 'savedSearch',
|
||||
title: 'savedSearchTitle',
|
||||
searchSource: {},
|
||||
}),
|
||||
throwErrorOnSavedSearchUrlConflict: jest.fn(),
|
||||
}));
|
||||
|
||||
let savedVisMock: VisSavedObject;
|
||||
|
||||
describe('getVisualizationInstance', () => {
|
||||
|
@ -69,6 +59,16 @@ describe('getVisualizationInstance', () => {
|
|||
mockServices.createVisEmbeddableFromObject = jest.fn().mockImplementation(() => ({
|
||||
getOutput$: jest.fn(() => subj.asObservable()),
|
||||
}));
|
||||
mockServices.savedSearch = {
|
||||
get: jest.fn().mockImplementation(() => ({
|
||||
id: 'savedSearch',
|
||||
searchSource: {},
|
||||
title: 'savedSearchTitle',
|
||||
})),
|
||||
getAll: jest.fn(),
|
||||
getNew: jest.fn().mockImplementation(() => ({})),
|
||||
save: jest.fn().mockImplementation(() => ({})),
|
||||
};
|
||||
});
|
||||
|
||||
test('should create new instances of savedVis, vis and embeddableHandler', async () => {
|
||||
|
@ -120,7 +120,6 @@ describe('getVisualizationInstance', () => {
|
|||
visMock.data.savedSearchId = 'saved_search_id';
|
||||
const { savedSearch } = await getVisualizationInstance(mockServices, 'saved_vis_id');
|
||||
|
||||
expect(getSavedSearch).toHaveBeenCalled();
|
||||
expect(savedSearch).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"id": "savedSearch",
|
||||
|
|
|
@ -9,11 +9,7 @@ import { cloneDeep } from 'lodash';
|
|||
import type { SerializedSearchSourceFields } from '@kbn/data-plugin/public';
|
||||
import type { ExpressionValueError } from '@kbn/expressions-plugin/public';
|
||||
import { SavedFieldNotFound, SavedFieldTypeInvalidForAgg } from '@kbn/kibana-utils-plugin/common';
|
||||
import {
|
||||
getSavedSearch,
|
||||
SavedSearch,
|
||||
throwErrorOnSavedSearchUrlConflict,
|
||||
} from '@kbn/saved-search-plugin/public';
|
||||
import { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { createVisAsync } from '../../vis_async';
|
||||
import { convertToSerializedVis, getSavedVisualization } from '../../utils/saved_visualize_utils';
|
||||
import {
|
||||
|
@ -37,26 +33,18 @@ const createVisualizeEmbeddableAndLinkSavedSearch = async (
|
|||
vis: Vis,
|
||||
visualizeServices: VisualizeServices
|
||||
) => {
|
||||
const { data, createVisEmbeddableFromObject, savedObjects, spaces, savedObjectsTagging } =
|
||||
visualizeServices;
|
||||
const { data, createVisEmbeddableFromObject, savedSearch: savedSearchApi } = visualizeServices;
|
||||
|
||||
let savedSearch: SavedSearch | undefined;
|
||||
|
||||
if (vis.data.savedSearchId) {
|
||||
try {
|
||||
savedSearch = await getSavedSearch(vis.data.savedSearchId, {
|
||||
search: data.search,
|
||||
savedObjectsClient: savedObjects.client,
|
||||
spaces,
|
||||
savedObjectsTagging,
|
||||
});
|
||||
savedSearch = vis.data.savedSearchId
|
||||
? await savedSearchApi.get(vis.data.savedSearchId)
|
||||
: await savedSearchApi.getNew();
|
||||
} catch (e) {
|
||||
// skip this catch block
|
||||
}
|
||||
|
||||
if (savedSearch) {
|
||||
await throwErrorOnSavedSearchUrlConflict(savedSearch);
|
||||
}
|
||||
}
|
||||
|
||||
const embeddableHandler = (await createVisEmbeddableFromObject(vis, {
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
import { cloneDeep } from 'lodash';
|
||||
import { IUiSettingsClient } from '@kbn/core/public';
|
||||
import { getEsQueryConfig, SearchSource } from '@kbn/data-plugin/common';
|
||||
import type { SavedSearch } from '@kbn/discover-plugin/public';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { FilterManager, isQuery, mapAndFlattenFilters } from '@kbn/data-plugin/public';
|
||||
import {
|
||||
fromKueryExpression,
|
||||
|
|
|
@ -11,7 +11,7 @@ import { pick } from 'lodash';
|
|||
import { EuiCallOut } from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { SavedSearch } from '@kbn/discover-plugin/public';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { StorageContextProvider } from '@kbn/ml-local-storage';
|
||||
import { UrlStateProvider } from '@kbn/ml-url-state';
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import React, { FC } from 'react';
|
||||
import { pick } from 'lodash';
|
||||
|
||||
import type { SavedSearch } from '@kbn/discover-plugin/public';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { StorageContextProvider } from '@kbn/ml-local-storage';
|
||||
import { UrlStateProvider } from '@kbn/ml-url-state';
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
import React, { FC, useState, useEffect, useCallback, useRef, useMemo } from 'react';
|
||||
import type { SavedSearch } from '@kbn/discover-plugin/public';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import type { DataView, DataViewField } from '@kbn/data-views-plugin/public';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
|
|
|
@ -12,6 +12,7 @@ import type { Moment } from 'moment';
|
|||
import { useExecutionContext } from '@kbn/kibana-react-plugin/public';
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import type { SignificantTerm } from '@kbn/ml-agg-utils';
|
||||
|
||||
import type { Dictionary } from '@kbn/ml-url-state';
|
||||
import { mlTimefilterRefresh$, useTimefilter } from '@kbn/ml-date-picker';
|
||||
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import type { SavedSearch } from '@kbn/discover-plugin/public';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
|
||||
import { getEsQueryFromSavedSearch } from '../application/utils/search_utils';
|
||||
import type { AiOpsIndexBasedAppState } from '../application/utils/url_state';
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
"@kbn/data-plugin",
|
||||
"@kbn/data-views-plugin",
|
||||
"@kbn/datemath",
|
||||
"@kbn/discover-plugin",
|
||||
"@kbn/es-query",
|
||||
"@kbn/es-types",
|
||||
"@kbn/field-formats-plugin",
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
"fileUpload",
|
||||
"uiActions",
|
||||
"charts",
|
||||
"unifiedSearch"
|
||||
"unifiedSearch",
|
||||
"savedSearch"
|
||||
],
|
||||
"optionalPlugins": [
|
||||
"security",
|
||||
|
@ -37,7 +38,6 @@
|
|||
"unifiedFieldList",
|
||||
"lens",
|
||||
"cloudChat",
|
||||
"savedSearch"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-pl
|
|||
import type { Query } from '@kbn/es-query';
|
||||
import { DataView, DataViewField } from '@kbn/data-views-plugin/public';
|
||||
import { DatePickerContextProvider } from '@kbn/ml-date-picker';
|
||||
import type { SavedSearch } from '@kbn/discover-plugin/public';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import type { SamplingOption } from '../../../../../common/types/field_stats';
|
||||
import { DATA_VISUALIZER_GRID_EMBEDDABLE_TYPE } from './constants';
|
||||
import { EmbeddableLoading } from './embeddable_loading_fallback';
|
||||
|
|
|
@ -32,7 +32,7 @@ import {
|
|||
type Dictionary,
|
||||
type SetUrlState,
|
||||
} from '@kbn/ml-url-state';
|
||||
import { getSavedSearch, type SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { getCoreStart, getPluginsStart } from '../../kibana_services';
|
||||
import {
|
||||
type IndexDataVisualizerViewProps,
|
||||
|
@ -94,6 +94,7 @@ export const DataVisualizerStateContextProvider: FC<DataVisualizerStateContextPr
|
|||
data: { dataViews, search },
|
||||
savedObjects: { client: savedObjectsClient },
|
||||
notifications: { toasts },
|
||||
savedSearch: savedSearchService,
|
||||
} = services;
|
||||
|
||||
const history = useHistory();
|
||||
|
@ -159,10 +160,7 @@ export const DataVisualizerStateContextProvider: FC<DataVisualizerStateContextPr
|
|||
if (typeof parsedQueryString?.savedSearchId === 'string') {
|
||||
const savedSearchId = parsedQueryString.savedSearchId;
|
||||
try {
|
||||
const savedSearch = await getSavedSearch(savedSearchId, {
|
||||
search,
|
||||
savedObjectsClient,
|
||||
});
|
||||
const savedSearch = await savedSearchService.get(savedSearchId);
|
||||
const dataView = savedSearch.searchSource.getField('index');
|
||||
|
||||
if (!dataView) {
|
||||
|
@ -190,7 +188,7 @@ export const DataVisualizerStateContextProvider: FC<DataVisualizerStateContextPr
|
|||
}
|
||||
};
|
||||
getDataView();
|
||||
}, [savedObjectsClient, toasts, dataViews, urlSearchString, search]);
|
||||
}, [savedObjectsClient, toasts, dataViews, urlSearchString, search, savedSearchService]);
|
||||
|
||||
const setUrlState: SetUrlState = useCallback(
|
||||
(
|
||||
|
|
|
@ -11,7 +11,7 @@ import {
|
|||
getEsQueryFromSavedSearch,
|
||||
} from './saved_search_utils';
|
||||
import type { SavedSearchSavedObject } from '../../../../common/types';
|
||||
import type { SavedSearch } from '@kbn/discover-plugin/public';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { type Filter, FilterStateStore } from '@kbn/es-query';
|
||||
import { stubbedSavedObjectIndexPattern } from '@kbn/data-views-plugin/common/data_view.stub';
|
||||
import { DataView } from '@kbn/data-views-plugin/public';
|
||||
|
|
|
@ -15,6 +15,7 @@ import { Plugin } from '@kbn/core/public';
|
|||
|
||||
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import type { HomePublicPluginSetup } from '@kbn/home-plugin/public';
|
||||
import type { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public';
|
||||
import type { FileUploadPluginStart } from '@kbn/file-upload-plugin/public';
|
||||
import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
|
||||
import type { MapsStartApi } from '@kbn/maps-plugin/public';
|
||||
|
@ -51,6 +52,7 @@ export interface DataVisualizerStartDependencies {
|
|||
fieldFormats: FieldFormatsStart;
|
||||
uiActions?: UiActionsStart;
|
||||
cloud?: CloudStart;
|
||||
savedSearch: SavedSearchPublicPluginStart;
|
||||
}
|
||||
|
||||
export type DataVisualizerPluginSetup = ReturnType<DataVisualizerPlugin['setup']>;
|
||||
|
|
|
@ -20,10 +20,4 @@ export interface Route {
|
|||
// TODO define saved object type
|
||||
export type SavedSearchSavedObject = SimpleSavedObject<any>;
|
||||
|
||||
export function isSavedSearchSavedObject(
|
||||
ss: SavedSearchSavedObject | null
|
||||
): ss is SavedSearchSavedObject {
|
||||
return ss !== null;
|
||||
}
|
||||
|
||||
export type FieldFormatsRegistryProvider = () => Promise<FieldFormatsRegistry>;
|
||||
|
|
|
@ -30,7 +30,8 @@
|
|||
"uiActions",
|
||||
"unifiedSearch",
|
||||
"savedObjectsFinder",
|
||||
"savedObjectsManagement"
|
||||
"savedObjectsManagement",
|
||||
"savedSearch"
|
||||
],
|
||||
"optionalPlugins": [
|
||||
"alerting",
|
||||
|
@ -54,7 +55,6 @@
|
|||
"kibanaUtils",
|
||||
"lens",
|
||||
"maps",
|
||||
"savedSearch",
|
||||
"usageCollection",
|
||||
"unifiedFieldList",
|
||||
"unifiedSearch"
|
||||
|
|
|
@ -97,10 +97,6 @@ const App: FC<AppProps> = ({ coreStart, deps, appMountParams }) => {
|
|||
config: coreStart.uiSettings!,
|
||||
setBreadcrumbs: coreStart.chrome!.setBreadcrumbs,
|
||||
redirectToMlAccessDeniedPage,
|
||||
getSavedSearchDeps: {
|
||||
search: deps.data.search,
|
||||
savedObjectsClient: coreStart.savedObjects.client,
|
||||
},
|
||||
};
|
||||
|
||||
const services = {
|
||||
|
@ -123,6 +119,7 @@ const App: FC<AppProps> = ({ coreStart, deps, appMountParams }) => {
|
|||
licensing: deps.licensing,
|
||||
lens: deps.lens,
|
||||
savedObjectsManagement: deps.savedObjectsManagement,
|
||||
savedSearch: deps.savedSearch,
|
||||
...coreStart,
|
||||
};
|
||||
|
||||
|
@ -177,6 +174,7 @@ export const renderApp = (
|
|||
recentlyAccessed: coreStart.chrome!.recentlyAccessed,
|
||||
basePath: coreStart.http.basePath,
|
||||
savedObjectsClient: coreStart.savedObjects.client,
|
||||
savedSearch: deps.savedSearch,
|
||||
application: coreStart.application,
|
||||
http: coreStart.http,
|
||||
security: deps.security,
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
|
||||
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { SavedSearchSavedObject } from '../../../../../../common/types/kibana';
|
||||
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { JobCreator } from './job_creator';
|
||||
import { Field, Aggregation, SplitField } from '../../../../../../common/types/fields';
|
||||
import {
|
||||
|
@ -39,7 +38,7 @@ export class AdvancedJobCreator extends JobCreator {
|
|||
private _richDetectors: RichDetector[] = [];
|
||||
private _queryString: string;
|
||||
|
||||
constructor(indexPattern: DataView, savedSearch: SavedSearchSavedObject | null, query: object) {
|
||||
constructor(indexPattern: DataView, savedSearch: SavedSearch | null, query: object) {
|
||||
super(indexPattern, savedSearch, query);
|
||||
|
||||
this._queryString = JSON.stringify(this._datafeed_config.query);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { isEqual } from 'lodash';
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { SavedSearchSavedObject } from '../../../../../../common/types/kibana';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { JobCreator } from './job_creator';
|
||||
import { Field, Aggregation, mlCategory } from '../../../../../../common/types/fields';
|
||||
import { Job, Datafeed, Detector } from '../../../../../../common/types/anomaly_detection_jobs';
|
||||
|
@ -47,7 +47,7 @@ export class CategorizationJobCreator extends JobCreator {
|
|||
private _partitionFieldName: string | null = null;
|
||||
private _ccsVersionFailure: boolean = false;
|
||||
|
||||
constructor(indexPattern: DataView, savedSearch: SavedSearchSavedObject | null, query: object) {
|
||||
constructor(indexPattern: DataView, savedSearch: SavedSearch | null, query: object) {
|
||||
super(indexPattern, savedSearch, query);
|
||||
this.createdBy = CREATED_BY_LABEL.CATEGORIZATION;
|
||||
this._examplesLoader = new CategorizationExamplesLoader(this, indexPattern, query);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { SavedSearchSavedObject } from '../../../../../../common/types/kibana';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { JobCreator } from './job_creator';
|
||||
import {
|
||||
Field,
|
||||
|
@ -28,7 +28,7 @@ export class GeoJobCreator extends JobCreator {
|
|||
|
||||
protected _type: JOB_TYPE = JOB_TYPE.GEO;
|
||||
|
||||
constructor(indexPattern: DataView, savedSearch: SavedSearchSavedObject | null, query: object) {
|
||||
constructor(indexPattern: DataView, savedSearch: SavedSearch | null, query: object) {
|
||||
super(indexPattern, savedSearch, query);
|
||||
this.createdBy = CREATED_BY_LABEL.GEO;
|
||||
this._wizardInitialized$.next(true);
|
||||
|
|
|
@ -12,7 +12,7 @@ import type { Query } from '@kbn/es-query';
|
|||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { addExcludeFrozenToQuery } from '@kbn/ml-query-utils';
|
||||
import { MlUrlConfig } from '@kbn/ml-anomaly-utils';
|
||||
import { SavedSearchSavedObject } from '../../../../../../common/types/kibana';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { IndexPatternTitle } from '../../../../../../common/types/kibana';
|
||||
import {
|
||||
ML_JOB_AGGREGATION,
|
||||
|
@ -51,7 +51,7 @@ import { ml } from '../../../../services/ml_api_service';
|
|||
export class JobCreator {
|
||||
protected _type: JOB_TYPE = JOB_TYPE.SINGLE_METRIC;
|
||||
protected _indexPattern: DataView;
|
||||
protected _savedSearch: SavedSearchSavedObject | null;
|
||||
protected _savedSearch: SavedSearch | null;
|
||||
protected _indexPatternTitle: IndexPatternTitle = '';
|
||||
protected _indexPatternDisplayName: string = '';
|
||||
protected _job_config: Job;
|
||||
|
@ -79,7 +79,7 @@ export class JobCreator {
|
|||
protected _wizardInitialized$ = new BehaviorSubject<boolean>(false);
|
||||
public wizardInitialized$ = this._wizardInitialized$.asObservable();
|
||||
|
||||
constructor(indexPattern: DataView, savedSearch: SavedSearchSavedObject | null, query: object) {
|
||||
constructor(indexPattern: DataView, savedSearch: SavedSearch | null, query: object) {
|
||||
this._indexPattern = indexPattern;
|
||||
this._savedSearch = savedSearch;
|
||||
|
||||
|
@ -107,7 +107,7 @@ export class JobCreator {
|
|||
return this._type;
|
||||
}
|
||||
|
||||
public get savedSearch(): SavedSearchSavedObject | null {
|
||||
public get savedSearch(): SavedSearch | null {
|
||||
return this._savedSearch;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { SavedSearchSavedObject } from '../../../../../../common/types/kibana';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { SingleMetricJobCreator } from './single_metric_job_creator';
|
||||
import { MultiMetricJobCreator } from './multi_metric_job_creator';
|
||||
import { PopulationJobCreator } from './population_job_creator';
|
||||
|
@ -19,7 +19,7 @@ import { JOB_TYPE } from '../../../../../../common/constants/new_job';
|
|||
|
||||
export const jobCreatorFactory =
|
||||
(jobType: JOB_TYPE) =>
|
||||
(indexPattern: DataView, savedSearch: SavedSearchSavedObject | null, query: object) => {
|
||||
(indexPattern: DataView, savedSearch: SavedSearch | null, query: object) => {
|
||||
let jc;
|
||||
switch (jobType) {
|
||||
case JOB_TYPE.SINGLE_METRIC:
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { SavedSearchSavedObject } from '../../../../../../common/types/kibana';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { JobCreator } from './job_creator';
|
||||
import {
|
||||
Field,
|
||||
|
@ -27,7 +27,7 @@ export class MultiMetricJobCreator extends JobCreator {
|
|||
|
||||
protected _type: JOB_TYPE = JOB_TYPE.MULTI_METRIC;
|
||||
|
||||
constructor(indexPattern: DataView, savedSearch: SavedSearchSavedObject | null, query: object) {
|
||||
constructor(indexPattern: DataView, savedSearch: SavedSearch | null, query: object) {
|
||||
super(indexPattern, savedSearch, query);
|
||||
this.createdBy = CREATED_BY_LABEL.MULTI_METRIC;
|
||||
this._wizardInitialized$.next(true);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { SavedSearchSavedObject } from '../../../../../../common/types/kibana';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { JobCreator } from './job_creator';
|
||||
import {
|
||||
Field,
|
||||
|
@ -26,7 +26,7 @@ export class PopulationJobCreator extends JobCreator {
|
|||
private _byFields: SplitField[] = [];
|
||||
protected _type: JOB_TYPE = JOB_TYPE.POPULATION;
|
||||
|
||||
constructor(indexPattern: DataView, savedSearch: SavedSearchSavedObject | null, query: object) {
|
||||
constructor(indexPattern: DataView, savedSearch: SavedSearch | null, query: object) {
|
||||
super(indexPattern, savedSearch, query);
|
||||
this.createdBy = CREATED_BY_LABEL.POPULATION;
|
||||
this._wizardInitialized$.next(true);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { SavedSearchSavedObject } from '../../../../../../common/types/kibana';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { JobCreator } from './job_creator';
|
||||
import { Field, SplitField, Aggregation } from '../../../../../../common/types/fields';
|
||||
import { Job, Datafeed, Detector } from '../../../../../../common/types/anomaly_detection_jobs';
|
||||
|
@ -26,7 +26,7 @@ export class RareJobCreator extends JobCreator {
|
|||
private _rareAgg: Aggregation;
|
||||
private _freqRareAgg: Aggregation;
|
||||
|
||||
constructor(indexPattern: DataView, savedSearch: SavedSearchSavedObject | null, query: object) {
|
||||
constructor(indexPattern: DataView, savedSearch: SavedSearch | null, query: object) {
|
||||
super(indexPattern, savedSearch, query);
|
||||
this.createdBy = CREATED_BY_LABEL.RARE;
|
||||
this._wizardInitialized$.next(true);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { SavedSearchSavedObject } from '../../../../../../common/types/kibana';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { parseInterval } from '../../../../../../common/util/parse_interval';
|
||||
import { JobCreator } from './job_creator';
|
||||
import { Field, Aggregation, AggFieldPair } from '../../../../../../common/types/fields';
|
||||
|
@ -29,7 +29,7 @@ import { isSparseDataJob } from './util/general';
|
|||
export class SingleMetricJobCreator extends JobCreator {
|
||||
protected _type: JOB_TYPE = JOB_TYPE.SINGLE_METRIC;
|
||||
|
||||
constructor(indexPattern: DataView, savedSearch: SavedSearchSavedObject | null, query: object) {
|
||||
constructor(indexPattern: DataView, savedSearch: SavedSearch | null, query: object) {
|
||||
super(indexPattern, savedSearch, query);
|
||||
this.createdBy = CREATED_BY_LABEL.SINGLE_METRIC;
|
||||
this._wizardInitialized$.next(true);
|
||||
|
|
|
@ -64,7 +64,7 @@ export const Page: FC<PageProps> = ({ existingJobsAndGroups, jobType }) => {
|
|||
() =>
|
||||
jobCreatorFactory(jobType)(
|
||||
mlContext.currentDataView,
|
||||
mlContext.deprecatedSavedSearchObj,
|
||||
mlContext.selectedSavedSearch,
|
||||
mlContext.combinedQuery
|
||||
),
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
|
||||
import { IUiSettingsClient } from '@kbn/core/public';
|
||||
import { DataView } from '@kbn/data-views-plugin/common';
|
||||
import { SavedSearchSavedObject } from '../../../../../common/types/kibana';
|
||||
import { createSearchItems } from './new_job_utils';
|
||||
import { fromSavedSearchAttributes } from '@kbn/saved-search-plugin/public/services/saved_searches/saved_searches_utils';
|
||||
import type { ISearchSource } from '@kbn/data-plugin/public';
|
||||
|
||||
describe('createSearchItems', () => {
|
||||
const kibanaConfig = {} as IUiSettingsClient;
|
||||
|
@ -16,45 +17,43 @@ describe('createSearchItems', () => {
|
|||
fields: [],
|
||||
} as unknown as DataView;
|
||||
|
||||
let savedSearch = {} as unknown as SavedSearchSavedObject;
|
||||
beforeEach(() => {
|
||||
savedSearch = {
|
||||
client: {
|
||||
http: {
|
||||
basePath: {
|
||||
basePath: '/abc',
|
||||
serverBasePath: '/abc',
|
||||
},
|
||||
anonymousPaths: {},
|
||||
},
|
||||
batchQueue: [],
|
||||
},
|
||||
attributes: {
|
||||
const getFieldMock = (searchSource: any) =>
|
||||
jest.fn().mockImplementation((name: string) => {
|
||||
if (name === 'query') {
|
||||
return searchSource.query;
|
||||
} else {
|
||||
return searchSource.filter;
|
||||
}
|
||||
});
|
||||
|
||||
const getSavedSearchMock = (searchSource: any = {}) =>
|
||||
fromSavedSearchAttributes(
|
||||
'4b9b1010-c678-11ea-b6e6-e942978da29c',
|
||||
{
|
||||
title: 'not test',
|
||||
description: '',
|
||||
hits: 0,
|
||||
columns: ['_source'],
|
||||
sort: [],
|
||||
version: 1,
|
||||
kibanaSavedObjectMeta: {
|
||||
searchSourceJSON: '',
|
||||
},
|
||||
grid: {},
|
||||
hideChart: false,
|
||||
isTextBasedQuery: false,
|
||||
},
|
||||
_version: 'WzI0OSw0XQ==',
|
||||
id: '4b9b1010-c678-11ea-b6e6-e942978da29c',
|
||||
type: 'search',
|
||||
migrationVersion: {
|
||||
search: '7.4.0',
|
||||
},
|
||||
references: [
|
||||
[],
|
||||
[
|
||||
{
|
||||
name: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||
type: 'index-pattern',
|
||||
id: '7e252840-bd27-11ea-8a6c-75d1a0bd08ab',
|
||||
},
|
||||
],
|
||||
} as unknown as SavedSearchSavedObject;
|
||||
});
|
||||
{
|
||||
getField: getFieldMock(searchSource),
|
||||
} as unknown as ISearchSource,
|
||||
{}
|
||||
);
|
||||
|
||||
test('should match data view', () => {
|
||||
const resp = createSearchItems(kibanaConfig, indexPattern, null);
|
||||
|
@ -65,14 +64,13 @@ describe('createSearchItems', () => {
|
|||
});
|
||||
|
||||
test('should match saved search with kuery and condition', () => {
|
||||
const searchSource = {
|
||||
const savedSearch = getSavedSearchMock({
|
||||
highlightAll: true,
|
||||
version: true,
|
||||
query: { query: 'airline : "AAL" ', language: 'kuery' },
|
||||
filter: [],
|
||||
indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||
};
|
||||
savedSearch.attributes.kibanaSavedObjectMeta.searchSourceJSON = JSON.stringify(searchSource);
|
||||
});
|
||||
|
||||
const resp = createSearchItems(kibanaConfig, indexPattern, savedSearch);
|
||||
expect(resp).toStrictEqual({
|
||||
|
@ -92,14 +90,13 @@ describe('createSearchItems', () => {
|
|||
});
|
||||
|
||||
test('should match saved search with kuery and not condition', () => {
|
||||
const searchSource = {
|
||||
const savedSearch = getSavedSearchMock({
|
||||
highlightAll: true,
|
||||
version: true,
|
||||
query: { query: 'NOT airline : "AAL" ', language: 'kuery' },
|
||||
filter: [],
|
||||
indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||
};
|
||||
savedSearch.attributes.kibanaSavedObjectMeta.searchSourceJSON = JSON.stringify(searchSource);
|
||||
});
|
||||
|
||||
const resp = createSearchItems(kibanaConfig, indexPattern, savedSearch);
|
||||
expect(resp).toStrictEqual({
|
||||
|
@ -130,14 +127,13 @@ describe('createSearchItems', () => {
|
|||
});
|
||||
|
||||
test('should match saved search with kuery and condition and not condition', () => {
|
||||
const searchSource = {
|
||||
const savedSearch = getSavedSearchMock({
|
||||
highlightAll: true,
|
||||
version: true,
|
||||
query: { query: 'airline : "AAL" and NOT airline : "AWE" ', language: 'kuery' },
|
||||
filter: [],
|
||||
indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||
};
|
||||
savedSearch.attributes.kibanaSavedObjectMeta.searchSourceJSON = JSON.stringify(searchSource);
|
||||
});
|
||||
|
||||
const resp = createSearchItems(kibanaConfig, indexPattern, savedSearch);
|
||||
expect(resp).toStrictEqual({
|
||||
|
@ -161,7 +157,7 @@ describe('createSearchItems', () => {
|
|||
});
|
||||
|
||||
test('should match saved search with kuery and filter', () => {
|
||||
const searchSource = {
|
||||
const savedSearch = getSavedSearchMock({
|
||||
highlightAll: true,
|
||||
version: true,
|
||||
query: {
|
||||
|
@ -192,8 +188,7 @@ describe('createSearchItems', () => {
|
|||
},
|
||||
],
|
||||
indexRefName: 'kibanaSavedObjectMeta.searchSourceJSON.index',
|
||||
};
|
||||
savedSearch.attributes.kibanaSavedObjectMeta.searchSourceJSON = JSON.stringify(searchSource);
|
||||
});
|
||||
|
||||
const resp = createSearchItems(kibanaConfig, indexPattern, savedSearch);
|
||||
expect(resp).toStrictEqual({
|
||||
|
|
|
@ -18,8 +18,8 @@ import {
|
|||
import { Filter } from '@kbn/es-query';
|
||||
import { IUiSettingsClient } from '@kbn/core/public';
|
||||
import { getEsQueryConfig } from '@kbn/data-plugin/public';
|
||||
import type { SavedSearch } from '@kbn/saved-search-plugin/public';
|
||||
import { SEARCH_QUERY_LANGUAGE } from '../../../../../common/constants/search';
|
||||
import { SavedSearchSavedObject } from '../../../../../common/types/kibana';
|
||||
import { getQueryFromSavedSearchObject } from '../../../util/index_utils';
|
||||
|
||||
// Provider for creating the items used for searching and job creation.
|
||||
|
@ -50,7 +50,7 @@ export function getDefaultQuery() {
|
|||
export function createSearchItems(
|
||||
kibanaConfig: IUiSettingsClient,
|
||||
indexPattern: DataViewBase | undefined,
|
||||
savedSearch: SavedSearchSavedObject | null
|
||||
savedSearch: SavedSearch | null
|
||||
) {
|
||||
// query is only used by the data visualizer as it needs
|
||||
// a lucene query_string.
|
||||
|
|
|
@ -19,8 +19,6 @@ import type { DataViewsContract } from '@kbn/data-views-plugin/public';
|
|||
|
||||
import { EuiSkeletonText } from '@elastic/eui';
|
||||
import { UrlStateProvider } from '@kbn/ml-url-state';
|
||||
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import { SavedObjectsClientContract } from '@kbn/core/public';
|
||||
import { MlNotificationsContextProvider } from '../contexts/ml/ml_notifications_context';
|
||||
import { MlContext, MlContextValue } from '../contexts/ml';
|
||||
|
||||
|
@ -67,10 +65,6 @@ export interface PageDependencies {
|
|||
dataViewsContract: DataViewsContract;
|
||||
setBreadcrumbs: ChromeStart['setBreadcrumbs'];
|
||||
redirectToMlAccessDeniedPage: () => Promise<void>;
|
||||
getSavedSearchDeps: {
|
||||
search: DataPublicPluginStart['search'];
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
};
|
||||
}
|
||||
|
||||
export const PageLoader: FC<{ context: MlContextValue }> = ({ context, children }) => {
|
||||
|
|
|
@ -30,14 +30,7 @@ export const accessDeniedRouteFactory = (): MlRoute => ({
|
|||
});
|
||||
|
||||
const PageWrapper: FC<PageProps> = ({ deps }) => {
|
||||
const { context } = useResolver(
|
||||
undefined,
|
||||
undefined,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
{}
|
||||
);
|
||||
const { context } = useResolver(undefined, undefined, deps.config, deps.dataViewsContract, {});
|
||||
|
||||
return (
|
||||
<PageLoader context={context}>
|
||||
|
|
|
@ -43,17 +43,10 @@ export const changePointDetectionRouteFactory = (
|
|||
|
||||
const PageWrapper: FC<PageProps> = ({ location, deps }) => {
|
||||
const { index, savedSearchId }: Record<string, any> = parse(location.search, { sort: false });
|
||||
const { context } = useResolver(
|
||||
index,
|
||||
savedSearchId,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
{
|
||||
checkBasicLicense,
|
||||
cacheDataViewsContract: () => cacheDataViewsContract(deps.dataViewsContract),
|
||||
}
|
||||
);
|
||||
const { context } = useResolver(index, savedSearchId, deps.config, deps.dataViewsContract, {
|
||||
checkBasicLicense,
|
||||
cacheDataViewsContract: () => cacheDataViewsContract(deps.dataViewsContract),
|
||||
});
|
||||
|
||||
return (
|
||||
<PageLoader context={context}>
|
||||
|
|
|
@ -54,19 +54,11 @@ const PageWrapper: FC<PageProps> = ({ location, deps, ...restProps }) => {
|
|||
const { redirectToMlAccessDeniedPage } = deps;
|
||||
|
||||
const { index, savedSearchId }: Record<string, any> = parse(location.search, { sort: false });
|
||||
const { context } = useResolver(
|
||||
index,
|
||||
savedSearchId,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
{
|
||||
checkBasicLicense,
|
||||
cacheDataViewsContract: () => cacheDataViewsContract(deps.dataViewsContract),
|
||||
checkGetJobsCapabilities: () =>
|
||||
checkGetJobsCapabilitiesResolver(redirectToMlAccessDeniedPage),
|
||||
}
|
||||
);
|
||||
const { context } = useResolver(index, savedSearchId, deps.config, deps.dataViewsContract, {
|
||||
checkBasicLicense,
|
||||
cacheDataViewsContract: () => cacheDataViewsContract(deps.dataViewsContract),
|
||||
checkGetJobsCapabilities: () => checkGetJobsCapabilitiesResolver(redirectToMlAccessDeniedPage),
|
||||
});
|
||||
|
||||
return (
|
||||
<PageLoader context={context}>
|
||||
|
|
|
@ -50,19 +50,11 @@ const PageWrapper: FC<PageProps> = ({ location, deps }) => {
|
|||
const { redirectToMlAccessDeniedPage } = deps;
|
||||
|
||||
const { index, savedSearchId }: Record<string, any> = parse(location.search, { sort: false });
|
||||
const { context } = useResolver(
|
||||
index,
|
||||
savedSearchId,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
{
|
||||
checkBasicLicense,
|
||||
cacheDataViewsContract: () => cacheDataViewsContract(deps.dataViewsContract),
|
||||
checkGetJobsCapabilities: () =>
|
||||
checkGetJobsCapabilitiesResolver(redirectToMlAccessDeniedPage),
|
||||
}
|
||||
);
|
||||
const { context } = useResolver(index, savedSearchId, deps.config, deps.dataViewsContract, {
|
||||
checkBasicLicense,
|
||||
cacheDataViewsContract: () => cacheDataViewsContract(deps.dataViewsContract),
|
||||
checkGetJobsCapabilities: () => checkGetJobsCapabilitiesResolver(redirectToMlAccessDeniedPage),
|
||||
});
|
||||
|
||||
return (
|
||||
<PageLoader context={context}>
|
||||
|
|
|
@ -48,18 +48,11 @@ const PageWrapper: FC<PageProps> = ({ location, deps }) => {
|
|||
sort: false,
|
||||
});
|
||||
|
||||
const { context } = useResolver(
|
||||
index,
|
||||
savedSearchId,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
{
|
||||
...basicResolvers(deps),
|
||||
analyticsFields: () =>
|
||||
loadNewJobCapabilities(index, savedSearchId, deps.dataViewsContract, DATA_FRAME_ANALYTICS),
|
||||
}
|
||||
);
|
||||
const { context } = useResolver(index, savedSearchId, deps.config, deps.dataViewsContract, {
|
||||
...basicResolvers(deps),
|
||||
analyticsFields: () =>
|
||||
loadNewJobCapabilities(index, savedSearchId, deps.dataViewsContract, DATA_FRAME_ANALYTICS),
|
||||
});
|
||||
|
||||
return (
|
||||
<PageLoader context={context}>
|
||||
|
|
|
@ -46,7 +46,6 @@ const PageWrapper: FC<PageProps> = ({ deps }) => {
|
|||
undefined,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
basicResolvers(deps)
|
||||
);
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@ const PageWrapper: FC<PageProps> = ({ location, deps }) => {
|
|||
undefined,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
basicResolvers(deps)
|
||||
);
|
||||
return (
|
||||
|
|
|
@ -45,7 +45,6 @@ const PageWrapper: FC<PageProps> = ({ deps }) => {
|
|||
undefined,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
basicResolvers(deps)
|
||||
);
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@ const PageWrapper: FC<PageProps> = ({ deps }) => {
|
|||
undefined,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
basicResolvers(deps)
|
||||
);
|
||||
|
||||
|
|
|
@ -35,18 +35,11 @@ export const selectorRouteFactory = (
|
|||
const PageWrapper: FC<PageProps> = ({ location, deps }) => {
|
||||
const { redirectToMlAccessDeniedPage } = deps;
|
||||
|
||||
const { context } = useResolver(
|
||||
undefined,
|
||||
undefined,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
{
|
||||
checkBasicLicense,
|
||||
checkFindFileStructurePrivilege: () =>
|
||||
checkFindFileStructurePrivilegeResolver(redirectToMlAccessDeniedPage),
|
||||
}
|
||||
);
|
||||
const { context } = useResolver(undefined, undefined, deps.config, deps.dataViewsContract, {
|
||||
checkBasicLicense,
|
||||
checkFindFileStructurePrivilege: () =>
|
||||
checkFindFileStructurePrivilegeResolver(redirectToMlAccessDeniedPage),
|
||||
});
|
||||
return (
|
||||
<PageLoader context={context}>
|
||||
<DatavisualizerSelector />
|
||||
|
|
|
@ -45,19 +45,12 @@ export const fileBasedRouteFactory = (
|
|||
const PageWrapper: FC<PageProps> = ({ deps }) => {
|
||||
const { redirectToMlAccessDeniedPage } = deps;
|
||||
|
||||
const { context } = useResolver(
|
||||
undefined,
|
||||
undefined,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
{
|
||||
checkBasicLicense,
|
||||
cacheDataViewsContract: () => cacheDataViewsContract(deps.dataViewsContract),
|
||||
checkFindFileStructurePrivilege: () =>
|
||||
checkFindFileStructurePrivilegeResolver(redirectToMlAccessDeniedPage),
|
||||
}
|
||||
);
|
||||
const { context } = useResolver(undefined, undefined, deps.config, deps.dataViewsContract, {
|
||||
checkBasicLicense,
|
||||
cacheDataViewsContract: () => cacheDataViewsContract(deps.dataViewsContract),
|
||||
checkFindFileStructurePrivilege: () =>
|
||||
checkFindFileStructurePrivilegeResolver(redirectToMlAccessDeniedPage),
|
||||
});
|
||||
|
||||
return (
|
||||
<PageLoader context={context}>
|
||||
|
|
|
@ -47,19 +47,11 @@ const PageWrapper: FC<PageProps> = ({ location, deps }) => {
|
|||
const { redirectToMlAccessDeniedPage } = deps;
|
||||
|
||||
const { index, savedSearchId }: Record<string, any> = parse(location.search, { sort: false });
|
||||
const { context } = useResolver(
|
||||
index,
|
||||
savedSearchId,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
{
|
||||
checkBasicLicense,
|
||||
cacheDataViewsContract: () => cacheDataViewsContract(deps.dataViewsContract),
|
||||
checkGetJobsCapabilities: () =>
|
||||
checkGetJobsCapabilitiesResolver(redirectToMlAccessDeniedPage),
|
||||
}
|
||||
);
|
||||
const { context } = useResolver(index, savedSearchId, deps.config, deps.dataViewsContract, {
|
||||
checkBasicLicense,
|
||||
cacheDataViewsContract: () => cacheDataViewsContract(deps.dataViewsContract),
|
||||
checkGetJobsCapabilities: () => checkGetJobsCapabilitiesResolver(redirectToMlAccessDeniedPage),
|
||||
});
|
||||
|
||||
return (
|
||||
<PageLoader context={context}>
|
||||
|
|
|
@ -75,7 +75,6 @@ const PageWrapper: FC<PageProps> = ({ deps }) => {
|
|||
undefined,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
{
|
||||
...basicResolvers(deps),
|
||||
jobs: mlJobService.loadJobsWrapper,
|
||||
|
|
|
@ -50,7 +50,6 @@ const PageWrapper: FC<PageProps> = ({ deps }) => {
|
|||
undefined,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
basicResolvers(deps)
|
||||
);
|
||||
const timefilter = useTimefilter({ timeRangeSelector: false, autoRefreshSelector: true });
|
||||
|
|
|
@ -41,7 +41,6 @@ const PageWrapper: FC<PageProps> = ({ location, deps }) => {
|
|||
undefined,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
basicResolvers(deps)
|
||||
);
|
||||
|
||||
|
|
|
@ -30,16 +30,9 @@ const PageWrapper: FC<PageProps> = ({ location, deps }) => {
|
|||
}
|
||||
);
|
||||
|
||||
const { context } = useResolver(
|
||||
undefined,
|
||||
undefined,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
{
|
||||
redirect: () => resolver(lensId, vis, from, to, query, filters, layerIndex),
|
||||
}
|
||||
);
|
||||
const { context } = useResolver(undefined, undefined, deps.config, deps.dataViewsContract, {
|
||||
redirect: () => resolver(lensId, vis, from, to, query, filters, layerIndex),
|
||||
});
|
||||
return (
|
||||
<PageLoader context={context}>
|
||||
{<Redirect to={createPath(ML_PAGES.ANOMALY_DETECTION_CREATE_JOB)} />}
|
||||
|
|
|
@ -36,17 +36,10 @@ const PageWrapper: FC<PageProps> = ({ location, deps }) => {
|
|||
sort: false,
|
||||
});
|
||||
|
||||
const { context } = useResolver(
|
||||
undefined,
|
||||
undefined,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
{
|
||||
redirect: () =>
|
||||
resolver(dashboard, dataViewId, embeddable, geoField, splitField, from, to, layer),
|
||||
}
|
||||
);
|
||||
const { context } = useResolver(undefined, undefined, deps.config, deps.dataViewsContract, {
|
||||
redirect: () =>
|
||||
resolver(dashboard, dataViewId, embeddable, geoField, splitField, from, to, layer),
|
||||
});
|
||||
return (
|
||||
<PageLoader context={context}>
|
||||
{<Redirect to={createPath(ML_PAGES.ANOMALY_DETECTION_CREATE_JOB)} />}
|
||||
|
|
|
@ -206,7 +206,6 @@ const PageWrapper: FC<IndexOrSearchPageProps> = ({ nextStepPath, deps, mode }) =
|
|||
undefined,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
mode === MODE.NEW_JOB ? newJobResolvers : dataVizResolvers
|
||||
);
|
||||
return (
|
||||
|
|
|
@ -41,7 +41,6 @@ const PageWrapper: FC<PageProps> = ({ location, deps }) => {
|
|||
savedSearchId,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
basicResolvers(deps)
|
||||
);
|
||||
return (
|
||||
|
|
|
@ -55,7 +55,6 @@ const PageWrapper: FC<PageProps> = ({ location, deps }) => {
|
|||
savedSearchId,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
|
||||
{
|
||||
...basicResolvers(deps),
|
||||
|
@ -79,7 +78,7 @@ const CheckViewOrCreateWrapper: FC<PageProps> = ({ location, deps }) => {
|
|||
const navigateToPath = useNavigateToPath();
|
||||
|
||||
// the single resolver checkViewOrCreateJobs redirects only. so will always reject
|
||||
useResolver(undefined, undefined, deps.config, deps.dataViewsContract, deps.getSavedSearchDeps, {
|
||||
useResolver(undefined, undefined, deps.config, deps.dataViewsContract, {
|
||||
checkViewOrCreateJobs: () =>
|
||||
checkViewOrCreateJobs(moduleId, dataViewId, createLinkWithUserDefaults, navigateToPath),
|
||||
});
|
||||
|
|
|
@ -199,7 +199,6 @@ const PageWrapper: FC<WizardPageProps> = ({ location, jobType, deps }) => {
|
|||
savedSearchId,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
{
|
||||
...basicResolvers(deps),
|
||||
privileges: () => checkCreateJobsCapabilitiesResolver(redirectToJobsManagementPage),
|
||||
|
|
|
@ -46,20 +46,12 @@ export const notificationsRouteFactory = (
|
|||
const PageWrapper: FC<PageProps> = ({ deps }) => {
|
||||
const { redirectToMlAccessDeniedPage } = deps;
|
||||
|
||||
const { context } = useResolver(
|
||||
undefined,
|
||||
undefined,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
{
|
||||
checkFullLicense,
|
||||
checkGetJobsCapabilities: () =>
|
||||
checkGetJobsCapabilitiesResolver(redirectToMlAccessDeniedPage),
|
||||
getMlNodeCount,
|
||||
loadMlServerInfo,
|
||||
}
|
||||
);
|
||||
const { context } = useResolver(undefined, undefined, deps.config, deps.dataViewsContract, {
|
||||
checkFullLicense,
|
||||
checkGetJobsCapabilities: () => checkGetJobsCapabilitiesResolver(redirectToMlAccessDeniedPage),
|
||||
getMlNodeCount,
|
||||
loadMlServerInfo,
|
||||
});
|
||||
useTimefilter({ timeRangeSelector: false, autoRefreshSelector: false });
|
||||
|
||||
return (
|
||||
|
|
|
@ -50,20 +50,12 @@ export const overviewRouteFactory = (
|
|||
const PageWrapper: FC<PageProps> = ({ deps }) => {
|
||||
const { redirectToMlAccessDeniedPage } = deps;
|
||||
|
||||
const { context } = useResolver(
|
||||
undefined,
|
||||
undefined,
|
||||
deps.config,
|
||||
deps.dataViewsContract,
|
||||
deps.getSavedSearchDeps,
|
||||
{
|
||||
checkFullLicense,
|
||||
checkGetJobsCapabilities: () =>
|
||||
checkGetJobsCapabilitiesResolver(redirectToMlAccessDeniedPage),
|
||||
getMlNodeCount,
|
||||
loadMlServerInfo,
|
||||
}
|
||||
);
|
||||
const { context } = useResolver(undefined, undefined, deps.config, deps.dataViewsContract, {
|
||||
checkFullLicense,
|
||||
checkGetJobsCapabilities: () => checkGetJobsCapabilitiesResolver(redirectToMlAccessDeniedPage),
|
||||
getMlNodeCount,
|
||||
loadMlServerInfo,
|
||||
});
|
||||
useTimefilter({ timeRangeSelector: false, autoRefreshSelector: false });
|
||||
|
||||
return (
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue