Skip to content

Commit

Permalink
Make SavedObjectFinder backward compatible (#162904)
Browse files Browse the repository at this point in the history
## Summary

close #161545
close #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
#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
  • Loading branch information
Dosant authored Aug 8, 2023
1 parent 863ea15 commit 304cb25
Show file tree
Hide file tree
Showing 98 changed files with 636 additions and 938 deletions.
3 changes: 2 additions & 1 deletion examples/content_management_examples/kibana.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"developerExamples",
"kibanaReact",
"savedObjectsTaggingOss"
]
],
"requiredBundles": ["savedObjectsFinder"]
}
}
Original file line number Diff line number Diff line change
@@ -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 (
<ContentClientProvider contentClient={props.contentClient}>
<I18nProvider>
<SavedObjectFinder
showFilter={true}
services={{
savedObjectsTagging: props.savedObjectsTagging.getTaggingApi(),
contentClient: props.contentClient,
uiSettings: props.core.uiSettings,
}}
onChoose={(...args) => {
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',
},
]}
/>
</I18nProvider>
</ContentClientProvider>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,4 @@
* Side Public License, v 1.
*/

export const registerRoutesMock = jest.fn();
jest.doMock('./routes', () => ({
registerRoutes: registerRoutesMock,
}));
export { FinderApp } from './finder_app';
14 changes: 14 additions & 0 deletions examples/content_management_examples/public/examples/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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',
},
],
},
]}
Expand All @@ -64,6 +71,13 @@ export const renderApp = (
savedObjectsTagging={savedObjectsTaggingOss}
/>
</Route>
<Route path="/finder">
<FinderApp
contentClient={contentManagement.client}
core={core}
savedObjectsTagging={savedObjectsTaggingOss}
/>
</Route>
</Routes>
</EuiPageTemplate.Section>
</EuiPageTemplate>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,20 @@ export const MSearchTable = () => {
const { hits, pagination } = await contentClient.mSearch<UserContentCommonSchema>({
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))
Expand Down
1 change: 1 addition & 0 deletions examples/content_management_examples/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ export interface SOContentStorageConstrutorParams<Types extends CMCrudTypes> {
updateArgsToSoUpdateOptions?: UpdateArgsToSoUpdateOptions<Types>;
searchArgsToSOFindOptions?: SearchArgsToSOFindOptions<Types>;
enableMSearch?: boolean;
mSearchAdditionalSearchFields?: string[];
}

export abstract class SOContentStorage<Types extends CMCrudTypes>
Expand All @@ -153,6 +154,7 @@ export abstract class SOContentStorage<Types extends CMCrudTypes>
searchArgsToSOFindOptions,
enableMSearch,
allowedSavedObjectAttributes,
mSearchAdditionalSearchFields,
}: SOContentStorageConstrutorParams<Types>) {
this.savedObjectType = savedObjectType;
this.cmServicesDefinition = cmServicesDefinition;
Expand All @@ -166,6 +168,7 @@ export abstract class SOContentStorage<Types extends CMCrudTypes>
if (enableMSearch) {
this.mSearch = {
savedObjectType: this.savedObjectType,
additionalSearchFields: mSearchAdditionalSearchFields,
toItemResult: (ctx: StorageContext, savedObject: SavedObjectsFindResult): Types['Item'] => {
const transforms = ctx.utils.getTransforms(this.cmServicesDefinition);

Expand Down Expand Up @@ -201,6 +204,7 @@ export abstract class SOContentStorage<Types extends CMCrudTypes>
mSearch?: {
savedObjectType: string;
toItemResult: (ctx: StorageContext, savedObject: SavedObjectsFindResult) => Types['Item'];
additionalSearchFields?: string[];
};

async get(ctx: StorageContext, id: string): Promise<Types['GetOut']> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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<boolean>;
onChoose: (value: {
id: string;
type: string;
fullName: string;
savedObject: SavedObjectCommon<unknown>;
savedObject: SavedObjectCommon;
}) => void;
onCreateNew: () => void;
}) => {
Expand Down Expand Up @@ -115,9 +112,8 @@ export const EventAnnotationGroupSavedObjectFinder = ({
}
savedObjectMetaData={savedObjectMetaData}
services={{
contentClient,
uiSettings,
http,
savedObjectsManagement,
}}
/>
);
Expand Down
3 changes: 1 addition & 2 deletions packages/kbn-event-annotation-components/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
]
}
2 changes: 1 addition & 1 deletion packages/kbn-event-annotation-components/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export interface EventAnnotationServiceType {
id: string;
type: string;
fullName: string;
savedObject: SavedObjectCommon<unknown>;
savedObject: SavedObjectCommon;
}) => void;
onCreateNew: () => void;
}) => JSX.Element;
Expand Down
1 change: 1 addition & 0 deletions src/plugins/content_management/public/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
9 changes: 3 additions & 6 deletions src/plugins/dashboard/public/dashboard_actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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<ContentManagementPublicStart>;

export const contentManagementServiceFactory: ContentManagementServiceFactory = () => {
return contentManagementMock.createStartContract();
};
Original file line number Diff line number Diff line change
@@ -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;
};
2 changes: 2 additions & 0 deletions src/plugins/dashboard/public/services/plugin_services.stub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<DashboardServices> = {
dashboardContentManagement: new PluginServiceProvider(dashboardContentManagementServiceFactory),
Expand Down Expand Up @@ -68,6 +69,7 @@ export const providers: PluginServiceProviders<DashboardServices> = {
visualizations: new PluginServiceProvider(visualizationsServiceFactory),
customBranding: new PluginServiceProvider(customBrandingServiceFactory),
savedObjectsManagement: new PluginServiceProvider(savedObjectsManagementServiceFactory),
contentManagement: new PluginServiceProvider(contentManagementServiceFactory),
};

export const registry = new PluginServiceRegistry<DashboardServices>(providers);
2 changes: 2 additions & 0 deletions src/plugins/dashboard/public/services/plugin_services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<DashboardServices, DashboardPluginServiceParams> = {
dashboardContentManagement: new PluginServiceProvider(dashboardContentManagementServiceFactory, [
Expand Down Expand Up @@ -82,6 +83,7 @@ const providers: PluginServiceProviders<DashboardServices, DashboardPluginServic
visualizations: new PluginServiceProvider(visualizationsServiceFactory),
customBranding: new PluginServiceProvider(customBrandingServiceFactory),
savedObjectsManagement: new PluginServiceProvider(savedObjectsManagementServiceFactory),
contentManagement: new PluginServiceProvider(contentManagementServiceFactory),
};

export const pluginServices = new PluginServices<DashboardServices>();
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/dashboard/public/services/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -68,4 +69,5 @@ export interface DashboardServices {
visualizations: DashboardVisualizationsService;
customBranding: DashboardCustomBrandingService;
savedObjectsManagement: SavedObjectsManagementPluginStart;
contentManagement: ContentManagementPublicStart;
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export class DataViewsStorage extends SOContentStorage<DataViewCrudTypes> {
'allowNoIndex',
'name',
],
mSearchAdditionalSearchFields: ['name'],
});
}
}
Loading

0 comments on commit 304cb25

Please sign in to comment.