Skip to content

Commit

Permalink
[App Search] Elasticsearch indexed engines UI affordance updates (#12…
Browse files Browse the repository at this point in the history
…8508)

* Add isElasticsearchEngine selector and type

* Add badge to elasticsearch engines

* Hide Index documents button for elasticsearch engines

* Hide delete buttons from documents that are part of meta or elasticsearch engines

* Hide crawler nav item from elasticsearch engines

* Add callout to documents page for elasticsearch engines

* Add empty state for an elasticsearch index

* Make schema read-only for elasticsearch engines

* Hide PrecisionSlider for elasticsearch engines

* Add conditional relevance tuning description

* Fix failing test

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
scottybollinger and kibanamachine committed Mar 24, 2022
1 parent c9af8f0 commit 2b4d721
Show file tree
Hide file tree
Showing 16 changed files with 299 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import { DocumentDetail } from '.';

describe('DocumentDetail', () => {
const values = {
isMetaEngine: false,
isElasticsearchEngine: false,
dataLoading: false,
fields: [],
};
Expand Down Expand Up @@ -98,4 +100,22 @@ describe('DocumentDetail', () => {

expect(actions.deleteDocument).toHaveBeenCalledWith('1');
});

it('hides delete button when the document is a part of a meta engine', () => {
setMockValues({ ...values, isMetaEngine: true });
const wrapper = shallow(<DocumentDetail />);

expect(
getPageHeaderActions(wrapper).find('[data-test-subj="DeleteDocumentButton"]')
).toHaveLength(0);
});

it('hides delete button when the document is a part of an elasticsearch-indexed engine', () => {
setMockValues({ ...values, isElasticsearchEngine: true });
const wrapper = shallow(<DocumentDetail />);

expect(
getPageHeaderActions(wrapper).find('[data-test-subj="DeleteDocumentButton"]')
).toHaveLength(0);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { i18n } from '@kbn/i18n';

import { DELETE_BUTTON_LABEL } from '../../../shared/constants';
import { useDecodedParams } from '../../utils/encode_path_params';
import { getEngineBreadcrumbs } from '../engine';
import { EngineLogic, getEngineBreadcrumbs } from '../engine';
import { AppSearchPageTemplate } from '../layout';
import { ResultFieldValue } from '../result';

Expand All @@ -32,6 +32,8 @@ const DOCUMENT_DETAIL_TITLE = (documentId: string) =>
export const DocumentDetail: React.FC = () => {
const { dataLoading, fields } = useValues(DocumentDetailLogic);
const { deleteDocument, getDocumentDetails, setFields } = useActions(DocumentDetailLogic);
const { isMetaEngine, isElasticsearchEngine } = useValues(EngineLogic);
const showDeleteButton = !isMetaEngine && !isElasticsearchEngine;

const { documentId } = useParams() as { documentId: string };
const { documentId: documentTitle } = useDecodedParams();
Expand Down Expand Up @@ -60,21 +62,23 @@ export const DocumentDetail: React.FC = () => {
},
];

const deleteButton = (
<EuiButton
color="danger"
iconType="trash"
onClick={() => deleteDocument(documentId)}
data-test-subj="DeleteDocumentButton"
>
{DELETE_BUTTON_LABEL}
</EuiButton>
);

return (
<AppSearchPageTemplate
pageChrome={getEngineBreadcrumbs([DOCUMENTS_TITLE, documentTitle])}
pageHeader={{
pageTitle: DOCUMENT_DETAIL_TITLE(documentTitle),
rightSideItems: [
<EuiButton
color="danger"
iconType="trash"
onClick={() => deleteDocument(documentId)}
data-test-subj="DeleteDocumentButton"
>
{DELETE_BUTTON_LABEL}
</EuiButton>,
],
rightSideItems: showDeleteButton ? [deleteButton] : [],
}}
isLoading={dataLoading}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ describe('Documents', () => {
const values = {
isMetaEngine: false,
myRole: { canManageEngineDocuments: true },
engine: { elasticsearchIndexName: 'my-elasticsearch-index' },
};

beforeEach(() => {
Expand Down Expand Up @@ -66,6 +67,17 @@ describe('Documents', () => {
const wrapper = shallow(<Documents />);
expect(getPageHeaderActions(wrapper).find(DocumentCreationButton).exists()).toBe(false);
});

it('does not render a DocumentCreationButton for elasticsearch engines even if the user can manage engine documents', () => {
setMockValues({
...values,
myRole: { canManageEngineDocuments: true },
isElasticsearchEngine: true,
});

const wrapper = shallow(<Documents />);
expect(getPageHeaderActions(wrapper).find(DocumentCreationButton).exists()).toBe(false);
});
});

describe('Meta Engines', () => {
Expand All @@ -89,4 +101,26 @@ describe('Documents', () => {
expect(wrapper.find('[data-test-subj="MetaEnginesCallout"]').exists()).toBe(false);
});
});

describe('Elasticsearch indices', () => {
it('renders an Elasticsearch indices message if this is an Elasticsearch index', () => {
setMockValues({
...values,
isElasticsearchEngine: true,
});

const wrapper = shallow(<Documents />);
expect(wrapper.find('[data-test-subj="ElasticsearchEnginesCallout"]').exists()).toBe(true);
});

it('does not render an Elasticsearch indices message if this is not an Elasticsearch index', () => {
setMockValues({
...values,
isElasticsearchEngine: false,
});

const wrapper = shallow(<Documents />);
expect(wrapper.find('[data-test-subj="ElasticsearchEnginesCallout"]').exists()).toBe(false);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,22 @@ import { DOCUMENTS_TITLE } from './constants';
import { SearchExperience } from './search_experience';

export const Documents: React.FC = () => {
const { isMetaEngine, hasNoDocuments } = useValues(EngineLogic);
const {
isMetaEngine,
isElasticsearchEngine,
hasNoDocuments,
engine: { elasticsearchIndexName },
} = useValues(EngineLogic);
const { myRole } = useValues(AppLogic);
const showDocumentCreationButton =
myRole.canManageEngineDocuments && !isMetaEngine && !isElasticsearchEngine;

return (
<AppSearchPageTemplate
pageChrome={getEngineBreadcrumbs([DOCUMENTS_TITLE])}
pageHeader={{
pageTitle: DOCUMENTS_TITLE,
rightSideItems:
myRole.canManageEngineDocuments && !isMetaEngine ? [<DocumentCreationButton />] : [],
rightSideItems: showDocumentCreationButton ? [<DocumentCreationButton />] : [],
}}
isEmptyState={hasNoDocuments}
emptyState={<EmptyState />}
Expand All @@ -57,6 +63,32 @@ export const Documents: React.FC = () => {
<EuiSpacer />
</>
)}
{isElasticsearchEngine && (
<>
<EuiCallOut
data-test-subj="ElasticsearchEnginesCallout"
iconType="iInCircle"
title={i18n.translate(
'xpack.enterpriseSearch.appSearch.documents.elasticsearchEngineCallout.title',
{
defaultMessage: "This engine's data is managed by Elasticsearch.",
}
)}
>
<p>
{i18n.translate(
'xpack.enterpriseSearch.appSearch.documents.elasticsearchEngineCallout',
{
defaultMessage:
"The engine is attached to {elasticsearchIndexName}. You can modify this index's data in Kibana.",
values: { elasticsearchIndexName },
}
)}
</p>
</EuiCallOut>
<EuiSpacer />
</>
)}
<SearchExperience />
</AppSearchPageTemplate>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ describe('EngineLogic', () => {
hasNoDocuments: true,
hasEmptySchema: true,
isMetaEngine: false,
isElasticsearchEngine: false,
isSampleEngine: false,
hasSchemaErrors: false,
hasSchemaConflicts: false,
Expand Down Expand Up @@ -383,6 +384,19 @@ describe('EngineLogic', () => {
});
});

describe('isElasticsearchEngine', () => {
it('should be set based on engine.type', () => {
const engine = { ...mockEngineData, type: EngineTypes.elasticsearch };
mount({ engine });

expect(EngineLogic.values).toEqual({
...DEFAULT_VALUES_WITH_ENGINE,
engine,
isElasticsearchEngine: true,
});
});
});

describe('hasSchemaErrors', () => {
it('should be set based on engine.activeReindexJob.numDocumentsWithErrors', () => {
const engine = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ interface EngineValues {
hasNoDocuments: boolean;
hasEmptySchema: boolean;
isMetaEngine: boolean;
isElasticsearchEngine: boolean;
isSampleEngine: boolean;
hasSchemaErrors: boolean;
hasSchemaConflicts: boolean;
Expand Down Expand Up @@ -100,6 +101,10 @@ export const EngineLogic = kea<MakeLogicType<EngineValues, EngineActions>>({
(engine) => Object.keys(engine.schema || {}).length === 0,
],
isMetaEngine: [() => [selectors.engine], (engine) => engine?.type === EngineTypes.meta],
isElasticsearchEngine: [
() => [selectors.engine],
(engine) => engine?.type === EngineTypes.elasticsearch,
],
isSampleEngine: [() => [selectors.engine], (engine) => !!engine?.sample],
// Indexed engines
hasSchemaErrors: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ describe('useEngineNav', () => {

expect(wrapper.find(EuiBadge).prop('children')).toEqual('META ENGINE');
});

it('renders an elasticsearch index badge for elasticsearch indexed engines', () => {
setMockValues({ ...values, isElasticsearchEngine: true });
const wrapper = renderEngineLabel(useEngineNav());

expect(wrapper.find(EuiBadge).prop('children')).toEqual('ELASTICSEARCH INDEX');
});
});

it('returns an analytics nav item', () => {
Expand Down Expand Up @@ -183,6 +190,11 @@ describe('useEngineNav', () => {
setMockValues({ ...values, myRole, isMetaEngine: true });
expect(useEngineNav()).toEqual(BASE_NAV);
});

it('does not return a crawler nav item for elasticsearch engines', () => {
setMockValues({ ...values, myRole, isElasticsearchEngine: true });
expect(useEngineNav()).toEqual(BASE_NAV);
});
});

describe('meta engine source engines', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export const useEngineNav = () => {
dataLoading,
isSampleEngine,
isMetaEngine,
isElasticsearchEngine,
hasSchemaErrors,
hasSchemaConflicts,
hasUnconfirmedSchemaFields,
Expand Down Expand Up @@ -99,6 +100,13 @@ export const useEngineNav = () => {
})}
</EuiBadge>
)}
{isElasticsearchEngine && (
<EuiBadge>
{i18n.translate('xpack.enterpriseSearch.appSearch.engine.elasticsearchEngineBadge', {
defaultMessage: 'ELASTICSEARCH INDEX',
})}
</EuiBadge>
)}
</EuiText>
),
'data-test-subj': 'EngineLabel',
Expand Down Expand Up @@ -185,7 +193,8 @@ export const useEngineNav = () => {
});
}

if (canViewEngineCrawler && !isMetaEngine) {
const showCrawlerNavItem = canViewEngineCrawler && !isMetaEngine && !isElasticsearchEngine;
if (showCrawlerNavItem) {
navItems.push({
id: 'crawler',
name: CRAWLER_TITLE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export interface EngineDetails extends Engine {
unsearchedUnconfirmedFields: boolean;
apiTokens: ApiToken[];
apiKey: string;
elasticsearchIndexName?: string;
schema: Schema;
schemaConflicts?: SchemaConflicts;
unconfirmedFields?: string[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import '../../__mocks__/engine_logic.mock';
import { setMockValues } from '../../../__mocks__/kea_logic';

import React from 'react';

Expand All @@ -22,11 +23,23 @@ import { EmptyEngineOverview } from './engine_overview_empty';

describe('EmptyEngineOverview', () => {
let wrapper: ShallowWrapper;
const values = {
isElasticsearchEngine: false,
engine: {
elasticsearchIndexName: 'my-elasticsearch-index',
},
};

beforeAll(() => {
setMockValues(values);
wrapper = shallow(<EmptyEngineOverview />);
});

beforeEach(() => {
jest.clearAllMocks();
setMockValues(values);
});

it('renders', () => {
expect(getPageTitle(wrapper)).toEqual('Engine setup');
});
Expand All @@ -41,4 +54,11 @@ describe('EmptyEngineOverview', () => {
expect(wrapper.find(DocumentCreationButtons)).toHaveLength(1);
expect(wrapper.find(DocumentCreationFlyout)).toHaveLength(1);
});

it('renders elasticsearch index empty state', () => {
setMockValues({ ...values, isElasticsearchEngine: true });
wrapper = shallow(<EmptyEngineOverview />);

expect(wrapper.find('[data-test-subj="ElasticsearchIndexEmptyState"]')).toHaveLength(1);
});
});
Loading

0 comments on commit 2b4d721

Please sign in to comment.