From a3e390f924d89a083b9f5244aae1498c4923d031 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 7 Oct 2021 14:03:20 -0400 Subject: [PATCH] [App Search] General UX Improvements for Curations and Suggestions (#114213) (#114312) Co-authored-by: Byron Hulcher --- .../components/suggestions_table.tsx | 2 +- .../components/curations/constants.ts | 4 +- .../curation/automated_curation.test.tsx | 25 ++++++- .../curations/curation/automated_curation.tsx | 37 ++++++---- .../curations/curation/constants.ts | 4 +- .../curations/curation/curation_logic.test.ts | 46 +++++++----- .../curations/curation/curation_logic.ts | 31 ++++++-- .../curation/delete_curation_button.test.tsx | 65 ++++++++++++++++ .../curation/delete_curation_button.tsx | 36 +++++++++ .../documents/hidden_documents.test.tsx | 10 ++- .../curation/documents/hidden_documents.tsx | 24 +++--- .../documents/organic_documents.test.tsx | 16 ++-- .../curation/documents/organic_documents.tsx | 17 ++--- .../documents/promoted_documents.test.tsx | 52 ++++++------- .../curation/documents/promoted_documents.tsx | 74 ++++++++++--------- .../curation/manual_curation.test.tsx | 39 +++++----- .../curations/curation/manual_curation.tsx | 43 +++++------ .../curation/queries/active_query_select.tsx | 6 ++ .../curation/queries/manage_queries_modal.tsx | 2 +- .../curation/results/add_result_button.tsx | 2 +- .../curation/results/curation_result.test.tsx | 12 +++ .../curation/results/curation_result.tsx | 6 +- .../components/curations/curations_logic.ts | 6 +- .../app_search/components/curations/types.ts | 2 +- .../curation_result_panel.test.tsx | 1 + .../curation_result_panel.tsx | 3 +- .../curation_suggestion.tsx | 6 +- .../components/data_panel/data_panel.test.tsx | 6 +- .../components/data_panel/data_panel.tsx | 2 +- .../components/result/result_header.test.tsx | 11 +++ .../components/result/result_header.tsx | 2 +- .../public/applications/shared/icons/index.ts | 1 + .../applications/shared/icons/leaf_icon.tsx | 23 ++++++ .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 35 files changed, 418 insertions(+), 200 deletions(-) create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/delete_curation_button.test.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/delete_curation_button.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/shared/icons/leaf_icon.tsx diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/suggestions_table.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/suggestions_table.tsx index 2a252a9666ac..b7a731c1654c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/suggestions_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/components/suggestions_table.tsx @@ -68,7 +68,7 @@ const columns: Array> = [ field: 'promoted', name: i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.curations.suggestionsTable.column.promotedDocumentsTableHeader', - { defaultMessage: 'Promoted documents' } + { defaultMessage: 'Promoted results' } ), render: (promoted: string[]) => {promoted.length}, }, diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/constants.ts index 01ca80776ae8..73e085ff83c5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/constants.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/constants.ts @@ -34,11 +34,11 @@ export const QUERY_INPUTS_PLACEHOLDER = i18n.translate( { defaultMessage: 'Enter a query' } ); -export const DELETE_MESSAGE = i18n.translate( +export const DELETE_CONFIRMATION_MESSAGE = i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.curations.deleteConfirmation', { defaultMessage: 'Are you sure you want to remove this curation?' } ); -export const SUCCESS_MESSAGE = i18n.translate( +export const DELETE_SUCCESS_MESSAGE = i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.curations.deleteSuccessMessage', { defaultMessage: 'Your curation was deleted' } ); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/automated_curation.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/automated_curation.test.tsx index 55725bb130de..2cee5bbbec80 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/automated_curation.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/automated_curation.test.tsx @@ -14,7 +14,7 @@ import React from 'react'; import { shallow, ShallowWrapper } from 'enzyme'; -import { EuiBadge, EuiTab } from '@elastic/eui'; +import { EuiBadge, EuiButton, EuiLoadingSpinner, EuiTab } from '@elastic/eui'; import { getPageHeaderActions, getPageHeaderTabs, getPageTitle } from '../../../../test_helpers'; @@ -25,6 +25,7 @@ import { AppSearchPageTemplate } from '../../layout'; import { AutomatedCuration } from './automated_curation'; import { CurationLogic } from './curation_logic'; +import { DeleteCurationButton } from './delete_curation_button'; import { PromotedDocuments, OrganicDocuments } from './documents'; describe('AutomatedCuration', () => { @@ -33,6 +34,8 @@ describe('AutomatedCuration', () => { queries: ['query A', 'query B'], isFlyoutOpen: false, curation: { + promoted: [], + hidden: [], suggestion: { status: 'applied', }, @@ -89,13 +92,29 @@ describe('AutomatedCuration', () => { expect(pageTitle.find(EuiBadge)).toHaveLength(1); }); + it('displays a spinner in the title when loading', () => { + setMockValues({ ...values, dataLoading: true }); + + const wrapper = shallow(); + const pageTitle = shallow(
{getPageTitle(wrapper)}
); + + expect(pageTitle.find(EuiLoadingSpinner)).toHaveLength(1); + }); + + it('contains a button to delete the curation', () => { + const wrapper = shallow(); + const pageHeaderActions = getPageHeaderActions(wrapper); + + expect(pageHeaderActions.find(DeleteCurationButton)).toHaveLength(1); + }); + describe('convert to manual button', () => { let convertToManualButton: ShallowWrapper; let confirmSpy: jest.SpyInstance; beforeAll(() => { const wrapper = shallow(); - convertToManualButton = getPageHeaderActions(wrapper).childAt(0); + convertToManualButton = getPageHeaderActions(wrapper).find(EuiButton); confirmSpy = jest.spyOn(window, 'confirm'); }); @@ -107,12 +126,14 @@ describe('AutomatedCuration', () => { it('converts the curation upon user confirmation', () => { confirmSpy.mockReturnValueOnce(true); convertToManualButton.simulate('click'); + expect(actions.convertToManual).toHaveBeenCalled(); }); it('does not convert the curation if the user cancels', () => { confirmSpy.mockReturnValueOnce(false); convertToManualButton.simulate('click'); + expect(actions.convertToManual).not.toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/automated_curation.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/automated_curation.tsx index e5c212d8f292..fa34fa071b85 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/automated_curation.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/automated_curation.tsx @@ -10,7 +10,7 @@ import { useParams } from 'react-router-dom'; import { useValues, useActions } from 'kea'; -import { EuiSpacer, EuiButton, EuiBadge } from '@elastic/eui'; +import { EuiButton, EuiBadge, EuiLoadingSpinner, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { AppSearchPageTemplate } from '../../layout'; import { AutomatedIcon } from '../components/automated_icon'; @@ -24,22 +24,25 @@ import { getCurationsBreadcrumbs } from '../utils'; import { HIDDEN_DOCUMENTS_TITLE, PROMOTED_DOCUMENTS_TITLE } from './constants'; import { CurationLogic } from './curation_logic'; +import { DeleteCurationButton } from './delete_curation_button'; import { PromotedDocuments, OrganicDocuments } from './documents'; export const AutomatedCuration: React.FC = () => { const { curationId } = useParams<{ curationId: string }>(); const logic = CurationLogic({ curationId }); const { convertToManual } = useActions(logic); - const { activeQuery, dataLoading, queries } = useValues(logic); + const { activeQuery, dataLoading, queries, curation } = useValues(logic); // This tab group is meant to visually mirror the dynamic group of tags in the ManualCuration component const pageTabs = [ { label: PROMOTED_DOCUMENTS_TITLE, + append: {curation.promoted.length}, isSelected: true, }, { label: HIDDEN_DOCUMENTS_TITLE, + append: 0, isSelected: false, disabled: true, }, @@ -51,30 +54,36 @@ export const AutomatedCuration: React.FC = () => { pageHeader={{ pageTitle: ( <> - {activeQuery}{' '} + {dataLoading ? : activeQuery}{' '} {AUTOMATED_LABEL} ), rightSideItems: [ - { - if (window.confirm(CONVERT_TO_MANUAL_CONFIRMATION)) convertToManual(); - }} - > - {COVERT_TO_MANUAL_BUTTON_LABEL} - , + + + + + + { + if (window.confirm(CONVERT_TO_MANUAL_CONFIRMATION)) convertToManual(); + }} + > + {COVERT_TO_MANUAL_BUTTON_LABEL} + + + , ], tabs: pageTabs, }} isLoading={dataLoading} > - ); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/constants.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/constants.ts index 3ea907bfa3cb..b5e5108e42e7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/constants.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/constants.ts @@ -9,10 +9,10 @@ import { i18n } from '@kbn/i18n'; export const PROMOTED_DOCUMENTS_TITLE = i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.curations.promotedDocuments.title', - { defaultMessage: 'Promoted documents' } + { defaultMessage: 'Promoted results' } ); export const HIDDEN_DOCUMENTS_TITLE = i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.title', - { defaultMessage: 'Hidden documents' } + { defaultMessage: 'Hidden results' } ); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.test.ts index d80a07e75692..5c3ac6d700de 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.test.ts @@ -21,7 +21,7 @@ describe('CurationLogic', () => { const { mount } = new LogicMounter(CurationLogic); const { http } = mockHttpValues; const { navigateToUrl } = mockKibanaValues; - const { clearFlashMessages, flashAPIErrors } = mockFlashMessageHelpers; + const { clearFlashMessages, flashAPIErrors, flashSuccessToast } = mockFlashMessageHelpers; const MOCK_CURATION_RESPONSE = { id: 'cur-123456789', @@ -249,23 +249,6 @@ describe('CurationLogic', () => { }); }); - describe('resetCuration', () => { - it('should clear promotedIds & hiddenIds & set dataLoading to true', () => { - mount({ promotedIds: ['hello'], hiddenIds: ['world'] }); - - CurationLogic.actions.resetCuration(); - - expect(CurationLogic.values).toEqual({ - ...DEFAULT_VALUES, - dataLoading: true, - promotedIds: [], - promotedDocumentsLoading: true, - hiddenIds: [], - hiddenDocumentsLoading: true, - }); - }); - }); - describe('onSelectPageTab', () => { it('should set the selected page tab', () => { mount({ @@ -336,6 +319,33 @@ describe('CurationLogic', () => { }); }); + describe('deleteCuration', () => { + it('should make an API call and navigate to the curations page', async () => { + http.delete.mockReturnValueOnce(Promise.resolve()); + mount({}, { curationId: 'cur-123456789' }); + jest.spyOn(CurationLogic.actions, 'onCurationLoad'); + + CurationLogic.actions.deleteCuration(); + await nextTick(); + + expect(http.delete).toHaveBeenCalledWith( + '/internal/app_search/engines/some-engine/curations/cur-123456789' + ); + expect(flashSuccessToast).toHaveBeenCalled(); + expect(navigateToUrl).toHaveBeenCalledWith('/engines/some-engine/curations'); + }); + + it('flashes any errors', async () => { + http.delete.mockReturnValueOnce(Promise.reject('error')); + mount({}, { curationId: 'cur-404' }); + + CurationLogic.actions.deleteCuration(); + await nextTick(); + + expect(flashAPIErrors).toHaveBeenCalledWith('error'); + }); + }); + describe('loadCuration', () => { it('should set dataLoading state', () => { mount({ dataLoading: false }, { curationId: 'cur-123456789' }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.ts index c54a2d1f31e1..7b617dd89e96 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/curation_logic.ts @@ -7,11 +7,16 @@ import { kea, MakeLogicType } from 'kea'; -import { clearFlashMessages, flashAPIErrors } from '../../../../shared/flash_messages'; +import { + clearFlashMessages, + flashAPIErrors, + flashSuccessToast, +} from '../../../../shared/flash_messages'; import { HttpLogic } from '../../../../shared/http'; import { KibanaLogic } from '../../../../shared/kibana'; import { ENGINE_CURATIONS_PATH } from '../../../routes'; import { EngineLogic, generateEnginePath } from '../../engine'; +import { DELETE_SUCCESS_MESSAGE } from '../constants'; import { Curation } from '../types'; import { addDocument, removeDocument } from '../utils'; @@ -35,6 +40,7 @@ interface CurationValues { interface CurationActions { convertToManual(): void; + deleteCuration(): void; loadCuration(): void; onCurationLoad(curation: Curation): { curation: Curation }; updateCuration(): void; @@ -48,7 +54,6 @@ interface CurationActions { addHiddenId(id: string): { id: string }; removeHiddenId(id: string): { id: string }; clearHiddenIds(): void; - resetCuration(): void; onSelectPageTab(pageTab: CurationPageTabs): { pageTab: CurationPageTabs }; } @@ -60,6 +65,7 @@ export const CurationLogic = kea ({ convertToManual: true, + deleteCuration: true, loadCuration: true, onCurationLoad: (curation) => ({ curation }), updateCuration: true, @@ -73,7 +79,6 @@ export const CurationLogic = kea ({ id }), removeHiddenId: (id) => ({ id }), clearHiddenIds: true, - resetCuration: true, onSelectPageTab: (pageTab) => ({ pageTab }), }), reducers: () => ({ @@ -81,7 +86,6 @@ export const CurationLogic = kea true, - resetCuration: () => true, onCurationLoad: () => false, onCurationError: () => false, }, @@ -204,6 +208,21 @@ export const CurationLogic = kea { + const { http } = HttpLogic.values; + const { engineName } = EngineLogic.values; + const { navigateToUrl } = KibanaLogic.values; + + try { + await http.delete( + `/internal/app_search/engines/${engineName}/curations/${props.curationId}` + ); + navigateToUrl(generateEnginePath(ENGINE_CURATIONS_PATH)); + flashSuccessToast(DELETE_SUCCESS_MESSAGE); + } catch (e) { + flashAPIErrors(e); + } + }, loadCuration: async () => { const { http } = HttpLogic.values; const { engineName } = EngineLogic.values; @@ -260,9 +279,5 @@ export const CurationLogic = kea actions.updateCuration(), removeHiddenId: () => actions.updateCuration(), clearHiddenIds: () => actions.updateCuration(), - resetCuration: () => { - actions.clearPromotedIds(); - actions.clearHiddenIds(); - }, }), }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/delete_curation_button.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/delete_curation_button.test.tsx new file mode 100644 index 000000000000..2a69b2bcd974 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/delete_curation_button.test.tsx @@ -0,0 +1,65 @@ +/* + * 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 '../../../../__mocks__/shallow_useeffect.mock'; +import { setMockActions } from '../../../../__mocks__/kea_logic'; +import { mockUseParams } from '../../../../__mocks__/react_router'; +import '../../../__mocks__/engine_logic.mock'; + +import React from 'react'; + +import { shallow, ShallowWrapper } from 'enzyme'; + +import { EuiButton } from '@elastic/eui'; + +jest.mock('./curation_logic', () => ({ CurationLogic: jest.fn() })); + +import { DeleteCurationButton } from './delete_curation_button'; + +describe('DeleteCurationButton', () => { + const actions = { + deleteCuration: jest.fn(), + }; + + beforeEach(() => { + jest.clearAllMocks(); + setMockActions(actions); + mockUseParams.mockReturnValueOnce({ curationId: 'hello-world' }); + }); + + it('renders', () => { + const wrapper = shallow(); + + expect(wrapper.is(EuiButton)).toBe(true); + }); + + describe('restore defaults button', () => { + let wrapper: ShallowWrapper; + let confirmSpy: jest.SpyInstance; + + beforeAll(() => { + wrapper = shallow(); + confirmSpy = jest.spyOn(window, 'confirm'); + }); + + afterAll(() => { + confirmSpy.mockRestore(); + }); + + it('resets the curation upon user confirmation', () => { + confirmSpy.mockReturnValueOnce(true); + wrapper.simulate('click'); + expect(actions.deleteCuration).toHaveBeenCalled(); + }); + + it('does not reset the curation if the user cancels', () => { + confirmSpy.mockReturnValueOnce(false); + wrapper.simulate('click'); + expect(actions.deleteCuration).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/delete_curation_button.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/delete_curation_button.tsx new file mode 100644 index 000000000000..49e1dc8b70b1 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/delete_curation_button.tsx @@ -0,0 +1,36 @@ +/* + * 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 React from 'react'; + +import { useParams } from 'react-router-dom'; + +import { useActions } from 'kea'; + +import { EuiButton } from '@elastic/eui'; + +import { DELETE_BUTTON_LABEL } from '../../../../shared/constants'; +import { DELETE_CONFIRMATION_MESSAGE } from '../constants'; + +import { CurationLogic } from '.'; + +export const DeleteCurationButton: React.FC = () => { + const { curationId } = useParams() as { curationId: string }; + const { deleteCuration } = useActions(CurationLogic({ curationId })); + + return ( + { + if (window.confirm(DELETE_CONFIRMATION_MESSAGE)) deleteCuration(); + }} + > + {DELETE_BUTTON_LABEL} + + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/hidden_documents.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/hidden_documents.test.tsx index c2377d010949..7160931bcf40 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/hidden_documents.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/hidden_documents.test.tsx @@ -11,7 +11,7 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { EuiEmptyPrompt, EuiButtonEmpty } from '@elastic/eui'; +import { EuiEmptyPrompt, EuiButtonEmpty, EuiBadge } from '@elastic/eui'; import { DataPanel } from '../../../data_panel'; import { CurationResult } from '../results'; @@ -48,6 +48,14 @@ describe('HiddenDocuments', () => { expect(wrapper.find(CurationResult)).toHaveLength(5); }); + it('displays the number of documents in a badge', () => { + const wrapper = shallow(); + const Icon = wrapper.prop('iconType'); + const iconWrapper = shallow(); + + expect(iconWrapper.find(EuiBadge).prop('children')).toEqual(5); + }); + it('renders an empty state & hides the panel actions when empty', () => { setMockValues({ ...values, curation: { hidden: [] } }); const wrapper = shallow(); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/hidden_documents.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/hidden_documents.tsx index be50b03960ac..519808940fa1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/hidden_documents.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/hidden_documents.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { useValues, useActions } from 'kea'; -import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiEmptyPrompt } from '@elastic/eui'; +import { EuiBadge, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiEmptyPrompt } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { DataPanel } from '../../../data_panel'; @@ -26,39 +26,37 @@ export const HiddenDocuments: React.FC = () => { const documents = curation.hidden; const hasDocuments = documents.length > 0; + const CountBadge: React.FC = () => {documents.length}; + return ( {HIDDEN_DOCUMENTS_TITLE}} - subtitle={i18n.translate( - 'xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.description', - { defaultMessage: 'Hidden documents will not appear in organic results.' } - )} action={ hasDocuments && ( - - - - + {i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.removeAllButtonLabel', - { defaultMessage: 'Restore all' } + { defaultMessage: 'Unhide all' } )} + + + ) } isLoading={hiddenDocumentsLoading} > {hasDocuments ? ( - documents.map((document) => ( + documents.map((document, index) => ( { expect(titleText).toEqual('Top organic documents for "world"'); }); - it('shows a title when the curation is manual', () => { - setMockValues({ ...values, isAutomated: false }); - const wrapper = shallow(); - - expect(wrapper.find(DataPanel).prop('subtitle')).toContain('Promote results'); - }); - it('renders a loading state', () => { setMockValues({ ...values, organicDocumentsLoading: true }); const wrapper = shallow(); @@ -74,13 +67,20 @@ describe('OrganicDocuments', () => { }); describe('empty state', () => { - it('renders', () => { + it('renders when organic results is empty', () => { setMockValues({ ...values, curation: { organic: [] } }); const wrapper = shallow(); expect(wrapper.find(EuiEmptyPrompt)).toHaveLength(1); }); + it('renders when organic results is undefined', () => { + setMockValues({ ...values, curation: { organic: undefined } }); + const wrapper = shallow(); + + expect(wrapper.find(EuiEmptyPrompt)).toHaveLength(1); + }); + it('tells the user to modify the query if the curation is manual', () => { setMockValues({ ...values, curation: { organic: [] }, isAutomated: false }); const wrapper = shallow(); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/organic_documents.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/organic_documents.tsx index 7314376a4a7a..166cce902948 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/organic_documents.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/organic_documents.tsx @@ -13,14 +13,12 @@ import { EuiLoadingContent, EuiEmptyPrompt } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import { LeafIcon } from '../../../../../shared/icons'; + import { DataPanel } from '../../../data_panel'; import { Result } from '../../../result/types'; -import { - RESULT_ACTIONS_DIRECTIONS, - PROMOTE_DOCUMENT_ACTION, - HIDE_DOCUMENT_ACTION, -} from '../../constants'; +import { PROMOTE_DOCUMENT_ACTION, HIDE_DOCUMENT_ACTION } from '../../constants'; import { CurationLogic } from '../curation_logic'; import { CurationResult } from '../results'; @@ -28,14 +26,13 @@ export const OrganicDocuments: React.FC = () => { const { addPromotedId, addHiddenId } = useActions(CurationLogic); const { curation, activeQuery, isAutomated, organicDocumentsLoading } = useValues(CurationLogic); - const documents = curation.organic; + const documents = curation.organic || []; const hasDocuments = documents.length > 0 && !organicDocumentsLoading; const currentQuery = activeQuery; return ( {i18n.translate( @@ -47,12 +44,12 @@ export const OrganicDocuments: React.FC = () => { )} } - subtitle={!isAutomated && RESULT_ACTIONS_DIRECTIONS} > {hasDocuments ? ( - documents.map((document: Result) => ( + documents.map((document: Result, index) => ( { return draggableWrapper.renderProp('children')({}, {}, {}); }; + it('displays the number of documents in a badge', () => { + const wrapper = shallow(); + const Icon = wrapper.prop('iconType'); + const iconWrapper = shallow(); + + expect(iconWrapper.find(EuiBadge).prop('children')).toEqual(4); + }); + it('renders a list of draggable promoted documents', () => { const wrapper = shallow(); @@ -57,22 +72,6 @@ describe('PromotedDocuments', () => { }); }); - it('informs the user documents can be re-ordered if the curation is manual', () => { - setMockValues({ ...values, isAutomated: false }); - const wrapper = shallow(); - const subtitle = mountWithIntl(wrapper.prop('subtitle')); - - expect(subtitle.text()).toContain('Documents can be re-ordered'); - }); - - it('informs the user the curation is managed if the curation is automated', () => { - setMockValues({ ...values, isAutomated: true }); - const wrapper = shallow(); - const subtitle = mountWithIntl(wrapper.prop('subtitle')); - - expect(subtitle.text()).toContain('managed by App Search'); - }); - describe('empty state', () => { it('renders', () => { setMockValues({ ...values, curation: { promoted: [] } }); @@ -90,18 +89,12 @@ describe('PromotedDocuments', () => { }); }); - it('hides the panel actions when empty', () => { - setMockValues({ ...values, curation: { promoted: [] } }); - const wrapper = shallow(); - - expect(wrapper.find(DataPanel).prop('action')).toBe(false); - }); - - it('hides the panel actions when the curation is automated', () => { + it('shows a message when the curation is automated', () => { setMockValues({ ...values, isAutomated: true }); const wrapper = shallow(); + const panelAction = shallow(wrapper.find(DataPanel).prop('action') as React.ReactElement); - expect(wrapper.find(DataPanel).prop('action')).toBe(false); + expect(panelAction.find(EuiTextColor)).toHaveLength(1); }); it('renders a loading state', () => { @@ -136,6 +129,13 @@ describe('PromotedDocuments', () => { expect(actions.clearPromotedIds).toHaveBeenCalled(); }); + it('hides the demote all button when there are on promoted results', () => { + setMockValues({ ...values, curation: { promoted: [] } }); + const wrapper = shallow(); + + expect(wrapper.find(DataPanel).prop('action')).toEqual(false); + }); + describe('dragging', () => { it('calls setPromotedIds with the reordered list when users are done dragging', () => { const wrapper = shallow(); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/promoted_documents.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/promoted_documents.tsx index 377e9d5d9a56..c953fb210c03 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/promoted_documents.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/documents/promoted_documents.tsx @@ -19,9 +19,10 @@ import { EuiDroppable, EuiDraggable, euiDragDropReorder, + EuiBadge, + EuiText, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; import { DataPanel } from '../../../data_panel'; @@ -43,45 +44,45 @@ export const PromotedDocuments: React.FC = () => { } }; + const CountBadge: React.FC = () => {documents.length}; + return ( {PROMOTED_DOCUMENTS_TITLE}} - subtitle={ - isAutomated ? ( - - ) : ( - - ) - } action={ - !isAutomated && - hasDocuments && ( - - - - - - + isAutomated ? ( + +

+ {i18n.translate( - 'xpack.enterpriseSearch.appSearch.engine.curations.promotedDocuments.removeAllButtonLabel', - { defaultMessage: 'Demote all' } + 'xpack.enterpriseSearch.appSearch.engine.curations.promotedDocuments.managedByAppSearchDescription', + { defaultMessage: 'This curation is being automated by App Search' } )} - - - + +

+
+ ) : ( + hasDocuments && ( + + + + {i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.curations.promotedDocuments.removeAllButtonLabel', + { defaultMessage: 'Demote all' } + )} + + + + + + + ) ) } isLoading={promotedDocumentsLoading} @@ -89,9 +90,9 @@ export const PromotedDocuments: React.FC = () => { {hasDocuments ? ( - {documents.map((document, i: number) => ( + {documents.map((document, index) => ( { {(provided) => ( ({ CurationLogic: jest.fn() })); import { CurationLogic } from './curation_logic'; +import { DeleteCurationButton } from './delete_curation_button'; import { PromotedDocuments, HiddenDocuments } from './documents'; import { ManualCuration } from './manual_curation'; +import { ActiveQuerySelect, ManageQueriesModal } from './queries'; import { AddResultFlyout } from './results'; import { SuggestedDocumentsCallout } from './suggested_documents_callout'; @@ -32,9 +34,13 @@ describe('ManualCuration', () => { queries: ['query A', 'query B'], isFlyoutOpen: false, selectedPageTab: 'promoted', + curation: { + promoted: [], + hidden: [], + }, }; const actions = { - resetCuration: jest.fn(), + deleteCuration: jest.fn(), onSelectPageTab: jest.fn(), }; @@ -108,31 +114,26 @@ describe('ManualCuration', () => { expect(CurationLogic).toHaveBeenCalledWith({ curationId: 'hello-world' }); }); - describe('restore defaults button', () => { - let restoreDefaultsButton: ShallowWrapper; - let confirmSpy: jest.SpyInstance; + describe('page header actions', () => { + let pageHeaderActions: ShallowWrapper; beforeAll(() => { const wrapper = shallow(); - restoreDefaultsButton = getPageHeaderActions(wrapper).childAt(0); - - confirmSpy = jest.spyOn(window, 'confirm'); + pageHeaderActions = getPageHeaderActions(wrapper); }); - afterAll(() => { - confirmSpy.mockRestore(); + it('contains a button to manage queries and an active query selector', () => { + expect(pageHeaderActions.find(ManageQueriesModal)).toHaveLength(1); }); - it('resets the curation upon user confirmation', () => { - confirmSpy.mockReturnValueOnce(true); - restoreDefaultsButton.simulate('click'); - expect(actions.resetCuration).toHaveBeenCalled(); - }); - - it('does not reset the curation if the user cancels', () => { - confirmSpy.mockReturnValueOnce(false); - restoreDefaultsButton.simulate('click'); - expect(actions.resetCuration).not.toHaveBeenCalled(); + it('contains a button to delete the curation', () => { + expect(pageHeaderActions.find(DeleteCurationButton)).toHaveLength(1); }); }); + + it('contains an active query selector', () => { + const wrapper = shallow(); + + expect(wrapper.find(ActiveQuerySelect)).toHaveLength(1); + }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/manual_curation.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/manual_curation.tsx index ab031ca4a5ee..3aee306e3d2f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/manual_curation.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/manual_curation.tsx @@ -10,15 +10,15 @@ import { useParams } from 'react-router-dom'; import { useValues, useActions } from 'kea'; -import { EuiSpacer, EuiFlexGroup, EuiFlexItem, EuiButton } from '@elastic/eui'; +import { EuiBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { RESTORE_DEFAULTS_BUTTON_LABEL } from '../../../constants'; import { AppSearchPageTemplate } from '../../layout'; -import { MANAGE_CURATION_TITLE, RESTORE_CONFIRMATION } from '../constants'; +import { MANAGE_CURATION_TITLE } from '../constants'; import { getCurationsBreadcrumbs } from '../utils'; import { PROMOTED_DOCUMENTS_TITLE, HIDDEN_DOCUMENTS_TITLE } from './constants'; import { CurationLogic } from './curation_logic'; +import { DeleteCurationButton } from './delete_curation_button'; import { PromotedDocuments, OrganicDocuments, HiddenDocuments } from './documents'; import { ActiveQuerySelect, ManageQueriesModal } from './queries'; import { AddResultLogic, AddResultFlyout } from './results'; @@ -26,18 +26,22 @@ import { SuggestedDocumentsCallout } from './suggested_documents_callout'; export const ManualCuration: React.FC = () => { const { curationId } = useParams() as { curationId: string }; - const { onSelectPageTab, resetCuration } = useActions(CurationLogic({ curationId })); - const { dataLoading, queries, selectedPageTab } = useValues(CurationLogic({ curationId })); + const { onSelectPageTab } = useActions(CurationLogic({ curationId })); + const { dataLoading, queries, selectedPageTab, curation } = useValues( + CurationLogic({ curationId }) + ); const { isFlyoutOpen } = useValues(AddResultLogic); const pageTabs = [ { label: PROMOTED_DOCUMENTS_TITLE, + append: {curation.promoted.length}, isSelected: selectedPageTab === 'promoted', onClick: () => onSelectPageTab('promoted'), }, { label: HIDDEN_DOCUMENTS_TITLE, + append: {curation.hidden.length}, isSelected: selectedPageTab === 'hidden', onClick: () => onSelectPageTab('hidden'), }, @@ -49,32 +53,23 @@ export const ManualCuration: React.FC = () => { pageHeader={{ pageTitle: MANAGE_CURATION_TITLE, rightSideItems: [ - { - if (window.confirm(RESTORE_CONFIRMATION)) resetCuration(); - }} - > - {RESTORE_DEFAULTS_BUTTON_LABEL} - , + + + + + + + + , ], tabs: pageTabs, }} isLoading={dataLoading} > - - - - - - - - - - + + {selectedPageTab === 'promoted' && } {selectedPageTab === 'promoted' && } {selectedPageTab === 'hidden' && } - {isFlyoutOpen && } diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/queries/active_query_select.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/queries/active_query_select.tsx index d4f42a8d70ad..4e62e3fb7ec7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/queries/active_query_select.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/queries/active_query_select.tsx @@ -23,6 +23,12 @@ export const ActiveQuerySelect: React.FC = () => { label={i18n.translate('xpack.enterpriseSearch.appSearch.engine.curations.activeQueryLabel', { defaultMessage: 'Active query', })} + helpText={i18n.translate( + 'xpack.enterpriseSearch.appSearch.engine.curations.activeQueryHelpText', + { + defaultMessage: 'Select a query to view the organic search results for them', + } + )} fullWidth > { return ( <> - + {i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.curations.manageQueryButtonLabel', { defaultMessage: 'Manage queries' } diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/add_result_button.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/add_result_button.tsx index f2285064da30..956b0ba0645c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/add_result_button.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/add_result_button.tsx @@ -21,7 +21,7 @@ export const AddResultButton: React.FC = () => { const { isAutomated } = useValues(CurationLogic); return ( - + {i18n.translate('xpack.enterpriseSearch.appSearch.engine.curations.addResult.buttonLabel', { defaultMessage: 'Add result manually', })} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/curation_result.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/curation_result.test.tsx index 67a26f2ecd4b..36a2f47956c2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/curation_result.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/curation_result.test.tsx @@ -51,4 +51,16 @@ describe('CurationResult', () => { expect(wrapper.find(Result).prop('actions')).toEqual(mockActions); expect(wrapper.find(Result).prop('dragHandleProps')).toEqual(mockDragging); }); + + it('increments the result index before passing it on', () => { + wrapper = shallow( + + ); + expect(wrapper.find(Result).prop('resultPosition')).toEqual(6); + }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/curation_result.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/curation_result.tsx index c737d93ce182..f0086e771234 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/curation_result.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/results/curation_result.tsx @@ -17,12 +17,13 @@ import { Result } from '../../../result'; import { Result as ResultType, ResultAction } from '../../../result/types'; interface Props { - result: ResultType; actions: ResultAction[]; dragHandleProps?: DraggableProvidedDragHandleProps; + result: ResultType; + index?: number; } -export const CurationResult: React.FC = ({ result, actions, dragHandleProps }) => { +export const CurationResult: React.FC = ({ actions, dragHandleProps, result, index }) => { const { isMetaEngine, engine: { schema }, @@ -36,6 +37,7 @@ export const CurationResult: React.FC = ({ result, actions, dragHandlePro isMetaEngine={isMetaEngine} schemaForTypeHighlights={schema} dragHandleProps={dragHandleProps} + resultPosition={typeof index === 'undefined' ? undefined : index + 1} /> diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_logic.ts index 76adfa4b6ed4..e623379e58d3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curations_logic.ts @@ -20,7 +20,7 @@ import { updateMetaPageIndex } from '../../../shared/table_pagination'; import { ENGINE_CURATION_PATH } from '../../routes'; import { EngineLogic, generateEnginePath } from '../engine'; -import { DELETE_MESSAGE, SUCCESS_MESSAGE } from './constants'; +import { DELETE_CONFIRMATION_MESSAGE, DELETE_SUCCESS_MESSAGE } from './constants'; import { Curation, CurationsAPIResponse } from './types'; type CurationsPageTabs = 'overview' | 'settings'; @@ -102,11 +102,11 @@ export const CurationsLogic = kea { expect(wrapper.find(Result).length).toBe(2); expect(wrapper.find(Result).at(0).props()).toEqual({ result: results[0], + resultPosition: 1, isMetaEngine: true, schemaForTypeHighlights: values.engine.schema, }); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_result_panel.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_result_panel.tsx index 5a21bfcb3884..bbd61804ad34 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_result_panel.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/views/curation_suggestion/curation_result_panel.tsx @@ -72,12 +72,13 @@ export const CurationResultPanel: React.FC = ({ variant, results }) => { className={`curationResultPanel curationResultPanel--${variant}`} > {results.length > 0 ? ( - results.map((result) => ( + results.map((result, index) => ( )) 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 3191d4e912cf..07184f6d668e 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 @@ -129,12 +129,13 @@ export const CurationSuggestion: React.FC = () => { gutterSize="s" data-test-subj="currentOrganicResults" > - {currentOrganicResults.map((result: ResultType) => ( + {currentOrganicResults.map((result: ResultType, index) => ( ))} @@ -148,12 +149,13 @@ export const CurationSuggestion: React.FC = () => { gutterSize="s" data-test-subj="proposedOrganicResults" > - {proposedOrganicResults.map((result: ResultType) => ( + {proposedOrganicResults.map((result: ResultType, index) => ( ))} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.test.tsx index 04f05349217c..e17b9263bb49 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.test.tsx @@ -34,7 +34,11 @@ describe('DataPanel', () => { wrapper.setProps({ children: 'hello world' }); - expect(wrapper.find(EuiSpacer)).toHaveLength(1); + expect(wrapper.find(EuiSpacer).prop('size')).toEqual('s'); + + wrapper.setProps({ filled: true }); + + expect(wrapper.find(EuiSpacer).prop('size')).toEqual('l'); }); describe('components', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.tsx index 4b22fbc93d41..8dc43d08e5e0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/data_panel/data_panel.tsx @@ -87,7 +87,7 @@ export const DataPanel: React.FC = ({
{children && ( <> - + {children} )} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header.test.tsx index cdd43c3efd97..f51087844e88 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header.test.tsx @@ -9,6 +9,10 @@ import React from 'react'; import { shallow } from 'enzyme'; +import { EuiBadge } from '@elastic/eui'; + +import { mountWithIntl } from '../../../test_helpers'; + import { ResultActions } from './result_actions'; import { ResultHeader } from './result_header'; @@ -46,6 +50,13 @@ describe('ResultHeader', () => { ); }); + it('renders position if one is passed in', () => { + const wrapper = mountWithIntl(); + + const badge = wrapper.find(EuiBadge); + expect(badge.text()).toContain('#5'); + }); + describe('score', () => { it('renders score if showScore is true ', () => { const wrapper = shallow(); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header.tsx index fd524e126b25..05af34c3fe3a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/result/result_header.tsx @@ -43,7 +43,7 @@ export const ResultHeader: React.FC = ({ responsive={false} wrap > - {resultPosition && ( + {typeof resultPosition !== 'undefined' && ( ( + +); diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 2461d3b58b07..ebe1e6aa0500 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -9485,7 +9485,6 @@ "xpack.enterpriseSearch.appSearch.engine.curations.empty.buttonLabel": "キュレーションガイドを読む", "xpack.enterpriseSearch.appSearch.engine.curations.empty.description": "キュレーションを使用して、ドキュメントを昇格させるか非表示にします。最も検出させたい内容をユーザーに検出させるように支援します。", "xpack.enterpriseSearch.appSearch.engine.curations.empty.noCurationsTitle": "最初のキュレーションを作成", - "xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.description": "非表示のドキュメントはオーガニック結果に表示されません。", "xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.emptyDescription": "上記のオーガニック結果の目アイコンをクリックしてドキュメントを非表示にするか、結果を手動で検索して非表示にします。", "xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.emptyTitle": "まだドキュメントを非表示にしていません", "xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.removeAllButtonLabel": "すべて復元", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 860a91676b3e..947edaae4fe1 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -9580,7 +9580,6 @@ "xpack.enterpriseSearch.appSearch.engine.curations.empty.buttonLabel": "阅读策展指南", "xpack.enterpriseSearch.appSearch.engine.curations.empty.description": "使用策展提升和隐藏文档。帮助人们发现最想让他们发现的内容。", "xpack.enterpriseSearch.appSearch.engine.curations.empty.noCurationsTitle": "创建您的首个策展", - "xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.description": "隐藏的文档将不显示在有机结果中。", "xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.emptyDescription": "通过单击上面有机结果上的眼睛图标,可隐藏文档,或手动搜索和隐藏结果。", "xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.emptyTitle": "您尚未隐藏任何文档", "xpack.enterpriseSearch.appSearch.engine.curations.hiddenDocuments.removeAllButtonLabel": "全部还原",