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 6ff7006c1b9b4..368d53ac29ce6 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,7 +42,7 @@ exports[`OpenSearchPanel render 1`] = ` } services={ Object { - "savedObjects": undefined, + "http": undefined, "savedObjectsManagement": 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 665ed87323188..af61b615fdc57 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 @@ -57,7 +57,7 @@ export function OpenSearchPanel(props: OpenSearchPanelProps) { = 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 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 5e19fc5ab469d..bfe35d688b9cf 100644 --- a/src/plugins/saved_objects_finder/kibana.jsonc +++ b/src/plugins/saved_objects_finder/kibana.jsonc @@ -4,7 +4,7 @@ "owner": "@elastic/kibana-data-discovery", "plugin": { "id": "savedObjectsFinder", - "server": false, + "server": true, "browser": true, "requiredBundles": [ "savedObjects" 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 cde6ce1ac0aee..7e560906b8ae9 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 @@ -98,17 +98,17 @@ describe('SavedObjectsFinder', () => { }, } as any as SavedObjectsTaggingApi; - it('should call saved object client on startup', async () => { + it('should call API 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( { wrapper.instance().componentDidMount!(); await nextTick(); - expect(core.savedObjects.client.find).toHaveBeenCalledWith({ - type: ['search'], - fields: ['title', 'name'], - search: undefined, - hasReference: 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, + hasReference: 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( { 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 = mount( { describe('sorting', () => { it('should list items by type ascending', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: [doc, doc3, doc2] }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: [doc, doc3, doc2] }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( { it('should list items by type descending', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: [doc, doc3, doc2] }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: [doc, doc3, doc2] }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( { it('should list items by title 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 = mount( { it('should list items by title 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 = mount( { it('should list items by tag ascending', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: [doc, doc3, doc2] }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: [doc, doc3, doc2] }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( { it('should list items by tag descending', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: [doc, doc3, doc2] }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: [doc, doc3, doc2] }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( { 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( { 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 = mount( { wrapper .find('[data-test-subj="savedObjectFinderSearchInput"] input') .simulate('keyup', { key: 'Enter', target: { value: 'abc' } }); - expect(core.savedObjects.client.find).toHaveBeenCalledWith({ - type: ['search'], - fields: ['title', 'name'], - search: 'abc*', - hasReference: 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: '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.savedObjects.client.find as jest.Mock).mockResolvedValue({ savedObjects: [] }); + (core.http.get as jest.Mock).mockResolvedValue({ saved_objects: [] }); core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( { wrapper .find('[data-test-subj="savedObjectFinderSearchInput"] input') .simulate('keyup', { key: 'Enter', target: { value: 'abc' } }); - expect(core.savedObjects.client.find).toHaveBeenCalledWith({ - type: ['type1', 'type2'], - fields: ['title', 'name', 'field1', 'field2', 'field3'], - search: 'abc*', - hasReference: undefined, - 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*', + hasReference: undefined, + 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 = mount( { 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( { 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', + }, }); }); describe('filter', () => { it('should render filter buttons if enabled', 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); @@ -584,7 +592,7 @@ describe('SavedObjectsFinder', () => { const wrapper = mount( { 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); @@ -613,7 +621,7 @@ describe('SavedObjectsFinder', () => { const wrapper = mount( { it('should not render types filter button if there is only one type in the metadata 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); @@ -640,7 +648,7 @@ describe('SavedObjectsFinder', () => { const wrapper = mount( { it('should not render tags filter button if savedObjectsTagging is undefined', 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); @@ -668,7 +676,7 @@ describe('SavedObjectsFinder', () => { const wrapper = mount( { it('should apply types 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); @@ -696,7 +704,7 @@ describe('SavedObjectsFinder', () => { const wrapper = mount( { const table = wrapper.find>(EuiInMemoryTable); const search = table.prop('search') as EuiSearchBarProps; search.onChange?.({ query: Query.parse('type:(vis)'), queryText: '', error: null }); - expect(core.savedObjects.client.find).toHaveBeenLastCalledWith({ - type: ['vis'], - fields: ['title', 'name'], - search: undefined, - hasReference: undefined, - page: 1, - perPage: 10, - searchFields: ['title^3', 'description'], - defaultSearchOperator: 'AND', + 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', + }, }); search.onChange?.({ query: Query.parse('type:(search or vis)'), queryText: '', error: null }); - expect(core.savedObjects.client.find).toHaveBeenLastCalledWith({ - type: ['search', 'vis'], - fields: ['title', 'name'], - search: undefined, - hasReference: undefined, - page: 1, - perPage: 10, - searchFields: ['title^3', 'description'], - defaultSearchOperator: 'AND', + 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', + }, }); }); it('should apply tags 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); @@ -746,7 +758,7 @@ describe('SavedObjectsFinder', () => { const wrapper = mount( { const table = wrapper.find>(EuiInMemoryTable); const search = table.prop('search') as EuiSearchBarProps; search.onChange?.({ query: Query.parse('tag:(tag1)'), queryText: '', error: null }); - expect(core.savedObjects.client.find).toHaveBeenLastCalledWith({ - type: ['search', 'vis'], - fields: ['title', 'name'], - search: undefined, - hasReference: ['tag1'], - page: 1, - perPage: 10, - searchFields: ['title^3', 'description'], - defaultSearchOperator: 'AND', + expect(core.http.get).toHaveBeenLastCalledWith('/internal/saved-objects-finder/find', { + query: { + type: ['search', 'vis'], + fields: ['title', 'name'], + search: undefined, + hasReference: JSON.stringify(['tag1']), + page: 1, + perPage: 10, + searchFields: ['title^3', 'description'], + defaultSearchOperator: 'AND', + }, }); search.onChange?.({ query: Query.parse('tag:(tag1 or tag2)'), queryText: '', error: null }); - expect(core.savedObjects.client.find).toHaveBeenLastCalledWith({ - type: ['search', 'vis'], - fields: ['title', 'name'], - search: undefined, - hasReference: ['tag1', 'tag2'], - page: 1, - perPage: 10, - searchFields: ['title^3', 'description'], - defaultSearchOperator: 'AND', + expect(core.http.get).toHaveBeenLastCalledWith('/internal/saved-objects-finder/find', { + query: { + type: ['search', 'vis'], + fields: ['title', 'name'], + search: undefined, + hasReference: JSON.stringify(['tag1', 'tag2']), + page: 1, + perPage: 10, + searchFields: ['title^3', 'description'], + defaultSearchOperator: 'AND', + }, }); }); }); 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); @@ -796,7 +812,7 @@ describe('SavedObjectsFinder', () => { const wrapper = mount( { 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 = mount( { 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 = mount( { 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 = mount( { 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 = mount( { 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 = mount( { describe('loading state', () => { it('should display a loading indicator 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: [] }); core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( { it('should hide the loading indicator 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] }) ); core.uiSettings.get.mockImplementation(() => 10); 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.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 = mount( { 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 = mount( { describe('columns', () => { it('should show all columns', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: [doc, doc2, doc3] }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: [doc, doc2, doc3] }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( { it('should hide the type column if there is only one type in the metadata list', 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 = mount( { it('should hide the tags column if savedObjectsTagging is undefined', async () => { const core = coreMock.createStart(); - (core.savedObjects.client.find as any as jest.SpyInstance).mockImplementation(() => - Promise.resolve({ savedObjects: [doc, doc2, doc3] }) + (core.http.get as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ saved_objects: [doc, doc2, doc3] }) ); core.uiSettings.get.mockImplementation(() => 10); const wrapper = mount( { type: string; name: string; - getIconForSavedObject(savedObject: SimpleSavedObject): IconType; - getTooltipForSavedObject?(savedObject: SimpleSavedObject): string; - showSavedObject?(savedObject: SimpleSavedObject): boolean; - getSavedObjectSubType?(savedObject: SimpleSavedObject): string; + getIconForSavedObject(savedObject: SavedObjectCommon): IconType; + getTooltipForSavedObject?(savedObject: SavedObjectCommon): string; + showSavedObject?(savedObject: SavedObjectCommon): boolean; + getSavedObjectSubType?(savedObject: SavedObjectCommon): string; includeFields?: string[]; defaultSearchField?: string; } @@ -51,10 +47,10 @@ interface FinderAttributes { type: string; } -interface SavedObjectFinderItem extends SavedObject { +interface SavedObjectFinderItem extends SavedObjectCommon { title: string | null; name: string | null; - simple: SimpleSavedObject; + simple: SavedObjectCommon; } interface SavedObjectFinderState { @@ -65,7 +61,7 @@ interface SavedObjectFinderState { } interface SavedObjectFinderServices { - savedObjects: SavedObjectsStart; + http: HttpStart; uiSettings: IUiSettingsClient; savedObjectsManagement: SavedObjectsManagementPluginStart; savedObjectsTagging: SavedObjectsTaggingApi | undefined; @@ -74,10 +70,10 @@ interface SavedObjectFinderServices { interface BaseSavedObjectFinder { services: SavedObjectFinderServices; 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>; @@ -136,7 +132,11 @@ export class SavedObjectFinderUi extends React.Component< }, []); const perPage = this.props.services.uiSettings.get(LISTING_LIMIT_SETTING); - const response = await this.props.services.savedObjects.client.find({ + const hasReference = this.props.services.savedObjectsManagement.getTagFindReferences({ + selectedTags, + taggingApi: this.props.services.savedObjectsTagging, + }); + const params: FindQueryHTTP = { type: visibleTypes ?? Object.keys(metaDataMap), fields: [...new Set(fields)], search: queryText ? `${queryText}*` : undefined, @@ -144,13 +144,13 @@ export class SavedObjectFinderUi extends React.Component< perPage, searchFields: ['title^3', 'description', ...additionalSearchFields], defaultSearchOperator: 'AND', - hasReference: this.props.services.savedObjectsManagement.getTagFindReferences({ - selectedTags, - taggingApi: this.props.services.savedObjectsTagging, - }), - }); + hasReference: hasReference ? JSON.stringify(hasReference) : undefined, + }; + const response = (await this.props.services.http.get('/internal/saved-objects-finder/find', { + query: params as Record, + })) as FindResponseHTTP; - const savedObjects = response.savedObjects + const savedObjects = response.saved_objects .map((savedObject) => { const { attributes: { name, title }, @@ -159,7 +159,7 @@ export class SavedObjectFinderUi extends React.Component< const nameToUse = name && typeof name === 'string' ? name : titleToUse; return { ...savedObject, - version: savedObject._version, + version: savedObject.version, title: titleToUse, name: nameToUse, simple: savedObject, @@ -228,7 +228,7 @@ export class SavedObjectFinderUi extends React.Component< const { onChoose, savedObjectMetaData } = this.props; const taggingApi = this.props.services.savedObjectsTagging; const originalTagColumn = taggingApi?.ui.getTableColumnDefinition(); - const tagColumn: EuiTableFieldDataColumnType | undefined = originalTagColumn + const tagColumn: EuiTableFieldDataColumnType | undefined = originalTagColumn ? { ...originalTagColumn, sortable: (item) => diff --git a/src/plugins/saved_objects/server/index.ts b/src/plugins/saved_objects_finder/server/index.ts similarity index 100% rename from src/plugins/saved_objects/server/index.ts rename to src/plugins/saved_objects_finder/server/index.ts diff --git a/src/plugins/saved_objects/server/plugin.test.mocks.ts b/src/plugins/saved_objects_finder/server/plugin.test.mocks.ts similarity index 100% rename from src/plugins/saved_objects/server/plugin.test.mocks.ts rename to src/plugins/saved_objects_finder/server/plugin.test.mocks.ts diff --git a/src/plugins/saved_objects/server/plugin.test.ts b/src/plugins/saved_objects_finder/server/plugin.test.ts similarity index 100% rename from src/plugins/saved_objects/server/plugin.test.ts rename to src/plugins/saved_objects_finder/server/plugin.test.ts diff --git a/src/plugins/saved_objects/server/plugin.ts b/src/plugins/saved_objects_finder/server/plugin.ts similarity index 100% rename from src/plugins/saved_objects/server/plugin.ts rename to src/plugins/saved_objects_finder/server/plugin.ts diff --git a/src/plugins/saved_objects/server/routes/find.ts b/src/plugins/saved_objects_finder/server/routes/find.ts similarity index 94% rename from src/plugins/saved_objects/server/routes/find.ts rename to src/plugins/saved_objects_finder/server/routes/find.ts index 37439429451ed..ce9377ce25333 100644 --- a/src/plugins/saved_objects/server/routes/find.ts +++ b/src/plugins/saved_objects_finder/server/routes/find.ts @@ -27,6 +27,7 @@ export const registerFindRoute = (router: SavedObjectsRouter) => { defaultValue: [], }), searchFields: schema.maybe(schema.arrayOf(schema.string())), + hasReference: schema.maybe(schema.string()), }), }, options: { @@ -44,6 +45,7 @@ export const registerFindRoute = (router: SavedObjectsRouter) => { ...query, type: searchTypes, fields: includedFields, + hasReference: query.hasReference ? JSON.parse(query.hasReference) : undefined, }); const savedObjects = findResponse.saved_objects; diff --git a/src/plugins/saved_objects/server/routes/index.ts b/src/plugins/saved_objects_finder/server/routes/index.ts similarity index 100% rename from src/plugins/saved_objects/server/routes/index.ts rename to src/plugins/saved_objects_finder/server/routes/index.ts diff --git a/src/plugins/saved_objects/server/types.ts b/src/plugins/saved_objects_finder/server/types.ts similarity index 100% rename from src/plugins/saved_objects/server/types.ts rename to src/plugins/saved_objects_finder/server/types.ts diff --git a/src/plugins/saved_objects/server/ui_settings.ts b/src/plugins/saved_objects_finder/server/ui_settings.ts similarity index 76% rename from src/plugins/saved_objects/server/ui_settings.ts rename to src/plugins/saved_objects_finder/server/ui_settings.ts index 6028a1a57f83c..793b76e7e3cf6 100644 --- a/src/plugins/saved_objects/server/ui_settings.ts +++ b/src/plugins/saved_objects_finder/server/ui_settings.ts @@ -14,23 +14,23 @@ import { PER_PAGE_SETTING, LISTING_LIMIT_SETTING } from '../common'; export const uiSettings: Record = { [PER_PAGE_SETTING]: { - name: i18n.translate('savedObjects.advancedSettings.perPageTitle', { + name: i18n.translate('savedObjectsFinder.advancedSettings.perPageTitle', { defaultMessage: 'Objects per page', }), value: 20, type: 'number', - description: i18n.translate('savedObjects.advancedSettings.perPageText', { + description: i18n.translate('savedObjectsFinder.advancedSettings.perPageText', { defaultMessage: 'Number of objects to show per page in the load dialog', }), schema: schema.number(), }, [LISTING_LIMIT_SETTING]: { - name: i18n.translate('savedObjects.advancedSettings.listingLimitTitle', { + name: i18n.translate('savedObjectsFinder.advancedSettings.listingLimitTitle', { defaultMessage: 'Objects listing limit', }), type: 'number', value: 1000, - description: i18n.translate('savedObjects.advancedSettings.listingLimitText', { + description: i18n.translate('savedObjectsFinder.advancedSettings.listingLimitText', { defaultMessage: 'Number of objects to fetch for the listing pages', }), schema: schema.number(), diff --git a/src/plugins/saved_objects_finder/tsconfig.json b/src/plugins/saved_objects_finder/tsconfig.json index 6d3b7ebaa6900..02aa4bf8208ea 100644 --- a/src/plugins/saved_objects_finder/tsconfig.json +++ b/src/plugins/saved_objects_finder/tsconfig.json @@ -11,6 +11,8 @@ "@kbn/saved-objects-tagging-oss-plugin", "@kbn/i18n", "@kbn/saved-objects-plugin", + "@kbn/core-saved-objects-server", + "@kbn/config-schema", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 471ffd12a8cf3..6dae54faebcb0 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -4529,10 +4529,6 @@ "savedObjects.saveModal.saveAsNewLabel": "Enregistrer en tant que nouveau {objectType}", "savedObjects.saveModal.saveTitle": "Enregistrer {objectType}", "savedObjects.saveModalOrigin.originAfterSavingSwitchLabel": "{originVerb} à {origin} après l'enregistrement", - "savedObjects.advancedSettings.listingLimitText": "Nombre d'objets à récupérer pour les pages de listing", - "savedObjects.advancedSettings.listingLimitTitle": "Limite de listing d’objets", - "savedObjects.advancedSettings.perPageText": "Nombre d'objets à afficher par page dans la boîte de dialogue de chargement", - "savedObjects.advancedSettings.perPageTitle": "Objets par page", "savedObjects.confirmModal.cancelButtonLabel": "Annuler", "savedObjects.confirmModal.overwriteButtonLabel": "Écraser", "savedObjects.finder.filterButtonLabel": "Types", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 09b2831430d3f..cb4050c4fe9c8 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -4527,10 +4527,6 @@ "savedObjects.saveModal.saveAsNewLabel": "新しい {objectType} として保存", "savedObjects.saveModal.saveTitle": "{objectType} を保存", "savedObjects.saveModalOrigin.originAfterSavingSwitchLabel": "保存後に{originVerb}から{origin}", - "savedObjects.advancedSettings.listingLimitText": "一覧ページ用に取得するオブジェクトの数です", - "savedObjects.advancedSettings.listingLimitTitle": "オブジェクト取得制限", - "savedObjects.advancedSettings.perPageText": "読み込みダイアログで表示されるページごとのオブジェクトの数です", - "savedObjects.advancedSettings.perPageTitle": "ページごとのオブジェクト数", "savedObjects.confirmModal.cancelButtonLabel": "キャンセル", "savedObjects.confirmModal.overwriteButtonLabel": "上書き", "savedObjects.finder.filterButtonLabel": "タイプ", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 8a3a56e2ba941..f4a5a07bf9a90 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -4532,10 +4532,6 @@ "savedObjects.saveModal.saveAsNewLabel": "另存为新的 {objectType}", "savedObjects.saveModal.saveTitle": "保存 {objectType}", "savedObjects.saveModalOrigin.originAfterSavingSwitchLabel": "保存后{originVerb}至{origin}", - "savedObjects.advancedSettings.listingLimitText": "要为列表页面提取的对象数目", - "savedObjects.advancedSettings.listingLimitTitle": "对象列表限制", - "savedObjects.advancedSettings.perPageText": "加载对话框中每页要显示的对象数目", - "savedObjects.advancedSettings.perPageTitle": "每页对象数", "savedObjects.confirmModal.cancelButtonLabel": "取消", "savedObjects.confirmModal.overwriteButtonLabel": "覆盖", "savedObjects.finder.filterButtonLabel": "类型",