From b7577b5695eebf8e62f151bad7559bc59c346804 Mon Sep 17 00:00:00 2001 From: Jason Stoltzfus Date: Tue, 19 Oct 2021 12:09:51 -0400 Subject: [PATCH] [App Search] Wired up organic results on Curation Suggestions view (#114717) --- .../app_search/components/curations/types.ts | 10 +- .../curation_suggestion.test.tsx | 129 +++-- .../curation_suggestion.tsx | 37 +- .../curation_suggestion_logic.test.ts | 259 ++++------ .../curation_suggestion_logic.ts | 147 ++---- .../views/curation_suggestion/temp_data.ts | 470 ------------------ .../search_relevance_suggestions.test.ts | 7 +- .../search_relevance_suggestions.ts | 15 +- 8 files changed, 274 insertions(+), 800 deletions(-) delete mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/temp_data.ts diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/types.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/types.ts index 7479505ea86da..b67664d8efde2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/types.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/types.ts @@ -13,11 +13,19 @@ export interface CurationSuggestion { updated_at: string; promoted: string[]; status: 'pending' | 'applied' | 'automated' | 'rejected' | 'disabled'; - curation_id?: string; + curation_id?: string; // The id of an existing curation that this suggestion would affect operation: 'create' | 'update' | 'delete'; override_manual_curation?: boolean; } +// A curation suggestion with linked ids hydrated with actual values +export interface HydratedCurationSuggestion + extends Omit { + organic: Curation['organic']; + promoted: Curation['promoted']; + curation?: Curation; +} + export interface Curation { id: string; last_updated: string; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion.test.tsx index 1c3f4645d89e9..604d2930a4b5d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion.test.tsx @@ -14,6 +14,8 @@ import React from 'react'; import { shallow } from 'enzyme'; +import { EuiEmptyPrompt } from '@elastic/eui'; + import { AppSearchPageTemplate } from '../../../layout'; import { Result } from '../../../result'; @@ -26,44 +28,29 @@ describe('CurationSuggestion', () => { suggestion: { query: 'foo', updated_at: '2021-07-08T14:35:50Z', - promoted: ['1', '2', '3'], - }, - suggestedPromotedDocuments: [ - { - id: { - raw: '1', - }, - _meta: { - id: '1', - engine: 'some-engine', - }, - }, - { - id: { - raw: '2', - }, - _meta: { - id: '2', - engine: 'some-engine', - }, - }, - { - id: { - raw: '3', - }, - _meta: { - id: '3', - engine: 'some-engine', - }, - }, - ], - curation: { - promoted: [ + promoted: [{ id: '4', foo: 'foo' }], + organic: [ { - id: '4', - foo: 'foo', + id: { raw: '3', snippet: null }, + foo: { raw: 'bar', snippet: null }, + _meta: { id: '3' }, }, ], + curation: { + promoted: [{ id: '1', foo: 'foo' }], + organic: [ + { + id: { raw: '5', snippet: null }, + foo: { raw: 'bar', snippet: null }, + _meta: { id: '5' }, + }, + { + id: { raw: '6', snippet: null }, + foo: { raw: 'bar', snippet: null }, + _meta: { id: '6' }, + }, + ], + }, }, isMetaEngine: true, engine: { @@ -99,11 +86,10 @@ describe('CurationSuggestion', () => { it('shows existing promoted documents', () => { const wrapper = shallow(); const suggestedResultsPanel = wrapper.find(CurationResultPanel).at(0); - // gets populated from 'curation' in state, and converted to results format (i.e, has raw properties, etc.) expect(suggestedResultsPanel.prop('results')).toEqual([ { id: { - raw: '4', + raw: '1', snippet: null, }, foo: { @@ -111,7 +97,7 @@ describe('CurationSuggestion', () => { snippet: null, }, _meta: { - id: '4', + id: '1', }, }, ]); @@ -120,7 +106,21 @@ describe('CurationSuggestion', () => { it('shows suggested promoted documents', () => { const wrapper = shallow(); const suggestedResultsPanel = wrapper.find(CurationResultPanel).at(1); - expect(suggestedResultsPanel.prop('results')).toEqual(values.suggestedPromotedDocuments); + expect(suggestedResultsPanel.prop('results')).toEqual([ + { + id: { + raw: '4', + snippet: null, + }, + foo: { + raw: 'foo', + snippet: null, + }, + _meta: { + id: '4', + }, + }, + ]); }); it('displays the query in the title', () => { @@ -142,9 +142,15 @@ describe('CurationSuggestion', () => { it('displays proposed organic results', () => { const wrapper = shallow(); wrapper.find('[data-test-subj="showOrganicResults"]').simulate('click'); - expect(wrapper.find('[data-test-subj="proposedOrganicResults"]').find(Result).length).toBe(4); - expect(wrapper.find(Result).at(0).prop('isMetaEngine')).toEqual(true); - expect(wrapper.find(Result).at(0).prop('schemaForTypeHighlights')).toEqual( + const resultsWrapper = wrapper.find('[data-test-subj="proposedOrganicResults"]').find(Result); + expect(resultsWrapper.length).toBe(1); + expect(resultsWrapper.find(Result).at(0).prop('result')).toEqual({ + id: { raw: '3', snippet: null }, + foo: { raw: 'bar', snippet: null }, + _meta: { id: '3' }, + }); + expect(resultsWrapper.find(Result).at(0).prop('isMetaEngine')).toEqual(true); + expect(resultsWrapper.find(Result).at(0).prop('schemaForTypeHighlights')).toEqual( values.engine.schema ); }); @@ -152,10 +158,43 @@ describe('CurationSuggestion', () => { it('displays current organic results', () => { const wrapper = shallow(); wrapper.find('[data-test-subj="showOrganicResults"]').simulate('click'); - expect(wrapper.find('[data-test-subj="currentOrganicResults"]').find(Result).length).toBe(4); - expect(wrapper.find(Result).at(0).prop('isMetaEngine')).toEqual(true); - expect(wrapper.find(Result).at(0).prop('schemaForTypeHighlights')).toEqual( + const resultWrapper = wrapper.find('[data-test-subj="currentOrganicResults"]').find(Result); + expect(resultWrapper.length).toBe(2); + expect(resultWrapper.find(Result).at(0).prop('result')).toEqual({ + id: { raw: '5', snippet: null }, + foo: { raw: 'bar', snippet: null }, + _meta: { id: '5' }, + }); + expect(resultWrapper.find(Result).at(0).prop('isMetaEngine')).toEqual(true); + expect(resultWrapper.find(Result).at(0).prop('schemaForTypeHighlights')).toEqual( values.engine.schema ); }); + + it('shows an empty prompt when there are no organic results', () => { + setMockValues({ + ...values, + suggestion: { + ...values.suggestion, + organic: [], + curation: { + ...values.suggestion.curation, + organic: [], + }, + }, + }); + const wrapper = shallow(); + wrapper.find('[data-test-subj="showOrganicResults"]').simulate('click'); + expect(wrapper.find('[data-test-subj="currentOrganicResults"]').exists()).toBe(false); + expect(wrapper.find('[data-test-subj="proposedOrganicResults"]').exists()).toBe(false); + expect(wrapper.find(EuiEmptyPrompt).exists()).toBe(true); + }); + + it('renders even if no data is set yet', () => { + setMockValues({ + suggestion: null, + }); + const wrapper = shallow(); + expect(wrapper.find(AppSearchPageTemplate).exists()).toBe(true); + }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion.tsx index 7539055253732..4e344d8cc2a39 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion.tsx @@ -11,6 +11,7 @@ import { useActions, useValues } from 'kea'; import { EuiButtonEmpty, + EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, @@ -20,6 +21,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { LeafIcon } from '../../../../../shared/icons'; import { useDecodedParams } from '../../../../utils/encode_path_params'; import { EngineLogic } from '../../../engine'; import { AppSearchPageTemplate } from '../../../layout'; @@ -32,19 +34,23 @@ import { CurationActionBar } from './curation_action_bar'; import { CurationResultPanel } from './curation_result_panel'; import { CurationSuggestionLogic } from './curation_suggestion_logic'; -import { DATA } from './temp_data'; export const CurationSuggestion: React.FC = () => { const { query } = useDecodedParams(); const { engine, isMetaEngine } = useValues(EngineLogic); const curationSuggestionLogic = CurationSuggestionLogic({ query }); const { loadSuggestion } = useActions(curationSuggestionLogic); - const { suggestion, suggestedPromotedDocuments, curation, dataLoading } = - useValues(curationSuggestionLogic); + const { suggestion, dataLoading } = useValues(curationSuggestionLogic); const [showOrganicResults, setShowOrganicResults] = useState(false); - const currentOrganicResults = [...DATA].splice(5, 4); - const proposedOrganicResults = [...DATA].splice(2, 4); - const existingCurationResults = curation ? curation.promoted.map(convertToResultFormat) : []; + const currentOrganicResults = suggestion?.curation?.organic || []; + const proposedOrganicResults = suggestion?.organic || []; + const totalNumberOfOrganicResults = currentOrganicResults.length + proposedOrganicResults.length; + const existingCurationResults = suggestion?.curation + ? suggestion.curation.promoted.map(convertToResultFormat) + : []; + const suggestedPromotedDocuments = suggestion?.promoted + ? suggestion?.promoted.map(convertToResultFormat) + : []; const suggestionQuery = suggestion?.query || ''; @@ -114,7 +120,24 @@ export const CurationSuggestion: React.FC = () => { { defaultMessage: 'Expand organic search results' } )} - {showOrganicResults && ( + {showOrganicResults && totalNumberOfOrganicResults === 0 && ( + + {i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.curations.suggestedCuration.noOrganicResultsTitle', + { defaultMessage: 'No results' } + )} + + } + body={i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.curations.suggestedCuration.noOrganicResultsDescription', + { defaultMessage: 'No organic search results were returned for this query' } + )} + /> + )} + {showOrganicResults && totalNumberOfOrganicResults > 0 && ( <> diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.test.ts index 7a91171cc2cc7..e6a847f6e9ec6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.test.ts @@ -12,109 +12,141 @@ import { mockKibanaValues, } from '../../../../../__mocks__/kea_logic'; -import { set } from 'lodash/fp'; - import '../../../../__mocks__/engine_logic.mock'; import { nextTick } from '@kbn/test/jest'; -import { CurationSuggestion } from '../../types'; +import { HydratedCurationSuggestion } from '../../types'; import { CurationSuggestionLogic } from './curation_suggestion_logic'; const DEFAULT_VALUES = { dataLoading: true, suggestion: null, - suggestedPromotedDocuments: [], - curation: null, }; -const suggestion: CurationSuggestion = { +const suggestion: HydratedCurationSuggestion = { query: 'foo', updated_at: '2021-07-08T14:35:50Z', - promoted: ['1', '2', '3'], - status: 'pending', - operation: 'create', -}; - -const curation = { - id: 'cur-6155e69c7a2f2e4f756303fd', - queries: ['foo'], promoted: [ { - id: '5', - }, - ], - hidden: [], - last_updated: 'September 30, 2021 at 04:32PM', - organic: [], -}; - -const suggestedPromotedDocuments = [ - { - id: { - raw: '1', - }, - _meta: { id: '1', - engine: 'some-engine', - }, - }, - { - id: { - raw: '2', }, - _meta: { + { id: '2', - engine: 'some-engine', - }, - }, - { - id: { - raw: '3', }, - _meta: { + { id: '3', - engine: 'some-engine', - }, - }, -]; - -const MOCK_RESPONSE = { - meta: { - page: { - current: 1, - size: 10, - total_results: 1, - total_pages: 1, }, + ], + status: 'pending', + operation: 'create', + curation: { + id: 'cur-6155e69c7a2f2e4f756303fd', + queries: ['foo'], + promoted: [ + { + id: '5', + }, + ], + hidden: [], + last_updated: 'September 30, 2021 at 04:32PM', + organic: [ + { + id: { + raw: '1', + }, + _meta: { + id: '1', + engine: 'some-engine', + }, + }, + ], }, - results: [suggestion], -}; - -const MOCK_DOCUMENTS_RESPONSE = { - results: [ + organic: [ { id: { - raw: '2', + raw: '1', }, _meta: { - id: '2', + id: '1', engine: 'some-engine', }, }, { id: { - raw: '1', + raw: '2', }, _meta: { - id: '1', + id: '2', engine: 'some-engine', }, }, ], }; +const MOCK_RESPONSE = { + query: 'foo', + status: 'pending', + updated_at: '2021-07-08T14:35:50Z', + operation: 'create', + suggestion: { + promoted: [ + { + id: '1', + }, + { + id: '2', + }, + { + id: '3', + }, + ], + organic: [ + { + id: { + raw: '1', + }, + _meta: { + id: '1', + engine: 'some-engine', + }, + }, + { + id: { + raw: '2', + }, + _meta: { + id: '2', + engine: 'some-engine', + }, + }, + ], + }, + curation: { + id: 'cur-6155e69c7a2f2e4f756303fd', + queries: ['foo'], + promoted: [ + { + id: '5', + }, + ], + hidden: [], + last_updated: 'September 30, 2021 at 04:32PM', + organic: [ + { + id: { + raw: '1', + }, + _meta: { + id: '1', + engine: 'some-engine', + }, + }, + ], + }, +}; + describe('CurationSuggestionLogic', () => { const { mount } = new LogicMounter(CurationSuggestionLogic); const { flashAPIErrors, setQueuedErrorMessage } = mockFlashMessageHelpers; @@ -177,14 +209,10 @@ describe('CurationSuggestionLogic', () => { mountLogic(); CurationSuggestionLogic.actions.onSuggestionLoaded({ suggestion, - suggestedPromotedDocuments, - curation, }); expect(CurationSuggestionLogic.values).toEqual({ ...DEFAULT_VALUES, suggestion, - suggestedPromotedDocuments, - curation, dataLoading: false, }); }); @@ -205,100 +233,24 @@ describe('CurationSuggestionLogic', () => { }); it('should make API calls to fetch data and trigger onSuggestionLoaded', async () => { - http.post.mockReturnValueOnce(Promise.resolve(MOCK_RESPONSE)); - http.post.mockReturnValueOnce(Promise.resolve(MOCK_DOCUMENTS_RESPONSE)); + http.get.mockReturnValueOnce(Promise.resolve(MOCK_RESPONSE)); mountLogic(); jest.spyOn(CurationSuggestionLogic.actions, 'onSuggestionLoaded'); CurationSuggestionLogic.actions.loadSuggestion(); await nextTick(); - expect(http.post).toHaveBeenCalledWith( + expect(http.get).toHaveBeenCalledWith( '/internal/app_search/engines/some-engine/search_relevance_suggestions/foo-query', { - body: JSON.stringify({ - page: { - current: 1, - size: 1, - }, - filters: { - status: ['pending'], - type: 'curation', - }, - }), - } - ); - - expect(http.post).toHaveBeenCalledWith('/internal/app_search/engines/some-engine/search', { - query: { query: '' }, - body: JSON.stringify({ - page: { - size: 100, - }, - filters: { - // The results of the first API call are used to make the second http call for document details - id: MOCK_RESPONSE.results[0].promoted, - }, - }), - }); - - expect(CurationSuggestionLogic.actions.onSuggestionLoaded).toHaveBeenCalledWith({ - suggestion: { - query: 'foo', - updated_at: '2021-07-08T14:35:50Z', - promoted: ['1', '2', '3'], - status: 'pending', - operation: 'create', - }, - // Note that these were re-ordered to match the 'promoted' list above, and since document - // 3 was not found it is not included in this list - suggestedPromotedDocuments: [ - { - id: { - raw: '1', - }, - _meta: { - id: '1', - engine: 'some-engine', - }, - }, - { - id: { - raw: '2', - }, - _meta: { - id: '2', - engine: 'some-engine', - }, + query: { + type: 'curation', }, - ], - curation: null, - }); - }); - - it('will also fetch curation details if the suggestion has a curation_id', async () => { - http.post.mockReturnValueOnce( - Promise.resolve( - set('results[0].curation_id', 'cur-6155e69c7a2f2e4f756303fd', MOCK_RESPONSE) - ) - ); - http.post.mockReturnValueOnce(Promise.resolve(MOCK_DOCUMENTS_RESPONSE)); - http.get.mockReturnValueOnce(Promise.resolve(curation)); - mountLogic(); - jest.spyOn(CurationSuggestionLogic.actions, 'onSuggestionLoaded'); - - CurationSuggestionLogic.actions.loadSuggestion(); - await nextTick(); - - expect(http.get).toHaveBeenCalledWith( - '/internal/app_search/engines/some-engine/curations/cur-6155e69c7a2f2e4f756303fd', - { query: { skip_record_analytics: 'true' } } + } ); expect(CurationSuggestionLogic.actions.onSuggestionLoaded).toHaveBeenCalledWith({ - suggestion: expect.any(Object), - suggestedPromotedDocuments: expect.any(Object), - curation, + suggestion, }); }); @@ -306,7 +258,12 @@ describe('CurationSuggestionLogic', () => { // the back button, etc. The suggestion still exists, it's just not in a "pending" state // so we can show it.ga it('will redirect if the suggestion is not found', async () => { - http.post.mockReturnValueOnce(Promise.resolve(set('results', [], MOCK_RESPONSE))); + http.get.mockReturnValueOnce( + Promise.reject({ + response: { status: 404 }, + }) + ); + mountLogic(); CurationSuggestionLogic.actions.loadSuggestion(); await nextTick(); @@ -314,7 +271,7 @@ describe('CurationSuggestionLogic', () => { expect(navigateToUrl).toHaveBeenCalledWith('/engines/some-engine/curations'); }); - itHandlesErrors(http.post, () => { + itHandlesErrors(http.get, () => { CurationSuggestionLogic.actions.loadSuggestion(); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.ts index 4ca1b0adb7814..b206c0c79ed26 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_suggestion_logic.ts @@ -19,33 +19,20 @@ import { HttpLogic } from '../../../../../shared/http'; import { KibanaLogic } from '../../../../../shared/kibana'; import { ENGINE_CURATIONS_PATH, ENGINE_CURATION_PATH } from '../../../../routes'; import { EngineLogic, generateEnginePath } from '../../../engine'; -import { Result } from '../../../result/types'; -import { Curation, CurationSuggestion } from '../../types'; +import { CurationSuggestion, HydratedCurationSuggestion } from '../../types'; interface Error { error: string; } interface CurationSuggestionValues { dataLoading: boolean; - suggestion: CurationSuggestion | null; - suggestedPromotedDocuments: Result[]; - curation: Curation | null; + suggestion: HydratedCurationSuggestion | null; } interface CurationSuggestionActions { loadSuggestion(): void; - onSuggestionLoaded({ - suggestion, - suggestedPromotedDocuments, - curation, - }: { - suggestion: CurationSuggestion; - suggestedPromotedDocuments: Result[]; - curation: Curation; - }): { - suggestion: CurationSuggestion; - suggestedPromotedDocuments: Result[]; - curation: Curation; + onSuggestionLoaded({ suggestion }: { suggestion: HydratedCurationSuggestion }): { + suggestion: HydratedCurationSuggestion; }; acceptSuggestion(): void; acceptAndAutomateSuggestion(): void; @@ -63,10 +50,8 @@ export const CurationSuggestionLogic = kea< path: ['enterprise_search', 'app_search', 'curations', 'suggestion_logic'], actions: () => ({ loadSuggestion: true, - onSuggestionLoaded: ({ suggestion, suggestedPromotedDocuments, curation }) => ({ + onSuggestionLoaded: ({ suggestion }) => ({ suggestion, - suggestedPromotedDocuments, - curation, }), acceptSuggestion: true, acceptAndAutomateSuggestion: true, @@ -87,18 +72,6 @@ export const CurationSuggestionLogic = kea< onSuggestionLoaded: (_, { suggestion }) => suggestion, }, ], - suggestedPromotedDocuments: [ - [], - { - onSuggestionLoaded: (_, { suggestedPromotedDocuments }) => suggestedPromotedDocuments, - }, - ], - curation: [ - null, - { - onSuggestionLoaded: (_, { curation }) => curation, - }, - ], }), listeners: ({ actions, values, props }) => ({ loadSuggestion: async () => { @@ -106,34 +79,41 @@ export const CurationSuggestionLogic = kea< const { engineName } = EngineLogic.values; try { - const suggestion = await getSuggestion(http, engineName, props.query); - if (!suggestion) return; - const promotedIds: string[] = suggestion.promoted; - const documentDetailsResopnse = getDocumentDetails(http, engineName, promotedIds); - - let promises = [documentDetailsResopnse]; - if (suggestion.curation_id) { - promises = [...promises, getCuration(http, engineName, suggestion.curation_id)]; - } - - const [documentDetails, curation] = await Promise.all(promises); + const suggestionResponse = await http.get( + `/internal/app_search/engines/${engineName}/search_relevance_suggestions/${props.query}`, + { + query: { + type: 'curation', + }, + } + ); - // Filter out docs that were not found and maintain promoted order - const suggestedPromotedDocuments = promotedIds.reduce((acc: Result[], id: string) => { - const found = documentDetails.results.find( - (documentDetail: Result) => documentDetail.id.raw === id - ); - if (!found) return acc; - return [...acc, found]; - }, []); + // We pull the `organic` and `promoted` fields up to the main body of the suggestion, + // out of the nested `suggestion` field on the response + const { suggestion, ...baseSuggestion } = suggestionResponse; + const suggestionData = { + ...baseSuggestion, + promoted: suggestion.promoted, + organic: suggestion.organic, + }; actions.onSuggestionLoaded({ - suggestion, - suggestedPromotedDocuments, - curation: curation || null, + suggestion: suggestionData, }); } catch (e) { - flashAPIErrors(e); + if (e.response?.status === 404) { + const message = i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.curations.suggestedCuration.notFoundError', + { + defaultMessage: + 'Could not find suggestion, it may have already been applied or rejected.', + } + ); + setQueuedErrorMessage(message); + KibanaLogic.values.navigateToUrl(generateEnginePath(ENGINE_CURATIONS_PATH)); + } else { + flashAPIErrors(e); + } } }, acceptSuggestion: async () => { @@ -289,63 +269,6 @@ const updateSuggestion = async ( return response.results[0] as CurationSuggestion; }; -const getSuggestion = async ( - http: HttpSetup, - engineName: string, - query: string -): Promise => { - const response = await http.post( - `/internal/app_search/engines/${engineName}/search_relevance_suggestions/${query}`, - { - body: JSON.stringify({ - page: { - current: 1, - size: 1, - }, - filters: { - status: ['pending'], - type: 'curation', - }, - }), - } - ); - - if (response.results.length < 1) { - const message = i18n.translate( - 'xpack.enterpriseSearch.appSearch.engine.curations.suggestedCuration.notFoundError', - { - defaultMessage: 'Could not find suggestion, it may have already been applied or rejected.', - } - ); - setQueuedErrorMessage(message); - KibanaLogic.values.navigateToUrl(generateEnginePath(ENGINE_CURATIONS_PATH)); - return; - } - - const suggestion = response.results[0] as CurationSuggestion; - return suggestion; -}; - -const getDocumentDetails = async (http: HttpSetup, engineName: string, documentIds: string[]) => { - return http.post(`/internal/app_search/engines/${engineName}/search`, { - query: { query: '' }, - body: JSON.stringify({ - page: { - size: 100, - }, - filters: { - id: documentIds, - }, - }), - }); -}; - -const getCuration = async (http: HttpSetup, engineName: string, curationId: string) => { - return http.get(`/internal/app_search/engines/${engineName}/curations/${curationId}`, { - query: { skip_record_analytics: 'true' }, - }); -}; - const confirmDialog = (msg: string) => { return new Promise(function (resolve) { const confirmed = window.confirm(msg); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/temp_data.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/temp_data.ts deleted file mode 100644 index 83bbc977427a9..0000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/temp_data.ts +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { Result } from '../../../result/types'; - -export const DATA: Result[] = [ - { - visitors: { - raw: 5028868.0, - }, - square_km: { - raw: 3082.7, - }, - world_heritage_site: { - raw: 'true', - snippet: 'true', - }, - date_established: { - raw: '1890-10-01T05:00:00+00:00', - }, - description: { - raw: "Yosemite features sheer granite cliffs, exceptionally tall waterfalls, and old-growth forests at a unique intersection of geology and hydrology. Half Dome and El Capitan rise from the park's centerpiece, the glacier-carved Yosemite Valley, and from its vertical walls drop Yosemite Falls, one of North America's tallest waterfalls at 2,425 feet (739 m) high. Three giant sequoia groves, along with a pristine wilderness in the heart of the Sierra Nevada, are home to a wide variety of rare plant and animal species.", - snippet: - 'Yosemite features sheer granite cliffs, exceptionally tall waterfalls, and old-growth forests', - }, - location: { - raw: '37.83,-119.5', - }, - acres: { - raw: 761747.5, - }, - title: { - raw: 'Yosemite', - snippet: 'Yosemite', - }, - nps_link: { - raw: 'https://www.nps.gov/yose/index.htm', - snippet: 'https://www.nps.gov/yose/index.htm', - }, - states: { - raw: ['California'], - snippet: 'California', - }, - _meta: { - engine: 'national-parks-demo', - score: 7543305.0, - id: 'park_yosemite', - }, - id: { - raw: 'park_yosemite', - }, - }, - { - visitors: { - raw: 4517585.0, - }, - square_km: { - raw: 1075.6, - }, - world_heritage_site: { - raw: 'false', - snippet: 'false', - }, - date_established: { - raw: '1915-01-26T06:00:00+00:00', - }, - description: { - raw: 'Bisected north to south by the Continental Divide, this portion of the Rockies has ecosystems varying from over 150 riparian lakes to montane and subalpine forests to treeless alpine tundra. Wildlife including mule deer, bighorn sheep, black bears, and cougars inhabit its igneous mountains and glacial valleys. Longs Peak, a classic Colorado fourteener, and the scenic Bear Lake are popular destinations, as well as the historic Trail Ridge Road, which reaches an elevation of more than 12,000 feet (3,700 m).', - snippet: - ' varying from over 150 riparian lakes to montane and subalpine forests to treeless alpine tundra. Wildlife', - }, - location: { - raw: '40.4,-105.58', - }, - acres: { - raw: 265795.2, - }, - title: { - raw: 'Rocky Mountain', - snippet: 'Rocky Mountain', - }, - nps_link: { - raw: 'https://www.nps.gov/romo/index.htm', - snippet: 'https://www.nps.gov/romo/index.htm', - }, - states: { - raw: ['Colorado'], - snippet: 'Colorado', - }, - _meta: { - engine: 'national-parks-demo', - score: 6776380.0, - id: 'park_rocky-mountain', - }, - id: { - raw: 'park_rocky-mountain', - }, - }, - { - visitors: { - raw: 4295127.0, - }, - square_km: { - raw: 595.8, - }, - world_heritage_site: { - raw: 'false', - snippet: 'false', - }, - date_established: { - raw: '1919-11-19T06:00:00+00:00', - }, - description: { - raw: 'Located at the junction of the Colorado Plateau, Great Basin, and Mojave Desert, this park contains sandstone features such as mesas, rock towers, and canyons, including the Virgin River Narrows. The various sandstone formations and the forks of the Virgin River create a wilderness divided into four ecosystems: desert, riparian, woodland, and coniferous forest.', - snippet: ' into four ecosystems: desert, riparian, woodland, and coniferous forest.', - }, - location: { - raw: '37.3,-113.05', - }, - acres: { - raw: 147237.02, - }, - title: { - raw: 'Zion', - snippet: 'Zion', - }, - nps_link: { - raw: 'https://www.nps.gov/zion/index.htm', - snippet: 'https://www.nps.gov/zion/index.htm', - }, - states: { - raw: ['Utah'], - snippet: 'Utah', - }, - _meta: { - engine: 'national-parks-demo', - score: 6442695.0, - id: 'park_zion', - }, - id: { - raw: 'park_zion', - }, - }, - { - visitors: { - raw: 3303393.0, - }, - square_km: { - raw: 198.5, - }, - world_heritage_site: { - raw: 'false', - snippet: 'false', - }, - date_established: { - raw: '1919-02-26T06:00:00+00:00', - }, - description: { - raw: 'Covering most of Mount Desert Island and other coastal islands, Acadia features the tallest mountain on the Atlantic coast of the United States, granite peaks, ocean shoreline, woodlands, and lakes. There are freshwater, estuary, forest, and intertidal habitats.', - snippet: - ' mountain on the Atlantic coast of the United States, granite peaks, ocean shoreline, woodlands, and lakes. There are freshwater, estuary, forest, and intertidal habitats.', - }, - location: { - raw: '44.35,-68.21', - }, - acres: { - raw: 49057.36, - }, - title: { - raw: 'Acadia', - snippet: 'Acadia', - }, - nps_link: { - raw: 'https://www.nps.gov/acad/index.htm', - snippet: 'https://www.nps.gov/acad/index.htm', - }, - states: { - raw: ['Maine'], - snippet: 'Maine', - }, - _meta: { - engine: 'national-parks-demo', - score: 4955094.5, - id: 'park_acadia', - }, - id: { - raw: 'park_acadia', - }, - }, - { - visitors: { - raw: 1887580.0, - }, - square_km: { - raw: 1308.9, - }, - world_heritage_site: { - raw: 'true', - snippet: 'true', - }, - date_established: { - raw: '1916-08-01T05:00:00+00:00', - }, - description: { - raw: "This park on the Big Island protects the KÄ«lauea and Mauna Loa volcanoes, two of the world's most active geological features. Diverse ecosystems range from tropical forests at sea level to barren lava beds at more than 13,000 feet (4,000 m).", - snippet: - ' active geological features. Diverse ecosystems range from tropical forests at sea level to barren lava beds at more than 13,000 feet (4,000 m).', - }, - location: { - raw: '19.38,-155.2', - }, - acres: { - raw: 323431.38, - }, - title: { - raw: 'Hawaii Volcanoes', - snippet: 'Hawaii Volcanoes', - }, - nps_link: { - raw: 'https://www.nps.gov/havo/index.htm', - snippet: 'https://www.nps.gov/havo/index.htm', - }, - states: { - raw: ['Hawaii'], - snippet: 'Hawaii', - }, - _meta: { - engine: 'national-parks-demo', - score: 2831373.2, - id: 'park_hawaii-volcanoes', - }, - id: { - raw: 'park_hawaii-volcanoes', - }, - }, - { - visitors: { - raw: 1437341.0, - }, - square_km: { - raw: 806.1, - }, - world_heritage_site: { - raw: 'false', - snippet: 'false', - }, - date_established: { - raw: '1935-12-26T06:00:00+00:00', - }, - description: { - raw: "Shenandoah's Blue Ridge Mountains are covered by hardwood forests that teem with a wide variety of wildlife. The Skyline Drive and Appalachian Trail run the entire length of this narrow park, along with more than 500 miles (800 km) of hiking trails passing scenic overlooks and cataracts of the Shenandoah River.", - snippet: - 'Shenandoah's Blue Ridge Mountains are covered by hardwood forests that teem with a wide variety', - }, - location: { - raw: '38.53,-78.35', - }, - acres: { - raw: 199195.27, - }, - title: { - raw: 'Shenandoah', - snippet: 'Shenandoah', - }, - nps_link: { - raw: 'https://www.nps.gov/shen/index.htm', - snippet: 'https://www.nps.gov/shen/index.htm', - }, - states: { - raw: ['Virginia'], - snippet: 'Virginia', - }, - _meta: { - engine: 'national-parks-demo', - score: 2156015.5, - id: 'park_shenandoah', - }, - id: { - raw: 'park_shenandoah', - }, - }, - { - visitors: { - raw: 1356913.0, - }, - square_km: { - raw: 956.6, - }, - world_heritage_site: { - raw: 'false', - snippet: 'false', - }, - date_established: { - raw: '1899-03-02T06:00:00+00:00', - }, - description: { - raw: 'Mount Rainier, an active stratovolcano, is the most prominent peak in the Cascades and is covered by 26 named glaciers including Carbon Glacier and Emmons Glacier, the largest in the contiguous United States. The mountain is popular for climbing, and more than half of the park is covered by subalpine and alpine forests and meadows seasonally in bloom with wildflowers. Paradise on the south slope is the snowiest place on Earth where snowfall is measured regularly. The Longmire visitor center is the start of the Wonderland Trail, which encircles the mountain.', - snippet: - ' by subalpine and alpine forests and meadows seasonally in bloom with wildflowers. Paradise on the south slope', - }, - location: { - raw: '46.85,-121.75', - }, - acres: { - raw: 236381.64, - }, - title: { - raw: 'Mount Rainier', - snippet: 'Mount Rainier', - }, - nps_link: { - raw: 'https://www.nps.gov/mora/index.htm', - snippet: 'https://www.nps.gov/mora/index.htm', - }, - states: { - raw: ['Washington'], - snippet: 'Washington', - }, - _meta: { - engine: 'national-parks-demo', - score: 2035372.0, - id: 'park_mount-rainier', - }, - id: { - raw: 'park_mount-rainier', - }, - }, - { - visitors: { - raw: 1254688.0, - }, - square_km: { - raw: 1635.2, - }, - world_heritage_site: { - raw: 'false', - snippet: 'false', - }, - date_established: { - raw: '1890-09-25T05:00:00+00:00', - }, - description: { - raw: "This park protects the Giant Forest, which boasts some of the world's largest trees, the General Sherman being the largest measured tree in the park. Other features include over 240 caves, a long segment of the Sierra Nevada including the tallest mountain in the contiguous United States, and Moro Rock, a large granite dome.", - snippet: - 'This park protects the Giant Forest, which boasts some of the world's largest trees, the General', - }, - location: { - raw: '36.43,-118.68', - }, - acres: { - raw: 404062.63, - }, - title: { - raw: 'Sequoia', - snippet: 'Sequoia', - }, - nps_link: { - raw: 'https://www.nps.gov/seki/index.htm', - snippet: 'https://www.nps.gov/seki/index.htm', - }, - states: { - raw: ['California'], - snippet: 'California', - }, - _meta: { - engine: 'national-parks-demo', - score: 1882038.0, - id: 'park_sequoia', - }, - id: { - raw: 'park_sequoia', - }, - }, - { - visitors: { - raw: 643274.0, - }, - square_km: { - raw: 896.0, - }, - world_heritage_site: { - raw: 'false', - snippet: 'false', - }, - date_established: { - raw: '1962-12-09T06:00:00+00:00', - }, - description: { - raw: 'This portion of the Chinle Formation has a large concentration of 225-million-year-old petrified wood. The surrounding Painted Desert features eroded cliffs of red-hued volcanic rock called bentonite. Dinosaur fossils and over 350 Native American sites are also protected in this park.', - snippet: - 'This portion of the Chinle Formation has a large concentration of 225-million-year-old petrified', - }, - location: { - raw: '35.07,-109.78', - }, - acres: { - raw: 221415.77, - }, - title: { - raw: 'Petrified Forest', - snippet: 'Petrified Forest', - }, - nps_link: { - raw: 'https://www.nps.gov/pefo/index.htm', - snippet: 'https://www.nps.gov/pefo/index.htm', - }, - states: { - raw: ['Arizona'], - snippet: 'Arizona', - }, - _meta: { - engine: 'national-parks-demo', - score: 964919.94, - id: 'park_petrified-forest', - }, - id: { - raw: 'park_petrified-forest', - }, - }, - { - visitors: { - raw: 617377.0, - }, - square_km: { - raw: 137.5, - }, - world_heritage_site: { - raw: 'false', - snippet: 'false', - }, - date_established: { - raw: '1903-01-09T06:00:00+00:00', - }, - description: { - raw: "Wind Cave is distinctive for its calcite fin formations called boxwork, a unique formation rarely found elsewhere, and needle-like growths called frostwork. The cave is one of the longest and most complex caves in the world. Above ground is a mixed-grass prairie with animals such as bison, black-footed ferrets, and prairie dogs, and ponderosa pine forests that are home to cougars and elk. The cave is culturally significant to the Lakota people as the site 'from which Wakan Tanka, the Great Mystery, sent the buffalo out into their hunting grounds.'", - snippet: - '-footed ferrets, and prairie dogs, and ponderosa pine forests that are home to cougars and elk', - }, - location: { - raw: '43.57,-103.48', - }, - acres: { - raw: 33970.84, - }, - title: { - raw: 'Wind Cave', - snippet: 'Wind Cave', - }, - nps_link: { - raw: 'https://www.nps.gov/wica/index.htm', - snippet: 'https://www.nps.gov/wica/index.htm', - }, - states: { - raw: ['South Dakota'], - snippet: 'South Dakota', - }, - _meta: { - engine: 'national-parks-demo', - score: 926068.7, - id: 'park_wind-cave', - }, - id: { - raw: 'park_wind-cave', - }, - }, -]; diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/search_relevance_suggestions.test.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/search_relevance_suggestions.test.ts index 2bdcfb9fe9d58..daab7c35596bf 100644 --- a/x-pack/plugins/enterprise_search/server/routes/app_search/search_relevance_suggestions.test.ts +++ b/x-pack/plugins/enterprise_search/server/routes/app_search/search_relevance_suggestions.test.ts @@ -116,9 +116,9 @@ describe('search relevance insights routes', () => { }); }); - describe('POST /internal/app_search/engines/{name}/search_relevance_suggestions/{query}', () => { + describe('GET /internal/app_search/engines/{engineName}/search_relevance_suggestions/{query}', () => { const mockRouter = new MockRouter({ - method: 'post', + method: 'get', path: '/internal/app_search/engines/{engineName}/search_relevance_suggestions/{query}', }); @@ -132,10 +132,11 @@ describe('search relevance insights routes', () => { it('creates a request to enterprise search', () => { mockRouter.callRoute({ params: { engineName: 'some-engine', query: 'foo' }, + query: { type: 'curation' }, }); expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({ - path: '/api/as/v0/engines/:engineName/search_relevance_suggestions/:query', + path: '/as/engines/:engineName/search_relevance_suggestions/:query', }); }); }); diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/search_relevance_suggestions.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/search_relevance_suggestions.ts index 8b3b204c24d70..95b50a9c4971e 100644 --- a/x-pack/plugins/enterprise_search/server/routes/app_search/search_relevance_suggestions.ts +++ b/x-pack/plugins/enterprise_search/server/routes/app_search/search_relevance_suggestions.ts @@ -81,7 +81,7 @@ export function registerSearchRelevanceSuggestionsRoutes({ }) ); - router.post( + router.get( { path: '/internal/app_search/engines/{engineName}/search_relevance_suggestions/{query}', validate: { @@ -89,20 +89,13 @@ export function registerSearchRelevanceSuggestionsRoutes({ engineName: schema.string(), query: schema.string(), }), - body: schema.object({ - page: schema.object({ - current: schema.number(), - size: schema.number(), - }), - filters: schema.object({ - status: schema.arrayOf(schema.string()), - type: schema.string(), - }), + query: schema.object({ + type: schema.string(), }), }, }, enterpriseSearchRequestHandler.createRequest({ - path: '/api/as/v0/engines/:engineName/search_relevance_suggestions/:query', + path: '/as/engines/:engineName/search_relevance_suggestions/:query', }) ); }