mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[SavedObjectFinder] Remove savedObjects.find (#151220)
## Summary This PR replaces deprecated client-side `savedObjects.find` method with a server-side one and a corresponding API call. As a result, the dependencies of the `SavedObjectFinder` component have changed slightly: instead of `coreStart.savedObjects`, the component is now taking `coreStart.http`. If you have been tagged as a reviewer, it means your plugin is using `SavedObjectFinder` somewhere. To test it, ensure it all works as previously. ### Checklist Delete any items that are not applicable to this PR. ~- [] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)~ ~ [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials~ - [X] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios ~- [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/))~ ~- [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))~ ~- [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)~ ~- [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server))~ ~- [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers)~ ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
b94c77780e
commit
b4f5fa6ed8
37 changed files with 373 additions and 201 deletions
|
@ -39,7 +39,7 @@ export const buildAllDashboardActions = async ({
|
|||
uiActions.registerAction(clonePanelAction);
|
||||
uiActions.attachAction(CONTEXT_MENU_TRIGGER, clonePanelAction.id);
|
||||
|
||||
const SavedObjectFinder = getSavedObjectFinder(core.savedObjects, uiSettings);
|
||||
const SavedObjectFinder = getSavedObjectFinder(uiSettings, core.http);
|
||||
const changeViewAction = new ReplacePanelAction(SavedObjectFinder);
|
||||
uiActions.registerAction(changeViewAction);
|
||||
uiActions.attachAction(CONTEXT_MENU_TRIGGER, changeViewAction.id);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { HttpStart } from '@kbn/core/public';
|
||||
import { isErrorEmbeddable, openAddPanelFlyout } from '@kbn/embeddable-plugin/public';
|
||||
import { getSavedObjectFinder } from '@kbn/saved-objects-plugin/public';
|
||||
|
||||
|
@ -18,14 +19,14 @@ export function addFromLibrary(this: DashboardContainer) {
|
|||
notifications,
|
||||
usageCollection,
|
||||
settings: { uiSettings, theme },
|
||||
dashboardSavedObject: { savedObjectsClient },
|
||||
embeddable: { getEmbeddableFactories, getEmbeddableFactory },
|
||||
http,
|
||||
} = pluginServices.getServices();
|
||||
|
||||
if (isErrorEmbeddable(this)) return;
|
||||
this.openOverlay(
|
||||
openAddPanelFlyout({
|
||||
SavedObjectFinder: getSavedObjectFinder({ client: savedObjectsClient }, uiSettings),
|
||||
SavedObjectFinder: getSavedObjectFinder(uiSettings, http as HttpStart),
|
||||
reportUiCounter: usageCollection.reportUiCounter,
|
||||
getAllFactories: getEmbeddableFactories,
|
||||
getFactory: getEmbeddableFactory,
|
||||
|
|
|
@ -17,5 +17,6 @@ export const httpServiceFactory: HttpServiceFactory = () => {
|
|||
|
||||
return {
|
||||
basePath: serviceMock.http.basePath,
|
||||
get: serviceMock.http.get,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -16,10 +16,11 @@ export type HttpServiceFactory = KibanaPluginServiceFactory<
|
|||
>;
|
||||
export const httpServiceFactory: HttpServiceFactory = ({ coreStart }) => {
|
||||
const {
|
||||
http: { basePath },
|
||||
http: { basePath, get },
|
||||
} = coreStart;
|
||||
|
||||
return {
|
||||
basePath,
|
||||
get,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -6,8 +6,9 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { CoreSetup } from '@kbn/core/public';
|
||||
import type { CoreStart } from '@kbn/core/public';
|
||||
|
||||
export interface DashboardHTTPService {
|
||||
basePath: CoreSetup['http']['basePath'];
|
||||
basePath: CoreStart['http']['basePath'];
|
||||
get: CoreStart['http']['get'];
|
||||
}
|
||||
|
|
|
@ -207,7 +207,7 @@ export class EmbeddablePublicPlugin implements Plugin<EmbeddableSetup, Embeddabl
|
|||
notifications={core.notifications}
|
||||
application={core.application}
|
||||
inspector={inspector}
|
||||
SavedObjectFinder={getSavedObjectFinder(core.savedObjects, core.uiSettings)}
|
||||
SavedObjectFinder={getSavedObjectFinder(core.uiSettings, core.http)}
|
||||
containerContext={containerContext}
|
||||
theme={theme}
|
||||
/>
|
||||
|
|
|
@ -8,3 +8,4 @@
|
|||
|
||||
export const PER_PAGE_SETTING = 'savedObjects:perPage';
|
||||
export const LISTING_LIMIT_SETTING = 'savedObjects:listingLimit';
|
||||
export type { SavedObjectCommon, FindQueryHTTP, FindResponseHTTP, FinderAttributes } from './types';
|
||||
|
|
35
src/plugins/saved_objects/common/types.ts
Normal file
35
src/plugins/saved_objects/common/types.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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 { SavedObject } from '@kbn/core-saved-objects-server';
|
||||
|
||||
export type SavedObjectCommon<T = unknown> = SavedObject<T>;
|
||||
|
||||
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[];
|
||||
}
|
||||
|
||||
export interface FinderAttributes {
|
||||
title?: string;
|
||||
name?: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface FindResponseHTTP<T> {
|
||||
saved_objects: Array<SavedObjectCommon<T>>;
|
||||
total: number;
|
||||
page: number;
|
||||
per_page: number;
|
||||
}
|
|
@ -6,9 +6,5 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export type {
|
||||
SavedObjectMetaData,
|
||||
SavedObjectFinderUiProps,
|
||||
FinderAttributes,
|
||||
} from './saved_object_finder';
|
||||
export type { SavedObjectMetaData, SavedObjectFinderUiProps } from './saved_object_finder';
|
||||
export { SavedObjectFinderUi, getSavedObjectFinder } from './saved_object_finder';
|
||||
|
|
|
@ -52,43 +52,45 @@ describe('SavedObjectsFinder', () => {
|
|||
},
|
||||
];
|
||||
|
||||
it('should call saved object client on startup', async () => {
|
||||
it('should call api find on startup', async () => {
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ savedObjects: [doc] })
|
||||
(core.http.get as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ saved_objects: [doc] })
|
||||
);
|
||||
core.uiSettings.get.mockImplementation(() => 10);
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
savedObjectMetaData={searchMetaData}
|
||||
/>
|
||||
);
|
||||
wrapper.instance().componentDidMount!();
|
||||
|
||||
expect(core.savedObjects.client.find).toHaveBeenCalledWith({
|
||||
type: ['search'],
|
||||
fields: ['title', 'name'],
|
||||
search: undefined,
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
searchFields: ['title^3', 'description', 'name'],
|
||||
defaultSearchOperator: 'AND',
|
||||
expect(core.http.get).toHaveBeenCalledWith('/internal/saved-objects-finder/find', {
|
||||
query: {
|
||||
type: ['search'],
|
||||
fields: ['title', 'name'],
|
||||
search: undefined,
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
searchFields: ['title^3', 'description', 'name'],
|
||||
defaultSearchOperator: 'AND',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should list initial items', async () => {
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ savedObjects: [doc] })
|
||||
(core.http.get as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ saved_objects: [doc] })
|
||||
);
|
||||
core.uiSettings.get.mockImplementation(() => 10);
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
savedObjectMetaData={searchMetaData}
|
||||
/>
|
||||
|
@ -104,14 +106,14 @@ describe('SavedObjectsFinder', () => {
|
|||
it('should call onChoose on item click', async () => {
|
||||
const chooseStub = sinon.stub();
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ savedObjects: [doc] })
|
||||
(core.http.get as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ saved_objects: [doc] })
|
||||
);
|
||||
core.uiSettings.get.mockImplementation(() => 10);
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
onChoose={chooseStub}
|
||||
savedObjectMetaData={searchMetaData}
|
||||
|
@ -129,14 +131,14 @@ describe('SavedObjectsFinder', () => {
|
|||
describe('sorting', () => {
|
||||
it('should list items ascending', async () => {
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ savedObjects: [doc, doc2] })
|
||||
(core.http.get as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ saved_objects: [doc, doc2] })
|
||||
);
|
||||
core.uiSettings.get.mockImplementation(() => 10);
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
savedObjectMetaData={searchMetaData}
|
||||
/>
|
||||
|
@ -150,14 +152,14 @@ describe('SavedObjectsFinder', () => {
|
|||
|
||||
it('should list items descending', async () => {
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ savedObjects: [doc, doc2] })
|
||||
(core.http.get as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ saved_objects: [doc, doc2] })
|
||||
);
|
||||
core.uiSettings.get.mockImplementation(() => 10);
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
savedObjectMetaData={searchMetaData}
|
||||
/>
|
||||
|
@ -174,14 +176,14 @@ describe('SavedObjectsFinder', () => {
|
|||
|
||||
it('should not show the saved objects which get filtered by showSavedObject', async () => {
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ savedObjects: [doc, doc2] })
|
||||
(core.http.get as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ saved_objects: [doc, doc2] })
|
||||
);
|
||||
core.uiSettings.get.mockImplementation(() => 10);
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
savedObjectMetaData={[
|
||||
{
|
||||
|
@ -204,14 +206,14 @@ describe('SavedObjectsFinder', () => {
|
|||
describe('search', () => {
|
||||
it('should request filtered list on search input', async () => {
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ savedObjects: [doc, doc2] })
|
||||
(core.http.get as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ saved_objects: [doc, doc2] })
|
||||
);
|
||||
core.uiSettings.get.mockImplementation(() => 10);
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
savedObjectMetaData={searchMetaData}
|
||||
/>
|
||||
|
@ -223,25 +225,27 @@ describe('SavedObjectsFinder', () => {
|
|||
.first()
|
||||
.simulate('change', { target: { value: 'abc' } });
|
||||
|
||||
expect(core.savedObjects.client.find).toHaveBeenCalledWith({
|
||||
type: ['search'],
|
||||
fields: ['title', 'name'],
|
||||
search: 'abc*',
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
searchFields: ['title^3', 'description', 'name'],
|
||||
defaultSearchOperator: 'AND',
|
||||
expect(core.http.get).toHaveBeenCalledWith('/internal/saved-objects-finder/find', {
|
||||
query: {
|
||||
type: ['search'],
|
||||
fields: ['title', 'name'],
|
||||
search: 'abc*',
|
||||
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.uiSettings.get.mockImplementation(() => 10);
|
||||
(core.savedObjects.client.find as jest.Mock).mockResolvedValue({ savedObjects: [] });
|
||||
(core.http.get as jest.Mock).mockResolvedValue({ saved_objects: [] });
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
savedObjectMetaData={[
|
||||
{
|
||||
|
@ -266,27 +270,29 @@ describe('SavedObjectsFinder', () => {
|
|||
.first()
|
||||
.simulate('change', { target: { value: 'abc' } });
|
||||
|
||||
expect(core.savedObjects.client.find).toHaveBeenCalledWith({
|
||||
type: ['type1', 'type2'],
|
||||
fields: ['title', 'name', 'field1', 'field2', 'field3'],
|
||||
search: 'abc*',
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
searchFields: ['title^3', 'description'],
|
||||
defaultSearchOperator: 'AND',
|
||||
expect(core.http.get).toHaveBeenCalledWith('/internal/saved-objects-finder/find', {
|
||||
query: {
|
||||
type: ['type1', 'type2'],
|
||||
fields: ['title', 'name', 'field1', 'field2', 'field3'],
|
||||
search: 'abc*',
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
searchFields: ['title^3', 'description'],
|
||||
defaultSearchOperator: 'AND',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should respect response order on search input', async () => {
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ savedObjects: [doc, doc2] })
|
||||
(core.http.get as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ saved_objects: [doc, doc2] })
|
||||
);
|
||||
core.uiSettings.get.mockImplementation(() => 10);
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
savedObjectMetaData={searchMetaData}
|
||||
/>
|
||||
|
@ -307,14 +313,14 @@ describe('SavedObjectsFinder', () => {
|
|||
|
||||
it('should request multiple saved object types at once', async () => {
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ savedObjects: [doc, doc2] })
|
||||
(core.http.get as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ saved_objects: [doc, doc2] })
|
||||
);
|
||||
core.uiSettings.get.mockImplementation(() => 10);
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
savedObjectMetaData={[
|
||||
{
|
||||
|
@ -332,14 +338,16 @@ describe('SavedObjectsFinder', () => {
|
|||
);
|
||||
wrapper.instance().componentDidMount!();
|
||||
|
||||
expect(core.savedObjects.client.find).toHaveBeenCalledWith({
|
||||
type: ['search', 'vis'],
|
||||
fields: ['title', 'name'],
|
||||
search: undefined,
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
searchFields: ['title^3', 'description'],
|
||||
defaultSearchOperator: 'AND',
|
||||
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',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -359,16 +367,16 @@ describe('SavedObjectsFinder', () => {
|
|||
|
||||
it('should not render filter buttons if disabled', async () => {
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() =>
|
||||
(core.http.get as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
savedObjects: [doc, doc2, doc3],
|
||||
saved_objects: [doc, doc2, doc3],
|
||||
})
|
||||
);
|
||||
core.uiSettings.get.mockImplementation(() => 10);
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
showFilter={false}
|
||||
savedObjectMetaData={metaDataConfig}
|
||||
|
@ -384,16 +392,16 @@ describe('SavedObjectsFinder', () => {
|
|||
|
||||
it('should not render filter buttons if there is only one type in the list', async () => {
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() =>
|
||||
(core.http.get as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
savedObjects: [doc, doc2],
|
||||
saved_objects: [doc, doc2],
|
||||
})
|
||||
);
|
||||
core.uiSettings.get.mockImplementation(() => 10);
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
showFilter={true}
|
||||
savedObjectMetaData={metaDataConfig}
|
||||
|
@ -409,16 +417,16 @@ describe('SavedObjectsFinder', () => {
|
|||
|
||||
it('should apply filter if selected', async () => {
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() =>
|
||||
(core.http.get as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
savedObjects: [doc, doc2, doc3],
|
||||
saved_objects: [doc, doc2, doc3],
|
||||
})
|
||||
);
|
||||
core.uiSettings.get.mockImplementation(() => 10);
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
showFilter={true}
|
||||
savedObjectMetaData={metaDataConfig}
|
||||
|
@ -439,15 +447,15 @@ describe('SavedObjectsFinder', () => {
|
|||
|
||||
it('should display no items message if there are no items', async () => {
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ savedObjects: [] })
|
||||
(core.http.get as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ saved_objects: [] })
|
||||
);
|
||||
core.uiSettings.get.mockImplementation(() => 10);
|
||||
|
||||
const noItemsMessage = <span id="myNoItemsMessage" />;
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
noItemsMessage={noItemsMessage}
|
||||
savedObjectMetaData={searchMetaData}
|
||||
|
@ -470,14 +478,14 @@ describe('SavedObjectsFinder', () => {
|
|||
|
||||
it('should show a table pagination with initial per page', async () => {
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ savedObjects: longItemList })
|
||||
(core.http.get as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ saved_objects: longItemList })
|
||||
);
|
||||
core.uiSettings.get.mockImplementation(() => 10);
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
initialPageSize={15}
|
||||
savedObjectMetaData={searchMetaData}
|
||||
|
@ -492,14 +500,14 @@ describe('SavedObjectsFinder', () => {
|
|||
|
||||
it('should allow switching the page size', async () => {
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ savedObjects: longItemList })
|
||||
(core.http.get as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ saved_objects: longItemList })
|
||||
);
|
||||
core.uiSettings.get.mockImplementation(() => 10);
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
initialPageSize={15}
|
||||
savedObjectMetaData={searchMetaData}
|
||||
|
@ -514,14 +522,14 @@ describe('SavedObjectsFinder', () => {
|
|||
|
||||
it('should switch page correctly', async () => {
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ savedObjects: longItemList })
|
||||
(core.http.get as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ saved_objects: longItemList })
|
||||
);
|
||||
core.uiSettings.get.mockImplementation(() => 10);
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
initialPageSize={15}
|
||||
savedObjectMetaData={searchMetaData}
|
||||
|
@ -536,14 +544,14 @@ describe('SavedObjectsFinder', () => {
|
|||
|
||||
it('should show an ordinary pagination for fixed page sizes', async () => {
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ savedObjects: longItemList })
|
||||
(core.http.get as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ saved_objects: longItemList })
|
||||
);
|
||||
core.uiSettings.get.mockImplementation(() => 10);
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
fixedPageSize={33}
|
||||
savedObjectMetaData={searchMetaData}
|
||||
|
@ -558,14 +566,14 @@ describe('SavedObjectsFinder', () => {
|
|||
|
||||
it('should switch page correctly for fixed page sizes', async () => {
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ savedObjects: longItemList })
|
||||
(core.http.get as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ saved_objects: longItemList })
|
||||
);
|
||||
core.uiSettings.get.mockImplementation(() => 10);
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
fixedPageSize={33}
|
||||
savedObjectMetaData={searchMetaData}
|
||||
|
@ -582,11 +590,11 @@ describe('SavedObjectsFinder', () => {
|
|||
describe('loading state', () => {
|
||||
it('should display a spinner during initial loading', () => {
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as jest.Mock).mockResolvedValue({ savedObjects: [] });
|
||||
(core.http.get as jest.Mock).mockResolvedValue({ saved_objects: [] });
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
savedObjectMetaData={searchMetaData}
|
||||
/>
|
||||
|
@ -597,13 +605,13 @@ describe('SavedObjectsFinder', () => {
|
|||
|
||||
it('should hide the spinner if data is shown', async () => {
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ savedObjects: [doc] })
|
||||
(core.http.get as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ saved_objects: [doc] })
|
||||
);
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
savedObjectMetaData={[
|
||||
{
|
||||
|
@ -622,13 +630,13 @@ describe('SavedObjectsFinder', () => {
|
|||
|
||||
it('should not show the spinner if there are already items', async () => {
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ savedObjects: [doc] })
|
||||
(core.http.get as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ saved_objects: [doc] })
|
||||
);
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
savedObjectMetaData={searchMetaData}
|
||||
/>
|
||||
|
@ -649,14 +657,14 @@ describe('SavedObjectsFinder', () => {
|
|||
|
||||
it('should render with children', async () => {
|
||||
const core = coreMock.createStart();
|
||||
(core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ savedObjects: [doc, doc2] })
|
||||
(core.http.get as any as jest.SpyInstance).mockImplementation(() =>
|
||||
Promise.resolve({ saved_objects: [doc, doc2] })
|
||||
);
|
||||
core.uiSettings.get.mockImplementation(() => 10);
|
||||
|
||||
const wrapper = shallow(
|
||||
<SavedObjectFinder
|
||||
savedObjects={core.savedObjects}
|
||||
http={core.http}
|
||||
uiSettings={core.uiSettings}
|
||||
savedObjectMetaData={[
|
||||
{
|
||||
|
|
|
@ -31,39 +31,34 @@ import {
|
|||
import { Direction } from '@elastic/eui/src/services/sort/sort_direction';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import {
|
||||
SimpleSavedObject,
|
||||
CoreStart,
|
||||
IUiSettingsClient,
|
||||
SavedObjectsStart,
|
||||
} from '@kbn/core/public';
|
||||
import { CoreStart, IUiSettingsClient, HttpStart } from '@kbn/core/public';
|
||||
|
||||
import type {
|
||||
FinderAttributes,
|
||||
FindQueryHTTP,
|
||||
FindResponseHTTP,
|
||||
SavedObjectCommon,
|
||||
} from '../../common';
|
||||
import { LISTING_LIMIT_SETTING } from '../../common';
|
||||
|
||||
export interface SavedObjectMetaData<T = unknown> {
|
||||
type: string;
|
||||
name: string;
|
||||
getIconForSavedObject(savedObject: SimpleSavedObject<T>): IconType;
|
||||
getTooltipForSavedObject?(savedObject: SimpleSavedObject<T>): string;
|
||||
showSavedObject?(savedObject: SimpleSavedObject<T>): boolean;
|
||||
getSavedObjectSubType?(savedObject: SimpleSavedObject<T>): string;
|
||||
getIconForSavedObject(savedObject: SavedObjectCommon<T>): IconType;
|
||||
getTooltipForSavedObject?(savedObject: SavedObjectCommon<T>): string;
|
||||
showSavedObject?(savedObject: SavedObjectCommon<T>): boolean;
|
||||
getSavedObjectSubType?(savedObject: SavedObjectCommon<T>): string;
|
||||
includeFields?: string[];
|
||||
defaultSearchField?: string;
|
||||
}
|
||||
|
||||
export interface FinderAttributes {
|
||||
title?: string;
|
||||
name?: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
interface SavedObjectFinderState {
|
||||
items: Array<{
|
||||
title: string | null;
|
||||
name: string | null;
|
||||
id: SimpleSavedObject['id'];
|
||||
type: SimpleSavedObject['type'];
|
||||
savedObject: SimpleSavedObject<FinderAttributes>;
|
||||
id: SavedObjectCommon['id'];
|
||||
type: SavedObjectCommon['type'];
|
||||
savedObject: SavedObjectCommon<FinderAttributes>;
|
||||
}>;
|
||||
query: string;
|
||||
isFetchingItems: boolean;
|
||||
|
@ -77,10 +72,10 @@ interface SavedObjectFinderState {
|
|||
|
||||
interface BaseSavedObjectFinder {
|
||||
onChoose?: (
|
||||
id: SimpleSavedObject['id'],
|
||||
type: SimpleSavedObject['type'],
|
||||
id: SavedObjectCommon['id'],
|
||||
type: SavedObjectCommon['type'],
|
||||
name: string,
|
||||
savedObject: SimpleSavedObject
|
||||
savedObject: SavedObjectCommon
|
||||
) => void;
|
||||
noItemsMessage?: React.ReactNode;
|
||||
savedObjectMetaData: Array<SavedObjectMetaData<FinderAttributes>>;
|
||||
|
@ -100,8 +95,8 @@ interface SavedObjectFinderInitialPageSize extends BaseSavedObjectFinder {
|
|||
export type SavedObjectFinderProps = SavedObjectFinderFixedPage | SavedObjectFinderInitialPageSize;
|
||||
|
||||
export type SavedObjectFinderUiProps = {
|
||||
savedObjects: CoreStart['savedObjects'];
|
||||
uiSettings: CoreStart['uiSettings'];
|
||||
http: CoreStart['http'];
|
||||
} & SavedObjectFinderProps;
|
||||
|
||||
class SavedObjectFinderUi extends React.Component<
|
||||
|
@ -134,7 +129,7 @@ class SavedObjectFinderUi extends React.Component<
|
|||
}, []);
|
||||
|
||||
const perPage = this.props.uiSettings.get(LISTING_LIMIT_SETTING);
|
||||
const resp = await this.props.savedObjects.client.find<FinderAttributes>({
|
||||
const params: FindQueryHTTP = {
|
||||
type: Object.keys(metaDataMap),
|
||||
fields: [...new Set(fields)],
|
||||
search: query ? `${query}*` : undefined,
|
||||
|
@ -142,15 +137,17 @@ class SavedObjectFinderUi extends React.Component<
|
|||
perPage,
|
||||
searchFields: ['title^3', 'description', ...additionalSearchFields],
|
||||
defaultSearchOperator: 'AND',
|
||||
});
|
||||
};
|
||||
const resp = (await this.props.http.get('/internal/saved-objects-finder/find', {
|
||||
query: params as Record<string, any>,
|
||||
})) as FindResponseHTTP<FinderAttributes>;
|
||||
|
||||
resp.savedObjects = resp.savedObjects.filter((savedObject) => {
|
||||
resp.saved_objects = resp.saved_objects.filter((savedObject) => {
|
||||
const metaData = metaDataMap[savedObject.type];
|
||||
if (metaData.showSavedObject) {
|
||||
return metaData.showSavedObject(savedObject);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!this.isComponentMounted) {
|
||||
|
@ -163,14 +160,11 @@ class SavedObjectFinderUi extends React.Component<
|
|||
this.setState({
|
||||
isFetchingItems: false,
|
||||
page: 0,
|
||||
items: resp.savedObjects.map((savedObject) => {
|
||||
const {
|
||||
attributes: { name, title },
|
||||
id,
|
||||
type,
|
||||
} = savedObject;
|
||||
items: resp.saved_objects.map((savedObject) => {
|
||||
const { attributes, id, type } = savedObject;
|
||||
const { name, title } = attributes as FinderAttributes;
|
||||
const titleToUse = typeof title === 'string' ? title : '';
|
||||
const nameToUse = name && typeof name === 'string' ? name : titleToUse;
|
||||
const nameToUse = name ? name : titleToUse;
|
||||
return {
|
||||
title: titleToUse,
|
||||
name: nameToUse,
|
||||
|
@ -533,9 +527,9 @@ class SavedObjectFinderUi extends React.Component<
|
|||
}
|
||||
}
|
||||
|
||||
const getSavedObjectFinder = (savedObject: SavedObjectsStart, uiSettings: IUiSettingsClient) => {
|
||||
const getSavedObjectFinder = (uiSettings: IUiSettingsClient, http: HttpStart) => {
|
||||
return (props: SavedObjectFinderProps) => (
|
||||
<SavedObjectFinderUi {...props} savedObjects={savedObject} uiSettings={uiSettings} />
|
||||
<SavedObjectFinderUi {...props} uiSettings={uiSettings} http={http} />
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -10,7 +10,8 @@ import { SavedObjectsPublicPlugin } from './plugin';
|
|||
|
||||
export type { OnSaveProps, OriginSaveModalProps, SaveModalState, SaveResult } from './save_modal';
|
||||
export { SavedObjectSaveModal, SavedObjectSaveModalOrigin, showSaveModal } from './save_modal';
|
||||
export type { SavedObjectFinderUiProps, SavedObjectMetaData, FinderAttributes } from './finder';
|
||||
export type { SavedObjectFinderUiProps, SavedObjectMetaData } from './finder';
|
||||
export type { FinderAttributes } from '../common/types';
|
||||
export { getSavedObjectFinder, SavedObjectFinderUi } from './finder';
|
||||
export type {
|
||||
SavedObjectDecorator,
|
||||
|
|
12
src/plugins/saved_objects/server/plugin.test.mocks.ts
Normal file
12
src/plugins/saved_objects/server/plugin.test.mocks.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export const registerRoutesMock = jest.fn();
|
||||
jest.doMock('./routes', () => ({
|
||||
registerRoutes: registerRoutesMock,
|
||||
}));
|
37
src/plugins/saved_objects/server/plugin.test.ts
Normal file
37
src/plugins/saved_objects/server/plugin.test.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { registerRoutesMock } from './plugin.test.mocks';
|
||||
|
||||
import { coreMock } from '@kbn/core/server/mocks';
|
||||
import { SavedObjectsServerPlugin } from './plugin';
|
||||
import { uiSettings } from './ui_settings';
|
||||
|
||||
describe('SavedObjectsPlugin', () => {
|
||||
let plugin: SavedObjectsServerPlugin;
|
||||
let coreSetup: ReturnType<typeof coreMock.createSetup>;
|
||||
|
||||
beforeEach(() => {
|
||||
coreSetup = coreMock.createSetup();
|
||||
plugin = new SavedObjectsServerPlugin();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
registerRoutesMock.mockReset();
|
||||
});
|
||||
|
||||
describe('#setup', () => {
|
||||
it('calls `registerRoutes` and `registerSettings` with the correct parameters', () => {
|
||||
plugin.setup(coreSetup);
|
||||
|
||||
expect(coreSetup.uiSettings.register).toHaveBeenCalledWith(uiSettings);
|
||||
expect(coreSetup.http.createRouter).toHaveBeenCalledTimes(1);
|
||||
expect(registerRoutesMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -6,12 +6,15 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { CoreSetup, Plugin } from '@kbn/core/server';
|
||||
import type { CoreSetup, Plugin, RequestHandlerContext } from '@kbn/core/server';
|
||||
import { registerRoutes } from './routes';
|
||||
import { uiSettings } from './ui_settings';
|
||||
|
||||
export class SavedObjectsServerPlugin implements Plugin<object, object> {
|
||||
public setup(core: CoreSetup) {
|
||||
core.uiSettings.register(uiSettings);
|
||||
const router = core.http.createRouter<RequestHandlerContext>();
|
||||
registerRoutes(router);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
61
src/plugins/saved_objects/server/routes/find.ts
Normal file
61
src/plugins/saved_objects/server/routes/find.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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())),
|
||||
}),
|
||||
},
|
||||
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<SavedObjectCommon<any>>({
|
||||
...query,
|
||||
type: searchTypes,
|
||||
fields: includedFields,
|
||||
});
|
||||
|
||||
const savedObjects = findResponse.saved_objects;
|
||||
|
||||
const response: FindResponseHTTP<any> = {
|
||||
saved_objects: savedObjects,
|
||||
total: findResponse.total,
|
||||
per_page: findResponse.per_page,
|
||||
page: findResponse.page,
|
||||
};
|
||||
|
||||
return res.ok({ body: response });
|
||||
}
|
||||
);
|
||||
};
|
14
src/plugins/saved_objects/server/routes/index.ts
Normal file
14
src/plugins/saved_objects/server/routes/index.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* 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);
|
||||
};
|
10
src/plugins/saved_objects/server/types.ts
Normal file
10
src/plugins/saved_objects/server/types.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* 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<RequestHandlerContext>;
|
|
@ -15,6 +15,7 @@
|
|||
"@kbn/test-jest-helpers",
|
||||
"@kbn/utility-types",
|
||||
"@kbn/config-schema",
|
||||
"@kbn/core-saved-objects-server",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -10,8 +10,9 @@ import React from 'react';
|
|||
import { mountWithIntl } from '@kbn/test-jest-helpers';
|
||||
import { TypesStart, VisGroups, BaseVisType } from '../vis_types';
|
||||
import NewVisModal from './new_vis_modal';
|
||||
import { ApplicationStart, SavedObjectsStart, DocLinksStart } from '@kbn/core/public';
|
||||
import { ApplicationStart, DocLinksStart } from '@kbn/core/public';
|
||||
import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks';
|
||||
import { httpServiceMock } from '@kbn/core-http-browser-mocks';
|
||||
|
||||
describe('NewVisModal', () => {
|
||||
const defaultVisTypeParams = {
|
||||
|
@ -75,6 +76,7 @@ describe('NewVisModal', () => {
|
|||
},
|
||||
},
|
||||
};
|
||||
const http = httpServiceMock.createStartContract({ basePath: '' });
|
||||
|
||||
beforeAll(() => {
|
||||
Object.defineProperty(window, 'location', {
|
||||
|
@ -98,7 +100,7 @@ describe('NewVisModal', () => {
|
|||
uiSettings={uiSettings}
|
||||
application={{} as ApplicationStart}
|
||||
docLinks={docLinks as DocLinksStart}
|
||||
savedObjects={{} as SavedObjectsStart}
|
||||
http={http}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="visGroup-aggbased"]').exists()).toBe(true);
|
||||
|
@ -115,7 +117,7 @@ describe('NewVisModal', () => {
|
|||
uiSettings={uiSettings}
|
||||
application={{} as ApplicationStart}
|
||||
docLinks={docLinks as DocLinksStart}
|
||||
savedObjects={{} as SavedObjectsStart}
|
||||
http={http}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="visGroup-tools"]').exists()).toBe(true);
|
||||
|
@ -131,7 +133,7 @@ describe('NewVisModal', () => {
|
|||
uiSettings={uiSettings}
|
||||
application={{} as ApplicationStart}
|
||||
docLinks={docLinks as DocLinksStart}
|
||||
savedObjects={{} as SavedObjectsStart}
|
||||
http={http}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="visType-vis2"]').exists()).toBe(true);
|
||||
|
@ -148,7 +150,7 @@ describe('NewVisModal', () => {
|
|||
uiSettings={uiSettings}
|
||||
application={{} as ApplicationStart}
|
||||
docLinks={docLinks as DocLinksStart}
|
||||
savedObjects={{} as SavedObjectsStart}
|
||||
http={http}
|
||||
/>
|
||||
);
|
||||
const visCard = wrapper.find('[data-test-subj="visType-vis"]').last();
|
||||
|
@ -167,7 +169,7 @@ describe('NewVisModal', () => {
|
|||
uiSettings={uiSettings}
|
||||
application={{} as ApplicationStart}
|
||||
docLinks={docLinks as DocLinksStart}
|
||||
savedObjects={{} as SavedObjectsStart}
|
||||
http={http}
|
||||
/>
|
||||
);
|
||||
const visCard = wrapper.find('[data-test-subj="visType-vis"]').last();
|
||||
|
@ -193,7 +195,7 @@ describe('NewVisModal', () => {
|
|||
application={{ navigateToApp } as unknown as ApplicationStart}
|
||||
docLinks={docLinks as DocLinksStart}
|
||||
stateTransfer={stateTransfer}
|
||||
savedObjects={{} as SavedObjectsStart}
|
||||
http={http}
|
||||
/>
|
||||
);
|
||||
const visCard = wrapper.find('[data-test-subj="visType-visWithAliasUrl"]').last();
|
||||
|
@ -218,7 +220,7 @@ describe('NewVisModal', () => {
|
|||
uiSettings={uiSettings}
|
||||
application={{ navigateToApp } as unknown as ApplicationStart}
|
||||
docLinks={docLinks as DocLinksStart}
|
||||
savedObjects={{} as SavedObjectsStart}
|
||||
http={http}
|
||||
/>
|
||||
);
|
||||
const visCard = wrapper.find('[data-test-subj="visType-visWithAliasUrl"]').last();
|
||||
|
@ -239,7 +241,7 @@ describe('NewVisModal', () => {
|
|||
uiSettings={uiSettings}
|
||||
application={{} as ApplicationStart}
|
||||
docLinks={docLinks as DocLinksStart}
|
||||
savedObjects={{} as SavedObjectsStart}
|
||||
http={http}
|
||||
/>
|
||||
);
|
||||
const aggBasedGroupCard = wrapper
|
||||
|
|
|
@ -12,12 +12,7 @@ import { EuiModal } from '@elastic/eui';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { METRIC_TYPE, UiCounterMetricType } from '@kbn/analytics';
|
||||
import {
|
||||
ApplicationStart,
|
||||
IUiSettingsClient,
|
||||
SavedObjectsStart,
|
||||
DocLinksStart,
|
||||
} from '@kbn/core/public';
|
||||
import { ApplicationStart, IUiSettingsClient, DocLinksStart, HttpStart } from '@kbn/core/public';
|
||||
import { EmbeddableStateTransfer } from '@kbn/embeddable-plugin/public';
|
||||
import { SearchSelection } from './search_selection';
|
||||
import { GroupSelection } from './group_selection';
|
||||
|
@ -34,7 +29,7 @@ interface TypeSelectionProps {
|
|||
addBasePath: (path: string) => string;
|
||||
uiSettings: IUiSettingsClient;
|
||||
docLinks: DocLinksStart;
|
||||
savedObjects: SavedObjectsStart;
|
||||
http: HttpStart;
|
||||
application: ApplicationStart;
|
||||
outsideVisualizeApp?: boolean;
|
||||
stateTransfer?: EmbeddableStateTransfer;
|
||||
|
@ -97,7 +92,7 @@ class NewVisModal extends React.Component<TypeSelectionProps, TypeSelectionState
|
|||
onSearchSelected={this.onSearchSelected}
|
||||
visType={this.state.visType}
|
||||
uiSettings={this.props.uiSettings}
|
||||
savedObjects={this.props.savedObjects}
|
||||
http={this.props.http}
|
||||
goBack={() => this.setState({ showSearchVisModal: false })}
|
||||
/>
|
||||
</EuiModal>
|
||||
|
|
|
@ -10,7 +10,7 @@ import React from 'react';
|
|||
import { EuiModalBody, EuiModalHeader, EuiModalHeaderTitle } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { IUiSettingsClient, SavedObjectsStart } from '@kbn/core/public';
|
||||
import { IUiSettingsClient, HttpStart } from '@kbn/core/public';
|
||||
|
||||
import { SavedObjectFinderUi } from '@kbn/saved-objects-plugin/public';
|
||||
import type { BaseVisType } from '../../vis_types';
|
||||
|
@ -21,7 +21,7 @@ interface SearchSelectionProps {
|
|||
onSearchSelected: (searchId: string, searchType: string) => void;
|
||||
visType: BaseVisType;
|
||||
uiSettings: IUiSettingsClient;
|
||||
savedObjects: SavedObjectsStart;
|
||||
http: HttpStart;
|
||||
goBack: () => void;
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,7 @@ export class SearchSelection extends React.Component<SearchSelectionProps> {
|
|||
]}
|
||||
fixedPageSize={this.fixedPageSize}
|
||||
uiSettings={this.props.uiSettings}
|
||||
savedObjects={this.props.savedObjects}
|
||||
http={this.props.http}
|
||||
/>
|
||||
</EuiModalBody>
|
||||
</React.Fragment>
|
||||
|
|
|
@ -13,7 +13,6 @@ import { I18nProvider } from '@kbn/i18n-react';
|
|||
import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public';
|
||||
import {
|
||||
getHttp,
|
||||
getSavedObjects,
|
||||
getTypes,
|
||||
getUISettings,
|
||||
getApplication,
|
||||
|
@ -81,7 +80,7 @@ export function showNewVisModal({
|
|||
visTypesRegistry={getTypes()}
|
||||
addBasePath={getHttp().basePath.prepend}
|
||||
uiSettings={getUISettings()}
|
||||
savedObjects={getSavedObjects()}
|
||||
http={getHttp()}
|
||||
application={getApplication()}
|
||||
docLinks={getDocLinks()}
|
||||
showAggsSelection={showAggsSelection}
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
"@kbn/core-overlays-browser",
|
||||
"@kbn/config-schema",
|
||||
"@kbn/usage-collection-plugin",
|
||||
"@kbn/core-http-browser-mocks",
|
||||
"@kbn/shared-ux-router",
|
||||
],
|
||||
"exclude": [
|
||||
|
|
|
@ -38,7 +38,7 @@ export const AddEmbeddableFlyout: FC<Props> = ({
|
|||
const embeddablesService = useEmbeddablesService();
|
||||
const platformService = usePlatformService();
|
||||
const { getEmbeddableFactories } = embeddablesService;
|
||||
const { getSavedObjects, getUISettings } = platformService;
|
||||
const { getHttp, getUISettings } = platformService;
|
||||
|
||||
const onAddPanel = useCallback(
|
||||
(id: string, savedObjectType: string) => {
|
||||
|
@ -82,8 +82,8 @@ export const AddEmbeddableFlyout: FC<Props> = ({
|
|||
savedObjectMetaData={availableSavedObjects}
|
||||
showFilter={true}
|
||||
noItemsMessage={strings.getNoItemsText()}
|
||||
savedObjects={getSavedObjects()}
|
||||
uiSettings={getUISettings()}
|
||||
http={getHttp()}
|
||||
/>
|
||||
</EuiFlyoutBody>
|
||||
</EuiFlyout>
|
||||
|
|
|
@ -45,5 +45,6 @@ export const platformServiceFactory: CanvaPlatformServiceFactory = ({
|
|||
getSavedObjects: () => coreStart.savedObjects,
|
||||
getSavedObjectsClient: () => coreStart.savedObjects.client,
|
||||
getUISettings: () => coreStart.uiSettings,
|
||||
getHttp: () => coreStart.http,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
ChromeBreadcrumb,
|
||||
IBasePath,
|
||||
ChromeStart,
|
||||
HttpStart,
|
||||
} from '@kbn/core/public';
|
||||
|
||||
import { SpacesPluginStart } from '@kbn/spaces-plugin/public';
|
||||
|
@ -37,4 +38,5 @@ export interface CanvasPlatformService {
|
|||
getSavedObjects: () => SavedObjectsStart;
|
||||
getSavedObjectsClient: () => SavedObjectsClientContract;
|
||||
getUISettings: () => IUiSettingsClient;
|
||||
getHttp: () => HttpStart;
|
||||
}
|
||||
|
|
|
@ -36,4 +36,5 @@ export const platformServiceFactory: CanvasPlatformServiceFactory = () => ({
|
|||
setFullscreen: noop,
|
||||
redirectLegacyUrl: noop,
|
||||
getLegacyUrlConflict: undefined,
|
||||
getHttp: noop,
|
||||
});
|
||||
|
|
|
@ -77,7 +77,7 @@ function GuidancePanelComponent(props: GuidancePanelProps) {
|
|||
|
||||
const kibana = useKibana<IUnifiedSearchPluginServices>();
|
||||
const { services, overlays } = kibana;
|
||||
const { savedObjects, uiSettings, application, data } = services;
|
||||
const { http, uiSettings, application, data } = services;
|
||||
const [hasDataViews, setHasDataViews] = useState<boolean>(true);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -90,7 +90,7 @@ function GuidancePanelComponent(props: GuidancePanelProps) {
|
|||
if (!overlays || !application) return null;
|
||||
|
||||
const onOpenDatasourcePicker = () => {
|
||||
openSourceModal({ overlays, savedObjects, uiSettings }, onIndexPatternSelected);
|
||||
openSourceModal({ overlays, http, uiSettings }, onIndexPatternSelected);
|
||||
};
|
||||
|
||||
let content = (
|
||||
|
|
|
@ -98,7 +98,6 @@ export function SearchBarComponent(props: SearchBarStateProps & SearchBarProps)
|
|||
const kibana = useKibana<IUnifiedSearchPluginServices>();
|
||||
const { services, overlays } = kibana;
|
||||
const {
|
||||
savedObjects,
|
||||
uiSettings,
|
||||
appName,
|
||||
unifiedSearch,
|
||||
|
@ -132,8 +131,7 @@ export function SearchBarComponent(props: SearchBarStateProps & SearchBarProps)
|
|||
data-test-subj="graphDatasourceButton"
|
||||
onClick={() => {
|
||||
confirmWipeWorkspace(
|
||||
() =>
|
||||
openSourceModal({ overlays, savedObjects, uiSettings }, onIndexPatternSelected),
|
||||
() => openSourceModal({ overlays, http, uiSettings }, onIndexPatternSelected),
|
||||
i18n.translate('xpack.graph.clearWorkspace.confirmText', {
|
||||
defaultMessage:
|
||||
'If you change data sources, your current fields and vertices will be reset.',
|
||||
|
|
|
@ -14,20 +14,16 @@ import { IndexPatternSavedObject } from '../types';
|
|||
|
||||
export interface SourcePickerProps {
|
||||
onIndexPatternSelected: (indexPattern: IndexPatternSavedObject) => void;
|
||||
savedObjects: CoreStart['savedObjects'];
|
||||
http: CoreStart['http'];
|
||||
uiSettings: CoreStart['uiSettings'];
|
||||
}
|
||||
|
||||
const fixedPageSize = 8;
|
||||
|
||||
export function SourcePicker({
|
||||
savedObjects,
|
||||
uiSettings,
|
||||
onIndexPatternSelected,
|
||||
}: SourcePickerProps) {
|
||||
export function SourcePicker({ http, uiSettings, onIndexPatternSelected }: SourcePickerProps) {
|
||||
return (
|
||||
<SavedObjectFinderUi
|
||||
savedObjects={savedObjects}
|
||||
http={http}
|
||||
uiSettings={uiSettings}
|
||||
onChoose={(_id, _type, _name, indexPattern) => {
|
||||
onIndexPatternSelected(indexPattern as IndexPatternSavedObject);
|
||||
|
|
|
@ -14,11 +14,11 @@ import { IndexPatternSavedObject } from '../types';
|
|||
export function openSourceModal(
|
||||
{
|
||||
overlays,
|
||||
savedObjects,
|
||||
http,
|
||||
uiSettings,
|
||||
}: {
|
||||
overlays: KibanaReactOverlays;
|
||||
savedObjects: CoreStart['savedObjects'];
|
||||
http: CoreStart['http'];
|
||||
uiSettings: CoreStart['uiSettings'];
|
||||
},
|
||||
onSelected: (indexPattern: IndexPatternSavedObject) => void
|
||||
|
@ -26,7 +26,7 @@ export function openSourceModal(
|
|||
const modalRef = overlays.openModal(
|
||||
<SourceModal
|
||||
uiSettings={uiSettings}
|
||||
savedObjects={savedObjects}
|
||||
http={http}
|
||||
onIndexPatternSelected={(indexPattern) => {
|
||||
onSelected(indexPattern);
|
||||
modalRef.close();
|
||||
|
|
|
@ -71,8 +71,8 @@ const mockNavigateToPath = jest.fn();
|
|||
jest.mock('../../../../../contexts/kibana', () => ({
|
||||
useMlKibana: () => ({
|
||||
services: {
|
||||
savedObjects: {},
|
||||
uiSettings: {},
|
||||
http: {},
|
||||
},
|
||||
}),
|
||||
useNavigateToPath: () => mockNavigateToPath,
|
||||
|
|
|
@ -14,11 +14,11 @@ import {
|
|||
EuiPageContent_Deprecated as EuiPageContent,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import type { SimpleSavedObject } from '@kbn/core/public';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { getNestedProperty } from '@kbn/ml-nested-property';
|
||||
import { SavedObjectFinderUi } from '@kbn/saved-objects-plugin/public';
|
||||
|
||||
import { SavedObjectCommon } from '@kbn/saved-objects-plugin/common';
|
||||
import { useMlKibana, useNavigateToPath } from '../../../../../contexts/kibana';
|
||||
import { useToastNotificationService } from '../../../../../services/toast_notification_service';
|
||||
import { getDataViewAndSavedSearch, isCcsIndexPattern } from '../../../../../util/index_utils';
|
||||
|
@ -27,7 +27,7 @@ const fixedPageSize: number = 20;
|
|||
|
||||
export const SourceSelection: FC = () => {
|
||||
const {
|
||||
services: { savedObjects, uiSettings },
|
||||
services: { http, uiSettings },
|
||||
} = useMlKibana();
|
||||
const navigateToPath = useNavigateToPath();
|
||||
|
||||
|
@ -39,7 +39,7 @@ export const SourceSelection: FC = () => {
|
|||
id: string,
|
||||
type: string,
|
||||
fullName: string,
|
||||
savedObject: SimpleSavedObject
|
||||
savedObject: SavedObjectCommon
|
||||
) => {
|
||||
// Kibana data views including `:` are cross-cluster search indices
|
||||
// and are not supported by Data Frame Analytics yet. For saved searches
|
||||
|
@ -152,7 +152,7 @@ export const SourceSelection: FC = () => {
|
|||
]}
|
||||
fixedPageSize={fixedPageSize}
|
||||
uiSettings={uiSettings}
|
||||
savedObjects={savedObjects}
|
||||
http={http}
|
||||
/>
|
||||
</EuiPageContent>
|
||||
</EuiPageBody>
|
||||
|
|
|
@ -54,7 +54,7 @@ interface Props {
|
|||
export const ChangeDataViewModal: FC<Props> = ({ onClose }) => {
|
||||
const {
|
||||
services: {
|
||||
savedObjects,
|
||||
http,
|
||||
uiSettings,
|
||||
data: { dataViews },
|
||||
},
|
||||
|
@ -171,7 +171,7 @@ export const ChangeDataViewModal: FC<Props> = ({ onClose }) => {
|
|||
]}
|
||||
fixedPageSize={fixedPageSize}
|
||||
uiSettings={uiSettings}
|
||||
savedObjects={savedObjects}
|
||||
http={http}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
|
|
@ -19,7 +19,7 @@ export interface PageProps {
|
|||
|
||||
export const Page: FC<PageProps> = ({ nextStepPath }) => {
|
||||
const RESULTS_PER_PAGE = 20;
|
||||
const { uiSettings, savedObjects } = useMlKibana().services;
|
||||
const { uiSettings, http } = useMlKibana().services;
|
||||
const navigateToPath = useNavigateToPath();
|
||||
|
||||
const onObjectSelection = (id: string, type: string) => {
|
||||
|
@ -72,7 +72,7 @@ export const Page: FC<PageProps> = ({ nextStepPath }) => {
|
|||
]}
|
||||
fixedPageSize={RESULTS_PER_PAGE}
|
||||
uiSettings={uiSettings}
|
||||
savedObjects={savedObjects}
|
||||
http={http}
|
||||
/>
|
||||
</EuiPageContent>
|
||||
</EuiPageBody>
|
||||
|
|
|
@ -19,7 +19,7 @@ interface SearchSelectionProps {
|
|||
const fixedPageSize: number = 8;
|
||||
|
||||
export const SearchSelection: FC<SearchSelectionProps> = ({ onSearchSelected }) => {
|
||||
const { uiSettings, savedObjects } = useAppDependencies();
|
||||
const { uiSettings, http } = useAppDependencies();
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -72,7 +72,7 @@ export const SearchSelection: FC<SearchSelectionProps> = ({ onSearchSelected })
|
|||
]}
|
||||
fixedPageSize={fixedPageSize}
|
||||
uiSettings={uiSettings}
|
||||
savedObjects={savedObjects}
|
||||
http={http}
|
||||
/>
|
||||
</EuiModalBody>
|
||||
</>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue