[App Search] Added a History tab to the Automated Curation detail view (#115090)

This commit is contained in:
Jason Stoltzfus 2021-10-18 12:20:19 -04:00 committed by GitHub
parent e9d6a072a8
commit c2571c7faf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 140 additions and 9 deletions

View file

@ -8,6 +8,7 @@
import '../../../../__mocks__/shallow_useeffect.mock';
import { setMockActions, setMockValues } from '../../../../__mocks__/kea_logic';
import { mockUseParams } from '../../../../__mocks__/react_router';
import '../../../__mocks__/engine_logic.mock';
import React from 'react';
@ -27,6 +28,7 @@ import { CurationLogic } from './curation_logic';
import { DeleteCurationButton } from './delete_curation_button';
import { PromotedDocuments, OrganicDocuments } from './documents';
import { History } from './history';
describe('AutomatedCuration', () => {
const values = {
@ -39,6 +41,7 @@ describe('AutomatedCuration', () => {
suggestion: {
status: 'applied',
},
queries: ['foo'],
},
activeQuery: 'query A',
isAutomated: true,
@ -61,20 +64,46 @@ describe('AutomatedCuration', () => {
expect(wrapper.is(AppSearchPageTemplate));
expect(wrapper.find(PromotedDocuments)).toHaveLength(1);
expect(wrapper.find(OrganicDocuments)).toHaveLength(1);
expect(wrapper.find(History)).toHaveLength(0);
});
it('includes a static tab group', () => {
it('includes tabs', () => {
const wrapper = shallow(<AutomatedCuration />);
const tabs = getPageHeaderTabs(wrapper).find(EuiTab);
let tabs = getPageHeaderTabs(wrapper).find(EuiTab);
expect(tabs).toHaveLength(2);
expect(tabs).toHaveLength(3);
expect(tabs.at(0).prop('onClick')).toBeUndefined();
expect(tabs.at(0).prop('isSelected')).toBe(true);
expect(tabs.at(1).prop('onClick')).toBeUndefined();
expect(tabs.at(1).prop('isSelected')).toBe(false);
expect(tabs.at(1).prop('disabled')).toBe(true);
expect(tabs.at(2).prop('isSelected')).toBe(false);
// Clicking on the History tab shows the history view
tabs.at(2).simulate('click');
tabs = getPageHeaderTabs(wrapper).find(EuiTab);
expect(tabs.at(0).prop('isSelected')).toBe(false);
expect(tabs.at(2).prop('isSelected')).toBe(true);
expect(wrapper.find(PromotedDocuments)).toHaveLength(0);
expect(wrapper.find(OrganicDocuments)).toHaveLength(0);
expect(wrapper.find(History)).toHaveLength(1);
// Clicking back to the Promoted tab shows promoted documents
tabs.at(0).simulate('click');
tabs = getPageHeaderTabs(wrapper).find(EuiTab);
expect(tabs.at(0).prop('isSelected')).toBe(true);
expect(tabs.at(2).prop('isSelected')).toBe(false);
expect(wrapper.find(PromotedDocuments)).toHaveLength(1);
expect(wrapper.find(OrganicDocuments)).toHaveLength(1);
expect(wrapper.find(History)).toHaveLength(0);
});
it('initializes CurationLogic with a curationId prop from URL param', () => {

View file

@ -5,15 +5,18 @@
* 2.0.
*/
import React from 'react';
import React, { useState } from 'react';
import { useParams } from 'react-router-dom';
import { useValues, useActions } from 'kea';
import { EuiButton, EuiBadge, EuiLoadingSpinner, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { EngineLogic } from '../../engine';
import { AppSearchPageTemplate } from '../../layout';
import { AutomatedIcon } from '../components/automated_icon';
import {
AUTOMATED_LABEL,
COVERT_TO_MANUAL_BUTTON_LABEL,
@ -26,19 +29,25 @@ 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';
import { History } from './history';
const PROMOTED = 'promoted';
const HISTORY = 'history';
export const AutomatedCuration: React.FC = () => {
const { curationId } = useParams<{ curationId: string }>();
const logic = CurationLogic({ curationId });
const { convertToManual } = useActions(logic);
const { activeQuery, dataLoading, queries, curation } = useValues(logic);
const { engineName } = useValues(EngineLogic);
const [selectedPageTab, setSelectedPageTab] = useState(PROMOTED);
// This tab group is meant to visually mirror the dynamic group of tags in the ManualCuration component
const pageTabs = [
{
label: PROMOTED_DOCUMENTS_TITLE,
append: <EuiBadge>{curation.promoted.length}</EuiBadge>,
isSelected: true,
isSelected: selectedPageTab === PROMOTED,
onClick: () => setSelectedPageTab(PROMOTED),
},
{
label: HIDDEN_DOCUMENTS_TITLE,
@ -46,6 +55,16 @@ export const AutomatedCuration: React.FC = () => {
isSelected: false,
disabled: true,
},
{
label: i18n.translate(
'xpack.enterpriseSearch.appSearch.engine.curation.detail.historyButtonLabel',
{
defaultMessage: 'History',
}
),
isSelected: selectedPageTab === HISTORY,
onClick: () => setSelectedPageTab(HISTORY),
},
];
return (
@ -83,8 +102,11 @@ export const AutomatedCuration: React.FC = () => {
}}
isLoading={dataLoading}
>
<PromotedDocuments />
<OrganicDocuments />
{selectedPageTab === PROMOTED && <PromotedDocuments />}
{selectedPageTab === PROMOTED && <OrganicDocuments />}
{selectedPageTab === HISTORY && (
<History query={curation.queries[0]} engineName={engineName} />
)}
</AppSearchPageTemplate>
);
};

View file

@ -0,0 +1,23 @@
/*
* 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 { shallow } from 'enzyme';
import { EntSearchLogStream } from '../../../../shared/log_stream';
import { History } from './history';
describe('History', () => {
it('renders', () => {
const wrapper = shallow(<History engineName="foo" query="some text" />);
expect(wrapper.find(EntSearchLogStream).prop('query')).toEqual(
'appsearch.search_relevance_suggestions.query: some text and event.kind: event and event.dataset: search-relevance-suggestions and appsearch.search_relevance_suggestions.engine: foo and event.action: curation_suggestion'
);
});
});

View file

@ -0,0 +1,57 @@
/*
* 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 { i18n } from '@kbn/i18n';
import { EntSearchLogStream } from '../../../../shared/log_stream';
import { DataPanel } from '../../data_panel';
interface Props {
query: string;
engineName: string;
}
export const History: React.FC<Props> = ({ query, engineName }) => {
const filters = [
`appsearch.search_relevance_suggestions.query: ${query}`,
'event.kind: event',
'event.dataset: search-relevance-suggestions',
`appsearch.search_relevance_suggestions.engine: ${engineName}`,
'event.action: curation_suggestion',
];
return (
<DataPanel
iconType="tableDensityNormal"
title={
<h2>
{i18n.translate(
'xpack.enterpriseSearch.appSearch.engine.curation.detail.historyTableTitle',
{
defaultMessage: 'Automated curation changes',
}
)}
</h2>
}
subtitle={i18n.translate(
'xpack.enterpriseSearch.appSearch.engine.curation.detail.historyTableDescription',
{
defaultMessage: 'A detailed log of recent changes to your automated curation.',
}
)}
hasBorder
>
<EntSearchLogStream
hoursAgo={720}
query={filters.join(' and ')}
columns={[{ type: 'timestamp' }, { type: 'message' }]}
/>
</DataPanel>
);
};