From 304cb256cf60ba689a8e0399693228986a5aff7e Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Tue, 8 Aug 2023 13:10:29 +0200 Subject: [PATCH] Make `SavedObjectFinder` backward compatible (#162904) ## Summary close https://github.com/elastic/kibana/issues/161545 close https://github.com/elastic/kibana/issues/153257 This PR makes `SavedObjectFinder` component backward compatible. It is achieved by going through content- management layer, more technical details [here](https://docs.google.com/document/d/1ssYmqSEUPrsuCR4iz8DohkEWekoYrm2yL4QR_fVxXLg/edit) ### Testing `SavedObjectFinder` is this component that allows to pick a saved object (supports: `search` `index-pattern` `map` `visualization` `lens` `event-annotation-group`: ![Screenshot 2023-08-07 at 16 53 32](https://github.com/elastic/kibana/assets/7784120/5c283ea5-3682-4dc8-a8ff-422e6f4f3195) It is used in the following places: - Dashboard - Add panel - Replace panel - Discover - Open Search - Visualization - Select search as a source for new viz - Graph - select source - Cases - markdown editor add lens - ML (3 places) - Canvas - select embeddable panel - Transform - Lens > select event annotation ### Risks / Follow up The `SavedObjectFinder` should stay mostly the same, the only notable functional change is that now `SavedObjectFinder` doesn't support `includeFields` which allowed partial saved object returns, this was done to make the call backward-compatible without making the system even more complicated as otherwise we'll need a way to abstract `includeFields` from so attributes and allow to run migrations on it before making a search. follow up issue to bring it back https://github.com/elastic/kibana/issues/163043 The risk with that is that some client that have a lot of large objects might run into performance issues when using `SavedObjectFinder`. This can be mitigated by changing listing limit in advanced setting from default 1000 to something lower --- .../content_management_examples/kibana.jsonc | 3 +- .../public/examples/finder/finder_app.tsx | 70 ++ .../public/examples/finder/index.tsx | 5 +- .../public/examples/index.tsx | 14 + .../public/examples/msearch/msearch_table.tsx | 12 +- .../content_management_examples/tsconfig.json | 1 + .../src/saved_object_content_storage.ts | 4 + ...t_annotation_group_saved_object_finder.tsx | 18 +- .../tsconfig.json | 3 +- .../kbn-event-annotation-components/types.ts | 2 +- .../content_management/public/mocks.ts | 1 + .../public/dashboard_actions/index.ts | 9 +- .../content_management_service.stub.ts | 17 + .../content_management_service.ts | 24 + .../public/services/plugin_services.stub.ts | 2 + .../public/services/plugin_services.ts | 2 + .../dashboard/public/services/types.ts | 2 + .../content_management/data_views_storage.ts | 1 + src/plugins/discover/kibana.jsonc | 13 +- .../open_search_panel.test.tsx.snap | 3 +- .../components/top_nav/open_search_panel.tsx | 15 +- src/plugins/discover/public/build_services.ts | 3 + src/plugins/discover/public/plugin.tsx | 2 + src/plugins/discover/tsconfig.json | 3 +- src/plugins/embeddable/kibana.jsonc | 3 +- .../add_panel_flyout.test.tsx | 2 +- .../add_panel_flyout/add_panel_flyout.tsx | 9 +- .../embeddable/public/kibana_services.ts | 2 + src/plugins/embeddable/public/mocks.tsx | 4 + src/plugins/embeddable/public/plugin.tsx | 2 + .../embeddable/public/tests/test_plugin.ts | 2 + src/plugins/embeddable/tsconfig.json | 3 +- src/plugins/event_annotation/kibana.jsonc | 1 - ...t_annotation_group_saved_object_finder.tsx | 19 +- .../public/event_annotation_service/index.tsx | 15 +- .../event_annotation_service/service.test.ts | 9 +- .../event_annotation_service/service.tsx | 7 +- src/plugins/event_annotation/public/mocks.ts | 21 +- src/plugins/event_annotation/public/plugin.ts | 11 +- src/plugins/event_annotation/tsconfig.json | 1 - .../saved_objects_finder/common/index.ts | 2 +- .../saved_objects_finder/common/types.ts | 25 +- src/plugins/saved_objects_finder/kibana.jsonc | 1 + .../public/finder/index.tsx | 13 +- .../finder/saved_object_finder.test.tsx | 672 +++++------------- .../public/finder/saved_object_finder.tsx | 87 +-- .../server/plugin.test.ts | 10 +- .../saved_objects_finder/server/plugin.ts | 5 +- .../server/routes/find.ts | 63 -- .../server/routes/index.ts | 14 - .../saved_objects_finder/server/types.ts | 10 - .../saved_objects_finder/tsconfig.json | 6 +- .../saved_objects_management/public/index.ts | 2 +- .../visualize_embeddable_factory.tsx | 1 + .../public/wizard/new_vis_modal.test.tsx | 31 +- .../public/wizard/new_vis_modal.tsx | 12 +- .../search_selection/search_selection.tsx | 14 +- .../search_selection/show_saved_object.ts | 6 +- .../public/wizard/show_new_vis.tsx | 9 +- src/plugins/visualizations/tsconfig.json | 1 - test/examples/content_management/finder.ts | 63 ++ test/examples/content_management/index.ts | 1 + test/examples/content_management/msearch.ts | 18 +- x-pack/plugins/canvas/kibana.jsonc | 2 +- .../embeddable_flyout/flyout.component.tsx | 5 +- x-pack/plugins/canvas/public/plugin.tsx | 4 +- .../canvas/public/services/kibana/platform.ts | 2 +- .../canvas/public/services/platform.ts | 4 +- .../canvas/public/services/stubs/platform.ts | 2 +- x-pack/plugins/canvas/tsconfig.json | 2 +- x-pack/plugins/cases/kibana.jsonc | 2 +- .../markdown_editor/plugins/lens/plugin.tsx | 6 +- x-pack/plugins/cases/public/types.ts | 4 +- x-pack/plugins/cases/tsconfig.json | 2 +- x-pack/plugins/graph/public/application.tsx | 3 +- .../graph/public/apps/workspace_route.tsx | 4 +- .../guidance_panel/guidance_panel.tsx | 9 +- .../graph/public/components/search_bar.tsx | 9 +- .../graph/public/components/source_picker.tsx | 21 +- x-pack/plugins/graph/public/plugin.ts | 1 + .../graph/public/services/source_modal.tsx | 15 +- x-pack/plugins/graph/tsconfig.json | 1 + x-pack/plugins/ml/kibana.jsonc | 12 +- x-pack/plugins/ml/public/application/app.tsx | 1 + .../contexts/kibana/kibana_context.ts | 2 + .../source_selection.test.tsx | 1 + .../source_selection/source_selection.tsx | 9 +- .../components/data_view/change_data_view.tsx | 12 +- .../new_job/pages/index_or_search/page.tsx | 6 +- x-pack/plugins/ml/public/plugin.ts | 3 + x-pack/plugins/ml/tsconfig.json | 1 + x-pack/plugins/transform/kibana.jsonc | 3 +- .../public/app/__mocks__/app_dependencies.tsx | 2 + .../transform/public/app/app_dependencies.tsx | 2 + .../public/app/mount_management_section.ts | 2 + .../search_selection/search_selection.tsx | 9 +- x-pack/plugins/transform/public/plugin.ts | 2 + x-pack/plugins/transform/tsconfig.json | 3 +- 98 files changed, 636 insertions(+), 938 deletions(-) create mode 100644 examples/content_management_examples/public/examples/finder/finder_app.tsx rename src/plugins/saved_objects_finder/server/plugin.test.mocks.ts => examples/content_management_examples/public/examples/finder/index.tsx (74%) create mode 100644 src/plugins/dashboard/public/services/content_management/content_management_service.stub.ts create mode 100644 src/plugins/dashboard/public/services/content_management/content_management_service.ts delete mode 100644 src/plugins/saved_objects_finder/server/routes/find.ts delete mode 100644 src/plugins/saved_objects_finder/server/routes/index.ts delete mode 100644 src/plugins/saved_objects_finder/server/types.ts create mode 100644 test/examples/content_management/finder.ts diff --git a/examples/content_management_examples/kibana.jsonc b/examples/content_management_examples/kibana.jsonc index ae7cd95e4190a..0d4a9b39dc0ef 100644 --- a/examples/content_management_examples/kibana.jsonc +++ b/examples/content_management_examples/kibana.jsonc @@ -12,6 +12,7 @@ "developerExamples", "kibanaReact", "savedObjectsTaggingOss" - ] + ], + "requiredBundles": ["savedObjectsFinder"] } } diff --git a/examples/content_management_examples/public/examples/finder/finder_app.tsx b/examples/content_management_examples/public/examples/finder/finder_app.tsx new file mode 100644 index 0000000000000..e033777216a61 --- /dev/null +++ b/examples/content_management_examples/public/examples/finder/finder_app.tsx @@ -0,0 +1,70 @@ +/* + * 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 React from 'react'; +import { ContentClientProvider, type ContentClient } from '@kbn/content-management-plugin/public'; +import type { CoreStart } from '@kbn/core/public'; +import { I18nProvider } from '@kbn/i18n-react'; +import { SavedObjectTaggingOssPluginStart } from '@kbn/saved-objects-tagging-oss-plugin/public'; +import { SavedObjectFinder } from '@kbn/saved-objects-finder-plugin/public'; + +export const FinderApp = (props: { + contentClient: ContentClient; + core: CoreStart; + savedObjectsTagging: SavedObjectTaggingOssPluginStart; +}) => { + return ( + + + { + alert(JSON.stringify(args)); + }} + savedObjectMetaData={[ + { + type: `search`, + getIconForSavedObject: () => 'discoverApp', + name: 'Saved search', + }, + { + type: 'index-pattern', + getIconForSavedObject: () => 'indexPatternApp', + name: 'Data view', + }, + { + type: `visualization`, + getIconForSavedObject: () => 'visualizeApp', + name: 'Visualization', + }, + { + type: 'lens', + getIconForSavedObject: () => 'lensApp', + name: 'Lens', + }, + { + type: 'map', + getIconForSavedObject: () => 'logoMaps', + name: 'Map', + }, + { + type: 'event-annotation-group', + getIconForSavedObject: () => 'annotation', + name: 'Annotation', + }, + ]} + /> + + + ); +}; diff --git a/src/plugins/saved_objects_finder/server/plugin.test.mocks.ts b/examples/content_management_examples/public/examples/finder/index.tsx similarity index 74% rename from src/plugins/saved_objects_finder/server/plugin.test.mocks.ts rename to examples/content_management_examples/public/examples/finder/index.tsx index af29314a63c79..64809019bbe84 100644 --- a/src/plugins/saved_objects_finder/server/plugin.test.mocks.ts +++ b/examples/content_management_examples/public/examples/finder/index.tsx @@ -6,7 +6,4 @@ * Side Public License, v 1. */ -export const registerRoutesMock = jest.fn(); -jest.doMock('./routes', () => ({ - registerRoutes: registerRoutesMock, -})); +export { FinderApp } from './finder_app'; diff --git a/examples/content_management_examples/public/examples/index.tsx b/examples/content_management_examples/public/examples/index.tsx index dbf1ed1bc01e2..3b92da0ba025e 100644 --- a/examples/content_management_examples/public/examples/index.tsx +++ b/examples/content_management_examples/public/examples/index.tsx @@ -16,6 +16,7 @@ import { AppMountParameters, CoreStart } from '@kbn/core/public'; import { StartDeps } from '../types'; import { TodoApp } from './todos'; import { MSearchApp } from './msearch'; +import { FinderApp } from './finder'; export const renderApp = ( core: CoreStart, @@ -45,6 +46,12 @@ export const renderApp = ( 'data-test-subj': 'msearchExample', href: '/app/contentManagementExamples/msearch', }, + { + id: 'finder', + name: 'Finder', + 'data-test-subj': 'finderExample', + href: '/app/contentManagementExamples/finder', + }, ], }, ]} @@ -64,6 +71,13 @@ export const renderApp = ( savedObjectsTagging={savedObjectsTaggingOss} /> + + + diff --git a/examples/content_management_examples/public/examples/msearch/msearch_table.tsx b/examples/content_management_examples/public/examples/msearch/msearch_table.tsx index a30c652cf0f79..84c5d58b86558 100644 --- a/examples/content_management_examples/public/examples/msearch/msearch_table.tsx +++ b/examples/content_management_examples/public/examples/msearch/msearch_table.tsx @@ -26,14 +26,20 @@ export const MSearchTable = () => { const { hits, pagination } = await contentClient.mSearch({ query: { text: searchQuery, - limit: LISTING_LIMIT, - cursor: '1', tags: { included: refs?.references?.map((ref) => ref.id), excluded: refs?.referencesToExclude?.map((ref) => ref.id), }, }, - contentTypes: [{ contentTypeId: 'map' }], // TODO: improve types to not require objects here? + contentTypes: [ + { contentTypeId: 'map' }, + { contentTypeId: 'dashboard' }, + { contentTypeId: 'visualization' }, + { contentTypeId: 'lens' }, + { contentTypeId: 'search' }, + { contentTypeId: 'index-pattern' }, + { contentTypeId: 'event-annotation-group' }, + ], // TODO: improve types to not require objects here? }); // TODO: needs to have logic of extracting common schema from an unknown mSearch hit: hits.map(hit => cm.convertToCommonSchema(hit)) diff --git a/examples/content_management_examples/tsconfig.json b/examples/content_management_examples/tsconfig.json index a9f20f45792a6..33d00ec0ee82d 100644 --- a/examples/content_management_examples/tsconfig.json +++ b/examples/content_management_examples/tsconfig.json @@ -29,5 +29,6 @@ "@kbn/content-management-table-list-view-table", "@kbn/content-management-table-list-view", "@kbn/shared-ux-router", + "@kbn/saved-objects-finder-plugin", ] } diff --git a/packages/kbn-content-management-utils/src/saved_object_content_storage.ts b/packages/kbn-content-management-utils/src/saved_object_content_storage.ts index ac8877e5a26da..721ce5e46b690 100644 --- a/packages/kbn-content-management-utils/src/saved_object_content_storage.ts +++ b/packages/kbn-content-management-utils/src/saved_object_content_storage.ts @@ -135,6 +135,7 @@ export interface SOContentStorageConstrutorParams { updateArgsToSoUpdateOptions?: UpdateArgsToSoUpdateOptions; searchArgsToSOFindOptions?: SearchArgsToSOFindOptions; enableMSearch?: boolean; + mSearchAdditionalSearchFields?: string[]; } export abstract class SOContentStorage @@ -153,6 +154,7 @@ export abstract class SOContentStorage searchArgsToSOFindOptions, enableMSearch, allowedSavedObjectAttributes, + mSearchAdditionalSearchFields, }: SOContentStorageConstrutorParams) { this.savedObjectType = savedObjectType; this.cmServicesDefinition = cmServicesDefinition; @@ -166,6 +168,7 @@ export abstract class SOContentStorage if (enableMSearch) { this.mSearch = { savedObjectType: this.savedObjectType, + additionalSearchFields: mSearchAdditionalSearchFields, toItemResult: (ctx: StorageContext, savedObject: SavedObjectsFindResult): Types['Item'] => { const transforms = ctx.utils.getTransforms(this.cmServicesDefinition); @@ -201,6 +204,7 @@ export abstract class SOContentStorage mSearch?: { savedObjectType: string; toItemResult: (ctx: StorageContext, savedObject: SavedObjectsFindResult) => Types['Item']; + additionalSearchFields?: string[]; }; async get(ctx: StorageContext, id: string): Promise { diff --git a/packages/kbn-event-annotation-components/components/event_annotation_group_saved_object_finder.tsx b/packages/kbn-event-annotation-components/components/event_annotation_group_saved_object_finder.tsx index 4ccdb6164a5a6..4b1549524874f 100644 --- a/packages/kbn-event-annotation-components/components/event_annotation_group_saved_object_finder.tsx +++ b/packages/kbn-event-annotation-components/components/event_annotation_group_saved_object_finder.tsx @@ -8,12 +8,10 @@ import React, { useEffect, useState } from 'react'; import { i18n } from '@kbn/i18n'; -import type { CoreStart } from '@kbn/core/public'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; import type { SavedObjectCommon } from '@kbn/saved-objects-finder-plugin/common'; import { SavedObjectFinder } from '@kbn/saved-objects-finder-plugin/public'; -import type { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; +import type { ContentClient } from '@kbn/content-management-plugin/public'; import { EuiButton, EuiEmptyPrompt, @@ -24,26 +22,25 @@ import { } from '@elastic/eui'; import { css } from '@emotion/react'; import { EVENT_ANNOTATION_GROUP_TYPE } from '@kbn/event-annotation-common'; +import { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; export const EventAnnotationGroupSavedObjectFinder = ({ - uiSettings, - http, - savedObjectsManagement, fixedPageSize = 10, checkHasAnnotationGroups, onChoose, onCreateNew, + contentClient, + uiSettings, }: { + contentClient: ContentClient; uiSettings: IUiSettingsClient; - http: CoreStart['http']; - savedObjectsManagement: SavedObjectsManagementPluginStart; fixedPageSize?: number; checkHasAnnotationGroups: () => Promise; onChoose: (value: { id: string; type: string; fullName: string; - savedObject: SavedObjectCommon; + savedObject: SavedObjectCommon; }) => void; onCreateNew: () => void; }) => { @@ -115,9 +112,8 @@ export const EventAnnotationGroupSavedObjectFinder = ({ } savedObjectMetaData={savedObjectMetaData} services={{ + contentClient, uiSettings, - http, - savedObjectsManagement, }} /> ); diff --git a/packages/kbn-event-annotation-components/tsconfig.json b/packages/kbn-event-annotation-components/tsconfig.json index 09fa401ec12c7..7a26b61878e2f 100644 --- a/packages/kbn-event-annotation-components/tsconfig.json +++ b/packages/kbn-event-annotation-components/tsconfig.json @@ -29,13 +29,12 @@ "@kbn/content-management-table-list-view-table", "@kbn/content-management-tabbed-table-list-view", "@kbn/event-annotation-common", - "@kbn/core", "@kbn/i18n-react", "@kbn/saved-objects-finder-plugin", - "@kbn/saved-objects-management-plugin", "@kbn/core-notifications-browser-mocks", "@kbn/core-notifications-browser", "@kbn/core-saved-objects-api-browser", "@kbn/expressions-plugin", + "@kbn/content-management-plugin", ] } diff --git a/packages/kbn-event-annotation-components/types.ts b/packages/kbn-event-annotation-components/types.ts index 495e204c1f4aa..6753fd95f1bf0 100644 --- a/packages/kbn-event-annotation-components/types.ts +++ b/packages/kbn-event-annotation-components/types.ts @@ -42,7 +42,7 @@ export interface EventAnnotationServiceType { id: string; type: string; fullName: string; - savedObject: SavedObjectCommon; + savedObject: SavedObjectCommon; }) => void; onCreateNew: () => void; }) => JSX.Element; diff --git a/src/plugins/content_management/public/mocks.ts b/src/plugins/content_management/public/mocks.ts index e868ac2d84453..c1fe460d4ce90 100644 --- a/src/plugins/content_management/public/mocks.ts +++ b/src/plugins/content_management/public/mocks.ts @@ -23,6 +23,7 @@ const createStartContract = (): ContentManagementPublicStart => { update: jest.fn(), delete: jest.fn(), search: jest.fn(), + mSearch: jest.fn(), } as unknown as ContentManagementPublicStart['client'], registry: { get: jest.fn(), diff --git a/src/plugins/dashboard/public/dashboard_actions/index.ts b/src/plugins/dashboard/public/dashboard_actions/index.ts index eb80313272826..8376ee1e65171 100644 --- a/src/plugins/dashboard/public/dashboard_actions/index.ts +++ b/src/plugins/dashboard/public/dashboard_actions/index.ts @@ -32,18 +32,15 @@ export const buildAllDashboardActions = async ({ plugins, allowByValueEmbeddables, }: BuildAllDashboardActionsProps) => { - const { uiSettings } = core; - const { uiActions, share, presentationUtil, savedObjectsManagement, savedObjectsTaggingOss } = - plugins; + const { uiActions, share, presentationUtil, savedObjectsTaggingOss, contentManagement } = plugins; const clonePanelAction = new ClonePanelAction(core.savedObjects); uiActions.registerAction(clonePanelAction); uiActions.attachAction(CONTEXT_MENU_TRIGGER, clonePanelAction.id); const SavedObjectFinder = getSavedObjectFinder( - uiSettings, - core.http, - savedObjectsManagement, + contentManagement.client, + core.uiSettings, savedObjectsTaggingOss?.getTaggingApi() ); const changeViewAction = new ReplacePanelAction(SavedObjectFinder); diff --git a/src/plugins/dashboard/public/services/content_management/content_management_service.stub.ts b/src/plugins/dashboard/public/services/content_management/content_management_service.stub.ts new file mode 100644 index 0000000000000..6f762fcadc40a --- /dev/null +++ b/src/plugins/dashboard/public/services/content_management/content_management_service.stub.ts @@ -0,0 +1,17 @@ +/* + * 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 { PluginServiceFactory } from '@kbn/presentation-util-plugin/public'; +import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; +import { contentManagementMock } from '@kbn/content-management-plugin/public/mocks'; + +export type ContentManagementServiceFactory = PluginServiceFactory; + +export const contentManagementServiceFactory: ContentManagementServiceFactory = () => { + return contentManagementMock.createStartContract(); +}; diff --git a/src/plugins/dashboard/public/services/content_management/content_management_service.ts b/src/plugins/dashboard/public/services/content_management/content_management_service.ts new file mode 100644 index 0000000000000..01c66a2c3682a --- /dev/null +++ b/src/plugins/dashboard/public/services/content_management/content_management_service.ts @@ -0,0 +1,24 @@ +/* + * 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 { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public'; +import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; +import { DashboardStartDependencies } from '../../plugin'; + +export type ContentManagementServiceFactory = KibanaPluginServiceFactory< + ContentManagementPublicStart, + DashboardStartDependencies +>; + +export const contentManagementServiceFactory: ContentManagementServiceFactory = ({ + startPlugins, +}) => { + const { contentManagement } = startPlugins; + + return contentManagement; +}; diff --git a/src/plugins/dashboard/public/services/plugin_services.stub.ts b/src/plugins/dashboard/public/services/plugin_services.stub.ts index e54cb783c71d6..3be6fe599cba6 100644 --- a/src/plugins/dashboard/public/services/plugin_services.stub.ts +++ b/src/plugins/dashboard/public/services/plugin_services.stub.ts @@ -40,6 +40,7 @@ import { visualizationsServiceFactory } from './visualizations/visualizations.st import { dashboardContentManagementServiceFactory } from './dashboard_content_management/dashboard_content_management.stub'; import { customBrandingServiceFactory } from './custom_branding/custom_branding.stub'; import { savedObjectsManagementServiceFactory } from './saved_objects_management/saved_objects_management_service.stub'; +import { contentManagementServiceFactory } from './content_management/content_management_service.stub'; export const providers: PluginServiceProviders = { dashboardContentManagement: new PluginServiceProvider(dashboardContentManagementServiceFactory), @@ -68,6 +69,7 @@ export const providers: PluginServiceProviders = { visualizations: new PluginServiceProvider(visualizationsServiceFactory), customBranding: new PluginServiceProvider(customBrandingServiceFactory), savedObjectsManagement: new PluginServiceProvider(savedObjectsManagementServiceFactory), + contentManagement: new PluginServiceProvider(contentManagementServiceFactory), }; export const registry = new PluginServiceRegistry(providers); diff --git a/src/plugins/dashboard/public/services/plugin_services.ts b/src/plugins/dashboard/public/services/plugin_services.ts index 716010cdbf0a8..c9e69481b2d69 100644 --- a/src/plugins/dashboard/public/services/plugin_services.ts +++ b/src/plugins/dashboard/public/services/plugin_services.ts @@ -41,6 +41,7 @@ import { analyticsServiceFactory } from './analytics/analytics_service'; import { customBrandingServiceFactory } from './custom_branding/custom_branding_service'; import { savedObjectsManagementServiceFactory } from './saved_objects_management/saved_objects_management_service'; import { dashboardContentManagementServiceFactory } from './dashboard_content_management/dashboard_content_management_service'; +import { contentManagementServiceFactory } from './content_management/content_management_service'; const providers: PluginServiceProviders = { dashboardContentManagement: new PluginServiceProvider(dashboardContentManagementServiceFactory, [ @@ -82,6 +83,7 @@ const providers: PluginServiceProviders(); diff --git a/src/plugins/dashboard/public/services/types.ts b/src/plugins/dashboard/public/services/types.ts index 2bb3753b132f0..27f980ef19b58 100644 --- a/src/plugins/dashboard/public/services/types.ts +++ b/src/plugins/dashboard/public/services/types.ts @@ -9,6 +9,7 @@ import { PluginInitializerContext } from '@kbn/core/public'; import { KibanaPluginServiceParams } from '@kbn/presentation-util-plugin/public'; import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; +import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import { DashboardStartDependencies } from '../plugin'; import { DashboardAnalyticsService } from './analytics/types'; @@ -68,4 +69,5 @@ export interface DashboardServices { visualizations: DashboardVisualizationsService; customBranding: DashboardCustomBrandingService; savedObjectsManagement: SavedObjectsManagementPluginStart; + contentManagement: ContentManagementPublicStart; } diff --git a/src/plugins/data_views/server/content_management/data_views_storage.ts b/src/plugins/data_views/server/content_management/data_views_storage.ts index c42a83f58e084..bd33b43a45bc1 100644 --- a/src/plugins/data_views/server/content_management/data_views_storage.ts +++ b/src/plugins/data_views/server/content_management/data_views_storage.ts @@ -31,6 +31,7 @@ export class DataViewsStorage extends SOContentStorage { 'allowNoIndex', 'name', ], + mSearchAdditionalSearchFields: ['name'], }); } } diff --git a/src/plugins/discover/kibana.jsonc b/src/plugins/discover/kibana.jsonc index 67e895bd0247d..96c4aef67fe18 100644 --- a/src/plugins/discover/kibana.jsonc +++ b/src/plugins/discover/kibana.jsonc @@ -25,7 +25,8 @@ "dataViewEditor", "expressions", "unifiedSearch", - "unifiedHistogram" + "unifiedHistogram", + "contentManagement" ], "optionalPlugins": [ "home", @@ -36,13 +37,7 @@ "savedObjectsTaggingOss", "lens" ], - "requiredBundles": [ - "kibanaUtils", - "kibanaReact", - "unifiedSearch" - ], - "extraPublicDirs": [ - "common" - ] + "requiredBundles": ["kibanaUtils", "kibanaReact", "unifiedSearch"], + "extraPublicDirs": ["common"] } } diff --git a/src/plugins/discover/public/application/main/components/top_nav/__snapshots__/open_search_panel.test.tsx.snap b/src/plugins/discover/public/application/main/components/top_nav/__snapshots__/open_search_panel.test.tsx.snap index 4ec374d62b9f0..98fe699ccd224 100644 --- a/src/plugins/discover/public/application/main/components/top_nav/__snapshots__/open_search_panel.test.tsx.snap +++ b/src/plugins/discover/public/application/main/components/top_nav/__snapshots__/open_search_panel.test.tsx.snap @@ -42,8 +42,7 @@ exports[`OpenSearchPanel render 1`] = ` } services={ Object { - "http": undefined, - "savedObjectsManagement": undefined, + "contentClient": undefined, "savedObjectsTagging": undefined, "uiSettings": undefined, } diff --git a/src/plugins/discover/public/application/main/components/top_nav/open_search_panel.tsx b/src/plugins/discover/public/application/main/components/top_nav/open_search_panel.tsx index cfb0badb677bc..a571ec2db7784 100644 --- a/src/plugins/discover/public/application/main/components/top_nav/open_search_panel.tsx +++ b/src/plugins/discover/public/application/main/components/top_nav/open_search_panel.tsx @@ -30,14 +30,8 @@ interface OpenSearchPanelProps { } export function OpenSearchPanel(props: OpenSearchPanelProps) { - const { - addBasePath, - capabilities, - core, - uiSettings, - savedObjectsManagement, - savedObjectsTagging, - } = useDiscoverServices(); + const { addBasePath, capabilities, savedObjectsTagging, contentClient, uiSettings } = + useDiscoverServices(); const hasSavedObjectPermission = capabilities.savedObjectsManagement?.edit || capabilities.savedObjectsManagement?.delete; @@ -56,10 +50,9 @@ export function OpenSearchPanel(props: OpenSearchPanelProps) { { 'testId', 'CONTACT_CARD_EMBEDDABLE', 'test name', - {} as unknown as SavedObjectCommon + {} as unknown as SavedObjectCommon ) } > diff --git a/src/plugins/embeddable/public/add_panel_flyout/add_panel_flyout.tsx b/src/plugins/embeddable/public/add_panel_flyout/add_panel_flyout.tsx index 82ee19cfaa2c0..07765836057ff 100644 --- a/src/plugins/embeddable/public/add_panel_flyout/add_panel_flyout.tsx +++ b/src/plugins/embeddable/public/add_panel_flyout/add_panel_flyout.tsx @@ -24,7 +24,7 @@ import { embeddableStart, usageCollection, savedObjectsTaggingOss, - savedObjectsManagement, + contentManagement, } from '../kibana_services'; import { IContainer, @@ -85,7 +85,7 @@ export const AddPanelFlyout = ({ (embeddableFactory) => Boolean(embeddableFactory.savedObjectMetaData) && !embeddableFactory.isContainerType ) - .map(({ savedObjectMetaData }) => savedObjectMetaData as SavedObjectMetaData), + .map(({ savedObjectMetaData }) => savedObjectMetaData as SavedObjectMetaData), [factoriesBySavedObjectType] ); @@ -125,10 +125,9 @@ export const AddPanelFlyout = ({ { @@ -45,6 +46,7 @@ export const setKibanaServices = ( usageCollection = deps.usageCollection; savedObjectsManagement = deps.savedObjectsManagement; savedObjectsTaggingOss = deps.savedObjectsTaggingOss; + contentManagement = deps.contentManagement; servicesReady$.next(true); }; diff --git a/src/plugins/embeddable/public/mocks.tsx b/src/plugins/embeddable/public/mocks.tsx index ef5ed38c82571..ec33b708d891d 100644 --- a/src/plugins/embeddable/public/mocks.tsx +++ b/src/plugins/embeddable/public/mocks.tsx @@ -16,6 +16,7 @@ import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks'; import { type AggregateQuery, type Filter, type Query } from '@kbn/es-query'; import { SavedObjectsTaggingApi } from '@kbn/saved-objects-tagging-oss-plugin/public'; import { savedObjectsManagementPluginMock } from '@kbn/saved-objects-management-plugin/public/mocks'; +import { contentManagementMock } from '@kbn/content-management-plugin/public/mocks'; import { EmbeddableStart, @@ -141,6 +142,8 @@ const createInstance = (setupPlugins: Partial = {}) savedObjectsManagement: savedObjectsManagementMock as unknown as SavedObjectsManagementPluginStart, usageCollection: { reportUiCounter: jest.fn() }, + contentManagement: + startPlugins.contentManagement || contentManagementMock.createStartContract(), }); return { plugin, @@ -167,5 +170,6 @@ export const setStubKibanaServices = () => { inspector: inspectorPluginMock.createStartContract(), savedObjectsManagement: savedObjectsManagementPluginMock.createStartContract(), usageCollection: { reportUiCounter: jest.fn() }, + contentManagement: contentManagementMock.createStartContract(), }); }; diff --git a/src/plugins/embeddable/public/plugin.tsx b/src/plugins/embeddable/public/plugin.tsx index df18c8e472457..89cd065d39cc3 100644 --- a/src/plugins/embeddable/public/plugin.tsx +++ b/src/plugins/embeddable/public/plugin.tsx @@ -23,6 +23,7 @@ import { Storage } from '@kbn/kibana-utils-plugin/public'; import { UsageCollectionStart } from '@kbn/usage-collection-plugin/public'; import { migrateToLatest, PersistableStateService } from '@kbn/kibana-utils-plugin/common'; import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; +import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import type { SavedObjectTaggingOssPluginStart } from '@kbn/saved-objects-tagging-oss-plugin/public'; import { EmbeddableFactoryRegistry, @@ -65,6 +66,7 @@ export interface EmbeddableStartDependencies { uiActions: UiActionsStart; inspector: InspectorStart; usageCollection: UsageCollectionStart; + contentManagement: ContentManagementPublicStart; savedObjectsManagement: SavedObjectsManagementPluginStart; savedObjectsTaggingOss?: SavedObjectTaggingOssPluginStart; } diff --git a/src/plugins/embeddable/public/tests/test_plugin.ts b/src/plugins/embeddable/public/tests/test_plugin.ts index 75792ab5fde3e..ee6dcdd36722b 100644 --- a/src/plugins/embeddable/public/tests/test_plugin.ts +++ b/src/plugins/embeddable/public/tests/test_plugin.ts @@ -17,6 +17,7 @@ import { } from '@kbn/saved-objects-management-plugin/public'; import { Query } from '@kbn/es-query'; import { SavedObjectsTaggingApi } from '@kbn/saved-objects-tagging-oss-plugin/public'; +import { contentManagementMock } from '@kbn/content-management-plugin/public/mocks'; import { EmbeddablePublicPlugin, EmbeddableSetup, EmbeddableStart } from '../plugin'; export interface TestPluginReturn { plugin: EmbeddablePublicPlugin; @@ -66,6 +67,7 @@ export const testPlugin = ( savedObjectsManagement: savedObjectsManagementMock as unknown as SavedObjectsManagementPluginStart, usageCollection: { reportUiCounter: jest.fn() }, + contentManagement: contentManagementMock.createStartContract(), }); return start; }, diff --git a/src/plugins/embeddable/tsconfig.json b/src/plugins/embeddable/tsconfig.json index 6470017e62220..80bc9afbc906f 100644 --- a/src/plugins/embeddable/tsconfig.json +++ b/src/plugins/embeddable/tsconfig.json @@ -29,7 +29,8 @@ "@kbn/analytics", "@kbn/usage-collection-plugin", "@kbn/ui-theme", - "@kbn/core-mount-utils-browser" + "@kbn/core-mount-utils-browser", + "@kbn/content-management-plugin" ], "exclude": ["target/**/*"] } diff --git a/src/plugins/event_annotation/kibana.jsonc b/src/plugins/event_annotation/kibana.jsonc index d343ecd76b4dc..315db78b8a68c 100644 --- a/src/plugins/event_annotation/kibana.jsonc +++ b/src/plugins/event_annotation/kibana.jsonc @@ -9,7 +9,6 @@ "browser": true, "requiredPlugins": [ "expressions", - "savedObjectsManagement", "data", "presentationUtil", "visualizations", diff --git a/src/plugins/event_annotation/public/components/event_annotation_group_saved_object_finder.tsx b/src/plugins/event_annotation/public/components/event_annotation_group_saved_object_finder.tsx index 4a969b210ef82..d9e97b0b2870c 100644 --- a/src/plugins/event_annotation/public/components/event_annotation_group_saved_object_finder.tsx +++ b/src/plugins/event_annotation/public/components/event_annotation_group_saved_object_finder.tsx @@ -8,12 +8,11 @@ import React, { useEffect, useState } from 'react'; import { i18n } from '@kbn/i18n'; -import { CoreStart } from '@kbn/core/public'; import { FormattedMessage } from '@kbn/i18n-react'; -import { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; import type { SavedObjectCommon } from '@kbn/saved-objects-finder-plugin/common'; import { SavedObjectFinder } from '@kbn/saved-objects-finder-plugin/public'; -import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; +import { ContentClient } from '@kbn/content-management-plugin/public'; +import { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; import { EuiButton, EuiEmptyPrompt, @@ -26,24 +25,22 @@ import { css } from '@emotion/react'; import { EVENT_ANNOTATION_GROUP_TYPE } from '@kbn/event-annotation-common'; export const EventAnnotationGroupSavedObjectFinder = ({ + contentClient, uiSettings, - http, - savedObjectsManagement, fixedPageSize = 10, checkHasAnnotationGroups, onChoose, onCreateNew, }: { uiSettings: IUiSettingsClient; - http: CoreStart['http']; - savedObjectsManagement: SavedObjectsManagementPluginStart; + contentClient: ContentClient; fixedPageSize?: number; checkHasAnnotationGroups: () => Promise; onChoose: (value: { id: string; type: string; fullName: string; - savedObject: SavedObjectCommon; + savedObject: SavedObjectCommon; }) => void; onCreateNew: () => void; }) => { @@ -114,11 +111,7 @@ export const EventAnnotationGroupSavedObjectFinder = ({ /> } savedObjectMetaData={savedObjectMetaData} - services={{ - uiSettings, - http, - savedObjectsManagement, - }} + services={{ contentClient, uiSettings }} /> ); }; diff --git a/src/plugins/event_annotation/public/event_annotation_service/index.tsx b/src/plugins/event_annotation/public/event_annotation_service/index.tsx index 0bc2f9e918038..d950e8af198ff 100644 --- a/src/plugins/event_annotation/public/event_annotation_service/index.tsx +++ b/src/plugins/event_annotation/public/event_annotation_service/index.tsx @@ -7,7 +7,6 @@ */ import { CoreStart } from '@kbn/core/public'; -import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import { EventAnnotationServiceType } from '@kbn/event-annotation-components'; export type { EventAnnotationServiceType }; @@ -16,27 +15,17 @@ export class EventAnnotationService { private eventAnnotationService?: EventAnnotationServiceType; private core: CoreStart; - private savedObjectsManagement: SavedObjectsManagementPluginStart; private contentManagement: ContentManagementPublicStart; - constructor( - core: CoreStart, - contentManagement: ContentManagementPublicStart, - savedObjectsManagement: SavedObjectsManagementPluginStart - ) { + constructor(core: CoreStart, contentManagement: ContentManagementPublicStart) { this.core = core; this.contentManagement = contentManagement; - this.savedObjectsManagement = savedObjectsManagement; } public async getService() { if (!this.eventAnnotationService) { const { getEventAnnotationService } = await import('./service'); - this.eventAnnotationService = getEventAnnotationService( - this.core, - this.contentManagement, - this.savedObjectsManagement - ); + this.eventAnnotationService = getEventAnnotationService(this.core, this.contentManagement); } return this.eventAnnotationService; } diff --git a/src/plugins/event_annotation/public/event_annotation_service/service.test.ts b/src/plugins/event_annotation/public/event_annotation_service/service.test.ts index 6463f14441995..c122102ae632a 100644 --- a/src/plugins/event_annotation/public/event_annotation_service/service.test.ts +++ b/src/plugins/event_annotation/public/event_annotation_service/service.test.ts @@ -9,7 +9,6 @@ import { CoreStart, SimpleSavedObject } from '@kbn/core/public'; import { ContentClient, ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import { coreMock } from '@kbn/core/public/mocks'; -import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; import { EventAnnotationConfig } from '@kbn/event-annotation-common'; import { getEventAnnotationService } from './service'; import { EventAnnotationServiceType } from '@kbn/event-annotation-components'; @@ -161,11 +160,9 @@ describe('Event Annotation Service', () => { hits: Object.values(annotationGroupResolveMocks), }); (contentClient.delete as jest.Mock).mockResolvedValue({}); - eventAnnotationService = getEventAnnotationService( - core, - { client: contentClient } as ContentManagementPublicStart, - {} as SavedObjectsManagementPluginStart - ); + eventAnnotationService = getEventAnnotationService(core, { + client: contentClient, + } as ContentManagementPublicStart); }); afterEach(() => { jest.clearAllMocks(); diff --git a/src/plugins/event_annotation/public/event_annotation_service/service.tsx b/src/plugins/event_annotation/public/event_annotation_service/service.tsx index c520f02d37dbd..b45748ed06eaf 100644 --- a/src/plugins/event_annotation/public/event_annotation_service/service.tsx +++ b/src/plugins/event_annotation/public/event_annotation_service/service.tsx @@ -11,7 +11,6 @@ import { partition } from 'lodash'; import { queryToAst } from '@kbn/data-plugin/common'; import { ExpressionAstExpression } from '@kbn/expressions-plugin/common'; import type { CoreStart, SavedObjectReference } from '@kbn/core/public'; -import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; import { DataViewPersistableStateService } from '@kbn/data-views-plugin/common'; import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import { type EventAnnotationServiceType } from '@kbn/event-annotation-components'; @@ -48,8 +47,7 @@ export function hasIcon(icon: string | undefined): icon is string { export function getEventAnnotationService( core: CoreStart, - contentManagement: ContentManagementPublicStart, - savedObjectsManagement: SavedObjectsManagementPluginStart + contentManagement: ContentManagementPublicStart ): EventAnnotationServiceType { const client = contentManagement.client; @@ -288,9 +286,8 @@ export function getEventAnnotationService( renderEventAnnotationGroupSavedObjectFinder: (props) => { return ( diff --git a/src/plugins/event_annotation/public/mocks.ts b/src/plugins/event_annotation/public/mocks.ts index f0e4dc34b876c..605f16f87c97b 100644 --- a/src/plugins/event_annotation/public/mocks.ts +++ b/src/plugins/event_annotation/public/mocks.ts @@ -7,20 +7,15 @@ */ import { coreMock } from '@kbn/core/public/mocks'; -import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import { getEventAnnotationService } from './event_annotation_service/service'; // not really mocking but avoiding async loading -export const eventAnnotationServiceMock = getEventAnnotationService( - coreMock.createStart(), - { - client: { - get: jest.fn(), - search: jest.fn(), - create: jest.fn(), - update: jest.fn(), - }, - } as unknown as ContentManagementPublicStart, - {} as SavedObjectsManagementPluginStart -); +export const eventAnnotationServiceMock = getEventAnnotationService(coreMock.createStart(), { + client: { + get: jest.fn(), + search: jest.fn(), + create: jest.fn(), + update: jest.fn(), + }, +} as unknown as ContentManagementPublicStart); diff --git a/src/plugins/event_annotation/public/plugin.ts b/src/plugins/event_annotation/public/plugin.ts index b58423b790b3d..bb1485210835f 100644 --- a/src/plugins/event_annotation/public/plugin.ts +++ b/src/plugins/event_annotation/public/plugin.ts @@ -11,7 +11,6 @@ import type { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/ import type { SavedObjectTaggingPluginStart } from '@kbn/saved-objects-tagging-plugin/public'; import type { ExpressionsSetup } from '@kbn/expressions-plugin/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; -import type { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; import { ContentManagementPublicSetup, ContentManagementPublicStart, @@ -34,7 +33,6 @@ import { ANNOTATIONS_LISTING_VIEW_ID } from '../common/constants'; import { CONTENT_ID, LATEST_VERSION } from '../common/content_management'; export interface EventAnnotationStartDependencies { - savedObjectsManagement: SavedObjectsManagementPluginStart; data: DataPublicPluginStart; savedObjectsTagging: SavedObjectTaggingPluginStart; presentationUtil: PresentationUtilPluginStart; @@ -89,8 +87,7 @@ export class EventAnnotationPlugin const eventAnnotationService = await new EventAnnotationService( coreStart, - pluginsStart.contentManagement, - pluginsStart.savedObjectsManagement + pluginsStart.contentManagement ).getService(); const ids = await pluginsStart.dataViews.getIds(); @@ -125,10 +122,6 @@ export class EventAnnotationPlugin core: CoreStart, startDependencies: EventAnnotationStartDependencies ): EventAnnotationService { - return new EventAnnotationService( - core, - startDependencies.contentManagement, - startDependencies.savedObjectsManagement - ); + return new EventAnnotationService(core, startDependencies.contentManagement); } } diff --git a/src/plugins/event_annotation/tsconfig.json b/src/plugins/event_annotation/tsconfig.json index a14cebb9541e6..0c279bcd92436 100644 --- a/src/plugins/event_annotation/tsconfig.json +++ b/src/plugins/event_annotation/tsconfig.json @@ -19,7 +19,6 @@ "@kbn/core-ui-settings-browser", "@kbn/datemath", "@kbn/saved-objects-finder-plugin", - "@kbn/saved-objects-management-plugin", "@kbn/saved-objects-tagging-plugin", "@kbn/presentation-util-plugin", "@kbn/visualizations-plugin", diff --git a/src/plugins/saved_objects_finder/common/index.ts b/src/plugins/saved_objects_finder/common/index.ts index 8a0964edc100b..6b80798a41cc9 100644 --- a/src/plugins/saved_objects_finder/common/index.ts +++ b/src/plugins/saved_objects_finder/common/index.ts @@ -7,4 +7,4 @@ */ export { PER_PAGE_SETTING, LISTING_LIMIT_SETTING } from '@kbn/saved-objects-settings'; -export type { SavedObjectCommon, FindQueryHTTP, FindResponseHTTP, FinderAttributes } from './types'; +export type { FinderAttributes, SavedObjectCommon } from './types'; diff --git a/src/plugins/saved_objects_finder/common/types.ts b/src/plugins/saved_objects_finder/common/types.ts index 1575da09698fb..60ff52f9aedc3 100644 --- a/src/plugins/saved_objects_finder/common/types.ts +++ b/src/plugins/saved_objects_finder/common/types.ts @@ -5,32 +5,11 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { SavedObject } from '@kbn/core-saved-objects-server'; +import type { SOWithMetadata } from '@kbn/content-management-utils'; -export type SavedObjectCommon = SavedObject; - -export interface FindQueryHTTP { - perPage?: number; - page?: number; - type: string | string[]; - search?: string; - searchFields?: string[]; - defaultSearchOperator?: 'AND' | 'OR'; - sortField?: string; - sortOrder?: 'asc' | 'desc'; - fields?: string | string[]; - hasReference?: string; -} +export type SavedObjectCommon = SOWithMetadata; export interface FinderAttributes { title?: string; name?: string; - type: string; -} - -export interface FindResponseHTTP { - saved_objects: Array>; - total: number; - page: number; - per_page: number; } diff --git a/src/plugins/saved_objects_finder/kibana.jsonc b/src/plugins/saved_objects_finder/kibana.jsonc index dbfc1e8838161..ad53ee32ae369 100644 --- a/src/plugins/saved_objects_finder/kibana.jsonc +++ b/src/plugins/saved_objects_finder/kibana.jsonc @@ -6,5 +6,6 @@ "id": "savedObjectsFinder", "server": true, "browser": true, + "requiredBundles": ["savedObjectsManagement"] } } diff --git a/src/plugins/saved_objects_finder/public/finder/index.tsx b/src/plugins/saved_objects_finder/public/finder/index.tsx index 93f61401dbe0a..3d991ee7fd4dd 100644 --- a/src/plugins/saved_objects_finder/public/finder/index.tsx +++ b/src/plugins/saved_objects_finder/public/finder/index.tsx @@ -8,10 +8,9 @@ import { EuiDelayRender, EuiSkeletonText } from '@elastic/eui'; import React from 'react'; -import { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; -import { HttpStart } from '@kbn/core-http-browser'; -import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; import { SavedObjectsTaggingApi } from '@kbn/saved-objects-tagging-oss-plugin/public'; +import type { ContentClient } from '@kbn/content-management-plugin/public'; +import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; import type { SavedObjectFinderProps } from './saved_object_finder'; const LazySavedObjectFinder = React.lazy(() => import('./saved_object_finder')); @@ -28,16 +27,12 @@ const SavedObjectFinder = (props: SavedObjectFinderProps) => ( ); export const getSavedObjectFinder = ( + contentClient: ContentClient, uiSettings: IUiSettingsClient, - http: HttpStart, - savedObjectsManagement: SavedObjectsManagementPluginStart, savedObjectsTagging?: SavedObjectsTaggingApi ) => { return (props: SavedObjectFinderProps) => ( - + ); }; diff --git a/src/plugins/saved_objects_finder/public/finder/saved_object_finder.test.tsx b/src/plugins/saved_objects_finder/public/finder/saved_object_finder.test.tsx index 674e49a77c360..f02517e845ed9 100644 --- a/src/plugins/saved_objects_finder/public/finder/saved_object_finder.test.tsx +++ b/src/plugins/saved_objects_finder/public/finder/saved_object_finder.test.tsx @@ -23,11 +23,10 @@ import { mount, shallow } from 'enzyme'; import React from 'react'; import * as sinon from 'sinon'; import { SavedObjectFinderUi as SavedObjectFinder } from './saved_object_finder'; -import { coreMock } from '@kbn/core/public/mocks'; -import { savedObjectsManagementPluginMock } from '@kbn/saved-objects-management-plugin/public/mocks'; +import { contentManagementMock } from '@kbn/content-management-plugin/public/mocks'; import { findTestSubject } from '@kbn/test-jest-helpers'; -import { SavedObjectManagementTypeInfo } from '@kbn/saved-objects-management-plugin/public'; import { SavedObjectsTaggingApi } from '@kbn/saved-objects-tagging-oss-plugin/public'; +import { coreMock } from '@kbn/core/public/mocks'; describe('SavedObjectsFinder', () => { const doc = { @@ -67,23 +66,14 @@ describe('SavedObjectsFinder', () => { }, ]; - const savedObjectsManagement = savedObjectsManagementPluginMock.createStartContract(); - savedObjectsManagement.parseQuery.mockImplementation( - (query: Query, types: SavedObjectManagementTypeInfo[]) => { - const queryTypes = query.ast.getFieldClauses('type')?.[0].value as string[] | undefined; - return { - queryText: query.ast - .getTermClauses() - .map((clause: any) => clause.value) - .join(' '), - visibleTypes: queryTypes?.filter((name) => types.some((type) => type.name === name)), - selectedTags: query.ast.getFieldClauses('tag')?.[0].value as string[] | undefined, - }; - } - ); - savedObjectsManagement.getTagFindReferences.mockImplementation( - ({ selectedTags }) => selectedTags as any - ); + const contentManagement = contentManagementMock.createStartContract(); + const contentClient = contentManagement.client; + beforeEach(() => { + (contentClient.mSearch as any as jest.SpyInstance).mockClear(); + }); + const coreStart = coreMock.createStart(); + const uiSettings = coreStart.uiSettings; + uiSettings.get.mockImplementation(() => 10); const savedObjectsTagging = { ui: { @@ -102,22 +92,20 @@ describe('SavedObjectsFinder', () => { multiSelect: 'or', options: [], })), + convertNameToReference: jest.fn((name: string) => ({ type: 'tag', id: name })), }, } as any as SavedObjectsTaggingApi; it('should call API on startup', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [doc] }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc] }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( { wrapper.instance().componentDidMount!(); await nextTick(); - expect(core.http.get).toHaveBeenCalledWith('/internal/saved-objects-finder/find', { - query: { - type: ['search'], - fields: ['title', 'name'], - search: undefined, - hasReference: undefined, - page: 1, - perPage: 10, - searchFields: ['title^3', 'description', 'name'], - defaultSearchOperator: 'AND', - }, + expect(contentClient.mSearch).toHaveBeenCalledWith({ + contentTypes: [{ contentTypeId: 'search' }], + query: { limit: 10 }, }); }); describe('render', () => { it('lists initial items', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [doc] }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc] }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( ); @@ -172,20 +145,13 @@ describe('SavedObjectsFinder', () => { it('calls onChoose on item click', async () => { const chooseStub = sinon.stub(); - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [doc] }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc] }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( @@ -201,20 +167,13 @@ describe('SavedObjectsFinder', () => { }); it('with help text', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [doc] }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc] }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( @@ -228,20 +187,13 @@ describe('SavedObjectsFinder', () => { }); it('with left button', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [doc] }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc] }) ); - core.uiSettings.get.mockImplementation(() => 10); const button = Hello; const wrapper = shallow( @@ -268,20 +220,13 @@ describe('SavedObjectsFinder', () => { describe('sorting', () => { it('should list items by type ascending', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [doc, doc3, doc2] }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc, doc3, doc2] }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( ); @@ -299,20 +244,13 @@ describe('SavedObjectsFinder', () => { }); it('should list items by type descending', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [doc, doc3, doc2] }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc, doc3, doc2] }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( ); @@ -334,20 +272,13 @@ describe('SavedObjectsFinder', () => { }); it('should list items by title ascending', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [doc, doc2] }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc, doc2] }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( ); @@ -361,20 +292,13 @@ describe('SavedObjectsFinder', () => { }); it('should list items by title descending', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [doc, doc2] }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc, doc2] }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( ); @@ -391,20 +315,13 @@ describe('SavedObjectsFinder', () => { }); it('should list items by tag ascending', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [doc, doc3, doc2] }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc, doc3, doc2] }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( ); @@ -422,20 +339,13 @@ describe('SavedObjectsFinder', () => { }); it('should list items by tag descending', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [doc, doc3, doc2] }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc, doc3, doc2] }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( ); @@ -458,20 +368,13 @@ describe('SavedObjectsFinder', () => { }); it('should not show the saved objects which get filtered by showSavedObject', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [doc, doc2] }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc, doc2] }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( { describe('search', () => { it('should request filtered list on search input', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [doc, doc2] }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc, doc2] }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( ); @@ -515,84 +411,25 @@ describe('SavedObjectsFinder', () => { wrapper .find('[data-test-subj="savedObjectFinderSearchInput"] input') .simulate('keyup', { key: 'Enter', target: { value: 'abc' } }); - expect(core.http.get).toHaveBeenCalledWith('/internal/saved-objects-finder/find', { - query: { - type: ['search'], - fields: ['title', 'name'], - search: 'abc*', - hasReference: undefined, - page: 1, - perPage: 10, - searchFields: ['title^3', 'description', 'name'], - defaultSearchOperator: 'AND', - }, - }); - }); - - it('should include additional fields in search if listed in meta data', async () => { - const core = coreMock.createStart(); - (core.http.get as jest.Mock).mockResolvedValue({ saved_objects: [] }); - core.uiSettings.get.mockImplementation(() => 10); - - const wrapper = mount( - 'search', - includeFields: ['field1', 'field2'], - }, - { - type: 'type2', - name: '', - getIconForSavedObject: () => 'search', - includeFields: ['field2', 'field3'], - }, - ]} - /> - ); - wrapper.instance().componentDidMount!(); - await nextTick(); - wrapper - .find('[data-test-subj="savedObjectFinderSearchInput"] input') - .simulate('keyup', { key: 'Enter', target: { value: 'abc' } }); - expect(core.http.get).toHaveBeenCalledWith('/internal/saved-objects-finder/find', { - query: { - type: ['type1', 'type2'], - fields: ['title', 'name', 'field1', 'field2', 'field3'], - search: 'abc*', - hasReference: undefined, - page: 1, - perPage: 10, - searchFields: ['title^3', 'description'], - defaultSearchOperator: 'AND', - }, + expect(contentClient.mSearch).toHaveBeenCalledWith({ + contentTypes: [ + { + contentTypeId: 'search', + }, + ], + query: { limit: 10, text: 'abc*' }, }); }); it('should respect response order on search input', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [doc, doc2] }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc, doc2] }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( ); @@ -609,20 +446,13 @@ describe('SavedObjectsFinder', () => { }); it('should request multiple saved object types at once', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [doc, doc2] }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc, doc2] }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = shallow( { wrapper.instance().componentDidMount!(); - expect(core.http.get).toHaveBeenCalledWith('/internal/saved-objects-finder/find', { - query: { - type: ['search', 'vis'], - fields: ['title', 'name'], - search: undefined, - page: 1, - perPage: 10, - searchFields: ['title^3', 'description'], - defaultSearchOperator: 'AND', - }, + expect(contentClient.mSearch).toHaveBeenCalledWith({ + contentTypes: [ + { + contentTypeId: 'search', + }, + { + contentTypeId: 'vis', + }, + ], + query: { limit: 10, text: undefined }, }); }); describe('filter', () => { it('should render filter buttons if enabled', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ - saved_objects: [doc, doc2, doc3], - }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc, doc2, doc3] }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( @@ -684,22 +505,13 @@ describe('SavedObjectsFinder', () => { }); it('should not render filter buttons if disabled', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ - saved_objects: [doc, doc2, doc3], - }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc, doc2, doc3] }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( @@ -711,22 +523,13 @@ describe('SavedObjectsFinder', () => { }); it('should not render types filter button if there is only one type in the metadata list', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ - saved_objects: [doc, doc2], - }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc, doc2] }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( @@ -739,22 +542,13 @@ describe('SavedObjectsFinder', () => { }); it('should not render tags filter button if savedObjectsTagging is undefined', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ - saved_objects: [doc, doc2, doc3], - }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc, doc2, doc3] }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( @@ -767,22 +561,13 @@ describe('SavedObjectsFinder', () => { }); it('should apply types filter if selected', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ - saved_objects: [doc, doc2, doc3], - }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc, doc2, doc3] }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( @@ -793,50 +578,36 @@ describe('SavedObjectsFinder', () => { const table = wrapper.find>(EuiInMemoryTable); const search = table.prop('search') as EuiSearchBarProps; search.onChange?.({ query: Query.parse('type:(vis)'), queryText: '', error: null }); - expect(core.http.get).toHaveBeenLastCalledWith('/internal/saved-objects-finder/find', { - query: { - type: ['vis'], - fields: ['title', 'name'], - search: undefined, - hasReference: undefined, - page: 1, - perPage: 10, - searchFields: ['title^3', 'description'], - defaultSearchOperator: 'AND', - }, + expect(contentClient.mSearch).toHaveBeenLastCalledWith({ + contentTypes: [ + { + contentTypeId: 'vis', + }, + ], + query: { limit: 10, text: undefined }, }); search.onChange?.({ query: Query.parse('type:(search or vis)'), queryText: '', error: null }); - expect(core.http.get).toHaveBeenLastCalledWith('/internal/saved-objects-finder/find', { - query: { - type: ['search', 'vis'], - fields: ['title', 'name'], - search: undefined, - hasReference: undefined, - page: 1, - perPage: 10, - searchFields: ['title^3', 'description'], - defaultSearchOperator: 'AND', - }, + expect(contentClient.mSearch).toHaveBeenLastCalledWith({ + contentTypes: [ + { + contentTypeId: 'search', + }, + { + contentTypeId: 'vis', + }, + ], + query: { limit: 10, text: undefined }, }); }); it('should apply tags filter if selected', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ - saved_objects: [doc, doc2, doc3], - }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc, doc2, doc3] }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( @@ -847,50 +618,53 @@ describe('SavedObjectsFinder', () => { const table = wrapper.find>(EuiInMemoryTable); const search = table.prop('search') as EuiSearchBarProps; search.onChange?.({ query: Query.parse('tag:(tag1)'), queryText: '', error: null }); - expect(core.http.get).toHaveBeenLastCalledWith('/internal/saved-objects-finder/find', { + expect(contentClient.mSearch).toHaveBeenLastCalledWith({ + contentTypes: [ + { + contentTypeId: 'search', + }, + { + contentTypeId: 'vis', + }, + ], query: { - type: ['search', 'vis'], - fields: ['title', 'name'], - search: undefined, - hasReference: JSON.stringify(['tag1']), - page: 1, - perPage: 10, - searchFields: ['title^3', 'description'], - defaultSearchOperator: 'AND', + limit: 10, + text: undefined, + tags: { + included: ['tag1'], + }, }, }); search.onChange?.({ query: Query.parse('tag:(tag1 or tag2)'), queryText: '', error: null }); - expect(core.http.get).toHaveBeenLastCalledWith('/internal/saved-objects-finder/find', { + expect(contentClient.mSearch).toHaveBeenLastCalledWith({ + contentTypes: [ + { + contentTypeId: 'search', + }, + { + contentTypeId: 'vis', + }, + ], query: { - type: ['search', 'vis'], - fields: ['title', 'name'], - search: undefined, - hasReference: JSON.stringify(['tag1', 'tag2']), - page: 1, - perPage: 10, - searchFields: ['title^3', 'description'], - defaultSearchOperator: 'AND', + limit: 10, + text: undefined, + tags: { + included: ['tag1', 'tag2'], + }, }, }); }); }); it('should display no items message if there are no items', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [] }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [] }) ); - core.uiSettings.get.mockImplementation(() => 10); const noItemsMessage = ; const wrapper = mount( @@ -912,20 +686,13 @@ describe('SavedObjectsFinder', () => { })); it('should show a table pagination with initial per page', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: longItemList }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: longItemList }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( @@ -941,20 +708,13 @@ describe('SavedObjectsFinder', () => { }); it('should allow switching the page size', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: longItemList }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: longItemList }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( @@ -976,20 +736,13 @@ describe('SavedObjectsFinder', () => { }); it('should switch page correctly', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: longItemList }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: longItemList }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( @@ -1014,20 +767,13 @@ describe('SavedObjectsFinder', () => { }); it('should show an ordinary pagination for fixed page sizes', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: longItemList }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: longItemList }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( @@ -1043,20 +789,13 @@ describe('SavedObjectsFinder', () => { }); it('should switch page correctly for fixed page sizes', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: longItemList }) + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: longItemList }) ); - core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( @@ -1083,18 +822,11 @@ describe('SavedObjectsFinder', () => { describe('loading state', () => { it('should display a loading indicator during initial loading', () => { - const core = coreMock.createStart(); - (core.http.get as jest.Mock).mockResolvedValue({ saved_objects: [] }); - core.uiSettings.get.mockImplementation(() => 10); + (contentClient.mSearch as any as jest.SpyInstance).mockResolvedValue({ hits: [] }); const wrapper = mount( ); @@ -1103,20 +835,11 @@ describe('SavedObjectsFinder', () => { }); it('should hide the loading indicator if data is shown', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [doc] }) - ); - core.uiSettings.get.mockImplementation(() => 10); + (contentClient.mSearch as any as jest.SpyInstance).mockResolvedValue({ hits: [doc] }); const wrapper = mount( { }); it('should show the loading indicator if there are already items and the search is updated', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [doc] }) - ); - core.uiSettings.get.mockImplementation(() => 10); + (contentClient.mSearch as any as jest.SpyInstance).mockResolvedValue({ hits: [doc] }); const wrapper = mount( ); @@ -1165,20 +879,11 @@ describe('SavedObjectsFinder', () => { }); it('should render with children', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [doc, doc2] }) - ); - core.uiSettings.get.mockImplementation(() => 10); + (contentClient.mSearch as any as jest.SpyInstance).mockResolvedValue({ hits: [doc, doc2] }); const wrapper = mount( { describe('columns', () => { it('should show all columns', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [doc, doc2, doc3] }) - ); - core.uiSettings.get.mockImplementation(() => 10); + (contentClient.mSearch as any as jest.SpyInstance).mockResolvedValue({ + hits: [doc, doc2, doc3], + }); const wrapper = mount( ); @@ -1228,20 +926,13 @@ describe('SavedObjectsFinder', () => { }); it('should hide the type column if there is only one type in the metadata list', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [doc, doc2] }) - ); - core.uiSettings.get.mockImplementation(() => 10); + (contentClient.mSearch as any as jest.SpyInstance).mockResolvedValue({ + hits: [doc, doc2], + }); const wrapper = mount( ); @@ -1256,20 +947,13 @@ describe('SavedObjectsFinder', () => { }); it('should hide the tags column if savedObjectsTagging is undefined', async () => { - const core = coreMock.createStart(); - (core.http.get as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ saved_objects: [doc, doc2, doc3] }) - ); - core.uiSettings.get.mockImplementation(() => 10); + (contentClient.mSearch as any as jest.SpyInstance).mockResolvedValue({ + hits: [doc, doc2, doc3], + }); const wrapper = mount( ); diff --git a/src/plugins/saved_objects_finder/public/finder/saved_object_finder.tsx b/src/plugins/saved_objects_finder/public/finder/saved_object_finder.tsx index 3283bfed3fa64..aad1734dff657 100644 --- a/src/plugins/saved_objects_finder/public/finder/saved_object_finder.tsx +++ b/src/plugins/saved_objects_finder/public/finder/saved_object_finder.tsx @@ -9,44 +9,39 @@ import { debounce } from 'lodash'; import PropTypes from 'prop-types'; import React, { ReactElement, ReactNode } from 'react'; -import type { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; +import { getTagFindReferences, parseQuery } from '@kbn/saved-objects-management-plugin/public'; +import type { ContentClient } from '@kbn/content-management-plugin/public'; +import type { IUiSettingsClient } from '@kbn/core/public'; import { + EuiFlexGroup, + EuiFlexItem, + EuiIcon, EuiInMemoryTable, EuiLink, + EuiSearchBarProps, EuiTableFieldDataColumnType, - IconType, - EuiIcon, + EuiText, EuiToolTip, - EuiSearchBarProps, - SearchFilterConfig, - Query, + IconType, PropertySort, - EuiFlexItem, - EuiFlexGroup, - EuiText, + Query, + SearchFilterConfig, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import type { IUiSettingsClient, HttpStart } from '@kbn/core/public'; import type { SavedObjectsTaggingApi } from '@kbn/saved-objects-tagging-oss-plugin/public'; -import { - SavedObjectCommon, - FindQueryHTTP, - FindResponseHTTP, - FinderAttributes, - LISTING_LIMIT_SETTING, -} from '../../common'; - -export interface SavedObjectMetaData { +import { FinderAttributes, SavedObjectCommon, LISTING_LIMIT_SETTING } from '../../common'; + +export interface SavedObjectMetaData { type: string; name: string; getIconForSavedObject(savedObject: SavedObjectCommon): IconType; getTooltipForSavedObject?(savedObject: SavedObjectCommon): string; showSavedObject?(savedObject: SavedObjectCommon): boolean; getSavedObjectSubType?(savedObject: SavedObjectCommon): string; + /** @deprecated doesn't do anything, the full object is returned **/ includeFields?: string[]; - defaultSearchField?: string; } interface SavedObjectFinderItem extends SavedObjectCommon { @@ -63,10 +58,9 @@ interface SavedObjectFinderState { } interface SavedObjectFinderServices { - http: HttpStart; - uiSettings: IUiSettingsClient; - savedObjectsManagement: SavedObjectsManagementPluginStart; savedObjectsTagging?: SavedObjectsTaggingApi; + contentClient: ContentClient; + uiSettings: IUiSettingsClient; } interface BaseSavedObjectFinder { @@ -113,21 +107,9 @@ export class SavedObjectFinderUi extends React.Component< private debouncedFetch = debounce(async (query: Query) => { const metaDataMap = this.getSavedObjectMetaDataMap(); - const { savedObjectsManagement, uiSettings, http } = this.props.services; - - const fields = Object.values(metaDataMap) - .map((metaData) => metaData.includeFields || []) - .reduce((allFields, currentFields) => allFields.concat(currentFields), ['title', 'name']); + const { contentClient, uiSettings } = this.props.services; - const additionalSearchFields = Object.values(metaDataMap).reduce((col, item) => { - if (item.defaultSearchField) { - col.push(item.defaultSearchField); - } - return col; - }, []); - - const perPage = uiSettings.get(LISTING_LIMIT_SETTING); - const { queryText, visibleTypes, selectedTags } = savedObjectsManagement.parseQuery( + const { queryText, visibleTypes, selectedTags } = parseQuery( query, Object.values(metaDataMap).map((metadata) => ({ name: metadata.type, @@ -136,26 +118,23 @@ export class SavedObjectFinderUi extends React.Component< displayName: metadata.name, })) ); - const hasReference = savedObjectsManagement.getTagFindReferences({ + const includeTags = getTagFindReferences({ selectedTags, taggingApi: this.props.services.savedObjectsTagging, - }); - const params: FindQueryHTTP = { - type: visibleTypes ?? Object.keys(metaDataMap), - search: queryText ? `${queryText}*` : undefined, - fields: [...new Set(fields)], - page: 1, - perPage, - searchFields: ['title^3', 'description', ...additionalSearchFields], - defaultSearchOperator: 'AND', - hasReference: hasReference ? JSON.stringify(hasReference) : undefined, - }; + })?.map(({ id, type }) => id); - const response = (await http.get('/internal/saved-objects-finder/find', { - query: params as Record, - })) as FindResponseHTTP; + const types = visibleTypes ?? Object.keys(metaDataMap); + + const response = await contentClient.mSearch>({ + contentTypes: types.map((type) => ({ contentTypeId: type })), + query: { + text: queryText ? `${queryText}*` : undefined, + ...(includeTags?.length ? { tags: { included: includeTags } } : {}), + limit: uiSettings.get(LISTING_LIMIT_SETTING), // TODO: support pagination, + }, + }); - const savedObjects = response.saved_objects + const savedObjects = response.hits .map((savedObject) => { const { attributes: { name, title }, @@ -270,7 +249,7 @@ export class SavedObjectFinderUi extends React.Component< currentSavedObjectMetaData || ({ getIconForSavedObject: () => 'document', - } as Pick, 'getIconForSavedObject'>) + } as Pick) ).getIconForSavedObject(item.simple); return ( diff --git a/src/plugins/saved_objects_finder/server/plugin.test.ts b/src/plugins/saved_objects_finder/server/plugin.test.ts index 68569a6a24c17..3521acd5594b1 100644 --- a/src/plugins/saved_objects_finder/server/plugin.test.ts +++ b/src/plugins/saved_objects_finder/server/plugin.test.ts @@ -6,8 +6,6 @@ * Side Public License, v 1. */ -import { registerRoutesMock } from './plugin.test.mocks'; - import { coreMock } from '@kbn/core/server/mocks'; import { SavedObjectsServerPlugin } from './plugin'; import { uiSettings } from './ui_settings'; @@ -21,17 +19,11 @@ describe('SavedObjectsPlugin', () => { plugin = new SavedObjectsServerPlugin(); }); - afterEach(() => { - registerRoutesMock.mockReset(); - }); - describe('#setup', () => { - it('calls `registerRoutes` and `registerSettings` with the correct parameters', () => { + it('calls `registerSettings` with the correct parameters', () => { plugin.setup(coreSetup); expect(coreSetup.uiSettings.register).toHaveBeenCalledWith(uiSettings); - expect(coreSetup.http.createRouter).toHaveBeenCalledTimes(1); - expect(registerRoutesMock).toHaveBeenCalledTimes(1); }); }); }); diff --git a/src/plugins/saved_objects_finder/server/plugin.ts b/src/plugins/saved_objects_finder/server/plugin.ts index 6d01010e37612..f088465053c57 100644 --- a/src/plugins/saved_objects_finder/server/plugin.ts +++ b/src/plugins/saved_objects_finder/server/plugin.ts @@ -6,15 +6,12 @@ * Side Public License, v 1. */ -import type { CoreSetup, Plugin, RequestHandlerContext } from '@kbn/core/server'; -import { registerRoutes } from './routes'; +import type { CoreSetup, Plugin } from '@kbn/core/server'; import { uiSettings } from './ui_settings'; export class SavedObjectsServerPlugin implements Plugin { public setup(core: CoreSetup) { core.uiSettings.register(uiSettings); - const router = core.http.createRouter(); - registerRoutes(router); return {}; } diff --git a/src/plugins/saved_objects_finder/server/routes/find.ts b/src/plugins/saved_objects_finder/server/routes/find.ts deleted file mode 100644 index ce9377ce25333..0000000000000 --- a/src/plugins/saved_objects_finder/server/routes/find.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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 { SavedObjectsRouter } from '../types'; -import type { SavedObjectCommon, FindResponseHTTP } from '../../common'; - -export const registerFindRoute = (router: SavedObjectsRouter) => { - router.get( - { - path: '/internal/saved-objects-finder/find', - validate: { - query: schema.object({ - perPage: schema.number({ min: 0, defaultValue: 20 }), - page: schema.number({ min: 0, defaultValue: 1 }), - type: schema.oneOf([schema.string(), schema.arrayOf(schema.string())]), - search: schema.maybe(schema.string()), - defaultSearchOperator: schema.oneOf([schema.literal('AND'), schema.literal('OR')]), - sortField: schema.maybe(schema.string()), - sortOrder: schema.maybe(schema.oneOf([schema.literal('asc'), schema.literal('desc')])), - fields: schema.oneOf([schema.string(), schema.arrayOf(schema.string())], { - defaultValue: [], - }), - searchFields: schema.maybe(schema.arrayOf(schema.string())), - hasReference: schema.maybe(schema.string()), - }), - }, - options: { - authRequired: 'optional', - }, - }, - async (ctx, req, res) => { - const savedObjectsClient = (await ctx.core).savedObjects.client; - const { query } = req; - - const searchTypes = Array.isArray(query.type) ? query.type : [query.type]; - const includedFields = Array.isArray(query.fields) ? query.fields : [query.fields]; - - const findResponse = await savedObjectsClient.find>({ - ...query, - type: searchTypes, - fields: includedFields, - hasReference: query.hasReference ? JSON.parse(query.hasReference) : undefined, - }); - - const savedObjects = findResponse.saved_objects; - - const response: FindResponseHTTP = { - saved_objects: savedObjects, - total: findResponse.total, - per_page: findResponse.per_page, - page: findResponse.page, - }; - - return res.ok({ body: response }); - } - ); -}; diff --git a/src/plugins/saved_objects_finder/server/routes/index.ts b/src/plugins/saved_objects_finder/server/routes/index.ts deleted file mode 100644 index df9a797e8184d..0000000000000 --- a/src/plugins/saved_objects_finder/server/routes/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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 { SavedObjectsRouter } from '../types'; -import { registerFindRoute } from './find'; - -export const registerRoutes = (router: SavedObjectsRouter) => { - registerFindRoute(router); -}; diff --git a/src/plugins/saved_objects_finder/server/types.ts b/src/plugins/saved_objects_finder/server/types.ts deleted file mode 100644 index e6ec45a63d04f..0000000000000 --- a/src/plugins/saved_objects_finder/server/types.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * 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 { IRouter, RequestHandlerContext } from '@kbn/core/server'; - -export type SavedObjectsRouter = IRouter; diff --git a/src/plugins/saved_objects_finder/tsconfig.json b/src/plugins/saved_objects_finder/tsconfig.json index 217f4f7f0dbe3..cecc9fbdadb61 100644 --- a/src/plugins/saved_objects_finder/tsconfig.json +++ b/src/plugins/saved_objects_finder/tsconfig.json @@ -10,11 +10,11 @@ "@kbn/test-jest-helpers", "@kbn/saved-objects-tagging-oss-plugin", "@kbn/i18n", - "@kbn/core-saved-objects-server", "@kbn/config-schema", - "@kbn/core-ui-settings-browser", - "@kbn/core-http-browser", "@kbn/saved-objects-settings", + "@kbn/content-management-plugin", + "@kbn/content-management-utils", + "@kbn/core-ui-settings-browser", ], "exclude": [ "target/**/*", diff --git a/src/plugins/saved_objects_management/public/index.ts b/src/plugins/saved_objects_management/public/index.ts index 223a6333a0db7..6df2288d110b5 100644 --- a/src/plugins/saved_objects_management/public/index.ts +++ b/src/plugins/saved_objects_management/public/index.ts @@ -23,7 +23,7 @@ export type { } from './services'; export { SavedObjectsManagementAction } from './services'; export type { ProcessedImportResponse, FailedImport } from './lib'; -export { processImportResponse } from './lib'; +export { processImportResponse, getTagFindReferences, parseQuery } from './lib'; export type { SavedObjectRelation, SavedObjectWithMetadata, diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx b/src/plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx index da71f2fd59854..c04dec48f0c97 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx @@ -57,6 +57,7 @@ import { createVisEmbeddableFromObject } from './create_vis_embeddable_from_obje import type { VisualizationsStartDeps } from '../plugin'; interface VisualizationAttributes extends SavedObjectAttributes { + title: string; visState: string; } diff --git a/src/plugins/visualizations/public/wizard/new_vis_modal.test.tsx b/src/plugins/visualizations/public/wizard/new_vis_modal.test.tsx index a150a94a60516..907c989c7bb43 100644 --- a/src/plugins/visualizations/public/wizard/new_vis_modal.test.tsx +++ b/src/plugins/visualizations/public/wizard/new_vis_modal.test.tsx @@ -12,8 +12,7 @@ import { TypesStart, VisGroups, BaseVisType } from '../vis_types'; import NewVisModal from './new_vis_modal'; import { ApplicationStart, DocLinksStart } from '@kbn/core/public'; import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks'; -import { httpServiceMock } from '@kbn/core-http-browser-mocks'; -import { savedObjectsManagementPluginMock } from '@kbn/saved-objects-management-plugin/public/mocks'; +import { contentManagementMock } from '@kbn/content-management-plugin/public/mocks'; describe('NewVisModal', () => { const defaultVisTypeParams = { @@ -78,8 +77,8 @@ describe('NewVisModal', () => { }, }, }; - const http = httpServiceMock.createStartContract({ basePath: '' }); - const savedObjectsManagement = savedObjectsManagementPluginMock.createStartContract(); + + const contentManagement = contentManagementMock.createStartContract(); beforeAll(() => { Object.defineProperty(window, 'location', { @@ -103,8 +102,7 @@ describe('NewVisModal', () => { uiSettings={uiSettings} application={{} as ApplicationStart} docLinks={docLinks as DocLinksStart} - http={http} - savedObjectsManagement={savedObjectsManagement} + contentClient={contentManagement.client} /> ); expect(wrapper.find('[data-test-subj="visGroup-aggbased"]').exists()).toBe(true); @@ -121,8 +119,7 @@ describe('NewVisModal', () => { uiSettings={uiSettings} application={{} as ApplicationStart} docLinks={docLinks as DocLinksStart} - http={http} - savedObjectsManagement={savedObjectsManagement} + contentClient={contentManagement.client} /> ); expect(wrapper.find('[data-test-subj="visGroup-tools"]').exists()).toBe(true); @@ -138,8 +135,7 @@ describe('NewVisModal', () => { uiSettings={uiSettings} application={{} as ApplicationStart} docLinks={docLinks as DocLinksStart} - http={http} - savedObjectsManagement={savedObjectsManagement} + contentClient={contentManagement.client} /> ); expect(wrapper.find('[data-test-subj="visType-vis2"]').exists()).toBe(true); @@ -156,8 +152,7 @@ describe('NewVisModal', () => { uiSettings={uiSettings} application={{} as ApplicationStart} docLinks={docLinks as DocLinksStart} - http={http} - savedObjectsManagement={savedObjectsManagement} + contentClient={contentManagement.client} /> ); const visCard = wrapper.find('[data-test-subj="visType-vis"]').last(); @@ -176,8 +171,7 @@ describe('NewVisModal', () => { uiSettings={uiSettings} application={{} as ApplicationStart} docLinks={docLinks as DocLinksStart} - http={http} - savedObjectsManagement={savedObjectsManagement} + contentClient={contentManagement.client} /> ); const visCard = wrapper.find('[data-test-subj="visType-vis"]').last(); @@ -203,8 +197,7 @@ describe('NewVisModal', () => { application={{ navigateToApp } as unknown as ApplicationStart} docLinks={docLinks as DocLinksStart} stateTransfer={stateTransfer} - http={http} - savedObjectsManagement={savedObjectsManagement} + contentClient={contentManagement.client} /> ); const visCard = wrapper.find('[data-test-subj="visType-visWithAliasUrl"]').last(); @@ -229,8 +222,7 @@ describe('NewVisModal', () => { uiSettings={uiSettings} application={{ navigateToApp } as unknown as ApplicationStart} docLinks={docLinks as DocLinksStart} - http={http} - savedObjectsManagement={savedObjectsManagement} + contentClient={contentManagement.client} /> ); const visCard = wrapper.find('[data-test-subj="visType-visWithAliasUrl"]').last(); @@ -251,8 +243,7 @@ describe('NewVisModal', () => { uiSettings={uiSettings} application={{} as ApplicationStart} docLinks={docLinks as DocLinksStart} - http={http} - savedObjectsManagement={savedObjectsManagement} + contentClient={contentManagement.client} /> ); const aggBasedGroupCard = wrapper diff --git a/src/plugins/visualizations/public/wizard/new_vis_modal.tsx b/src/plugins/visualizations/public/wizard/new_vis_modal.tsx index 4ff2138169083..ac1f89e73700f 100644 --- a/src/plugins/visualizations/public/wizard/new_vis_modal.tsx +++ b/src/plugins/visualizations/public/wizard/new_vis_modal.tsx @@ -12,9 +12,9 @@ import { EuiModal } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { METRIC_TYPE, UiCounterMetricType } from '@kbn/analytics'; -import { ApplicationStart, IUiSettingsClient, DocLinksStart, HttpStart } from '@kbn/core/public'; +import { ApplicationStart, DocLinksStart, IUiSettingsClient } from '@kbn/core/public'; import { EmbeddableStateTransfer } from '@kbn/embeddable-plugin/public'; -import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; +import { ContentClient } from '@kbn/content-management-plugin/public'; import { SearchSelection } from './search_selection'; import { GroupSelection } from './group_selection'; import { AggBasedSelection } from './agg_based_selection'; @@ -22,6 +22,7 @@ import type { TypesStart, BaseVisType, VisTypeAlias } from '../vis_types'; import './dialog.scss'; interface TypeSelectionProps { + contentClient: ContentClient; isOpen: boolean; onClose: () => void; visTypesRegistry: TypesStart; @@ -29,14 +30,12 @@ interface TypeSelectionProps { addBasePath: (path: string) => string; uiSettings: IUiSettingsClient; docLinks: DocLinksStart; - http: HttpStart; application: ApplicationStart; outsideVisualizeApp?: boolean; stateTransfer?: EmbeddableStateTransfer; originatingApp?: string; showAggsSelection?: boolean; selectedVisType?: BaseVisType; - savedObjectsManagement: SavedObjectsManagementPluginStart; } interface TypeSelectionState { @@ -88,11 +87,10 @@ class NewVisModal extends React.Component this.setState({ showSearchVisModal: false })} /> diff --git a/src/plugins/visualizations/public/wizard/search_selection/search_selection.tsx b/src/plugins/visualizations/public/wizard/search_selection/search_selection.tsx index 341123b780445..374d2c4b8fa39 100644 --- a/src/plugins/visualizations/public/wizard/search_selection/search_selection.tsx +++ b/src/plugins/visualizations/public/wizard/search_selection/search_selection.tsx @@ -10,20 +10,18 @@ import React from 'react'; import { EuiModalBody, EuiModalHeader, EuiModalHeaderTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { IUiSettingsClient, HttpStart } from '@kbn/core/public'; - -import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; +import { ContentClient } from '@kbn/content-management-plugin/public'; import { SavedObjectFinder } from '@kbn/saved-objects-finder-plugin/public'; +import { IUiSettingsClient } from '@kbn/core/public'; import type { BaseVisType } from '../../vis_types'; import { DialogNavigation } from '../dialog_navigation'; import { showSavedObject } from './show_saved_object'; interface SearchSelectionProps { + contentClient: ContentClient; + uiSettings: IUiSettingsClient; onSearchSelected: (searchId: string, searchType: string) => void; visType: BaseVisType; - uiSettings: IUiSettingsClient; - http: HttpStart; - savedObjectsManagement: SavedObjectsManagementPluginStart; goBack: () => void; } @@ -81,14 +79,12 @@ export class SearchSelection extends React.Component { defaultMessage: 'Data view', } ), - defaultSearchField: 'name', }, ]} fixedPageSize={this.fixedPageSize} services={{ + contentClient: this.props.contentClient, uiSettings: this.props.uiSettings, - http: this.props.http, - savedObjectsManagement: this.props.savedObjectsManagement, }} /> diff --git a/src/plugins/visualizations/public/wizard/search_selection/show_saved_object.ts b/src/plugins/visualizations/public/wizard/search_selection/show_saved_object.ts index 02085d5acc2ba..3e61b0363b2bc 100644 --- a/src/plugins/visualizations/public/wizard/search_selection/show_saved_object.ts +++ b/src/plugins/visualizations/public/wizard/search_selection/show_saved_object.ts @@ -8,12 +8,12 @@ import type { SavedObjectCommon, FinderAttributes } from '@kbn/saved-objects-finder-plugin/common'; -export interface SavedSearchesAttributes extends SavedObjectCommon { +export interface SavedSearchesAttributes extends FinderAttributes { isTextBasedQuery: boolean; usesAdHocDataView?: boolean; } -export const showSavedObject = (savedObject: SavedObjectCommon) => { - const so = savedObject as unknown as SavedObjectCommon; +export const showSavedObject = (savedObject: SavedObjectCommon) => { + const so = savedObject as SavedObjectCommon; return !so.attributes.isTextBasedQuery && !so.attributes.usesAdHocDataView; }; diff --git a/src/plugins/visualizations/public/wizard/show_new_vis.tsx b/src/plugins/visualizations/public/wizard/show_new_vis.tsx index 3252a92ae8a4c..b4bfe17b177c4 100644 --- a/src/plugins/visualizations/public/wizard/show_new_vis.tsx +++ b/src/plugins/visualizations/public/wizard/show_new_vis.tsx @@ -14,12 +14,12 @@ import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import { getHttp, getTypes, - getUISettings, getApplication, getEmbeddable, getDocLinks, getTheme, - getSavedObjectsManagement, + getContentManagement, + getUISettings, } from '../services'; import type { BaseVisType } from '../vis_types'; @@ -79,10 +79,9 @@ export function showNewVisModal({ outsideVisualizeApp={outsideVisualizeApp} editorParams={editorParams} visTypesRegistry={getTypes()} - addBasePath={getHttp().basePath.prepend} + contentClient={getContentManagement().client} uiSettings={getUISettings()} - http={getHttp()} - savedObjectsManagement={getSavedObjectsManagement()} + addBasePath={getHttp().basePath.prepend} application={getApplication()} docLinks={getDocLinks()} showAggsSelection={showAggsSelection} diff --git a/src/plugins/visualizations/tsconfig.json b/src/plugins/visualizations/tsconfig.json index 4df8ede52adcb..e4c302c17a43b 100644 --- a/src/plugins/visualizations/tsconfig.json +++ b/src/plugins/visualizations/tsconfig.json @@ -50,7 +50,6 @@ "@kbn/core-overlays-browser", "@kbn/config-schema", "@kbn/usage-collection-plugin", - "@kbn/core-http-browser-mocks", "@kbn/shared-ux-router", "@kbn/saved-objects-management-plugin", "@kbn/saved-objects-finder-plugin", diff --git a/test/examples/content_management/finder.ts b/test/examples/content_management/finder.ts new file mode 100644 index 0000000000000..76c277ef75a1c --- /dev/null +++ b/test/examples/content_management/finder.ts @@ -0,0 +1,63 @@ +/* + * 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 expect from '@kbn/expect'; +import { PluginFunctionalProviderContext } from '../../plugin_functional/services'; + +// eslint-disable-next-line import/no-default-export +export default function ({ getService, getPageObjects }: PluginFunctionalProviderContext) { + const PageObjects = getPageObjects(['common', 'home', 'header']); + const log = getService('log'); + const testSubjects = getService('testSubjects'); + + describe('Finder demo', () => { + before(async () => { + await PageObjects.common.navigateToUrl('home', '/tutorial_directory/sampleData', { + useActualUrl: true, + }); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.home.addSampleDataSet('flights'); + }); + after(async () => { + await PageObjects.common.navigateToUrl('home', '/tutorial_directory/sampleData', { + useActualUrl: true, + }); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.home.removeSampleDataSet('flights'); + }); + + it('Finder demo works', async () => { + const appId = 'contentManagementExamples'; + await PageObjects.common.navigateToApp(appId, { + path: 'finder', + }); + + await testSubjects.existOrFail(`savedObjectsFinderTable`); + await testSubjects.existOrFail(`savedObjectFinderTitle`); + + const titles: string[] = []; + const titlesElements = await testSubjects.findAll(`savedObjectFinderTitle`); + for (let i = 0; i < titlesElements.length; i++) { + titles.push(await (await titlesElements[i].findByClassName(`euiLink`)).getVisibleText()); + } + + const expectExists = [ + `Kibana Sample Data Flights`, + `[Flights] Airport Connections (Hover Over Airport)`, + `[Flights] Departures Count Map`, + `[Flights] Origin Time Delayed`, + `[Flights] Flight Log`, + ]; + + expectExists.forEach((item) => { + log.debug(`Checking for ${item}`); + expect(titles.includes(item)).to.be(true); + }); + }); + }); +} diff --git a/test/examples/content_management/index.ts b/test/examples/content_management/index.ts index c02b022781187..15d71ecd2661e 100644 --- a/test/examples/content_management/index.ts +++ b/test/examples/content_management/index.ts @@ -13,5 +13,6 @@ export default function ({ loadTestFile }: PluginFunctionalProviderContext) { describe('content management examples', function () { loadTestFile(require.resolve('./todo_app')); loadTestFile(require.resolve('./msearch')); + loadTestFile(require.resolve('./finder')); }); } diff --git a/test/examples/content_management/msearch.ts b/test/examples/content_management/msearch.ts index 0a583b455cd04..52bb79dfd95fb 100644 --- a/test/examples/content_management/msearch.ts +++ b/test/examples/content_management/msearch.ts @@ -6,11 +6,11 @@ * Side Public License, v 1. */ +import expect from '@kbn/expect'; import { PluginFunctionalProviderContext } from '../../plugin_functional/services'; // eslint-disable-next-line import/no-default-export export default function ({ getService, getPageObjects }: PluginFunctionalProviderContext) { - const testSubjects = getService('testSubjects'); const PageObjects = getPageObjects(['common', 'home', 'header']); const listingTable = getService('listingTable'); @@ -37,11 +37,19 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide }); await listingTable.waitUntilTableIsLoaded(); - await listingTable.searchForItemWithName('Origin Time Delayed'); + const items = await listingTable.getAllItemsNames(); + const expectExists = [ + `kibana_sample_data_flights`, + `[Flights] Airport Connections (Hover Over Airport)`, + `[Flights] Departures Count Map`, + `[Flights] Global Flight Dashboard`, + `[Flights] Origin Time Delayed`, + `[Flights] Flight Log`, + ]; - await testSubjects.existOrFail( - `cm-msearch-tableListingTitleLink-[Flights]-Origin-Time-Delayed` - ); + expectExists.forEach((item) => { + expect(items.includes(item)).to.be(true); + }); }); }); } diff --git a/x-pack/plugins/canvas/kibana.jsonc b/x-pack/plugins/canvas/kibana.jsonc index 05d86386d341f..7e4d0fcff071d 100644 --- a/x-pack/plugins/canvas/kibana.jsonc +++ b/x-pack/plugins/canvas/kibana.jsonc @@ -30,7 +30,7 @@ "visualizations", "uiActions", "share", - "savedObjectsManagement", + "contentManagement", "savedObjectsFinder" ], "optionalPlugins": [ diff --git a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx index d9c665646e2b4..d93a9fb49d359 100644 --- a/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx +++ b/x-pack/plugins/canvas/public/components/embeddable_flyout/flyout.component.tsx @@ -38,7 +38,7 @@ export const AddEmbeddableFlyout: FC = ({ const embeddablesService = useEmbeddablesService(); const platformService = usePlatformService(); const { getEmbeddableFactories } = embeddablesService; - const { getHttp, getUISettings, getSavedObjectsManagement } = platformService; + const { getContentManagement, getUISettings } = platformService; const onAddPanel = useCallback( (id: string, savedObjectType: string) => { @@ -83,9 +83,8 @@ export const AddEmbeddableFlyout: FC = ({ showFilter={true} noItemsMessage={strings.getNoItemsText()} services={{ + contentClient: getContentManagement().client, uiSettings: getUISettings(), - http: getHttp(), - savedObjectsManagement: getSavedObjectsManagement(), }} /> diff --git a/x-pack/plugins/canvas/public/plugin.tsx b/x-pack/plugins/canvas/public/plugin.tsx index 20dee0bf5fa75..1fec67549eb5a 100644 --- a/x-pack/plugins/canvas/public/plugin.tsx +++ b/x-pack/plugins/canvas/public/plugin.tsx @@ -30,7 +30,7 @@ import { Start as InspectorStart } from '@kbn/inspector-plugin/public'; import { BfetchPublicSetup } from '@kbn/bfetch-plugin/public'; import { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/public'; import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; -import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; +import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import { featureCatalogueEntry } from './feature_catalogue_entry'; import { CanvasAppLocatorDefinition } from '../common/locator'; import { SESSIONSTORAGE_LASTPATH, CANVAS_APP } from '../common/lib/constants'; @@ -68,7 +68,7 @@ export interface CanvasStartDeps { presentationUtil: PresentationUtilPluginStart; visualizations: VisualizationsStart; spaces?: SpacesPluginStart; - savedObjectsManagement: SavedObjectsManagementPluginStart; + contentManagement: ContentManagementPublicStart; } /** diff --git a/x-pack/plugins/canvas/public/services/kibana/platform.ts b/x-pack/plugins/canvas/public/services/kibana/platform.ts index f88851a5e3bd0..1518280ab0688 100644 --- a/x-pack/plugins/canvas/public/services/kibana/platform.ts +++ b/x-pack/plugins/canvas/public/services/kibana/platform.ts @@ -41,6 +41,6 @@ export const platformServiceFactory: CanvaPlatformServiceFactory = ({ getLegacyUrlConflict: startPlugins.spaces?.ui.components.getLegacyUrlConflict, getUISettings: () => coreStart.uiSettings, getHttp: () => coreStart.http, - getSavedObjectsManagement: () => startPlugins.savedObjectsManagement, + getContentManagement: () => startPlugins.contentManagement, }; }; diff --git a/x-pack/plugins/canvas/public/services/platform.ts b/x-pack/plugins/canvas/public/services/platform.ts index 4eeaa8da8f1dc..555f8643fff9b 100644 --- a/x-pack/plugins/canvas/public/services/platform.ts +++ b/x-pack/plugins/canvas/public/services/platform.ts @@ -15,7 +15,7 @@ import { } from '@kbn/core/public'; import { SpacesPluginStart } from '@kbn/spaces-plugin/public'; -import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; +import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; export interface CanvasPlatformService { getBasePath: () => string; @@ -33,5 +33,5 @@ export interface CanvasPlatformService { getLegacyUrlConflict?: SpacesPluginStart['ui']['components']['getLegacyUrlConflict']; getUISettings: () => IUiSettingsClient; getHttp: () => HttpStart; - getSavedObjectsManagement: () => SavedObjectsManagementPluginStart; + getContentManagement: () => ContentManagementPublicStart; } diff --git a/x-pack/plugins/canvas/public/services/stubs/platform.ts b/x-pack/plugins/canvas/public/services/stubs/platform.ts index 3e40352f9ef59..0726810075251 100644 --- a/x-pack/plugins/canvas/public/services/stubs/platform.ts +++ b/x-pack/plugins/canvas/public/services/stubs/platform.ts @@ -35,5 +35,5 @@ export const platformServiceFactory: CanvasPlatformServiceFactory = () => ({ redirectLegacyUrl: noop, getLegacyUrlConflict: undefined, getHttp: noop, - getSavedObjectsManagement: noop, + getContentManagement: noop, }); diff --git a/x-pack/plugins/canvas/tsconfig.json b/x-pack/plugins/canvas/tsconfig.json index c921bde079b5e..04d1e78fc9555 100644 --- a/x-pack/plugins/canvas/tsconfig.json +++ b/x-pack/plugins/canvas/tsconfig.json @@ -79,9 +79,9 @@ "@kbn/babel-register", "@kbn/shared-ux-button-toolbar", "@kbn/saved-objects-finder-plugin", - "@kbn/saved-objects-management-plugin", "@kbn/core-saved-objects-server", "@kbn/discover-utils", + "@kbn/content-management-plugin", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/cases/kibana.jsonc b/x-pack/plugins/cases/kibana.jsonc index b0a03ad753e97..6b7cc4450985a 100644 --- a/x-pack/plugins/cases/kibana.jsonc +++ b/x-pack/plugins/cases/kibana.jsonc @@ -28,7 +28,7 @@ "ruleRegistry", "files", "savedObjectsFinder", - "savedObjectsManagement", + "contentManagement", "uiActions", ], "optionalPlugins": [ diff --git a/x-pack/plugins/cases/public/components/markdown_editor/plugins/lens/plugin.tsx b/x-pack/plugins/cases/public/components/markdown_editor/plugins/lens/plugin.tsx index 996d3d757186d..14d669c09c2fb 100644 --- a/x-pack/plugins/cases/public/components/markdown_editor/plugins/lens/plugin.tsx +++ b/x-pack/plugins/cases/public/components/markdown_editor/plugins/lens/plugin.tsx @@ -71,9 +71,8 @@ const LensEditorComponent: LensEuiMarkdownEditorUiPlugin['editor'] = ({ embeddable, lens, storage, - http, + contentManagement, uiSettings, - savedObjectsManagement, data: { query: { timefilter: { timefilter }, @@ -331,9 +330,8 @@ const LensEditorComponent: LensEuiMarkdownEditorUiPlugin['editor'] = ({ savedObjectMetaData={savedObjectMetaData} fixedPageSize={10} services={{ + contentClient: contentManagement.client, uiSettings, - http, - savedObjectsManagement, }} leftChildren={createLensButton} helpText={i18n.translate( diff --git a/x-pack/plugins/cases/public/types.ts b/x-pack/plugins/cases/public/types.ts index c9c74a48989a8..ee00fc034c1d6 100644 --- a/x-pack/plugins/cases/public/types.ts +++ b/x-pack/plugins/cases/public/types.ts @@ -23,7 +23,7 @@ import type { DistributiveOmit } from '@elastic/eui'; import type { ApmBase } from '@elastic/apm-rum'; import type { LicensingPluginStart } from '@kbn/licensing-plugin/public'; import type { FilesSetup, FilesStart } from '@kbn/files-plugin/public'; -import type { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; +import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; import type { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/public'; @@ -74,7 +74,7 @@ export interface CasesPluginStart { files: FilesStart; lens: LensPublicStart; licensing?: LicensingPluginStart; - savedObjectsManagement: SavedObjectsManagementPluginStart; + contentManagement: ContentManagementPublicStart; security: SecurityPluginStart; serverless?: ServerlessPluginStart; spaces?: SpacesPluginStart; diff --git a/x-pack/plugins/cases/tsconfig.json b/x-pack/plugins/cases/tsconfig.json index 059e132582d00..cb82b27d5334d 100644 --- a/x-pack/plugins/cases/tsconfig.json +++ b/x-pack/plugins/cases/tsconfig.json @@ -61,7 +61,6 @@ "@kbn/shared-ux-file-upload", "@kbn/shared-ux-file-mocks", "@kbn/saved-objects-finder-plugin", - "@kbn/saved-objects-management-plugin", "@kbn/utility-types-jest", "@kbn/ui-actions-plugin", "@kbn/core-lifecycle-browser", @@ -69,6 +68,7 @@ "@kbn/core-theme-browser", "@kbn/serverless", "@kbn/core-http-server", + "@kbn/content-management-plugin", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/graph/public/application.tsx b/x-pack/plugins/graph/public/application.tsx index 71ff604e1f476..89ba72b203413 100644 --- a/x-pack/plugins/graph/public/application.tsx +++ b/x-pack/plugins/graph/public/application.tsx @@ -33,7 +33,7 @@ import './index.scss'; import { SpacesApi } from '@kbn/spaces-plugin/public'; import { KibanaThemeProvider, toMountPoint } from '@kbn/kibana-react-plugin/public'; import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; -import { ContentClient } from '@kbn/content-management-plugin/public'; +import { ContentClient, ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import { GraphSavePolicy } from './types'; import { graphRouter } from './router'; import { checkLicense } from '../common/check_license'; @@ -71,6 +71,7 @@ export interface GraphDependencies { spaces?: SpacesApi; inspect: InspectorPublicPluginStart; savedObjectsManagement: SavedObjectsManagementPluginStart; + contentManagement: ContentManagementPublicStart; } export type GraphServices = Omit; diff --git a/x-pack/plugins/graph/public/apps/workspace_route.tsx b/x-pack/plugins/graph/public/apps/workspace_route.tsx index b8ca873a1aa33..192ab8daf065a 100644 --- a/x-pack/plugins/graph/public/apps/workspace_route.tsx +++ b/x-pack/plugins/graph/public/apps/workspace_route.tsx @@ -44,6 +44,7 @@ export const WorkspaceRoute = ({ indexPatterns: getIndexPatternProvider, inspect, savedObjectsManagement, + contentManagement, }, }: WorkspaceRouteProps) => { /** @@ -72,9 +73,10 @@ export const WorkspaceRoute = ({ data, unifiedSearch, savedObjectsManagement, + contentManagement, ...coreStart, }), - [coreStart, data, storage, unifiedSearch, savedObjectsManagement] + [coreStart, data, storage, unifiedSearch, savedObjectsManagement, contentManagement] ); const { loading, requestAdapter, callNodeProxy, callSearchNodeProxy, handleSearchQueryError } = diff --git a/x-pack/plugins/graph/public/components/guidance_panel/guidance_panel.tsx b/x-pack/plugins/graph/public/components/guidance_panel/guidance_panel.tsx index 6b6c06dbc02ba..898ca390499fb 100644 --- a/x-pack/plugins/graph/public/components/guidance_panel/guidance_panel.tsx +++ b/x-pack/plugins/graph/public/components/guidance_panel/guidance_panel.tsx @@ -22,6 +22,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { connect } from 'react-redux'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { IUnifiedSearchPluginServices } from '@kbn/unified-search-plugin/public/types'; +import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import { GraphState, hasDatasourceSelector, @@ -75,9 +76,11 @@ function GuidancePanelComponent(props: GuidancePanelProps) { const { onFillWorkspace, onOpenFieldPicker, onIndexPatternSelected, hasDatasource, hasFields } = props; - const kibana = useKibana(); + const kibana = useKibana< + IUnifiedSearchPluginServices & { contentManagement: ContentManagementPublicStart } + >(); const { services, overlays } = kibana; - const { http, uiSettings, application, data, savedObjectsManagement } = services; + const { application, data, contentManagement, uiSettings } = services; const [hasDataViews, setHasDataViews] = useState(true); useEffect(() => { @@ -90,7 +93,7 @@ function GuidancePanelComponent(props: GuidancePanelProps) { if (!overlays || !application) return null; const onOpenDatasourcePicker = () => { - openSourceModal({ overlays, http, uiSettings, savedObjectsManagement }, onIndexPatternSelected); + openSourceModal({ overlays, contentManagement, uiSettings }, onIndexPatternSelected); }; let content = ( diff --git a/x-pack/plugins/graph/public/components/search_bar.tsx b/x-pack/plugins/graph/public/components/search_bar.tsx index 5bf23c1705dec..101a2b3170f0b 100644 --- a/x-pack/plugins/graph/public/components/search_bar.tsx +++ b/x-pack/plugins/graph/public/components/search_bar.tsx @@ -15,6 +15,7 @@ import { useKibana } from '@kbn/kibana-react-plugin/public'; import { QueryStringInput } from '@kbn/unified-search-plugin/public'; import type { DataView } from '@kbn/data-views-plugin/public'; import { IUnifiedSearchPluginServices } from '@kbn/unified-search-plugin/public/types'; +import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import { IndexPatternSavedObject, IndexPatternProvider, WorkspaceField } from '../types'; import { openSourceModal } from '../services/source_modal'; import { @@ -95,7 +96,9 @@ export function SearchBarComponent(props: SearchBarStateProps & SearchBarProps) fetchPattern(); }, [currentDatasource, indexPatternProvider, onIndexPatternChange]); - const kibana = useKibana(); + const kibana = useKibana< + IUnifiedSearchPluginServices & { contentManagement: ContentManagementPublicStart } + >(); const { services, overlays } = kibana; const { uiSettings, @@ -107,7 +110,7 @@ export function SearchBarComponent(props: SearchBarStateProps & SearchBarProps) notifications, http, docLinks, - savedObjectsManagement, + contentManagement, } = services; if (!overlays) return null; return ( @@ -133,7 +136,7 @@ export function SearchBarComponent(props: SearchBarStateProps & SearchBarProps) confirmWipeWorkspace( () => openSourceModal( - { overlays, http, uiSettings, savedObjectsManagement }, + { overlays, contentManagement, uiSettings }, onIndexPatternSelected ), i18n.translate('xpack.graph.clearWorkspace.confirmText', { diff --git a/x-pack/plugins/graph/public/components/source_picker.tsx b/x-pack/plugins/graph/public/components/source_picker.tsx index ec227fdddc5bd..1c63c359ef938 100644 --- a/x-pack/plugins/graph/public/components/source_picker.tsx +++ b/x-pack/plugins/graph/public/components/source_picker.tsx @@ -8,29 +8,28 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; -import { CoreStart } from '@kbn/core/public'; import { SavedObjectFinder } from '@kbn/saved-objects-finder-plugin/public'; -import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; +import { SavedObjectCommon } from '@kbn/saved-objects-finder-plugin/common'; +import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; +import { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; import { IndexPatternSavedObject } from '../types'; export interface SourcePickerProps { onIndexPatternSelected: (indexPattern: IndexPatternSavedObject) => void; - http: CoreStart['http']; - uiSettings: CoreStart['uiSettings']; - savedObjectsManagement: SavedObjectsManagementPluginStart; + contentManagement: ContentManagementPublicStart; + uiSettings: IUiSettingsClient; } const fixedPageSize = 8; export function SourcePicker({ - http, - uiSettings, - savedObjectsManagement, + contentManagement, onIndexPatternSelected, + uiSettings, }: SourcePickerProps) { return ( { onIndexPatternSelected(indexPattern as IndexPatternSavedObject); }} @@ -45,9 +44,9 @@ export function SourcePicker({ name: i18n.translate('xpack.graph.sourceModal.savedObjectType.dataView', { defaultMessage: 'Data view', }), - showSavedObject: (indexPattern) => !indexPattern.attributes.type, + showSavedObject: (indexPattern: SavedObjectCommon<{ type?: string; title: string }>) => + !indexPattern.attributes.type, includeFields: ['type'], - defaultSearchField: 'name', }, ]} fixedPageSize={fixedPageSize} diff --git a/x-pack/plugins/graph/public/plugin.ts b/x-pack/plugins/graph/public/plugin.ts index 73e040dc4e760..3fc9b72873297 100644 --- a/x-pack/plugins/graph/public/plugin.ts +++ b/x-pack/plugins/graph/public/plugin.ts @@ -132,6 +132,7 @@ export class GraphPlugin spaces: pluginsStart.spaces, inspect: pluginsStart.inspector, savedObjectsManagement: pluginsStart.savedObjectsManagement, + contentManagement: pluginsStart.contentManagement, }); }, }); diff --git a/x-pack/plugins/graph/public/services/source_modal.tsx b/x-pack/plugins/graph/public/services/source_modal.tsx index 6da003833d1a9..791471b8a2470 100644 --- a/x-pack/plugins/graph/public/services/source_modal.tsx +++ b/x-pack/plugins/graph/public/services/source_modal.tsx @@ -5,32 +5,29 @@ * 2.0. */ -import { CoreStart } from '@kbn/core/public'; import React from 'react'; import { KibanaReactOverlays } from '@kbn/kibana-react-plugin/public'; -import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; +import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; +import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; import { SourceModal } from '../components/source_modal'; import { IndexPatternSavedObject } from '../types'; export function openSourceModal( { overlays, - http, + contentManagement, uiSettings, - savedObjectsManagement, }: { overlays: KibanaReactOverlays; - http: CoreStart['http']; - uiSettings: CoreStart['uiSettings']; - savedObjectsManagement: SavedObjectsManagementPluginStart; + contentManagement: ContentManagementPublicStart; + uiSettings: IUiSettingsClient; }, onSelected: (indexPattern: IndexPatternSavedObject) => void ) { const modalRef = overlays.openModal( { onSelected(indexPattern); modalRef.close(); diff --git a/x-pack/plugins/graph/tsconfig.json b/x-pack/plugins/graph/tsconfig.json index 4ee1639a2d4f8..f4dc6a3faaf73 100644 --- a/x-pack/plugins/graph/tsconfig.json +++ b/x-pack/plugins/graph/tsconfig.json @@ -45,6 +45,7 @@ "@kbn/object-versioning", "@kbn/content-management-table-list-view-table", "@kbn/content-management-table-list-view", + "@kbn/core-ui-settings-browser", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/ml/kibana.jsonc b/x-pack/plugins/ml/kibana.jsonc index 04ab462b564cd..c5d755a248a67 100644 --- a/x-pack/plugins/ml/kibana.jsonc +++ b/x-pack/plugins/ml/kibana.jsonc @@ -7,10 +7,7 @@ "id": "ml", "server": true, "browser": true, - "configPath": [ - "xpack", - "ml" - ], + "configPath": ["xpack", "ml"], "requiredPlugins": [ "aiops", "charts", @@ -30,7 +27,8 @@ "uiActions", "unifiedSearch", "savedObjectsManagement", - "savedSearch" + "savedSearch", + "contentManagement" ], "optionalPlugins": [ "alerting", @@ -58,8 +56,6 @@ "usageCollection", "unifiedSearch" ], - "extraPublicDirs": [ - "common" - ] + "extraPublicDirs": ["common"] } } diff --git a/x-pack/plugins/ml/public/application/app.tsx b/x-pack/plugins/ml/public/application/app.tsx index 559ec601da4d7..b4bb4526af910 100644 --- a/x-pack/plugins/ml/public/application/app.tsx +++ b/x-pack/plugins/ml/public/application/app.tsx @@ -101,6 +101,7 @@ const App: FC = ({ coreStart, deps, appMountParams }) => { lens: deps.lens, savedObjectsManagement: deps.savedObjectsManagement, savedSearch: deps.savedSearch, + contentManagement: deps.contentManagement, ...coreStart, mlServices: getMlGlobalServices(coreStart.http, deps.usageCollection), }; diff --git a/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts b/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts index 8ed1f396c51d3..af6c79710be08 100644 --- a/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts +++ b/x-pack/plugins/ml/public/application/contexts/kibana/kibana_context.ts @@ -26,6 +26,7 @@ import type { CasesUiStart } from '@kbn/cases-plugin/public'; import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; import type { LensPublicStart } from '@kbn/lens-plugin/public'; import type { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; +import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import type { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public'; import type { MlServicesContext } from '../../app'; @@ -51,6 +52,7 @@ interface StartPlugins { lens: LensPublicStart; savedObjectsManagement: SavedObjectsManagementPluginStart; savedSearch: SavedSearchPublicPluginStart; + contentManagement: ContentManagementPublicStart; } export type StartServices = CoreStart & StartPlugins & { diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.test.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.test.tsx index d3e4734f633b3..c17490f4506d9 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.test.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.test.tsx @@ -79,6 +79,7 @@ jest.mock('../../../../../contexts/kibana', () => ({ savedObjectsManagement: {}, data: { dataViews: jest.fn() }, savedSearch: jest.fn(), + contentManagement: {}, }, }), useNavigateToPath: () => mockNavigateToPath, diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx index 7ca404b036c29..d4987b17aeb59 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx @@ -31,11 +31,10 @@ const fixedPageSize: number = 20; export const SourceSelection: FC = () => { const { services: { - http, - uiSettings, - savedObjectsManagement, savedSearch: savedSearchService, data: { dataViews: dataViewsService }, + contentManagement, + uiSettings, }, } = useMlKibana(); const navigateToPath = useNavigateToPath(); @@ -159,14 +158,12 @@ export const SourceSelection: FC = () => { defaultMessage: 'Data view', } ), - defaultSearchField: 'name', }, ]} fixedPageSize={fixedPageSize} services={{ + contentClient: contentManagement.client, uiSettings, - http, - savedObjectsManagement, }} /> diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/datafeed_step/components/data_view/change_data_view.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/datafeed_step/components/data_view/change_data_view.tsx index 9e68d9f6f8c37..1e30004453616 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/datafeed_step/components/data_view/change_data_view.tsx +++ b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/datafeed_step/components/data_view/change_data_view.tsx @@ -55,10 +55,9 @@ interface Props { export const ChangeDataViewModal: FC = ({ onClose }) => { const { services: { - http, - uiSettings, data: { dataViews }, - savedObjectsManagement, + contentManagement, + uiSettings, }, } = useMlKibana(); const navigateToPath = useNavigateToPath(); @@ -168,15 +167,10 @@ export const ChangeDataViewModal: FC = ({ onClose }) => { defaultMessage: 'Data view', } ), - defaultSearchField: 'name', }, ]} fixedPageSize={fixedPageSize} - services={{ - uiSettings, - http, - savedObjectsManagement, - }} + services={{ contentClient: contentManagement.client, uiSettings }} /> )} diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx index 9d2cfa605f50b..d29654f8e9f8d 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx +++ b/x-pack/plugins/ml/public/application/jobs/new_job/pages/index_or_search/page.tsx @@ -19,7 +19,7 @@ export interface PageProps { export const Page: FC = ({ nextStepPath }) => { const RESULTS_PER_PAGE = 20; - const { uiSettings, http, savedObjectsManagement } = useMlKibana().services; + const { contentManagement, uiSettings } = useMlKibana().services; const navigateToPath = useNavigateToPath(); const onObjectSelection = (id: string, type: string) => { @@ -67,14 +67,12 @@ export const Page: FC = ({ nextStepPath }) => { defaultMessage: 'Data view', } ), - defaultSearchField: 'name', }, ]} fixedPageSize={RESULTS_PER_PAGE} services={{ + contentClient: contentManagement.client, uiSettings, - http, - savedObjectsManagement, }} /> diff --git a/x-pack/plugins/ml/public/plugin.ts b/x-pack/plugins/ml/public/plugin.ts index f9f3b6d22b0fc..f6b44e0226290 100644 --- a/x-pack/plugins/ml/public/plugin.ts +++ b/x-pack/plugins/ml/public/plugin.ts @@ -32,6 +32,7 @@ import type { LicenseManagementUIPluginSetup } from '@kbn/license-management-plu import type { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing-plugin/public'; import type { SecurityPluginStart } from '@kbn/security-plugin/public'; import type { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; +import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import type { MapsStartApi, MapsSetupApi } from '@kbn/maps-plugin/public'; import { @@ -73,6 +74,7 @@ export interface MlStartDependencies { security: SecurityPluginStart; savedObjectsManagement: SavedObjectsManagementPluginStart; savedSearch: SavedSearchPublicPluginStart; + contentManagement: ContentManagementPublicStart; } export interface MlSetupDependencies { @@ -142,6 +144,7 @@ export class MlPlugin implements Plugin { cases: pluginsStart.cases, savedObjectsManagement: pluginsStart.savedObjectsManagement, savedSearch: pluginsStart.savedSearch, + contentManagement: pluginsStart.contentManagement, }, params ); diff --git a/x-pack/plugins/ml/tsconfig.json b/x-pack/plugins/ml/tsconfig.json index 13560d5e0b962..db962727e67d4 100644 --- a/x-pack/plugins/ml/tsconfig.json +++ b/x-pack/plugins/ml/tsconfig.json @@ -100,6 +100,7 @@ "@kbn/core-notifications-browser-mocks", "@kbn/unified-field-list", "@kbn/core-ui-settings-browser", + "@kbn/content-management-plugin", "@kbn/ml-in-memory-table", ], } diff --git a/x-pack/plugins/transform/kibana.jsonc b/x-pack/plugins/transform/kibana.jsonc index 9927374ff1ade..4baea3243370a 100644 --- a/x-pack/plugins/transform/kibana.jsonc +++ b/x-pack/plugins/transform/kibana.jsonc @@ -25,7 +25,8 @@ "unifiedSearch", "charts", "savedObjectsFinder", - "savedObjectsManagement" + "savedObjectsManagement", + "contentManagement", ], "optionalPlugins": [ "security", diff --git a/x-pack/plugins/transform/public/app/__mocks__/app_dependencies.tsx b/x-pack/plugins/transform/public/app/__mocks__/app_dependencies.tsx index da8fc9ede7344..0e2dd130fa94f 100644 --- a/x-pack/plugins/transform/public/app/__mocks__/app_dependencies.tsx +++ b/x-pack/plugins/transform/public/app/__mocks__/app_dependencies.tsx @@ -25,6 +25,7 @@ import type { Storage } from '@kbn/kibana-utils-plugin/public'; import type { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public'; import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; import { savedSearchPluginMock } from '@kbn/saved-search-plugin/public/mocks'; +import { contentManagementMock } from '@kbn/content-management-plugin/public/mocks'; import type { AppDependencies } from '../app_dependencies'; import { MlSharedContext } from './shared_context'; @@ -96,6 +97,7 @@ const appDependencies: AppDependencies = { savedObjectsManagement: {} as jest.Mocked, settings: settingsServiceMock.createStartContract(), savedSearch: savedSearchPluginMock.createStartContract(), + contentManagement: contentManagementMock.createStartContract(), }; export const useAppDependencies = () => { diff --git a/x-pack/plugins/transform/public/app/app_dependencies.tsx b/x-pack/plugins/transform/public/app/app_dependencies.tsx index d637fc706eb44..93d74ca706d43 100644 --- a/x-pack/plugins/transform/public/app/app_dependencies.tsx +++ b/x-pack/plugins/transform/public/app/app_dependencies.tsx @@ -26,6 +26,7 @@ import type { SharePluginStart } from '@kbn/share-plugin/public'; import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; import type { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public'; +import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import type { Storage } from '@kbn/kibana-utils-plugin/public'; @@ -66,6 +67,7 @@ export interface AppDependencies { usageCollection?: UsageCollectionStart; savedObjectsManagement: SavedObjectsManagementPluginStart; settings: SettingsStart; + contentManagement: ContentManagementPublicStart; } export const useAppDependencies = () => { diff --git a/x-pack/plugins/transform/public/app/mount_management_section.ts b/x-pack/plugins/transform/public/app/mount_management_section.ts index f2b5663154e79..cb4032455adf2 100644 --- a/x-pack/plugins/transform/public/app/mount_management_section.ts +++ b/x-pack/plugins/transform/public/app/mount_management_section.ts @@ -52,6 +52,7 @@ export async function mountManagementSection( fieldFormats, savedObjectsManagement, savedSearch, + contentManagement, } = plugins; const { docTitle } = chrome; @@ -88,6 +89,7 @@ export async function mountManagementSection( fieldFormats, savedObjectsManagement, savedSearch, + contentManagement, }; const unmountAppCallback = renderApp(element, appDependencies); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx index 107f4c20fb4f1..5647060ee7a72 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx @@ -19,7 +19,7 @@ interface SearchSelectionProps { const fixedPageSize: number = 8; export const SearchSelection: FC = ({ onSearchSelected }) => { - const { uiSettings, http, savedObjectsManagement } = useAppDependencies(); + const { contentManagement, uiSettings } = useAppDependencies(); return ( <> @@ -67,15 +67,10 @@ export const SearchSelection: FC = ({ onSearchSelected }) defaultMessage: 'Data view', } ), - defaultSearchField: 'name', }, ]} fixedPageSize={fixedPageSize} - services={{ - uiSettings, - http, - savedObjectsManagement, - }} + services={{ contentClient: contentManagement.client, uiSettings }} /> diff --git a/x-pack/plugins/transform/public/plugin.ts b/x-pack/plugins/transform/public/plugin.ts index 2d5753e2460d6..789d76901aeaa 100644 --- a/x-pack/plugins/transform/public/plugin.ts +++ b/x-pack/plugins/transform/public/plugin.ts @@ -21,6 +21,7 @@ import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/ import { ChartsPluginStart } from '@kbn/charts-plugin/public'; import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public/plugin'; +import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public'; import { registerFeature } from './register_feature'; import { getTransformHealthRuleType } from './alerting'; @@ -40,6 +41,7 @@ export interface PluginsDependencies { triggersActionsUi: TriggersAndActionsUIPublicPluginStart; fieldFormats: FieldFormatsStart; savedObjectsManagement: SavedObjectsManagementPluginStart; + contentManagement: ContentManagementPublicStart; } export class TransformUiPlugin { diff --git a/x-pack/plugins/transform/tsconfig.json b/x-pack/plugins/transform/tsconfig.json index 2be11c9b9d48f..9c9ef2299c60d 100644 --- a/x-pack/plugins/transform/tsconfig.json +++ b/x-pack/plugins/transform/tsconfig.json @@ -66,7 +66,8 @@ "@kbn/ml-date-utils", "@kbn/saved-search-plugin", "@kbn/unified-field-list", - "@kbn/ebt-tools" + "@kbn/ebt-tools", + "@kbn/content-management-plugin" ], "exclude": [ "target/**/*",