Skip to content

Commit

Permalink
[App Search] Migrate Create Meta Engine View (#92127)
Browse files Browse the repository at this point in the history
* New empty MetaEngineCreation component

* Added MetaEngineCreation to AppSearchConfigured router

* Empty MetaEngineCreationLogic

* Add rawName value and setRawName action to MetaEngineCreationLogic

* Add indexedEngineNames value and setIndexedEngineNames action to MEtaEngineCreationLogic

* Add selectedIndexedEngineNames value and setIndexedEngineNames action to MetaEngineCreationLogic

* Add description to MetaEngineCreation

* Add name selector to MetaEngineCreationLogic

* Added MetaEngineCreationNameInput to MetaEngineCreation

* Add fetchIndexedEngineNames listener to MetaEngineCreationLogic

* Call fetchIndexedEngineNames when MetaEngineCreation first renders

* Add EuiComboBox for selectedEngineNames to MetaEngineCreation

* WIP Add meta engine source engine limit warning to MetaEngineCreation

* Add submitEngine listener to MetaEngineCreationLogic

* Add onEngineCreationSuccess to MetaEngineCreationLogic

* Fixing tests for MetaEngineCreationLogic

* Fix tests for MetaEngineCreation

* Add Create a meta engine button to EnginesOverview

* Use DEFAULT_META for fetching indexed engine names in MetaEngineCreationLogic

* Copy fixes

* Updating POST /api/engines tests

* Add noItemsMessage prop to EnginesTable

* Add empty prompt to Meta Engines table in EnginesOverview

* Apply suggestions from code review

Co-authored-by: Constance <[email protected]>

* Better form functionality in MetaEngineCreation

* Fix errors from github

* More MetaEngineCreation coverage

* Meta MetaEngineCreationLogic coverage

* Update x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation_logic.ts

Co-authored-by: Constance <[email protected]>

* Update x-pack/plugins/enterprise_search/public/applications/app_search/components/meta_engine_creation/meta_engine_creation_logic.ts

Co-authored-by: Constance <[email protected]>

* Update x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/constants.ts

Co-authored-by: Constance <[email protected]>

Co-authored-by: Constance <[email protected]>
  • Loading branch information
byronhulcher and Constance authored Mar 2, 2021
1 parent 41b81a1 commit 3d06573
Show file tree
Hide file tree
Showing 16 changed files with 981 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,25 @@ export const CREATE_AN_ENGINE_BUTTON_LABEL = i18n.translate(
defaultMessage: 'Create an engine',
}
);

export const CREATE_A_META_ENGINE_BUTTON_LABEL = i18n.translate(
'xpack.enterpriseSearch.appSearch.engines.createAMetaEngineButton.ButtonLabel',
{
defaultMessage: 'Create a meta engine',
}
);

export const META_ENGINE_EMPTY_PROMPT_TITLE = i18n.translate(
'xpack.enterpriseSearch.appSearch.engines.metaEngines.emptyPrompTitle',
{
defaultMessage: 'No meta engines yet',
}
);

export const META_ENGINE_EMPTY_PROMPT_DESCRIPTION = i18n.translate(
'xpack.enterpriseSearch.appSearch.engines.metaEngines.emptyPromptDescription',
{
defaultMessage:
'Meta engines allow you to combine multiple engines into one searchable engine.',
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ import React from 'react';

import { shallow, ShallowWrapper } from 'enzyme';

import { EuiEmptyPrompt } from '@elastic/eui';

import { LoadingState, EmptyState } from './components';
import { EnginesTable } from './engines_table';

import { EnginesOverview } from './';

describe('EnginesOverview', () => {
const values = {
hasPlatinumLicense: false,
dataLoading: false,
engines: [],
enginesMeta: {
Expand All @@ -39,6 +40,7 @@ describe('EnginesOverview', () => {
},
},
metaEnginesLoading: false,
hasPlatinumLicense: false,
};
const actions = {
loadEngines: jest.fn(),
Expand Down Expand Up @@ -73,7 +75,7 @@ describe('EnginesOverview', () => {
const valuesWithEngines = {
...values,
dataLoading: false,
engines: ['dummy-engine'],
engines: ['test-engine'],
enginesMeta: {
page: {
current: 1,
Expand All @@ -84,6 +86,7 @@ describe('EnginesOverview', () => {
};

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

Expand All @@ -102,18 +105,47 @@ describe('EnginesOverview', () => {
).toEqual('/engine_creation');
});

describe('when on a platinum license', () => {
it('renders a 2nd meta engines table & makes a 2nd meta engines API call', async () => {
describe('when user has a platinum license', () => {
let wrapper: ShallowWrapper;

beforeEach(() => {
setMockValues({
...valuesWithEngines,
hasPlatinumLicense: true,
metaEngines: ['dummy-meta-engine'],
});
const wrapper = shallow(<EnginesOverview />);
wrapper = shallow(<EnginesOverview />);
});

it('renders a 2nd meta engines table ', async () => {
expect(wrapper.find(EnginesTable)).toHaveLength(2);
});

it('makes a 2nd meta engines call', () => {
expect(actions.loadMetaEngines).toHaveBeenCalled();
});

it('renders a create engine button which takes users to the create meta engine page', () => {
expect(
wrapper.find('[data-test-subj="appSearchEnginesMetaEngineCreationButton"]').prop('to')
).toEqual('/meta_engine_creation');
});

it('contains an EuiEmptyPrompt that takes users to the create meta when metaEngines is empty', () => {
setMockValues({
...valuesWithEngines,
hasPlatinumLicense: true,
metaEngines: [],
});
wrapper = shallow(<EnginesOverview />);
const metaEnginesTable = wrapper.find(EnginesTable).last().dive();
const emptyPrompt = metaEnginesTable.dive().find(EuiEmptyPrompt).dive();

expect(
emptyPrompt
.find('[data-test-subj="appSearchMetaEnginesEmptyStateCreationButton"]')
.prop('to')
).toEqual('/meta_engine_creation');
});
});

describe('pagination', () => {
Expand Down Expand Up @@ -150,7 +182,7 @@ describe('EnginesOverview', () => {
setMockValues({
...valuesWithEngines,
hasPlatinumLicense: true,
metaEngines: ['dummy-meta-engine'],
metaEngines: ['test-meta-engine'],
});
const wrapper = shallow(<EnginesOverview />);
const pageEvent = { page: { index: 0 } };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
EuiPageContentBody,
EuiTitle,
EuiSpacer,
EuiEmptyPrompt,
} from '@elastic/eui';

import { FlashMessages } from '../../../shared/flash_messages';
Expand All @@ -24,19 +25,27 @@ import { LicensingLogic } from '../../../shared/licensing';
import { EuiButtonTo } from '../../../shared/react_router_helpers';
import { convertMetaToPagination, handlePageChange } from '../../../shared/table_pagination';
import { SendAppSearchTelemetry as SendTelemetry } from '../../../shared/telemetry';
import { ENGINE_CREATION_PATH } from '../../routes';
import { ENGINE_CREATION_PATH, META_ENGINE_CREATION_PATH } from '../../routes';

import { EngineIcon } from './assets/engine_icon';
import { MetaEngineIcon } from './assets/meta_engine_icon';
import { EnginesOverviewHeader, LoadingState, EmptyState } from './components';
import { CREATE_AN_ENGINE_BUTTON_LABEL, ENGINES_TITLE, META_ENGINES_TITLE } from './constants';
import {
CREATE_AN_ENGINE_BUTTON_LABEL,
CREATE_A_META_ENGINE_BUTTON_LABEL,
ENGINES_TITLE,
META_ENGINE_EMPTY_PROMPT_DESCRIPTION,
META_ENGINE_EMPTY_PROMPT_TITLE,
META_ENGINES_TITLE,
} from './constants';
import { EnginesLogic } from './engines_logic';
import { EnginesTable } from './engines_table';

import './engines_overview.scss';

export const EnginesOverview: React.FC = () => {
const { hasPlatinumLicense } = useValues(LicensingLogic);

const {
dataLoading,
engines,
Expand All @@ -46,6 +55,7 @@ export const EnginesOverview: React.FC = () => {
metaEnginesMeta,
metaEnginesLoading,
} = useValues(EnginesLogic);

const { loadEngines, loadMetaEngines, onEnginesPagination, onMetaEnginesPagination } = useActions(
EnginesLogic
);
Expand Down Expand Up @@ -100,15 +110,27 @@ export const EnginesOverview: React.FC = () => {
/>
</EuiPageContentBody>

{metaEngines.length > 0 && (
{hasPlatinumLicense && (
<>
<EuiSpacer size="xl" />
<EuiPageContentHeader>
<EuiTitle size="s">
<h2>
<MetaEngineIcon /> {META_ENGINES_TITLE}
</h2>
</EuiTitle>
<EuiPageContentHeaderSection>
<EuiTitle size="s">
<h2>
<MetaEngineIcon /> {META_ENGINES_TITLE}
</h2>
</EuiTitle>
</EuiPageContentHeaderSection>
<EuiPageContentHeaderSection>
<EuiButtonTo
color="primary"
fill
data-test-subj="appSearchEnginesMetaEngineCreationButton"
to={META_ENGINE_CREATION_PATH}
>
{CREATE_A_META_ENGINE_BUTTON_LABEL}
</EuiButtonTo>
</EuiPageContentHeaderSection>
</EuiPageContentHeader>
<EuiPageContentBody data-test-subj="appSearchMetaEngines">
<EnginesTable
Expand All @@ -118,6 +140,21 @@ export const EnginesOverview: React.FC = () => {
...convertMetaToPagination(metaEnginesMeta),
hidePerPageOptions: true,
}}
noItemsMessage={
<EuiEmptyPrompt
title={<h2>{META_ENGINE_EMPTY_PROMPT_TITLE}</h2>}
body={<p>{META_ENGINE_EMPTY_PROMPT_DESCRIPTION}</p>}
actions={
<EuiButtonTo
data-test-subj="appSearchMetaEnginesEmptyStateCreationButton"
fill
to={META_ENGINE_CREATION_PATH}
>
{CREATE_A_META_ENGINE_BUTTON_LABEL}
</EuiButtonTo>
}
/>
}
onChange={handlePageChange(onMetaEnginesPagination)}
/>
</EuiPageContentBody>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ describe('EnginesTable', () => {
});
});

describe('noItemsMessage', () => {
it('passes the noItemsMessage prop', () => {
const wrapper = mountWithIntl(<EnginesTable {...props} noItemsMessage={'No items.'} />);
expect(wrapper.find(EuiBasicTable).prop('noItemsMessage')).toEqual('No items.');
});
});

describe('language field', () => {
it('renders language when available', () => {
const wrapper = mountWithIntl(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import React from 'react';
import React, { ReactNode } from 'react';

import { useActions } from 'kea';

Expand All @@ -24,6 +24,7 @@ import { EngineDetails } from '../engine/types';
interface EnginesTableProps {
items: EngineDetails[];
loading: boolean;
noItemsMessage?: ReactNode;
pagination: {
pageIndex: number;
pageSize: number;
Expand All @@ -36,6 +37,7 @@ interface EnginesTableProps {
export const EnginesTable: React.FC<EnginesTableProps> = ({
items,
loading,
noItemsMessage,
pagination,
onChange,
}) => {
Expand Down Expand Up @@ -148,6 +150,7 @@ export const EnginesTable: React.FC<EnginesTableProps> = ({
loading={loading}
pagination={pagination}
onChange={onChange}
noItemsMessage={noItemsMessage}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* 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 { EuiLink } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';

import { DOCS_PREFIX } from '../../routes';

export const DEFAULT_LANGUAGE = 'Universal';

export const META_ENGINE_CREATION_TITLE = i18n.translate(
'xpack.enterpriseSearch.appSearch.metaEngineCreation.title',
{
defaultMessage: 'Create a meta engine',
}
);

export const META_ENGINE_CREATION_FORM_TITLE = i18n.translate(
'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.title',
{
defaultMessage: 'Name your meta engine',
}
);

export const META_ENGINE_CREATION_FORM_SUBMIT_BUTTON_LABEL = i18n.translate(
'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.submitButton.buttonLabel',
{
defaultMessage: 'Create meta engine',
}
);

export const META_ENGINE_CREATION_FORM_META_ENGINE_DESCRIPTION = i18n.translate(
'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.metaEngineDescription',
{
defaultMessage:
'Meta engines allow you to combine multiple engines into one searchable engine.',
}
);

export const META_ENGINE_CREATION_FORM_DOCUMENTATION_LINK = i18n.translate(
'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.documentationLink',
{
defaultMessage: 'Read the documentation',
}
);

export const META_ENGINE_CREATION_FORM_DOCUMENTATION_DESCRIPTION = (
<FormattedMessage
id="xpack.enterpriseSearch.appSearch.metaEngineCreation.form.documentationDescription"
defaultMessage="{documentationLink} for information about how to get started."
values={{
documentationLink: (
<EuiLink href={`${DOCS_PREFIX}/meta-engines-guide.html`} target="_blank">
{META_ENGINE_CREATION_FORM_DOCUMENTATION_LINK}
</EuiLink>
),
}}
/>
);

export const META_ENGINE_CREATION_FORM_ENGINE_NAME_LABEL = i18n.translate(
'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.engineName.label',
{
defaultMessage: 'Meta engine name',
}
);

export const ALLOWED_CHARS_NOTE = i18n.translate(
'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.engineName.allowedCharactersHelpText',
{
defaultMessage: 'Meta engine names can only contain lowercase letters, numbers, and hyphens',
}
);

export const SANITIZED_NAME_NOTE = i18n.translate(
'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.engineName.sanitizedNameHelpText',
{
defaultMessage: 'Your meta engine will be named',
}
);

export const META_ENGINE_CREATION_FORM_ENGINE_NAME_PLACEHOLDER = i18n.translate(
'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.engineName.placeholder',
{
defaultMessage: 'i.e., my-meta-engine',
}
);

export const META_ENGINE_CREATION_FORM_ENGINE_SOURCE_ENGINES_LABEL = i18n.translate(
'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.sourceEngines.label',
{
defaultMessage: 'Add source engines to this meta engine',
}
);

export const META_ENGINE_CREATION_FORM_MAX_SOURCE_ENGINES_WARNING_TITLE = (
maxEnginesPerMetaEngine: number
) =>
i18n.translate(
'xpack.enterpriseSearch.appSearch.metaEngineCreation.form.sourceEngines.maxSourceEnginesWarningTitle',
{
defaultMessage: 'Meta engines have a limit of {maxEnginesPerMetaEngine} source engines',
values: { maxEnginesPerMetaEngine },
}
);

export const META_ENGINE_CREATION_SUCCESS_MESSAGE = i18n.translate(
'xpack.enterpriseSearch.appSearch.metaEngineCreation.successMessage',
{
defaultMessage: 'Successfully created meta engine.',
}
);
Loading

0 comments on commit 3d06573

Please sign in to comment.